diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index c17cd4bb2290..1b777b960492 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -328,8 +328,6 @@ sysrq.txt - info on the magic SysRq key. telephony/ - directory with info on telephony (e.g. voice over IP) support. -uml/ - - directory with information about User Mode Linux. unicode.txt - info on the Unicode character/font mapping used in Linux. unshare.txt diff --git a/Documentation/ABI/testing/sysfs-bus-bcma b/Documentation/ABI/testing/sysfs-bus-bcma new file mode 100644 index 000000000000..06b62badddd1 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-bcma @@ -0,0 +1,31 @@ +What: /sys/bus/bcma/devices/.../manuf +Date: May 2011 +KernelVersion: 2.6.40 +Contact: Rafał Miłecki +Description: + Each BCMA core has it's manufacturer id. See + include/linux/bcma/bcma.h for possible values. + +What: /sys/bus/bcma/devices/.../id +Date: May 2011 +KernelVersion: 2.6.40 +Contact: Rafał Miłecki +Description: + There are a few types of BCMA cores, they can be identified by + id field. + +What: /sys/bus/bcma/devices/.../rev +Date: May 2011 +KernelVersion: 2.6.40 +Contact: Rafał Miłecki +Description: + BCMA cores of the same type can still slightly differ depending + on their revision. Use it for detailed programming. + +What: /sys/bus/bcma/devices/.../class +Date: May 2011 +KernelVersion: 2.6.40 +Contact: Rafał Miłecki +Description: + Each BCMA core is identified by few fields, including class it + belongs to. See include/linux/bcma/bcma.h for possible values. diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index 7564e88bfa43..e7be75b96e4b 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -183,21 +183,21 @@ Description: Discover and change clock speed of CPUs to learn how to control the knobs. -What: /sys/devices/system/cpu/cpu*/cache/index*/cache_disable_X -Date: August 2008 +What: /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1} +Date: August 2008 KernelVersion: 2.6.27 -Contact: mark.langsdorf@amd.com -Description: These files exist in every cpu's cache index directories. - There are currently 2 cache_disable_# files in each - directory. Reading from these files on a supported - processor will return that cache disable index value - for that processor and node. Writing to one of these - files will cause the specificed cache index to be disabled. +Contact: discuss@x86-64.org +Description: Disable L3 cache indices - Currently, only AMD Family 10h Processors support cache index - disable, and only for their L3 caches. See the BIOS and - Kernel Developer's Guide at - http://support.amd.com/us/Embedded_TechDocs/31116-Public-GH-BKDG_3-28_5-28-09.pdf - for formatting information and other details on the - cache index disable. -Users: joachim.deguara@amd.com + These files exist in every CPU's cache/index3 directory. Each + cache_disable_{0,1} file corresponds to one disable slot which + can be used to disable a cache index. Reading from these files + on a processor with this functionality will return the currently + disabled index for that node. There is one L3 structure per + node, or per internal node on MCM machines. Writing a valid + index to one of these files will cause the specificed cache + index to be disabled. + + All AMD processors with L3 caches provide this functionality. + For details, see BKDGs at + http://developer.amd.com/documentation/guides/Pages/default.aspx diff --git a/Documentation/ABI/testing/sysfs-firmware-dmi b/Documentation/ABI/testing/sysfs-firmware-dmi index ba9da9503c23..c78f9ab01e56 100644 --- a/Documentation/ABI/testing/sysfs-firmware-dmi +++ b/Documentation/ABI/testing/sysfs-firmware-dmi @@ -14,14 +14,15 @@ Description: DMI is structured as a large table of entries, where each entry has a common header indicating the type and - length of the entry, as well as 'handle' that is - supposed to be unique amongst all entries. + length of the entry, as well as a firmware-provided + 'handle' that is supposed to be unique amongst all + entries. Some entries are required by the specification, but many others are optional. In general though, users should never expect to find a specific entry type on their system unless they know for certain what their firmware - is doing. Machine to machine will vary. + is doing. Machine to machine experiences will vary. Multiple entries of the same type are allowed. In order to handle these duplicate entry types, each entry is @@ -67,25 +68,24 @@ Description: and the two terminating nul characters. type : The type of the entry. This value is the same as found in the directory name. It indicates - how the rest of the entry should be - interpreted. + how the rest of the entry should be interpreted. instance: The instance ordinal of the entry for the given type. This value is the same as found in the parent directory name. - position: The position of the entry within the entirety - of the entirety. + position: The ordinal position (zero-based) of the entry + within the entirety of the DMI entry table. === Entry Specialization === Some entry types may have other information available in - sysfs. + sysfs. Not all types are specialized. --- Type 15 - System Event Log --- This entry allows the firmware to export a log of events the system has taken. This information is typically backed by nvram, but the implementation - details are abstracted by this table. This entries data + details are abstracted by this table. This entry's data is exported in the directory: /sys/firmware/dmi/entries/15-0/system_event_log diff --git a/Documentation/ABI/testing/sysfs-firmware-gsmi b/Documentation/ABI/testing/sysfs-firmware-gsmi new file mode 100644 index 000000000000..0faa0aaf4b6a --- /dev/null +++ b/Documentation/ABI/testing/sysfs-firmware-gsmi @@ -0,0 +1,58 @@ +What: /sys/firmware/gsmi +Date: March 2011 +Contact: Mike Waychison +Description: + Some servers used internally at Google have firmware + that provides callback functionality via explicit SMI + triggers. Some of the callbacks are similar to those + provided by the EFI runtime services page, but due to + historical reasons this different entry-point has been + used. + + The gsmi driver implements the kernel's abstraction for + these firmware callbacks. Currently, this functionality + is limited to handling the system event log and getting + access to EFI-style variables stored in nvram. + + Layout: + + /sys/firmware/gsmi/vars: + + This directory has the same layout (and + underlying implementation as /sys/firmware/efi/vars. + See Documentation/ABI/*/sysfs-firmware-efi-vars + for more information on how to interact with + this structure. + + /sys/firmware/gsmi/append_to_eventlog - write-only: + + This file takes a binary blob and passes it onto + the firmware to be timestamped and appended to + the system eventlog. The binary format is + interpreted by the firmware and may change from + platform to platform. The only kernel-enforced + requirement is that the blob be prefixed with a + 32bit host-endian type used as part of the + firmware call. + + /sys/firmware/gsmi/clear_config - write-only: + + Writing any value to this file will cause the + entire firmware configuration to be reset to + "factory defaults". Callers should assume that + a reboot is required for the configuration to be + cleared. + + /sys/firmware/gsmi/clear_eventlog - write-only: + + This file is used to clear out a portion/the + whole of the system event log. Values written + should be values between 1 and 100 inclusive (in + ASCII) representing the fraction of the log to + clear. Not all platforms support fractional + clearing though, and this writes to this file + will error out if the firmware doesn't like your + submitted fraction. + + Callers should assume that a reboot is needed + for this operation to complete. diff --git a/Documentation/ABI/testing/sysfs-firmware-log b/Documentation/ABI/testing/sysfs-firmware-log new file mode 100644 index 000000000000..9b58e7c5365f --- /dev/null +++ b/Documentation/ABI/testing/sysfs-firmware-log @@ -0,0 +1,7 @@ +What: /sys/firmware/log +Date: February 2011 +Contact: Mike Waychison +Description: + The /sys/firmware/log is a binary file that represents a + read-only copy of the firmware's log if one is + available. diff --git a/Documentation/ABI/testing/sysfs-kernel-fscaps b/Documentation/ABI/testing/sysfs-kernel-fscaps new file mode 100644 index 000000000000..50a3033b5e15 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-fscaps @@ -0,0 +1,8 @@ +What: /sys/kernel/fscaps +Date: February 2011 +KernelVersion: 2.6.38 +Contact: Ludwig Nussel +Description + Shows whether file system capabilities are honored + when executing a binary + diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index 194ca446ac28..b464d12761ba 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -158,3 +158,17 @@ Description: successful, will make the kernel abort a subsequent transition to a sleep state if any wakeup events are reported after the write has returned. + +What: /sys/power/reserved_size +Date: May 2011 +Contact: Rafael J. Wysocki +Description: + The /sys/power/reserved_size file allows user space to control + the amount of memory reserved for allocations made by device + drivers during the "device freeze" stage of hibernation. It can + be written a string representing a non-negative integer that + will be used as the amount of memory to reserve for allocations + made by device drivers' "freeze" callbacks, in bytes. + + Reading from this file will display the current value, which is + set to 1 MB by default. diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index 36f63d4a0a06..b638e50cf8f6 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -96,10 +96,10 @@ X!Iinclude/linux/kobject.h Device drivers infrastructure + The Basic Device Driver-Model Structures +!Iinclude/linux/device.h + Device Drivers Base - !Edrivers/base/driver.c !Edrivers/base/core.c !Edrivers/base/class.c diff --git a/Documentation/DocBook/genericirq.tmpl b/Documentation/DocBook/genericirq.tmpl index fb10fd08c05c..b3422341d65c 100644 --- a/Documentation/DocBook/genericirq.tmpl +++ b/Documentation/DocBook/genericirq.tmpl @@ -191,8 +191,8 @@ Whenever an interrupt triggers, the lowlevel arch code calls into the generic interrupt code by calling desc->handle_irq(). - This highlevel IRQ handling function only uses desc->chip primitives - referenced by the assigned chip descriptor structure. + This highlevel IRQ handling function only uses desc->irq_data.chip + primitives referenced by the assigned chip descriptor structure. @@ -206,11 +206,11 @@ enable_irq() disable_irq_nosync() (SMP only) synchronize_irq() (SMP only) - set_irq_type() - set_irq_wake() - set_irq_data() - set_irq_chip() - set_irq_chip_data() + irq_set_irq_type() + irq_set_irq_wake() + irq_set_handler_data() + irq_set_chip() + irq_set_chip_data() See the autogenerated function documentation for details. @@ -225,6 +225,8 @@ handle_fasteoi_irq handle_simple_irq handle_percpu_irq + handle_edge_eoi_irq + handle_bad_irq The interrupt flow handlers (either predefined or architecture specific) are assigned to specific interrupts by the architecture @@ -241,13 +243,13 @@ default_enable(struct irq_data *data) { - desc->chip->irq_unmask(data); + desc->irq_data.chip->irq_unmask(data); } default_disable(struct irq_data *data) { if (!delay_disable(data)) - desc->chip->irq_mask(data); + desc->irq_data.chip->irq_mask(data); } default_ack(struct irq_data *data) @@ -284,9 +286,9 @@ noop(struct irq_data *data)) The following control flow is implemented (simplified excerpt): -desc->chip->irq_mask(); -handle_IRQ_event(desc->action); -desc->chip->irq_unmask(); +desc->irq_data.chip->irq_mask_ack(); +handle_irq_event(desc->action); +desc->irq_data.chip->irq_unmask(); @@ -300,8 +302,8 @@ desc->chip->irq_unmask(); The following control flow is implemented (simplified excerpt): -handle_IRQ_event(desc->action); -desc->chip->irq_eoi(); +handle_irq_event(desc->action); +desc->irq_data.chip->irq_eoi(); @@ -315,17 +317,17 @@ desc->chip->irq_eoi(); The following control flow is implemented (simplified excerpt): if (desc->status & running) { - desc->chip->irq_mask(); + desc->irq_data.chip->irq_mask_ack(); desc->status |= pending | masked; return; } -desc->chip->irq_ack(); +desc->irq_data.chip->irq_ack(); desc->status |= running; do { if (desc->status & masked) - desc->chip->irq_unmask(); + desc->irq_data.chip->irq_unmask(); desc->status &= ~pending; - handle_IRQ_event(desc->action); + handle_irq_event(desc->action); } while (status & pending); desc->status &= ~running; @@ -344,7 +346,7 @@ desc->status &= ~running; The following control flow is implemented (simplified excerpt): -handle_IRQ_event(desc->action); +handle_irq_event(desc->action); @@ -362,12 +364,29 @@ handle_IRQ_event(desc->action); The following control flow is implemented (simplified excerpt): -handle_IRQ_event(desc->action); -if (desc->chip->irq_eoi) - desc->chip->irq_eoi(); +if (desc->irq_data.chip->irq_ack) + desc->irq_data.chip->irq_ack(); +handle_irq_event(desc->action); +if (desc->irq_data.chip->irq_eoi) + desc->irq_data.chip->irq_eoi(); + + EOI Edge IRQ flow handler + + handle_edge_eoi_irq provides an abnomination of the edge + handler which is solely used to tame a badly wreckaged + irq controller on powerpc/cell. + + + + Bad IRQ flow handler + + handle_bad_irq is used for spurious interrupts which + have no real handler assigned.. + + Quirks and optimizations @@ -410,6 +429,7 @@ if (desc->chip->irq_eoi) irq_mask_ack() - Optional, recommended for performance irq_mask() irq_unmask() + irq_eoi() - Optional, required for eoi flow handlers irq_retrigger() - Optional irq_set_type() - Optional irq_set_wake() - Optional @@ -424,32 +444,24 @@ if (desc->chip->irq_eoi) __do_IRQ entry point - The original implementation __do_IRQ() is an alternative entry - point for all types of interrupts. + The original implementation __do_IRQ() was an alternative entry + point for all types of interrupts. It not longer exists. This handler turned out to be not suitable for all interrupt hardware and was therefore reimplemented with split - functionality for egde/level/simple/percpu interrupts. This is not + functionality for edge/level/simple/percpu interrupts. This is not only a functional optimization. It also shortens code paths for interrupts. - - To make use of the split implementation, replace the call to - __do_IRQ by a call to desc->handle_irq() and associate - the appropriate handler function to desc->handle_irq(). - In most cases the generic handler implementations should - be sufficient. - Locking on SMP The locking of chip registers is up to the architecture that - defines the chip primitives. There is a chip->lock field that can be used - for serialization, but the generic layer does not touch it. The per-irq - structure is protected via desc->lock, by the generic layer. + defines the chip primitives. The per-irq structure is + protected via desc->lock, by the generic layer. diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl index 5d259c632cdf..fea63b45471a 100644 --- a/Documentation/DocBook/media-entities.tmpl +++ b/Documentation/DocBook/media-entities.tmpl @@ -294,6 +294,7 @@ + diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml index 2331e76ded17..cec97af4dab4 100644 --- a/Documentation/DocBook/v4l/media-ioc-setup-link.xml +++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml @@ -34,7 +34,7 @@ request - MEDIA_IOC_ENUM_LINKS + MEDIA_IOC_SETUP_LINK diff --git a/Documentation/DocBook/v4l/pixfmt-y12.xml b/Documentation/DocBook/v4l/pixfmt-y12.xml new file mode 100644 index 000000000000..ff417b858cc9 --- /dev/null +++ b/Documentation/DocBook/v4l/pixfmt-y12.xml @@ -0,0 +1,79 @@ + + + V4L2_PIX_FMT_Y12 ('Y12 ') + &manvol; + + + V4L2_PIX_FMT_Y12 + Grey-scale image + + + Description + + This is a grey-scale image with a depth of 12 bits per pixel. Pixels +are stored in 16-bit words with unused high bits padded with 0. The least +significant byte is stored at lower memory addresses (little-endian). + + + <constant>V4L2_PIX_FMT_Y12</constant> 4 × 4 +pixel image + + + Byte Order. + Each cell is one byte. + + + + + + start + 0: + Y'00low + Y'00high + Y'01low + Y'01high + Y'02low + Y'02high + Y'03low + Y'03high + + + start + 8: + Y'10low + Y'10high + Y'11low + Y'11high + Y'12low + Y'12high + Y'13low + Y'13high + + + start + 16: + Y'20low + Y'20high + Y'21low + Y'21high + Y'22low + Y'22high + Y'23low + Y'23high + + + start + 24: + Y'30low + Y'30high + Y'31low + Y'31high + Y'32low + Y'32high + Y'33low + Y'33high + + + + + + + + + diff --git a/Documentation/DocBook/v4l/pixfmt.xml b/Documentation/DocBook/v4l/pixfmt.xml index c6fdcbbd1b41..40af4beb48b9 100644 --- a/Documentation/DocBook/v4l/pixfmt.xml +++ b/Documentation/DocBook/v4l/pixfmt.xml @@ -696,6 +696,7 @@ information. &sub-packed-yuv; &sub-grey; &sub-y10; + &sub-y12; &sub-y16; &sub-yuyv; &sub-uyvy; diff --git a/Documentation/DocBook/v4l/subdev-formats.xml b/Documentation/DocBook/v4l/subdev-formats.xml index 7041127d6dfc..d7ccd25edcc1 100644 --- a/Documentation/DocBook/v4l/subdev-formats.xml +++ b/Documentation/DocBook/v4l/subdev-formats.xml @@ -456,6 +456,23 @@ b1 b0 + + V4L2_MBUS_FMT_SGBRG8_1X8 + 0x3013 + + - + - + - + - + g7 + g6 + g5 + g4 + g3 + g2 + g1 + g0 + V4L2_MBUS_FMT_SGRBG8_1X8 0x3002 @@ -473,6 +490,23 @@ g1 g0 + + V4L2_MBUS_FMT_SRGGB8_1X8 + 0x3014 + + - + - + - + - + r7 + r6 + r5 + r4 + r3 + r2 + r1 + r0 + V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 0x300b @@ -2159,6 +2193,31 @@ u1 u0 + + V4L2_MBUS_FMT_Y12_1X12 + 0x2013 + + - + - + - + - + - + - + - + - + y11 + y10 + y9 + y8 + y7 + y6 + y5 + y4 + y3 + y2 + y1 + y0 + V4L2_MBUS_FMT_UYVY8_1X16 0x200f diff --git a/Documentation/RCU/00-INDEX b/Documentation/RCU/00-INDEX index 71b6f500ddb9..1d7a885761f5 100644 --- a/Documentation/RCU/00-INDEX +++ b/Documentation/RCU/00-INDEX @@ -21,7 +21,7 @@ rcu.txt RTFP.txt - List of RCU papers (bibliography) going back to 1980. stallwarn.txt - - RCU CPU stall warnings (CONFIG_RCU_CPU_STALL_DETECTOR) + - RCU CPU stall warnings (module parameter rcu_cpu_stall_suppress) torture.txt - RCU Torture Test Operation (CONFIG_RCU_TORTURE_TEST) trace.txt diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index 862c08ef1fde..4e959208f736 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -1,22 +1,25 @@ Using RCU's CPU Stall Detector -The CONFIG_RCU_CPU_STALL_DETECTOR kernel config parameter enables -RCU's CPU stall detector, which detects conditions that unduly delay -RCU grace periods. The stall detector's idea of what constitutes -"unduly delayed" is controlled by a set of C preprocessor macros: +The rcu_cpu_stall_suppress module parameter enables RCU's CPU stall +detector, which detects conditions that unduly delay RCU grace periods. +This module parameter enables CPU stall detection by default, but +may be overridden via boot-time parameter or at runtime via sysfs. +The stall detector's idea of what constitutes "unduly delayed" is +controlled by a set of kernel configuration variables and cpp macros: -RCU_SECONDS_TILL_STALL_CHECK +CONFIG_RCU_CPU_STALL_TIMEOUT - This macro defines the period of time that RCU will wait from - the beginning of a grace period until it issues an RCU CPU - stall warning. This time period is normally ten seconds. + This kernel configuration parameter defines the period of time + that RCU will wait from the beginning of a grace period until it + issues an RCU CPU stall warning. This time period is normally + ten seconds. RCU_SECONDS_TILL_STALL_RECHECK This macro defines the period of time that RCU will wait after issuing a stall warning until it issues another stall warning - for the same stall. This time period is normally set to thirty - seconds. + for the same stall. This time period is normally set to three + times the check interval plus thirty seconds. RCU_STALL_RAT_DELAY diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 6a8c73f55b80..c078ad48f7a1 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -10,34 +10,46 @@ for rcutree and next for rcutiny. CONFIG_TREE_RCU and CONFIG_TREE_PREEMPT_RCU debugfs Files and Formats -These implementations of RCU provides five debugfs files under the -top-level directory RCU: rcu/rcudata (which displays fields in struct -rcu_data), rcu/rcudata.csv (which is a .csv spreadsheet version of -rcu/rcudata), rcu/rcugp (which displays grace-period counters), -rcu/rcuhier (which displays the struct rcu_node hierarchy), and -rcu/rcu_pending (which displays counts of the reasons that the -rcu_pending() function decided that there was core RCU work to do). +These implementations of RCU provides several debugfs files under the +top-level directory "rcu": + +rcu/rcudata: + Displays fields in struct rcu_data. +rcu/rcudata.csv: + Comma-separated values spreadsheet version of rcudata. +rcu/rcugp: + Displays grace-period counters. +rcu/rcuhier: + Displays the struct rcu_node hierarchy. +rcu/rcu_pending: + Displays counts of the reasons rcu_pending() decided that RCU had + work to do. +rcu/rcutorture: + Displays rcutorture test progress. +rcu/rcuboost: + Displays RCU boosting statistics. Only present if + CONFIG_RCU_BOOST=y. The output of "cat rcu/rcudata" looks as follows: rcu_sched: - 0 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=10951/1 dn=0 df=1101 of=0 ri=36 ql=0 b=10 - 1 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=16117/1 dn=0 df=1015 of=0 ri=0 ql=0 b=10 - 2 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1445/1 dn=0 df=1839 of=0 ri=0 ql=0 b=10 - 3 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=6681/1 dn=0 df=1545 of=0 ri=0 ql=0 b=10 - 4 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1003/1 dn=0 df=1992 of=0 ri=0 ql=0 b=10 - 5 c=17829 g=17830 pq=1 pqc=17829 qp=1 dt=3887/1 dn=0 df=3331 of=0 ri=4 ql=2 b=10 - 6 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=859/1 dn=0 df=3224 of=0 ri=0 ql=0 b=10 - 7 c=17829 g=17830 pq=0 pqc=17829 qp=1 dt=3761/1 dn=0 df=1818 of=0 ri=0 ql=2 b=10 + 0 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=545/1/0 df=50 of=0 ri=0 ql=163 qs=NRW. kt=0/W/0 ktl=ebc3 b=10 ci=153737 co=0 ca=0 + 1 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=967/1/0 df=58 of=0 ri=0 ql=634 qs=NRW. kt=0/W/1 ktl=58c b=10 ci=191037 co=0 ca=0 + 2 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=1081/1/0 df=175 of=0 ri=0 ql=74 qs=N.W. kt=0/W/2 ktl=da94 b=10 ci=75991 co=0 ca=0 + 3 c=20942 g=20943 pq=1 pqc=20942 qp=1 dt=1846/0/0 df=404 of=0 ri=0 ql=0 qs=.... kt=0/W/3 ktl=d1cd b=10 ci=72261 co=0 ca=0 + 4 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=369/1/0 df=83 of=0 ri=0 ql=48 qs=N.W. kt=0/W/4 ktl=e0e7 b=10 ci=128365 co=0 ca=0 + 5 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=381/1/0 df=64 of=0 ri=0 ql=169 qs=NRW. kt=0/W/5 ktl=fb2f b=10 ci=164360 co=0 ca=0 + 6 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=1037/1/0 df=183 of=0 ri=0 ql=62 qs=N.W. kt=0/W/6 ktl=d2ad b=10 ci=65663 co=0 ca=0 + 7 c=20897 g=20897 pq=1 pqc=20896 qp=0 dt=1572/0/0 df=382 of=0 ri=0 ql=0 qs=.... kt=0/W/7 ktl=cf15 b=10 ci=75006 co=0 ca=0 rcu_bh: - 0 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=10951/1 dn=0 df=0 of=0 ri=0 ql=0 b=10 - 1 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=16117/1 dn=0 df=13 of=0 ri=0 ql=0 b=10 - 2 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1445/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 - 3 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=6681/1 dn=0 df=9 of=0 ri=0 ql=0 b=10 - 4 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1003/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 - 5 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3887/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 - 6 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=859/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 - 7 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3761/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 + 0 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=545/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/0 ktl=ebc3 b=10 ci=0 co=0 ca=0 + 1 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=967/1/0 df=3 of=0 ri=1 ql=0 qs=.... kt=0/W/1 ktl=58c b=10 ci=151 co=0 ca=0 + 2 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=1081/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/2 ktl=da94 b=10 ci=0 co=0 ca=0 + 3 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=1846/0/0 df=8 of=0 ri=1 ql=0 qs=.... kt=0/W/3 ktl=d1cd b=10 ci=0 co=0 ca=0 + 4 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=369/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/4 ktl=e0e7 b=10 ci=0 co=0 ca=0 + 5 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=381/1/0 df=4 of=0 ri=1 ql=0 qs=.... kt=0/W/5 ktl=fb2f b=10 ci=0 co=0 ca=0 + 6 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=1037/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/6 ktl=d2ad b=10 ci=0 co=0 ca=0 + 7 c=1474 g=1474 pq=1 pqc=1473 qp=0 dt=1572/0/0 df=8 of=0 ri=1 ql=0 qs=.... kt=0/W/7 ktl=cf15 b=10 ci=0 co=0 ca=0 The first section lists the rcu_data structures for rcu_sched, the second for rcu_bh. Note that CONFIG_TREE_PREEMPT_RCU kernels will have an @@ -52,17 +64,18 @@ o The number at the beginning of each line is the CPU number. substantially larger than the number of actual CPUs. o "c" is the count of grace periods that this CPU believes have - completed. CPUs in dynticks idle mode may lag quite a ways - behind, for example, CPU 4 under "rcu_sched" above, which has - slept through the past 25 RCU grace periods. It is not unusual - to see CPUs lagging by thousands of grace periods. + completed. Offlined CPUs and CPUs in dynticks idle mode may + lag quite a ways behind, for example, CPU 6 under "rcu_sched" + above, which has been offline through not quite 40,000 RCU grace + periods. It is not unusual to see CPUs lagging by thousands of + grace periods. o "g" is the count of grace periods that this CPU believes have - started. Again, CPUs in dynticks idle mode may lag behind. - If the "c" and "g" values are equal, this CPU has already - reported a quiescent state for the last RCU grace period that - it is aware of, otherwise, the CPU believes that it owes RCU a - quiescent state. + started. Again, offlined CPUs and CPUs in dynticks idle mode + may lag behind. If the "c" and "g" values are equal, this CPU + has already reported a quiescent state for the last RCU grace + period that it is aware of, otherwise, the CPU believes that it + owes RCU a quiescent state. o "pq" indicates that this CPU has passed through a quiescent state for the current grace period. It is possible for "pq" to be @@ -81,7 +94,8 @@ o "pqc" indicates which grace period the last-observed quiescent the next grace period! o "qp" indicates that RCU still expects a quiescent state from - this CPU. + this CPU. Offlined CPUs and CPUs in dyntick idle mode might + well have qp=1, which is OK: RCU is still ignoring them. o "dt" is the current value of the dyntick counter that is incremented when entering or leaving dynticks idle state, either by the @@ -108,7 +122,7 @@ o "df" is the number of times that some other CPU has forced a o "of" is the number of times that some other CPU has forced a quiescent state on behalf of this CPU due to this CPU being - offline. In a perfect world, this might neve happen, but it + offline. In a perfect world, this might never happen, but it turns out that offlining and onlining a CPU can take several grace periods, and so there is likely to be an extended period of time when RCU believes that the CPU is online when it really is not. @@ -125,6 +139,62 @@ o "ql" is the number of RCU callbacks currently residing on of what state they are in (new, waiting for grace period to start, waiting for grace period to end, ready to invoke). +o "qs" gives an indication of the state of the callback queue + with four characters: + + "N" Indicates that there are callbacks queued that are not + ready to be handled by the next grace period, and thus + will be handled by the grace period following the next + one. + + "R" Indicates that there are callbacks queued that are + ready to be handled by the next grace period. + + "W" Indicates that there are callbacks queued that are + waiting on the current grace period. + + "D" Indicates that there are callbacks queued that have + already been handled by a prior grace period, and are + thus waiting to be invoked. Note that callbacks in + the process of being invoked are not counted here. + Callbacks in the process of being invoked are those + that have been removed from the rcu_data structures + queues by rcu_do_batch(), but which have not yet been + invoked. + + If there are no callbacks in a given one of the above states, + the corresponding character is replaced by ".". + +o "kt" is the per-CPU kernel-thread state. The digit preceding + the first slash is zero if there is no work pending and 1 + otherwise. The character between the first pair of slashes is + as follows: + + "S" The kernel thread is stopped, in other words, all + CPUs corresponding to this rcu_node structure are + offline. + + "R" The kernel thread is running. + + "W" The kernel thread is waiting because there is no work + for it to do. + + "O" The kernel thread is waiting because it has been + forced off of its designated CPU or because its + ->cpus_allowed mask permits it to run on other than + its designated CPU. + + "Y" The kernel thread is yielding to avoid hogging CPU. + + "?" Unknown value, indicates a bug. + + The number after the final slash is the CPU that the kthread + is actually running on. + +o "ktl" is the low-order 16 bits (in hexadecimal) of the count of + the number of times that this CPU's per-CPU kthread has gone + through its loop servicing invoke_rcu_cpu_kthread() requests. + o "b" is the batch limit for this CPU. If more than this number of RCU callbacks is ready to invoke, then the remainder will be deferred. @@ -174,14 +244,14 @@ o "gpnum" is the number of grace periods that have started. It is The output of "cat rcu/rcuhier" looks as follows, with very long lines: c=6902 g=6903 s=2 jfq=3 j=72c7 nfqs=13142/nfqsng=0(13142) fqlh=6 -1/1 .>. 0:127 ^0 -3/3 .>. 0:35 ^0 0/0 .>. 36:71 ^1 0/0 .>. 72:107 ^2 0/0 .>. 108:127 ^3 -3/3f .>. 0:5 ^0 2/3 .>. 6:11 ^1 0/0 .>. 12:17 ^2 0/0 .>. 18:23 ^3 0/0 .>. 24:29 ^4 0/0 .>. 30:35 ^5 0/0 .>. 36:41 ^0 0/0 .>. 42:47 ^1 0/0 .>. 48:53 ^2 0/0 .>. 54:59 ^3 0/0 .>. 60:65 ^4 0/0 .>. 66:71 ^5 0/0 .>. 72:77 ^0 0/0 .>. 78:83 ^1 0/0 .>. 84:89 ^2 0/0 .>. 90:95 ^3 0/0 .>. 96:101 ^4 0/0 .>. 102:107 ^5 0/0 .>. 108:113 ^0 0/0 .>. 114:119 ^1 0/0 .>. 120:125 ^2 0/0 .>. 126:127 ^3 +1/1 ..>. 0:127 ^0 +3/3 ..>. 0:35 ^0 0/0 ..>. 36:71 ^1 0/0 ..>. 72:107 ^2 0/0 ..>. 108:127 ^3 +3/3f ..>. 0:5 ^0 2/3 ..>. 6:11 ^1 0/0 ..>. 12:17 ^2 0/0 ..>. 18:23 ^3 0/0 ..>. 24:29 ^4 0/0 ..>. 30:35 ^5 0/0 ..>. 36:41 ^0 0/0 ..>. 42:47 ^1 0/0 ..>. 48:53 ^2 0/0 ..>. 54:59 ^3 0/0 ..>. 60:65 ^4 0/0 ..>. 66:71 ^5 0/0 ..>. 72:77 ^0 0/0 ..>. 78:83 ^1 0/0 ..>. 84:89 ^2 0/0 ..>. 90:95 ^3 0/0 ..>. 96:101 ^4 0/0 ..>. 102:107 ^5 0/0 ..>. 108:113 ^0 0/0 ..>. 114:119 ^1 0/0 ..>. 120:125 ^2 0/0 ..>. 126:127 ^3 rcu_bh: c=-226 g=-226 s=1 jfq=-5701 j=72c7 nfqs=88/nfqsng=0(88) fqlh=0 -0/1 .>. 0:127 ^0 -0/3 .>. 0:35 ^0 0/0 .>. 36:71 ^1 0/0 .>. 72:107 ^2 0/0 .>. 108:127 ^3 -0/3f .>. 0:5 ^0 0/3 .>. 6:11 ^1 0/0 .>. 12:17 ^2 0/0 .>. 18:23 ^3 0/0 .>. 24:29 ^4 0/0 .>. 30:35 ^5 0/0 .>. 36:41 ^0 0/0 .>. 42:47 ^1 0/0 .>. 48:53 ^2 0/0 .>. 54:59 ^3 0/0 .>. 60:65 ^4 0/0 .>. 66:71 ^5 0/0 .>. 72:77 ^0 0/0 .>. 78:83 ^1 0/0 .>. 84:89 ^2 0/0 .>. 90:95 ^3 0/0 .>. 96:101 ^4 0/0 .>. 102:107 ^5 0/0 .>. 108:113 ^0 0/0 .>. 114:119 ^1 0/0 .>. 120:125 ^2 0/0 .>. 126:127 ^3 +0/1 ..>. 0:127 ^0 +0/3 ..>. 0:35 ^0 0/0 ..>. 36:71 ^1 0/0 ..>. 72:107 ^2 0/0 ..>. 108:127 ^3 +0/3f ..>. 0:5 ^0 0/3 ..>. 6:11 ^1 0/0 ..>. 12:17 ^2 0/0 ..>. 18:23 ^3 0/0 ..>. 24:29 ^4 0/0 ..>. 30:35 ^5 0/0 ..>. 36:41 ^0 0/0 ..>. 42:47 ^1 0/0 ..>. 48:53 ^2 0/0 ..>. 54:59 ^3 0/0 ..>. 60:65 ^4 0/0 ..>. 66:71 ^5 0/0 ..>. 72:77 ^0 0/0 ..>. 78:83 ^1 0/0 ..>. 84:89 ^2 0/0 ..>. 90:95 ^3 0/0 ..>. 96:101 ^4 0/0 ..>. 102:107 ^5 0/0 ..>. 108:113 ^0 0/0 ..>. 114:119 ^1 0/0 ..>. 120:125 ^2 0/0 ..>. 126:127 ^3 This is once again split into "rcu_sched" and "rcu_bh" portions, and CONFIG_TREE_PREEMPT_RCU kernels will again have an additional @@ -240,13 +310,20 @@ o Each element of the form "1/1 0:127 ^0" represents one struct current grace period. o The characters separated by the ">" indicate the state - of the blocked-tasks lists. A "T" preceding the ">" + of the blocked-tasks lists. A "G" preceding the ">" indicates that at least one task blocked in an RCU read-side critical section blocks the current grace - period, while a "." preceding the ">" indicates otherwise. - The character following the ">" indicates similarly for - the next grace period. A "T" should appear in this - field only for rcu-preempt. + period, while a "E" preceding the ">" indicates that + at least one task blocked in an RCU read-side critical + section blocks the current expedited grace period. + A "T" character following the ">" indicates that at + least one task is blocked within an RCU read-side + critical section, regardless of whether any current + grace period (expedited or normal) is inconvenienced. + A "." character appears if the corresponding condition + does not hold, so that "..>." indicates that no tasks + are blocked. In contrast, "GE>T" indicates maximal + inconvenience from blocked tasks. o The numbers separated by the ":" are the range of CPUs served by this struct rcu_node. This can be helpful @@ -328,6 +405,113 @@ o "nn" is the number of times that this CPU needed nothing. Alert is due to short-circuit evaluation in rcu_pending(). +The output of "cat rcu/rcutorture" looks as follows: + +rcutorture test sequence: 0 (test in progress) +rcutorture update version number: 615 + +The first line shows the number of rcutorture tests that have completed +since boot. If a test is currently running, the "(test in progress)" +string will appear as shown above. The second line shows the number of +update cycles that the current test has started, or zero if there is +no test in progress. + + +The output of "cat rcu/rcuboost" looks as follows: + +0:5 tasks=.... kt=W ntb=0 neb=0 nnb=0 j=2f95 bt=300f + balk: nt=0 egt=989 bt=0 nb=0 ny=0 nos=16 +6:7 tasks=.... kt=W ntb=0 neb=0 nnb=0 j=2f95 bt=300f + balk: nt=0 egt=225 bt=0 nb=0 ny=0 nos=6 + +This information is output only for rcu_preempt. Each two-line entry +corresponds to a leaf rcu_node strcuture. The fields are as follows: + +o "n:m" is the CPU-number range for the corresponding two-line + entry. In the sample output above, the first entry covers + CPUs zero through five and the second entry covers CPUs 6 + and 7. + +o "tasks=TNEB" gives the state of the various segments of the + rnp->blocked_tasks list: + + "T" This indicates that there are some tasks that blocked + while running on one of the corresponding CPUs while + in an RCU read-side critical section. + + "N" This indicates that some of the blocked tasks are preventing + the current normal (non-expedited) grace period from + completing. + + "E" This indicates that some of the blocked tasks are preventing + the current expedited grace period from completing. + + "B" This indicates that some of the blocked tasks are in + need of RCU priority boosting. + + Each character is replaced with "." if the corresponding + condition does not hold. + +o "kt" is the state of the RCU priority-boosting kernel + thread associated with the corresponding rcu_node structure. + The state can be one of the following: + + "S" The kernel thread is stopped, in other words, all + CPUs corresponding to this rcu_node structure are + offline. + + "R" The kernel thread is running. + + "W" The kernel thread is waiting because there is no work + for it to do. + + "Y" The kernel thread is yielding to avoid hogging CPU. + + "?" Unknown value, indicates a bug. + +o "ntb" is the number of tasks boosted. + +o "neb" is the number of tasks boosted in order to complete an + expedited grace period. + +o "nnb" is the number of tasks boosted in order to complete a + normal (non-expedited) grace period. When boosting a task + that was blocking both an expedited and a normal grace period, + it is counted against the expedited total above. + +o "j" is the low-order 16 bits of the jiffies counter in + hexadecimal. + +o "bt" is the low-order 16 bits of the value that the jiffies + counter will have when we next start boosting, assuming that + the current grace period does not end beforehand. This is + also in hexadecimal. + +o "balk: nt" counts the number of times we didn't boost (in + other words, we balked) even though it was time to boost because + there were no blocked tasks to boost. This situation occurs + when there is one blocked task on one rcu_node structure and + none on some other rcu_node structure. + +o "egt" counts the number of times we balked because although + there were blocked tasks, none of them were blocking the + current grace period, whether expedited or otherwise. + +o "bt" counts the number of times we balked because boosting + had already been initiated for the current grace period. + +o "nb" counts the number of times we balked because there + was at least one task blocking the current non-expedited grace + period that never had blocked. If it is already running, it + just won't help to boost its priority! + +o "ny" counts the number of times we balked because it was + not yet time to start boosting. + +o "nos" counts the number of times we balked for other + reasons, e.g., the grace period ended first. + + CONFIG_TINY_RCU and CONFIG_TINY_PREEMPT_RCU debugfs Files and Formats These implementations of RCU provides a single debugfs file under the @@ -394,9 +578,9 @@ o "neb" is the number of expedited grace periods that have had o "nnb" is the number of normal grace periods that have had to resort to RCU priority boosting since boot. -o "j" is the low-order 12 bits of the jiffies counter in hexadecimal. +o "j" is the low-order 16 bits of the jiffies counter in hexadecimal. -o "bt" is the low-order 12 bits of the value that the jiffies counter +o "bt" is the low-order 16 bits of the value that the jiffies counter will have at the next time that boosting is scheduled to begin. o In the line beginning with "normal balk", the fields are as follows: diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index b6ed61c95856..7c163477fcd8 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -52,8 +52,10 @@ Brief summary of control files. tasks # attach a task(thread) and show list of threads cgroup.procs # show list of processes cgroup.event_control # an interface for event_fd() - memory.usage_in_bytes # show current memory(RSS+Cache) usage. - memory.memsw.usage_in_bytes # show current memory+Swap usage + memory.usage_in_bytes # show current res_counter usage for memory + (See 5.5 for details) + memory.memsw.usage_in_bytes # show current res_counter usage for memory+Swap + (See 5.5 for details) memory.limit_in_bytes # set/show limit of memory usage memory.memsw.limit_in_bytes # set/show limit of memory+Swap usage memory.failcnt # show the number of memory usage hits limits @@ -453,6 +455,15 @@ memory under it will be reclaimed. You can reset failcnt by writing 0 to failcnt file. # echo 0 > .../memory.failcnt +5.5 usage_in_bytes + +For efficiency, as other kernel components, memory cgroup uses some optimization +to avoid unnecessary cacheline false sharing. usage_in_bytes is affected by the +method and doesn't show 'exact' value of memory(and swap) usage, it's an fuzz +value for efficient access. (Of course, when necessary, it's synchronized.) +If you want to know more exact memory usage, you should use RSS+CACHE(+SWAP) +value in memory.stat(see 5.2). + 6. Hierarchy support The memory controller supports a deep hierarchy and hierarchical accounting. diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt new file mode 100644 index 000000000000..bf57ecd5d73a --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt @@ -0,0 +1,397 @@ +===================================================================== +SEC 4 Device Tree Binding +Copyright (C) 2008-2011 Freescale Semiconductor Inc. + + CONTENTS + -Overview + -SEC 4 Node + -Job Ring Node + -Run Time Integrity Check (RTIC) Node + -Run Time Integrity Check (RTIC) Memory Node + -Secure Non-Volatile Storage (SNVS) Node + -Full Example + +NOTE: the SEC 4 is also known as Freescale's Cryptographic Accelerator +Accelerator and Assurance Module (CAAM). + +===================================================================== +Overview + +DESCRIPTION + +SEC 4 h/w can process requests from 2 types of sources. +1. DPAA Queue Interface (HW interface between Queue Manager & SEC 4). +2. Job Rings (HW interface between cores & SEC 4 registers). + +High Speed Data Path Configuration: + +HW interface between QM & SEC 4 and also BM & SEC 4, on DPAA-enabled parts +such as the P4080. The number of simultaneous dequeues the QI can make is +equal to the number of Descriptor Controller (DECO) engines in a particular +SEC version. E.g., the SEC 4.0 in the P4080 has 5 DECOs and can thus +dequeue from 5 subportals simultaneously. + +Job Ring Data Path Configuration: + +Each JR is located on a separate 4k page, they may (or may not) be made visible +in the memory partition devoted to a particular core. The P4080 has 4 JRs, so +up to 4 JRs can be configured; and all 4 JRs process requests in parallel. + +===================================================================== +SEC 4 Node + +Description + + Node defines the base address of the SEC 4 block. + This block specifies the address range of all global + configuration registers for the SEC 4 block. It + also receives interrupts from the Run Time Integrity Check + (RTIC) function within the SEC 4 block. + +PROPERTIES + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,sec-v4.0" + + - #address-cells + Usage: required + Value type: + Definition: A standard property. Defines the number of cells + for representing physical addresses in child nodes. + + - #size-cells + Usage: required + Value type: + Definition: A standard property. Defines the number of cells + for representing the size of physical addresses in + child nodes. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical + address and length of the SEC4 configuration registers. + registers + + - ranges + Usage: required + Value type: + Definition: A standard property. Specifies the physical address + range of the SEC 4.0 register space (-SNVS not included). A + triplet that includes the child address, parent address, & + length. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this + device. The value of the interrupts property + consists of one interrupt specifier. The format + of the specifier is defined by the binding document + describing the node's interrupt parent. + + - interrupt-parent + Usage: (required if interrupt property is defined) + Value type: + Definition: A single value that points + to the interrupt parent to which the child domain + is being mapped. + + Note: All other standard properties (see the ePAPR) are allowed + but are optional. + + +EXAMPLE + crypto@300000 { + compatible = "fsl,sec-v4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x300000 0x10000>; + ranges = <0 0x300000 0x10000>; + interrupt-parent = <&mpic>; + interrupts = <92 2>; + }; + +===================================================================== +Job Ring (JR) Node + + Child of the crypto node defines data processing interface to SEC 4 + across the peripheral bus for purposes of processing + cryptographic descriptors. The specified address + range can be made visible to one (or more) cores. + The interrupt defined for this node is controlled within + the address range of this node. + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,sec-v4.0-job-ring" + + - reg + Usage: required + Value type: + Definition: Specifies a two JR parameters: an offset from + the parent physical address and the length the JR registers. + + - fsl,liodn + Usage: optional-but-recommended + Value type: + Definition: + Specifies the LIODN to be used in conjunction with + the ppid-to-liodn table that specifies the PPID to LIODN mapping. + Needed if the PAMU is used. Value is a 12 bit value + where value is a LIODN ID for this JR. This property is + normally set by boot firmware. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this + device. The value of the interrupts property + consists of one interrupt specifier. The format + of the specifier is defined by the binding document + describing the node's interrupt parent. + + - interrupt-parent + Usage: (required if interrupt property is defined) + Value type: + Definition: A single value that points + to the interrupt parent to which the child domain + is being mapped. + +EXAMPLE + jr@1000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x1000 0x1000>; + fsl,liodn = <0x081>; + interrupt-parent = <&mpic>; + interrupts = <88 2>; + }; + + +===================================================================== +Run Time Integrity Check (RTIC) Node + + Child node of the crypto node. Defines a register space that + contains up to 5 sets of addresses and their lengths (sizes) that + will be checked at run time. After an initial hash result is + calculated, these addresses are checked by HW to monitor any + change. If any memory is modified, a Security Violation is + triggered (see SNVS definition). + + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,sec-v4.0-rtic". + + - #address-cells + Usage: required + Value type: + Definition: A standard property. Defines the number of cells + for representing physical addresses in child nodes. Must + have a value of 1. + + - #size-cells + Usage: required + Value type: + Definition: A standard property. Defines the number of cells + for representing the size of physical addresses in + child nodes. Must have a value of 1. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies a two parameters: + an offset from the parent physical address and the length + the SEC4 registers. + + - ranges + Usage: required + Value type: + Definition: A standard property. Specifies the physical address + range of the SEC 4 register space (-SNVS not included). A + triplet that includes the child address, parent address, & + length. + +EXAMPLE + rtic@6000 { + compatible = "fsl,sec-v4.0-rtic"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x6000 0x100>; + ranges = <0x0 0x6100 0xe00>; + }; + +===================================================================== +Run Time Integrity Check (RTIC) Memory Node + A child node that defines individual RTIC memory regions that are used to + perform run-time integrity check of memory areas that should not modified. + The node defines a register that contains the memory address & + length (combined) and a second register that contains the hash result + in big endian format. + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,sec-v4.0-rtic-memory". + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies two parameters: + an offset from the parent physical address and the length: + + 1. The location of the RTIC memory address & length registers. + 2. The location RTIC hash result. + + - fsl,rtic-region + Usage: optional-but-recommended + Value type: + Definition: + Specifies the HW address (36 bit address) for this region + followed by the length of the HW partition to be checked; + the address is represented as a 64 bit quantity followed + by a 32 bit length. + + - fsl,liodn + Usage: optional-but-recommended + Value type: + Definition: + Specifies the LIODN to be used in conjunction with + the ppid-to-liodn table that specifies the PPID to LIODN + mapping. Needed if the PAMU is used. Value is a 12 bit value + where value is a LIODN ID for this RTIC memory region. This + property is normally set by boot firmware. + +EXAMPLE + rtic-a@0 { + compatible = "fsl,sec-v4.0-rtic-memory"; + reg = <0x00 0x20 0x100 0x80>; + fsl,liodn = <0x03c>; + fsl,rtic-region = <0x12345678 0x12345678 0x12345678>; + }; + +===================================================================== +Secure Non-Volatile Storage (SNVS) Node + + Node defines address range and the associated + interrupt for the SNVS function. This function + monitors security state information & reports + security violations. + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,sec-v4.0-mon". + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical + address and length of the SEC4 configuration + registers. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this + device. The value of the interrupts property + consists of one interrupt specifier. The format + of the specifier is defined by the binding document + describing the node's interrupt parent. + + - interrupt-parent + Usage: (required if interrupt property is defined) + Value type: + Definition: A single value that points + to the interrupt parent to which the child domain + is being mapped. + +EXAMPLE + sec_mon@314000 { + compatible = "fsl,sec-v4.0-mon"; + reg = <0x314000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <93 2>; + }; + +===================================================================== +FULL EXAMPLE + + crypto: crypto@300000 { + compatible = "fsl,sec-v4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x300000 0x10000>; + ranges = <0 0x300000 0x10000>; + interrupt-parent = <&mpic>; + interrupts = <92 2>; + + sec_jr0: jr@1000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x1000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <88 2>; + }; + + sec_jr1: jr@2000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <89 2>; + }; + + sec_jr2: jr@3000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x3000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <90 2>; + }; + + sec_jr3: jr@4000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x4000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <91 2>; + }; + + rtic@6000 { + compatible = "fsl,sec-v4.0-rtic"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x6000 0x100>; + ranges = <0x0 0x6100 0xe00>; + + rtic_a: rtic-a@0 { + compatible = "fsl,sec-v4.0-rtic-memory"; + reg = <0x00 0x20 0x100 0x80>; + }; + + rtic_b: rtic-b@20 { + compatible = "fsl,sec-v4.0-rtic-memory"; + reg = <0x20 0x20 0x200 0x80>; + }; + + rtic_c: rtic-c@40 { + compatible = "fsl,sec-v4.0-rtic-memory"; + reg = <0x40 0x20 0x300 0x80>; + }; + + rtic_d: rtic-d@60 { + compatible = "fsl,sec-v4.0-rtic-memory"; + reg = <0x60 0x20 0x500 0x80>; + }; + }; + }; + + sec_mon: sec_mon@314000 { + compatible = "fsl,sec-v4.0-mon"; + reg = <0x314000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <93 2>; + }; + +===================================================================== diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt new file mode 100755 index 000000000000..1a729f089866 --- /dev/null +++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt @@ -0,0 +1,61 @@ +CAN Device Tree Bindings +------------------------ +2011 Freescale Semiconductor, Inc. + +fsl,flexcan-v1.0 nodes +----------------------- +In addition to the required compatible-, reg- and interrupt-properties, you can +also specify which clock source shall be used for the controller. + +CPI Clock- Can Protocol Interface Clock + This CLK_SRC bit of CTRL(control register) selects the clock source to + the CAN Protocol Interface(CPI) to be either the peripheral clock + (driven by the PLL) or the crystal oscillator clock. The selected clock + is the one fed to the prescaler to generate the Serial Clock (Sclock). + The PRESDIV field of CTRL(control register) controls a prescaler that + generates the Serial Clock (Sclock), whose period defines the + time quantum used to compose the CAN waveform. + +Can Engine Clock Source + There are two sources for CAN clock + - Platform Clock It represents the bus clock + - Oscillator Clock + + Peripheral Clock (PLL) + -------------- + | + --------- ------------- + | |CPI Clock | Prescaler | Sclock + | |---------------->| (1.. 256) |------------> + --------- ------------- + | | + -------------- ---------------------CLK_SRC + Oscillator Clock + +- fsl,flexcan-clock-source : CAN Engine Clock Source.This property selects + the peripheral clock. PLL clock is fed to the + prescaler to generate the Serial Clock (Sclock). + Valid values are "oscillator" and "platform" + "oscillator": CAN engine clock source is oscillator clock. + "platform" The CAN engine clock source is the bus clock + (platform clock). + +- fsl,flexcan-clock-divider : for the reference and system clock, an additional + clock divider can be specified. +- clock-frequency: frequency required to calculate the bitrate for FlexCAN. + +Note: + - v1.0 of flexcan-v1.0 represent the IP block version for P1010 SOC. + - P1010 does not have oscillator as the Clock Source.So the default + Clock Source is platform clock. +Examples: + + can0@1c000 { + compatible = "fsl,flexcan-v1.0"; + reg = <0x1c000 0x1000>; + interrupts = <48 0x2>; + interrupt-parent = <&mpic>; + fsl,flexcan-clock-source = "platform"; + fsl,flexcan-clock-divider = <2>; + clock-frequency = ; + }; diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt new file mode 100644 index 000000000000..939a26d541f6 --- /dev/null +++ b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt @@ -0,0 +1,76 @@ +Integrated Flash Controller + +Properties: +- name : Should be ifc +- compatible : should contain "fsl,ifc". The version of the integrated + flash controller can be found in the IFC_REV register at + offset zero. + +- #address-cells : Should be either two or three. The first cell is the + chipselect number, and the remaining cells are the + offset into the chipselect. +- #size-cells : Either one or two, depending on how large each chipselect + can be. +- reg : Offset and length of the register set for the device +- interrupts : IFC has two interrupts. The first one is the "common" + interrupt(CM_EVTER_STAT), and second is the NAND interrupt + (NAND_EVTER_STAT). + +- ranges : Each range corresponds to a single chipselect, and covers + the entire access window as configured. + +Child device nodes describe the devices connected to IFC such as NOR (e.g. +cfi-flash) and NAND (fsl,ifc-nand). There might be board specific devices +like FPGAs, CPLDs, etc. + +Example: + + ifc@ffe1e000 { + compatible = "fsl,ifc", "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0x0 0xffe1e000 0 0x2000>; + interrupts = <16 2 19 2>; + + /* NOR, NAND Flashes and CPLD on board */ + ranges = <0x0 0x0 0x0 0xee000000 0x02000000 + 0x1 0x0 0x0 0xffa00000 0x00010000 + 0x3 0x0 0x0 0xffb00000 0x00020000>; + + flash@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x2000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + /* 32MB for user data */ + reg = <0x0 0x02000000>; + label = "NOR Data"; + }; + }; + + flash@1,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,ifc-nand"; + reg = <0x1 0x0 0x10000>; + + partition@0 { + /* This location must not be altered */ + /* 1MB for u-boot Bootloader Image */ + reg = <0x0 0x00100000>; + label = "NAND U-Boot Image"; + read-only; + }; + }; + + cpld@3,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,p1010rdb-cpld"; + reg = <0x3 0x0 0x000001f>; + }; + }; diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic-timer.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic-timer.txt new file mode 100644 index 000000000000..df41958140e8 --- /dev/null +++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic-timer.txt @@ -0,0 +1,38 @@ +* Freescale MPIC timers + +Required properties: +- compatible: "fsl,mpic-global-timer" + +- reg : Contains two regions. The first is the main timer register bank + (GTCCRxx, GTBCRxx, GTVPRxx, GTDRxx). The second is the timer control + register (TCRx) for the group. + +- fsl,available-ranges: use style section to define which + timer interrupts can be used. This property is optional; without this, + all timers within the group can be used. + +- interrupts: one interrupt per timer in the group, in order, starting + with timer zero. If timer-available-ranges is present, only the + interrupts that correspond to available timers shall be present. + +Example: + /* Note that this requires #interrupt-cells to be 4 */ + timer0: timer@41100 { + compatible = "fsl,mpic-global-timer"; + reg = <0x41100 0x100 0x41300 4>; + + /* Another AMP partition is using timers 0 and 1 */ + fsl,available-ranges = <2 2>; + + interrupts = <2 0 3 0 + 3 0 3 0>; + }; + + timer1: timer@42100 { + compatible = "fsl,mpic-global-timer"; + reg = <0x42100 0x100 0x42300 4>; + interrupts = <4 0 3 0 + 5 0 3 0 + 6 0 3 0 + 7 0 3 0>; + }; diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt index 4f6145859aab..2cf38bd841fd 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt @@ -190,7 +190,7 @@ EXAMPLE 4 */ timer0: timer@41100 { compatible = "fsl,mpic-global-timer"; - reg = <0x41100 0x100>; + reg = <0x41100 0x100 0x41300 4>; interrupts = <0 0 3 0 1 0 3 0 2 0 3 0 diff --git a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt index 5001b7511626..6754b2df8aa1 100644 --- a/Documentation/driver-model/bus.txt +++ b/Documentation/driver-model/bus.txt @@ -3,24 +3,7 @@ Bus Types Definition ~~~~~~~~~~ - -struct bus_type { - char * name; - - struct subsystem subsys; - struct kset drivers; - struct kset devices; - - struct bus_attribute * bus_attrs; - struct device_attribute * dev_attrs; - struct driver_attribute * drv_attrs; - - int (*match)(struct device * dev, struct device_driver * drv); - int (*hotplug) (struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); - int (*suspend)(struct device * dev, pm_message_t state); - int (*resume)(struct device * dev); -}; +See the kerneldoc for the struct bus_type. int bus_register(struct bus_type * bus); diff --git a/Documentation/driver-model/class.txt b/Documentation/driver-model/class.txt index 548505f14aa4..1fefc480a80b 100644 --- a/Documentation/driver-model/class.txt +++ b/Documentation/driver-model/class.txt @@ -27,22 +27,7 @@ The device class structure looks like: typedef int (*devclass_add)(struct device *); typedef void (*devclass_remove)(struct device *); -struct device_class { - char * name; - rwlock_t lock; - u32 devnum; - struct list_head node; - - struct list_head drivers; - struct list_head intf_list; - - struct driver_dir_entry dir; - struct driver_dir_entry device_dir; - struct driver_dir_entry driver_dir; - - devclass_add add_device; - devclass_remove remove_device; -}; +See the kerneldoc for the struct class. A typical device class definition would look like: diff --git a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt index a124f3126b0d..b2ff42685bcb 100644 --- a/Documentation/driver-model/device.txt +++ b/Documentation/driver-model/device.txt @@ -2,96 +2,7 @@ The Basic Device Structure ~~~~~~~~~~~~~~~~~~~~~~~~~~ -struct device { - struct list_head g_list; - struct list_head node; - struct list_head bus_list; - struct list_head driver_list; - struct list_head intf_list; - struct list_head children; - struct device * parent; - - char name[DEVICE_NAME_SIZE]; - char bus_id[BUS_ID_SIZE]; - - spinlock_t lock; - atomic_t refcount; - - struct bus_type * bus; - struct driver_dir_entry dir; - - u32 class_num; - - struct device_driver *driver; - void *driver_data; - void *platform_data; - - u32 current_state; - unsigned char *saved_state; - - void (*release)(struct device * dev); -}; - -Fields -~~~~~~ -g_list: Node in the global device list. - -node: Node in device's parent's children list. - -bus_list: Node in device's bus's devices list. - -driver_list: Node in device's driver's devices list. - -intf_list: List of intf_data. There is one structure allocated for - each interface that the device supports. - -children: List of child devices. - -parent: *** FIXME *** - -name: ASCII description of device. - Example: " 3Com Corporation 3c905 100BaseTX [Boomerang]" - -bus_id: ASCII representation of device's bus position. This - field should be a name unique across all devices on the - bus type the device belongs to. - - Example: PCI bus_ids are in the form of - :. - This name is unique across all PCI devices in the system. - -lock: Spinlock for the device. - -refcount: Reference count on the device. - -bus: Pointer to struct bus_type that device belongs to. - -dir: Device's sysfs directory. - -class_num: Class-enumerated value of the device. - -driver: Pointer to struct device_driver that controls the device. - -driver_data: Driver-specific data. - -platform_data: Platform data specific to the device. - - Example: for devices on custom boards, as typical of embedded - and SOC based hardware, Linux often uses platform_data to point - to board-specific structures describing devices and how they - are wired. That can include what ports are available, chip - variants, which GPIO pins act in what additional roles, and so - on. This shrinks the "Board Support Packages" (BSPs) and - minimizes board-specific #ifdefs in drivers. - -current_state: Current power state of the device. - -saved_state: Pointer to saved state of the device. This is usable by - the device driver controlling the device. - -release: Callback to free the device after all references have - gone away. This should be set by the allocator of the - device (i.e. the bus driver that discovered the device). +See the kerneldoc for the struct device. Programming Interface diff --git a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt index d2cd6fb8ba9e..4421135826a2 100644 --- a/Documentation/driver-model/driver.txt +++ b/Documentation/driver-model/driver.txt @@ -1,23 +1,7 @@ Device Drivers -struct device_driver { - char * name; - struct bus_type * bus; - - struct completion unloaded; - struct kobject kobj; - list_t devices; - - struct module *owner; - - int (*probe) (struct device * dev); - int (*remove) (struct device * dev); - - int (*suspend) (struct device * dev, pm_message_t state); - int (*resume) (struct device * dev); -}; - +See the kerneldoc for the struct device_driver. Allocation diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 492e81df2968..4cba260e3059 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -35,17 +35,6 @@ Who: Luis R. Rodriguez --------------------------- -What: AR9170USB -When: 2.6.40 - -Why: This driver is deprecated and the firmware is no longer - maintained. The replacement driver "carl9170" has been - around for a while, so the devices are still supported. - -Who: Christian Lamparter - ---------------------------- - What: IRQF_SAMPLE_RANDOM Check: IRQF_SAMPLE_RANDOM When: July 2009 @@ -405,16 +394,6 @@ Who: anybody or Florian Mickler ---------------------------- -What: capifs -When: February 2011 -Files: drivers/isdn/capi/capifs.* -Why: udev fully replaces this special file system that only contains CAPI - NCCI TTY device nodes. User space (pppdcapiplugin) works without - noticing the difference. -Who: Jan Kiszka - ----------------------------- - What: KVM paravirt mmu host support When: January 2011 Why: The paravirt mmu host support is slower than non-paravirt mmu, both @@ -460,14 +439,6 @@ Who: Thomas Gleixner ---------------------------- -What: The acpi_sleep=s4_nonvs command line option -When: 2.6.37 -Files: arch/x86/kernel/acpi/sleep.c -Why: superseded by acpi_sleep=nonvs -Who: Rafael J. Wysocki - ----------------------------- - What: PCI DMA unmap state API When: August 2012 Why: PCI DMA unmap state API (include/linux/pci-dma.h) was replaced diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index b0b814d75ca1..60740e8ecb37 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -836,7 +836,6 @@ Provides counts of softirq handlers serviced since boot time, for each cpu. TASKLET: 0 0 0 290 SCHED: 27035 26983 26971 26746 HRTIMER: 0 0 0 0 - RCU: 1678 1769 2178 2250 1.3 IDE devices in /proc/ide diff --git a/Documentation/flexible-arrays.txt b/Documentation/flexible-arrays.txt index cb8a3a00cc92..df904aec9904 100644 --- a/Documentation/flexible-arrays.txt +++ b/Documentation/flexible-arrays.txt @@ -66,10 +66,10 @@ trick is to ensure that any needed memory allocations are done before entering atomic context, using: int flex_array_prealloc(struct flex_array *array, unsigned int start, - unsigned int end, gfp_t flags); + unsigned int nr_elements, gfp_t flags); This function will ensure that memory for the elements indexed in the range -defined by start and end has been allocated. Thereafter, a +defined by start and nr_elements has been allocated. Thereafter, a flex_array_put() call on an element in that range is guaranteed not to block. diff --git a/Documentation/hwmon/adm1021 b/Documentation/hwmon/adm1021 index 03d02bfb3df1..02ad96cf9b2b 100644 --- a/Documentation/hwmon/adm1021 +++ b/Documentation/hwmon/adm1021 @@ -14,10 +14,6 @@ Supported chips: Prefix: 'gl523sm' Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e Datasheet: - * Intel Xeon Processor - Prefix: - any other - may require 'force_adm1021' parameter - Addresses scanned: none - Datasheet: Publicly available at Intel website * Maxim MAX1617 Prefix: 'max1617' Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e @@ -91,21 +87,27 @@ will do no harm, but will return 'old' values. It is possible to make ADM1021-clones do faster measurements, but there is really no good reason for that. -Xeon support ------------- -Some Xeon processors have real max1617, adm1021, or compatible chips -within them, with two temperature sensors. +Netburst-based Xeon support +--------------------------- -Other Xeons have chips with only one sensor. +Some Xeon processors based on the Netburst (early Pentium 4, from 2001 to +2003) microarchitecture had real MAX1617, ADM1021, or compatible chips +within them, with two temperature sensors. Other Xeon processors of this +era (with 400 MHz FSB) had chips with only one temperature sensor. -If you have a Xeon, and the adm1021 module loads, and both temperatures -appear valid, then things are good. +If you have such an old Xeon, and you get two valid temperatures when +loading the adm1021 module, then things are good. -If the adm1021 module doesn't load, you should try this: - modprobe adm1021 force_adm1021=BUS,ADDRESS - ADDRESS can only be 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e. +If nothing happens when loading the adm1021 module, and you are certain +that your specific Xeon processor model includes compatible sensors, you +will have to explicitly instantiate the sensor chips from user-space. See +method 4 in Documentation/i2c/instantiating-devices. Possible slave +addresses are 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e. It is likely that +only temp2 will be correct and temp1 will have to be ignored. -If you have dual Xeons you may have appear to have two separate -adm1021-compatible chips, or two single-temperature sensors, at distinct -addresses. +Previous generations of the Xeon processor (based on Pentium II/III) +didn't have these sensors. Next generations of Xeon processors (533 MHz +FSB and faster) lost them, until the Core-based generation which +introduced integrated digital thermal sensors. These are supported by +the coretemp driver. diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90 index fa475c0a48a3..f3efd18e87f4 100644 --- a/Documentation/hwmon/lm90 +++ b/Documentation/hwmon/lm90 @@ -32,6 +32,16 @@ Supported chips: Addresses scanned: I2C 0x4c and 0x4d Datasheet: Publicly available at the ON Semiconductor website http://www.onsemi.com/PowerSolutions/product.do?id=ADT7461 + * Analog Devices ADT7461A + Prefix: 'adt7461a' + Addresses scanned: I2C 0x4c and 0x4d + Datasheet: Publicly available at the ON Semiconductor website + http://www.onsemi.com/PowerSolutions/product.do?id=ADT7461A + * ON Semiconductor NCT1008 + Prefix: 'nct1008' + Addresses scanned: I2C 0x4c and 0x4d + Datasheet: Publicly available at the ON Semiconductor website + http://www.onsemi.com/PowerSolutions/product.do?id=NCT1008 * Maxim MAX6646 Prefix: 'max6646' Addresses scanned: I2C 0x4d @@ -149,7 +159,7 @@ ADM1032: * ALERT is triggered by open remote sensor. * SMBus PEC support for Write Byte and Receive Byte transactions. -ADT7461: +ADT7461, ADT7461A, NCT1008: * Extended temperature range (breaks compatibility) * Lower resolution for remote temperature @@ -195,9 +205,9 @@ are exported, one for each channel, but these values are of course linked. Only the local hysteresis can be set from user-space, and the same delta applies to the remote hysteresis. -The lm90 driver will not update its values more frequently than every -other second; reading them more often will do no harm, but will return -'old' values. +The lm90 driver will not update its values more frequently than configured with +the update_interval attribute; reading them more often will do no harm, but will +return 'old' values. SMBus Alert Support ------------------- @@ -205,11 +215,12 @@ SMBus Alert Support This driver has basic support for SMBus alert. When an alert is received, the status register is read and the faulty temperature channel is logged. -The Analog Devices chips (ADM1032 and ADT7461) do not implement the SMBus -alert protocol properly so additional care is needed: the ALERT output is -disabled when an alert is received, and is re-enabled only when the alarm -is gone. Otherwise the chip would block alerts from other chips in the bus -as long as the alarm is active. +The Analog Devices chips (ADM1032, ADT7461 and ADT7461A) and ON +Semiconductor chips (NCT1008) do not implement the SMBus alert protocol +properly so additional care is needed: the ALERT output is disabled when +an alert is received, and is re-enabled only when the alarm is gone. +Otherwise the chip would block alerts from other chips in the bus as long +as the alarm is active. PEC Support ----------- diff --git a/Documentation/hwmon/max16064 b/Documentation/hwmon/max16064 new file mode 100644 index 000000000000..41728999e142 --- /dev/null +++ b/Documentation/hwmon/max16064 @@ -0,0 +1,62 @@ +Kernel driver max16064 +====================== + +Supported chips: + * Maxim MAX16064 + Prefix: 'max16064' + Addresses scanned: - + Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX16064.pdf + +Author: Guenter Roeck + + +Description +----------- + +This driver supports hardware montoring for Maxim MAX16064 Quad Power-Supply +Controller with Active-Voltage Output Control and PMBus Interface. + +The driver is a client driver to the core PMBus driver. +Please see Documentation/hwmon/pmbus for details on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices for +details. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. + + +Sysfs entries +------------- + +The following attributes are supported. Limits are read-write; all other +attributes are read-only. + +in[1-4]_label "vout[1-4]" +in[1-4]_input Measured voltage. From READ_VOUT register. +in[1-4]_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. +in[1-4]_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. +in[1-4]_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register. +in[1-4]_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register. +in[1-4]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. +in[1-4]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. +in[1-4]_lcrit_alarm Voltage critical low alarm. From VOLTAGE_UV_FAULT status. +in[1-4]_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status. + +temp1_input Measured temperature. From READ_TEMPERATURE_1 register. +temp1_max Maximum temperature. From OT_WARN_LIMIT register. +temp1_crit Critical high temperature. From OT_FAULT_LIMIT register. +temp1_max_alarm Chip temperature high alarm. Set by comparing + READ_TEMPERATURE_1 with OT_WARN_LIMIT if TEMP_OT_WARNING + status is set. +temp1_crit_alarm Chip temperature critical high alarm. Set by comparing + READ_TEMPERATURE_1 with OT_FAULT_LIMIT if TEMP_OT_FAULT + status is set. diff --git a/Documentation/hwmon/max34440 b/Documentation/hwmon/max34440 new file mode 100644 index 000000000000..6c525dd07d59 --- /dev/null +++ b/Documentation/hwmon/max34440 @@ -0,0 +1,79 @@ +Kernel driver max34440 +====================== + +Supported chips: + * Maxim MAX34440 + Prefixes: 'max34440' + Addresses scanned: - + Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34440.pdf + * Maxim MAX34441 + PMBus 5-Channel Power-Supply Manager and Intelligent Fan Controller + Prefixes: 'max34441' + Addresses scanned: - + Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf + +Author: Guenter Roeck + + +Description +----------- + +This driver supports hardware montoring for Maxim MAX34440 PMBus 6-Channel +Power-Supply Manager and MAX34441 PMBus 5-Channel Power-Supply Manager +and Intelligent Fan Controller. + +The driver is a client driver to the core PMBus driver. Please see +Documentation/hwmon/pmbus for details on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices for +details. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. + + +Sysfs entries +------------- + +The following attributes are supported. Limits are read-write; all other +attributes are read-only. + +in[1-6]_label "vout[1-6]". +in[1-6]_input Measured voltage. From READ_VOUT register. +in[1-6]_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. +in[1-6]_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. +in[1-6]_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register. +in[1-6]_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register. +in[1-6]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. +in[1-6]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. +in[1-6]_lcrit_alarm Voltage critical low alarm. From VOLTAGE_UV_FAULT status. +in[1-6]_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status. + +curr[1-6]_label "iout[1-6]". +curr[1-6]_input Measured current. From READ_IOUT register. +curr[1-6]_max Maximum current. From IOUT_OC_WARN_LIMIT register. +curr[1-6]_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register. +curr[1-6]_max_alarm Current high alarm. From IOUT_OC_WARNING status. +curr[1-6]_crit_alarm Current critical high alarm. From IOUT_OC_FAULT status. + + in6 and curr6 attributes only exist for MAX34440. + +temp[1-8]_input Measured temperatures. From READ_TEMPERATURE_1 register. + temp1 is the chip's internal temperature. temp2..temp5 + are remote I2C temperature sensors. For MAX34441, temp6 + is a remote thermal-diode sensor. For MAX34440, temp6..8 + are remote I2C temperature sensors. +temp[1-8]_max Maximum temperature. From OT_WARN_LIMIT register. +temp[1-8]_crit Critical high temperature. From OT_FAULT_LIMIT register. +temp[1-8]_max_alarm Temperature high alarm. +temp[1-8]_crit_alarm Temperature critical high alarm. + + temp7 and temp8 attributes only exist for MAX34440. diff --git a/Documentation/hwmon/max8688 b/Documentation/hwmon/max8688 new file mode 100644 index 000000000000..0ddd3a412030 --- /dev/null +++ b/Documentation/hwmon/max8688 @@ -0,0 +1,69 @@ +Kernel driver max8688 +===================== + +Supported chips: + * Maxim MAX8688 + Prefix: 'max8688' + Addresses scanned: - + Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8688.pdf + +Author: Guenter Roeck + + +Description +----------- + +This driver supports hardware montoring for Maxim MAX8688 Digital Power-Supply +Controller/Monitor with PMBus Interface. + +The driver is a client driver to the core PMBus driver. Please see +Documentation/hwmon/pmbus for details on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices for +details. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. + + +Sysfs entries +------------- + +The following attributes are supported. Limits are read-write; all other +attributes are read-only. + +in1_label "vout1" +in1_input Measured voltage. From READ_VOUT register. +in1_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. +in1_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. +in1_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register. +in1_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register. +in1_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. +in1_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. +in1_lcrit_alarm Voltage critical low alarm. From VOLTAGE_UV_FAULT status. +in1_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status. + +curr1_label "iout1" +curr1_input Measured current. From READ_IOUT register. +curr1_max Maximum current. From IOUT_OC_WARN_LIMIT register. +curr1_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register. +curr1_max_alarm Current high alarm. From IOUT_OC_WARN_LIMIT register. +curr1_crit_alarm Current critical high alarm. From IOUT_OC_FAULT status. + +temp1_input Measured temperature. From READ_TEMPERATURE_1 register. +temp1_max Maximum temperature. From OT_WARN_LIMIT register. +temp1_crit Critical high temperature. From OT_FAULT_LIMIT register. +temp1_max_alarm Chip temperature high alarm. Set by comparing + READ_TEMPERATURE_1 with OT_WARN_LIMIT if TEMP_OT_WARNING + status is set. +temp1_crit_alarm Chip temperature critical high alarm. Set by comparing + READ_TEMPERATURE_1 with OT_FAULT_LIMIT if TEMP_OT_FAULT + status is set. diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus index dc4933e96344..5e462fc7f99b 100644 --- a/Documentation/hwmon/pmbus +++ b/Documentation/hwmon/pmbus @@ -13,26 +13,6 @@ Supported chips: Prefix: 'ltc2978' Addresses scanned: - Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf - * Maxim MAX16064 - Quad Power-Supply Controller - Prefix: 'max16064' - Addresses scanned: - - Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX16064.pdf - * Maxim MAX34440 - PMBus 6-Channel Power-Supply Manager - Prefixes: 'max34440' - Addresses scanned: - - Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34440.pdf - * Maxim MAX34441 - PMBus 5-Channel Power-Supply Manager and Intelligent Fan Controller - Prefixes: 'max34441' - Addresses scanned: - - Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf - * Maxim MAX8688 - Digital Power-Supply Controller/Monitor - Prefix: 'max8688' - Addresses scanned: - - Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8688.pdf * Generic PMBus devices Prefix: 'pmbus' Addresses scanned: - @@ -175,11 +155,13 @@ currX_crit Critical maximum current. From IIN_OC_FAULT_LIMIT or IOUT_OC_FAULT_LIMIT register. currX_alarm Current high alarm. From IIN_OC_WARNING or IOUT_OC_WARNING status. +currX_max_alarm Current high alarm. + From IIN_OC_WARN_LIMIT or IOUT_OC_WARN_LIMIT status. currX_lcrit_alarm Output current critical low alarm. From IOUT_UC_FAULT status. currX_crit_alarm Current critical high alarm. From IIN_OC_FAULT or IOUT_OC_FAULT status. -currX_label "iin" or "vinY" +currX_label "iin" or "ioutY" powerX_input Measured power. From READ_PIN or READ_POUT register. powerX_cap Output power cap. From POUT_MAX register. @@ -193,13 +175,13 @@ powerX_crit_alarm Output power critical high alarm. From POUT_OP_FAULT status. powerX_label "pin" or "poutY" -tempX_input Measured tempererature. +tempX_input Measured temperature. From READ_TEMPERATURE_X register. -tempX_min Mimimum tempererature. From UT_WARN_LIMIT register. -tempX_max Maximum tempererature. From OT_WARN_LIMIT register. -tempX_lcrit Critical low tempererature. +tempX_min Mimimum temperature. From UT_WARN_LIMIT register. +tempX_max Maximum temperature. From OT_WARN_LIMIT register. +tempX_lcrit Critical low temperature. From UT_FAULT_LIMIT register. -tempX_crit Critical high tempererature. +tempX_crit Critical high temperature. From OT_FAULT_LIMIT register. tempX_min_alarm Chip temperature low alarm. Set by comparing READ_TEMPERATURE_X with UT_WARN_LIMIT if diff --git a/Documentation/hwmon/smm665 b/Documentation/hwmon/smm665 index 3820fc9ca52d..59e316140542 100644 --- a/Documentation/hwmon/smm665 +++ b/Documentation/hwmon/smm665 @@ -150,8 +150,8 @@ in8_crit_alarm Channel F critical alarm in9_crit_alarm AIN1 critical alarm in10_crit_alarm AIN2 critical alarm -temp1_input Chip tempererature -temp1_min Mimimum chip tempererature -temp1_max Maximum chip tempererature -temp1_crit Critical chip tempererature +temp1_input Chip temperature +temp1_min Mimimum chip temperature +temp1_max Maximum chip temperature +temp1_crit Critical chip temperature temp1_crit_alarm Temperature critical alarm diff --git a/Documentation/hwmon/submitting-patches b/Documentation/hwmon/submitting-patches new file mode 100644 index 000000000000..86f42e8e9e49 --- /dev/null +++ b/Documentation/hwmon/submitting-patches @@ -0,0 +1,109 @@ + How to Get Your Patch Accepted Into the Hwmon Subsystem + ------------------------------------------------------- + +This text is is a collection of suggestions for people writing patches or +drivers for the hwmon subsystem. Following these suggestions will greatly +increase the chances of your change being accepted. + + +1. General +---------- + +* It should be unnecessary to mention, but please read and follow + Documentation/SubmitChecklist + Documentation/SubmittingDrivers + Documentation/SubmittingPatches + Documentation/CodingStyle + +* If your patch generates checkpatch warnings, please refrain from explanations + such as "I don't like that coding style". Keep in mind that each unnecessary + warning helps hiding a real problem. If you don't like the kernel coding + style, don't write kernel drivers. + +* Please test your patch thoroughly. We are not your test group. + Sometimes a patch can not or not completely be tested because of missing + hardware. In such cases, you should test-build the code on at least one + architecture. If run-time testing was not achieved, it should be written + explicitly below the patch header. + +* If your patch (or the driver) is affected by configuration options such as + CONFIG_SMP or CONFIG_HOTPLUG, make sure it compiles for all configuration + variants. + + +2. Adding functionality to existing drivers +------------------------------------------- + +* Make sure the documentation in Documentation/hwmon/ is up to + date. + +* Make sure the information in Kconfig is up to date. + +* If the added functionality requires some cleanup or structural changes, split + your patch into a cleanup part and the actual addition. This makes it easier + to review your changes, and to bisect any resulting problems. + +* Never mix bug fixes, cleanup, and functional enhancements in a single patch. + + +3. New drivers +-------------- + +* Running your patch or driver file(s) through checkpatch does not mean its + formatting is clean. If unsure about formatting in your new driver, run it + through Lindent. Lindent is not perfect, and you may have to do some minor + cleanup, but it is a good start. + +* Consider adding yourself to MAINTAINERS. + +* Document the driver in Documentation/hwmon/. + +* Add the driver to Kconfig and Makefile in alphabetical order. + +* Make sure that all dependencies are listed in Kconfig. For new drivers, it + is most likely prudent to add a dependency on EXPERIMENTAL. + +* Avoid forward declarations if you can. Rearrange the code if necessary. + +* Avoid calculations in macros and macro-generated functions. While such macros + may save a line or so in the source, it obfuscates the code and makes code + review more difficult. It may also result in code which is more complicated + than necessary. Use inline functions or just regular functions instead. + +* If the driver has a detect function, make sure it is silent. Debug messages + and messages printed after a successful detection are acceptable, but it + must not print messages such as "Chip XXX not found/supported". + + Keep in mind that the detect function will run for all drivers supporting an + address if a chip is detected on that address. Unnecessary messages will just + pollute the kernel log and not provide any value. + +* Provide a detect function if and only if a chip can be detected reliably. + +* Avoid writing to chip registers in the detect function. If you have to write, + only do it after you have already gathered enough data to be certain that the + detection is going to be successful. + + Keep in mind that the chip might not be what your driver believes it is, and + writing to it might cause a bad misconfiguration. + +* Make sure there are no race conditions in the probe function. Specifically, + completely initialize your chip first, then create sysfs entries and register + with the hwmon subsystem. + +* Do not provide support for deprecated sysfs attributes. + +* Do not create non-standard attributes unless really needed. If you have to use + non-standard attributes, or you believe you do, discuss it on the mailing list + first. Either case, provide a detailed explanation why you need the + non-standard attribute(s). + Standard attributes are specified in Documentation/hwmon/sysfs-interface. + +* When deciding which sysfs attributes to support, look at the chip's + capabilities. While we do not expect your driver to support everything the + chip may offer, it should at least support all limits and alarms. + +* Last but not least, please check if a driver for your chip already exists + before starting to write a new driver. Especially for temperature sensors, + new chips are often variants of previously released chips. In some cases, + a presumably new chip may simply have been relabeled. diff --git a/Documentation/input/event-codes.txt b/Documentation/input/event-codes.txt new file mode 100644 index 000000000000..23fcb05175be --- /dev/null +++ b/Documentation/input/event-codes.txt @@ -0,0 +1,262 @@ +The input protocol uses a map of types and codes to express input device values +to userspace. This document describes the types and codes and how and when they +may be used. + +A single hardware event generates multiple input events. Each input event +contains the new value of a single data item. A special event type, EV_SYN, is +used to separate input events into packets of input data changes occurring at +the same moment in time. In the following, the term "event" refers to a single +input event encompassing a type, code, and value. + +The input protocol is a stateful protocol. Events are emitted only when values +of event codes have changed. However, the state is maintained within the Linux +input subsystem; drivers do not need to maintain the state and may attempt to +emit unchanged values without harm. Userspace may obtain the current state of +event code values using the EVIOCG* ioctls defined in linux/input.h. The event +reports supported by a device are also provided by sysfs in +class/input/event*/device/capabilities/, and the properties of a device are +provided in class/input/event*/device/properties. + +Types: +========== +Types are groupings of codes under a logical input construct. Each type has a +set of applicable codes to be used in generating events. See the Codes section +for details on valid codes for each type. + +* EV_SYN: + - Used as markers to separate events. Events may be separated in time or in + space, such as with the multitouch protocol. + +* EV_KEY: + - Used to describe state changes of keyboards, buttons, or other key-like + devices. + +* EV_REL: + - Used to describe relative axis value changes, e.g. moving the mouse 5 units + to the left. + +* EV_ABS: + - Used to describe absolute axis value changes, e.g. describing the + coordinates of a touch on a touchscreen. + +* EV_MSC: + - Used to describe miscellaneous input data that do not fit into other types. + +* EV_SW: + - Used to describe binary state input switches. + +* EV_LED: + - Used to turn LEDs on devices on and off. + +* EV_SND: + - Used to output sound to devices. + +* EV_REP: + - Used for autorepeating devices. + +* EV_FF: + - Used to send force feedback commands to an input device. + +* EV_PWR: + - A special type for power button and switch input. + +* EV_FF_STATUS: + - Used to receive force feedback device status. + +Codes: +========== +Codes define the precise type of event. + +EV_SYN: +---------- +EV_SYN event values are undefined. Their usage is defined only by when they are +sent in the evdev event stream. + +* SYN_REPORT: + - Used to synchronize and separate events into packets of input data changes + occurring at the same moment in time. For example, motion of a mouse may set + the REL_X and REL_Y values for one motion, then emit a SYN_REPORT. The next + motion will emit more REL_X and REL_Y values and send another SYN_REPORT. + +* SYN_CONFIG: + - TBD + +* SYN_MT_REPORT: + - Used to synchronize and separate touch events. See the + multi-touch-protocol.txt document for more information. + +* SYN_DROPPED: + - Used to indicate buffer overrun in the evdev client's event queue. + Client should ignore all events up to and including next SYN_REPORT + event and query the device (using EVIOCG* ioctls) to obtain its + current state. + +EV_KEY: +---------- +EV_KEY events take the form KEY_ or BTN_. For example, KEY_A is used +to represent the 'A' key on a keyboard. When a key is depressed, an event with +the key's code is emitted with value 1. When the key is released, an event is +emitted with value 0. Some hardware send events when a key is repeated. These +events have a value of 2. In general, KEY_ is used for keyboard keys, and +BTN_ is used for other types of momentary switch events. + +A few EV_KEY codes have special meanings: + +* BTN_TOOL_: + - These codes are used in conjunction with input trackpads, tablets, and + touchscreens. These devices may be used with fingers, pens, or other tools. + When an event occurs and a tool is used, the corresponding BTN_TOOL_ + code should be set to a value of 1. When the tool is no longer interacting + with the input device, the BTN_TOOL_ code should be reset to 0. All + trackpads, tablets, and touchscreens should use at least one BTN_TOOL_ + code when events are generated. + +* BTN_TOUCH: + BTN_TOUCH is used for touch contact. While an input tool is determined to be + within meaningful physical contact, the value of this property must be set + to 1. Meaningful physical contact may mean any contact, or it may mean + contact conditioned by an implementation defined property. For example, a + touchpad may set the value to 1 only when the touch pressure rises above a + certain value. BTN_TOUCH may be combined with BTN_TOOL_ codes. For + example, a pen tablet may set BTN_TOOL_PEN to 1 and BTN_TOUCH to 0 while the + pen is hovering over but not touching the tablet surface. + +Note: For appropriate function of the legacy mousedev emulation driver, +BTN_TOUCH must be the first evdev code emitted in a synchronization frame. + +Note: Historically a touch device with BTN_TOOL_FINGER and BTN_TOUCH was +interpreted as a touchpad by userspace, while a similar device without +BTN_TOOL_FINGER was interpreted as a touchscreen. For backwards compatibility +with current userspace it is recommended to follow this distinction. In the +future, this distinction will be deprecated and the device properties ioctl +EVIOCGPROP, defined in linux/input.h, will be used to convey the device type. + +* BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP, BTN_TOOL_QUADTAP: + - These codes denote one, two, three, and four finger interaction on a + trackpad or touchscreen. For example, if the user uses two fingers and moves + them on the touchpad in an effort to scroll content on screen, + BTN_TOOL_DOUBLETAP should be set to value 1 for the duration of the motion. + Note that all BTN_TOOL_ codes and the BTN_TOUCH code are orthogonal in + purpose. A trackpad event generated by finger touches should generate events + for one code from each group. At most only one of these BTN_TOOL_ + codes should have a value of 1 during any synchronization frame. + +Note: Historically some drivers emitted multiple of the finger count codes with +a value of 1 in the same synchronization frame. This usage is deprecated. + +Note: In multitouch drivers, the input_mt_report_finger_count() function should +be used to emit these codes. Please see multi-touch-protocol.txt for details. + +EV_REL: +---------- +EV_REL events describe relative changes in a property. For example, a mouse may +move to the left by a certain number of units, but its absolute position in +space is unknown. If the absolute position is known, EV_ABS codes should be used +instead of EV_REL codes. + +A few EV_REL codes have special meanings: + +* REL_WHEEL, REL_HWHEEL: + - These codes are used for vertical and horizontal scroll wheels, + respectively. + +EV_ABS: +---------- +EV_ABS events describe absolute changes in a property. For example, a touchpad +may emit coordinates for a touch location. + +A few EV_ABS codes have special meanings: + +* ABS_DISTANCE: + - Used to describe the distance of a tool from an interaction surface. This + event should only be emitted while the tool is hovering, meaning in close + proximity of the device and while the value of the BTN_TOUCH code is 0. If + the input device may be used freely in three dimensions, consider ABS_Z + instead. + +* ABS_MT_: + - Used to describe multitouch input events. Please see + multi-touch-protocol.txt for details. + +EV_SW: +---------- +EV_SW events describe stateful binary switches. For example, the SW_LID code is +used to denote when a laptop lid is closed. + +Upon binding to a device or resuming from suspend, a driver must report +the current switch state. This ensures that the device, kernel, and userspace +state is in sync. + +Upon resume, if the switch state is the same as before suspend, then the input +subsystem will filter out the duplicate switch state reports. The driver does +not need to keep the state of the switch at any time. + +EV_MSC: +---------- +EV_MSC events are used for input and output events that do not fall under other +categories. + +EV_LED: +---------- +EV_LED events are used for input and output to set and query the state of +various LEDs on devices. + +EV_REP: +---------- +EV_REP events are used for specifying autorepeating events. + +EV_SND: +---------- +EV_SND events are used for sending sound commands to simple sound output +devices. + +EV_FF: +---------- +EV_FF events are used to initialize a force feedback capable device and to cause +such device to feedback. + +EV_PWR: +---------- +EV_PWR events are a special type of event used specifically for power +mangement. Its usage is not well defined. To be addressed later. + +Guidelines: +========== +The guidelines below ensure proper single-touch and multi-finger functionality. +For multi-touch functionality, see the multi-touch-protocol.txt document for +more information. + +Mice: +---------- +REL_{X,Y} must be reported when the mouse moves. BTN_LEFT must be used to report +the primary button press. BTN_{MIDDLE,RIGHT,4,5,etc.} should be used to report +further buttons of the device. REL_WHEEL and REL_HWHEEL should be used to report +scroll wheel events where available. + +Touchscreens: +---------- +ABS_{X,Y} must be reported with the location of the touch. BTN_TOUCH must be +used to report when a touch is active on the screen. +BTN_{MOUSE,LEFT,MIDDLE,RIGHT} must not be reported as the result of touch +contact. BTN_TOOL_ events should be reported where possible. + +Trackpads: +---------- +Legacy trackpads that only provide relative position information must report +events like mice described above. + +Trackpads that provide absolute touch position must report ABS_{X,Y} for the +location of the touch. BTN_TOUCH should be used to report when a touch is active +on the trackpad. Where multi-finger support is available, BTN_TOOL_ should +be used to report the number of touches active on the trackpad. + +Tablets: +---------- +BTN_TOOL_ events must be reported when a stylus or other tool is active on +the tablet. ABS_{X,Y} must be reported with the location of the tool. BTN_TOUCH +should be used to report when the tool is in contact with the tablet. +BTN_{STYLUS,STYLUS2} should be used to report buttons on the tool itself. Any +button may be used for buttons on the tablet except BTN_{MOUSE,LEFT}. +BTN_{0,1,2,etc} are good generic codes for unlabeled buttons. Do not use +meaningful buttons, like BTN_FORWARD, unless the button is labeled for that +purpose on the device. diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO index b63301a03811..050d37fe6d40 100644 --- a/Documentation/ja_JP/HOWTO +++ b/Documentation/ja_JP/HOWTO @@ -11,14 +11,14 @@ for non English (read: Japanese) speakers and is not intended as a fork. So if you have any comments or updates for this file, please try to update the original English file first. -Last Updated: 2008/10/24 +Last Updated: 2011/03/31 ================================== これは、 -linux-2.6.28/Documentation/HOWTO +linux-2.6.38/Documentation/HOWTO の和訳です。 翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ > -翻訳日: 2008/10/24 +翻訳日: 2011/3/28 翻訳者: Tsugikazu Shibata 校正者: 松倉さん 小林 雅典さん (Masanori Kobayasi) @@ -256,8 +256,8 @@ Linux カーネルの開発プロセスは現在幾つかの異なるメイン - メインの 2.6.x カーネルツリー - 2.6.x.y -stable カーネルツリー - 2.6.x -git カーネルパッチ - - 2.6.x -mm カーネルパッチ - サブシステム毎のカーネルツリーとパッチ + - 統合テストのための 2.6.x -next カーネルツリー 2.6.x カーネルツリー ----------------- @@ -268,9 +268,9 @@ Linux カーネルの開発プロセスは現在幾つかの異なるメイン - 新しいカーネルがリリースされた直後に、2週間の特別期間が設けられ、 この期間中に、メンテナ達は Linus に大きな差分を送ることができます。 - このような差分は通常 -mm カーネルに数週間含まれてきたパッチです。 + このような差分は通常 -next カーネルに数週間含まれてきたパッチです。 大きな変更は git(カーネルのソース管理ツール、詳細は - http://git.or.cz/ 参照) を使って送るのが好ましいやり方ですが、パッ + http://git-scm.com/ 参照) を使って送るのが好ましいやり方ですが、パッ チファイルの形式のまま送るのでも十分です。 - 2週間後、-rc1 カーネルがリリースされ、この後にはカーネル全体の安定 @@ -333,86 +333,44 @@ git リポジトリで管理されているLinus のカーネルツリーの毎 れは -rc カーネルと比べて、パッチが大丈夫かどうかも確認しないで自動的 に生成されるので、より実験的です。 -2.6.x -mm カーネルパッチ ------------------------- - -Andrew Morton によってリリースされる実験的なカーネルパッチ群です。 -Andrew は個別のサブシステムカーネルツリーとパッチを全て集めてきて -linux-kernel メーリングリストで収集された多数のパッチと同時に一つにま -とめます。 -このツリーは新機能とパッチが検証される場となります。ある期間の間パッチ -が -mm に入って価値を証明されたら、Andrew やサブシステムメンテナが、 -メインラインへ入れるように Linus にプッシュします。 - -メインカーネルツリーに含めるために Linus に送る前に、すべての新しいパッ -チが -mm ツリーでテストされることが強く推奨されています。マージウィン -ドウが開く前に -mm ツリーに現れなかったパッチはメインラインにマージさ -れることは困難になります。 - -これらのカーネルは安定して動作すべきシステムとして使うのには適切ではあ -りませんし、カーネルブランチの中でももっとも動作にリスクが高いものです。 - -もしあなたが、カーネル開発プロセスの支援をしたいと思っているのであれば、 -どうぞこれらのカーネルリリースをテストに使ってみて、そしてもし問題があ -れば、またもし全てが正しく動作したとしても、linux-kernel メーリングリ -ストにフィードバックを提供してください。 - -すべての他の実験的パッチに加えて、これらのカーネルは通常リリース時点で -メインラインの -git カーネルに含まれる全ての変更も含んでいます。 - --mm カーネルは決まったスケジュールではリリースされません、しかし通常幾 -つかの -mm カーネル (1 から 3 が普通)が各-rc カーネルの間にリリースさ -れます。 - サブシステム毎のカーネルツリーとパッチ ------------------------------------------- -カーネルの様々な領域で何が起きているかを見られるようにするため、多くの -カーネルサブシステム開発者は彼らの開発ツリーを公開しています。これらの -ツリーは説明したように -mm カーネルリリースに入れ込まれます。 +それぞれのカーネルサブシステムのメンテナ達は --- そして多くのカーネル +サブシステムの開発者達も --- 各自の最新の開発状況をソースリポジトリに +公開しています。そのため、自分とは異なる領域のカーネルで何が起きている +かを他の人が見られるようになっています。開発が早く進んでいる領域では、 +開発者は自身の投稿がどのサブシステムカーネルツリーを元にしているか質問 +されるので、その投稿とすでに進行中の他の作業との衝突が避けられます。 -以下はさまざまなカーネルツリーの中のいくつかのリスト- +大部分のこれらのリポジトリは git ツリーです。しかしその他の SCM や +quilt シリーズとして公開されているパッチキューも使われています。これら +のサブシステムリポジトリのアドレスは MAINTAINERS ファイルにリストされ +ています。これらの多くは http://git.kernel.org/ で参照することができま +す。 - git ツリー- - - Kbuild の開発ツリー、Sam Ravnborg - git.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git +提案されたパッチがこのようなサブシステムツリーにコミットされる前に、メー +リングリストで事前にレビューにかけられます(以下の対応するセクションを +参照)。いくつかのカーネルサブシステムでは、このレビューは patchwork +というツールによって追跡されます。Patchwork は web インターフェイスに +よってパッチ投稿の表示、パッチへのコメント付けや改訂などができ、そして +メンテナはパッチに対して、レビュー中、受付済み、拒否というようなマーク +をつけることができます。大部分のこれらの patchwork のサイトは +http://patchwork.kernel.org/ でリストされています。 - - ACPI の開発ツリー、 Len Brown - git.kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git +統合テストのための 2.6.x -next カーネルツリー +--------------------------------------------- - - Block の開発ツリー、Jens Axboe - git.kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git +サブシステムツリーの更新内容がメインラインの 2.6.x ツリーにマージされ +る前に、それらは統合テストされる必要があります。この目的のため、実質的 +に全サブシステムツリーからほぼ毎日プルされてできる特別なテスト用のリ +ポジトリが存在します- + http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git + http://linux.f-seidel.de/linux-next/pmwiki/ - - DRM の開発ツリー、Dave Airlie - git.kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git - - - ia64 の開発ツリー、Tony Luck - git.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git - - - infiniband, Roland Dreier - git.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git - - - libata, Jeff Garzik - git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git - - - ネットワークドライバ, Jeff Garzik - git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git - - - pcmcia, Dominik Brodowski - git.kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git - - - SCSI, James Bottomley - git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git - - - x86, Ingo Molnar - git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git - - quilt ツリー- - - USB, ドライバコアと I2C, Greg Kroah-Hartman - kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ - - その他のカーネルツリーは http://git.kernel.org/ と MAINTAINERS ファ - イルに一覧表があります。 +このやり方によって、-next カーネルは次のマージ機会でどんなものがメイン +ラインカーネルにマージされるか、おおまかなの展望を提供します。-next +カーネルの実行テストを行う冒険好きなテスターは大いに歓迎されます バグレポート ------------- @@ -673,10 +631,9 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を じところからスタートしたのですから。 Paolo Ciarrocchi に感謝、彼は彼の書いた "Development Process" -(http://linux.tar.bz/articles/2.6-development_process)セクショ -ンをこのテキストの原型にすることを許可してくれました。 -Rundy Dunlap と Gerrit Huizenga はメーリングリストでやるべきこととやっ -てはいけないことのリストを提供してくれました。 +(http://lwn.net/Articles/94386/) セクションをこのテキストの原型にする +ことを許可してくれました。Rundy Dunlap と Gerrit Huizenga はメーリング +リストでやるべきこととやってはいけないことのリストを提供してくれました。 以下の人々のレビュー、コメント、貢献に感謝。 Pat Mochel, Hanna Linder, Randy Dunlap, Kay Sievers, Vojtech Pavlik, Jan Kara, Josh Boyer, Kees Cook, Andrew Morton, Andi diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index cc85a9278190..c603ef7b0568 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -245,7 +245,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. acpi_sleep= [HW,ACPI] Sleep options Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, - old_ordering, s4_nonvs, sci_force_enable } + old_ordering, nonvs, sci_force_enable } See Documentation/power/video.txt for information on s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep @@ -1664,6 +1664,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. noexec=on: enable non-executable mappings (default) noexec=off: disable non-executable mappings + nosmep [X86] + Disable SMEP (Supervisor Mode Execution Protection) + even if it is supported by processor. + noexec32 [X86-64] This affects only 32-bit executables. noexec32=on: enable non-executable mappings (default) diff --git a/Documentation/md.txt b/Documentation/md.txt index a81c7b4790f2..2366b1c8cf19 100644 --- a/Documentation/md.txt +++ b/Documentation/md.txt @@ -552,6 +552,16 @@ also have within the array where IO will be blocked. This is currently only supported for raid4/5/6. + sync_min + sync_max + The two values, given as numbers of sectors, indicate a range + withing the array where 'check'/'repair' will operate. Must be + a multiple of chunk_size. When it reaches "sync_max" it will + pause, rather than complete. + You can use 'select' or 'poll' on "sync_completed" to wait for + that number to reach sync_max. Then you can either increase + "sync_max", or can write 'idle' to "sync_action". + Each active md device may also have attributes specific to the personality module that manages it. diff --git a/Documentation/networking/batman-adv.txt b/Documentation/networking/batman-adv.txt index ee496eb2f4a6..88d4afbdef98 100644 --- a/Documentation/networking/batman-adv.txt +++ b/Documentation/networking/batman-adv.txt @@ -1,4 +1,4 @@ -[state: 27-01-2011] +[state: 17-04-2011] BATMAN-ADV ---------- @@ -19,6 +19,7 @@ duce the overhead to a minimum. It does not depend on any (other) network driver, and can be used on wifi as well as ethernet lan, vpn, etc ... (anything with ethernet-style layer 2). + CONFIGURATION ------------- @@ -160,13 +161,13 @@ face. Each entry can/has to have the following values: -> "TQ mac value" - src mac's link quality towards mac address of a neighbor originator's interface which is being used for routing --> "HNA mac" - HNA announced by source mac +-> "TT mac" - TT announced by source mac -> "PRIMARY" - this is a primary interface -> "SEC mac" - secondary mac address of source (requires preceding PRIMARY) The TQ value has a range from 4 to 255 with 255 being the best. -The HNA entries are showing which hosts are connected to the mesh +The TT entries are showing which hosts are connected to the mesh via bat0 or being bridged into the mesh network. The PRIMARY/SEC values are only applied on primary interfaces @@ -199,7 +200,7 @@ abled during run time. Following log_levels are defined: 0 - All debug output disabled 1 - Enable messages related to routing / flooding / broadcasting -2 - Enable route or hna added / changed / deleted +2 - Enable route or tt entry added / changed / deleted 3 - Enable all messages The debug output can be changed at runtime using the file @@ -207,7 +208,7 @@ The debug output can be changed at runtime using the file # echo 2 > /sys/class/net/bat0/mesh/log_level -will enable debug messages for when routes or HNAs change. +will enable debug messages for when routes or TTs change. BATCTL diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index e27202bb8d75..1f45bd887d65 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -1,7 +1,7 @@ Linux Ethernet Bonding Driver HOWTO - Latest update: 23 September 2009 + Latest update: 27 April 2011 Initial release : Thomas Davis Corrections, HA extensions : 2000/10/03-15 : @@ -585,25 +585,23 @@ mode chosen. num_grat_arp - - Specifies the number of gratuitous ARPs to be issued after a - failover event. One gratuitous ARP is issued immediately after - the failover, subsequent ARPs are sent at a rate of one per link - monitor interval (arp_interval or miimon, whichever is active). - - The valid range is 0 - 255; the default value is 1. This option - affects only the active-backup mode. This option was added for - bonding version 3.3.0. - num_unsol_na - Specifies the number of unsolicited IPv6 Neighbor Advertisements - to be issued after a failover event. One unsolicited NA is issued - immediately after the failover. + Specify the number of peer notifications (gratuitous ARPs and + unsolicited IPv6 Neighbor Advertisements) to be issued after a + failover event. As soon as the link is up on the new slave + (possibly immediately) a peer notification is sent on the + bonding device and each VLAN sub-device. This is repeated at + each link monitor interval (arp_interval or miimon, whichever + is active) if the number is greater than 1. - The valid range is 0 - 255; the default value is 1. This option - affects only the active-backup mode. This option was added for - bonding version 3.4.0. + The valid range is 0 - 255; the default value is 1. These options + affect only the active-backup mode. These options were added for + bonding versions 3.3.0 and 3.4.0 respectively. + + From Linux 2.6.40 and bonding version 3.7.1, these notifications + are generated by the ipv4 and ipv6 code and the numbers of + repetitions cannot be set independently. primary diff --git a/Documentation/networking/igb.txt b/Documentation/networking/igb.txt index 98953c0d5342..9a2a037194a5 100644 --- a/Documentation/networking/igb.txt +++ b/Documentation/networking/igb.txt @@ -93,6 +93,19 @@ Additional Configurations REQUIREMENTS: MSI-X support is required for Multiqueue. If MSI-X is not found, the system will fallback to MSI or to Legacy interrupts. + MAC and VLAN anti-spoofing feature + ---------------------------------- + When a malicious driver attempts to send a spoofed packet, it is dropped by + the hardware and not transmitted. An interrupt is sent to the PF driver + notifying it of the spoof attempt. + + When a spoofed packet is detected the PF driver will send the following + message to the system log (displayed by the "dmesg" command): + + Spoof event(s) detected on VF(n) + + Where n=the VF that attempted to do the spoofing. + Support ======= diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index 1971bcf48a60..88880839ece4 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt @@ -279,11 +279,15 @@ When the system goes into the standby or memory sleep state, the phases are: time.) Unlike the other suspend-related phases, during the prepare phase the device tree is traversed top-down. - The prepare phase uses only a bus callback. After the callback method - returns, no new children may be registered below the device. The method - may also prepare the device or driver in some way for the upcoming - system power transition, but it should not put the device into a - low-power state. + In addition to that, if device drivers need to allocate additional + memory to be able to hadle device suspend correctly, that should be + done in the prepare phase. + + After the prepare callback method returns, no new children may be + registered below the device. The method may also prepare the device or + driver in some way for the upcoming system power transition (for + example, by allocating additional memory required for this purpose), but + it should not put the device into a low-power state. 2. The suspend methods should quiesce the device to stop it from performing I/O. They also may save the device registers and put it into the diff --git a/Documentation/power/notifiers.txt b/Documentation/power/notifiers.txt index cf980709122a..c2a4a346c0d9 100644 --- a/Documentation/power/notifiers.txt +++ b/Documentation/power/notifiers.txt @@ -1,46 +1,41 @@ Suspend notifiers - (C) 2007 Rafael J. Wysocki , GPL + (C) 2007-2011 Rafael J. Wysocki , GPL -There are some operations that device drivers may want to carry out in their -.suspend() routines, but shouldn't, because they can cause the hibernation or -suspend to fail. For example, a driver may want to allocate a substantial amount -of memory (like 50 MB) in .suspend(), but that shouldn't be done after the -swsusp's memory shrinker has run. +There are some operations that subsystems or drivers may want to carry out +before hibernation/suspend or after restore/resume, but they require the system +to be fully functional, so the drivers' and subsystems' .suspend() and .resume() +or even .prepare() and .complete() callbacks are not suitable for this purpose. +For example, device drivers may want to upload firmware to their devices after +resume/restore, but they cannot do it by calling request_firmware() from their +.resume() or .complete() routines (user land processes are frozen at these +points). The solution may be to load the firmware into memory before processes +are frozen and upload it from there in the .resume() routine. +A suspend/hibernation notifier may be used for this purpose. -Also, there may be some operations, that subsystems want to carry out before a -hibernation/suspend or after a restore/resume, requiring the system to be fully -functional, so the drivers' .suspend() and .resume() routines are not suitable -for this purpose. For example, device drivers may want to upload firmware to -their devices after a restore from a hibernation image, but they cannot do it by -calling request_firmware() from their .resume() routines (user land processes -are frozen at this point). The solution may be to load the firmware into -memory before processes are frozen and upload it from there in the .resume() -routine. Of course, a hibernation notifier may be used for this purpose. - -The subsystems that have such needs can register suspend notifiers that will be -called upon the following events by the suspend core: +The subsystems or drivers having such needs can register suspend notifiers that +will be called upon the following events by the PM core: PM_HIBERNATION_PREPARE The system is going to hibernate or suspend, tasks will be frozen immediately. PM_POST_HIBERNATION The system memory state has been restored from a - hibernation image or an error occurred during the - hibernation. Device drivers' .resume() callbacks have + hibernation image or an error occurred during + hibernation. Device drivers' restore callbacks have been executed and tasks have been thawed. PM_RESTORE_PREPARE The system is going to restore a hibernation image. - If all goes well the restored kernel will issue a + If all goes well, the restored kernel will issue a PM_POST_HIBERNATION notification. -PM_POST_RESTORE An error occurred during the hibernation restore. - Device drivers' .resume() callbacks have been executed +PM_POST_RESTORE An error occurred during restore from hibernation. + Device drivers' restore callbacks have been executed and tasks have been thawed. -PM_SUSPEND_PREPARE The system is preparing for a suspend. +PM_SUSPEND_PREPARE The system is preparing for suspend. PM_POST_SUSPEND The system has just resumed or an error occurred during - the suspend. Device drivers' .resume() callbacks have - been executed and tasks have been thawed. + suspend. Device drivers' resume callbacks have been + executed and tasks have been thawed. It is generally assumed that whatever the notifiers do for PM_HIBERNATION_PREPARE, should be undone for PM_POST_HIBERNATION. Analogously, diff --git a/Documentation/scsi/LICENSE.qla2xxx b/Documentation/scsi/LICENSE.qla2xxx index 9e15b4f9cd28..19e7cd4bba66 100644 --- a/Documentation/scsi/LICENSE.qla2xxx +++ b/Documentation/scsi/LICENSE.qla2xxx @@ -1,11 +1,11 @@ -Copyright (c) 2003-2005 QLogic Corporation -QLogic Linux Fibre Channel HBA Driver +Copyright (c) 2003-2011 QLogic Corporation +QLogic Linux/ESX Fibre Channel HBA Driver -This program includes a device driver for Linux 2.6 that may be +This program includes a device driver for Linux 2.6/ESX that may be distributed with QLogic hardware specific firmware binary file. You may modify and redistribute the device driver code under the -GNU General Public License as published by the Free Software -Foundation (version 2 or a later version). +GNU General Public License (a copy of which is attached hereto as +Exhibit A) published by the Free Software Foundation (version 2). You may redistribute the hardware specific firmware binary file under the following terms: @@ -43,3 +43,285 @@ OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS (PATENT, COPYRIGHT, TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) EMBODIED IN ANY OTHER QLOGIC HARDWARE OR SOFTWARE EITHER SOLELY OR IN COMBINATION WITH THIS PROGRAM. + + +EXHIBIT A + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. diff --git a/Documentation/sound/alsa/SB-Live-mixer.txt b/Documentation/sound/alsa/SB-Live-mixer.txt index f5639d40521d..f4b5988f450c 100644 --- a/Documentation/sound/alsa/SB-Live-mixer.txt +++ b/Documentation/sound/alsa/SB-Live-mixer.txt @@ -87,14 +87,14 @@ accumulator. ALSA uses accumulators 0 and 1 for left and right PCM. The result is forwarded to the ADC capture FIFO (thus to the standard capture PCM device). -name='Music Playback Volume',index=0 +name='Synth Playback Volume',index=0 This control is used to attenuate samples for left and right MIDI FX-bus accumulators. ALSA uses accumulators 4 and 5 for left and right MIDI samples. The result samples are forwarded to the front DAC PCM slots of the AC97 codec. -name='Music Capture Volume',index=0 -name='Music Capture Switch',index=0 +name='Synth Capture Volume',index=0 +name='Synth Capture Switch',index=0 These controls are used to attenuate samples for left and right MIDI FX-bus accumulator. ALSA uses accumulators 4 and 5 for left and right PCM. diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt index cbd05ffc606b..3201a7097e4d 100644 --- a/Documentation/sysctl/net.txt +++ b/Documentation/sysctl/net.txt @@ -32,6 +32,17 @@ Table : Subdirectories in /proc/sys/net 1. /proc/sys/net/core - Network core options ------------------------------------------------------- +bpf_jit_enable +-------------- + +This enables Berkeley Packet Filter Just in Time compiler. +Currently supported on x86_64 architecture, bpf_jit provides a framework +to speed packet filtering, the one used by tcpdump/libpcap for example. +Values : + 0 - disable the JIT (default value) + 1 - enable the JIT + 2 - enable the JIT and ask the compiler to emit traces on kernel log. + rmem_default ------------ diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt index 6d27ab8d6e9f..c83bd6b4e6e8 100644 --- a/Documentation/trace/kprobetrace.txt +++ b/Documentation/trace/kprobetrace.txt @@ -120,7 +120,6 @@ format: field:unsigned char common_flags; offset:2; size:1; signed:0; field:unsigned char common_preempt_count; offset:3; size:1;signed:0; field:int common_pid; offset:4; size:4; signed:1; - field:int common_lock_depth; offset:8; size:4; signed:1; field:unsigned long __probe_ip; offset:12; size:4; signed:0; field:int __probe_nargs; offset:16; size:4; signed:1; diff --git a/Documentation/video4linux/sh_mobile_ceu_camera.txt b/Documentation/video4linux/sh_mobile_ceu_camera.txt index cb47e723af74..1e96ce6e2d2f 100644 --- a/Documentation/video4linux/sh_mobile_ceu_camera.txt +++ b/Documentation/video4linux/sh_mobile_ceu_camera.txt @@ -37,7 +37,7 @@ Generic scaling / cropping scheme -1'- In the above chart minuses and slashes represent "real" data amounts, points and -accents represent "useful" data, basically, CEU scaled amd cropped output, +accents represent "useful" data, basically, CEU scaled and cropped output, mapped back onto the client's source plane. Such a configuration can be produced by user requests: @@ -65,7 +65,7 @@ Do not touch input rectangle - it is already optimal. 1. Calculate current sensor scales: - scale_s = ((3') - (3)) / ((2') - (2)) + scale_s = ((2') - (2)) / ((3') - (3)) 2. Calculate "effective" input crop (sensor subwindow) - CEU crop scaled back at current sensor scales onto input window - this is user S_CROP: @@ -80,7 +80,7 @@ window: 4. Calculate sensor output window by applying combined scales to real input window: - width_s_out = ((2') - (2)) / scale_comb + width_s_out = ((7') - (7)) = ((2') - (2)) / scale_comb 5. Apply iterative sensor S_FMT for sensor output window. diff --git a/Documentation/virtual/00-INDEX b/Documentation/virtual/00-INDEX new file mode 100644 index 000000000000..fe0251c4cfb7 --- /dev/null +++ b/Documentation/virtual/00-INDEX @@ -0,0 +1,10 @@ +Virtualization support in the Linux kernel. + +00-INDEX + - this file. +kvm/ + - Kernel Virtual Machine. See also http://linux-kvm.org +lguest/ + - Extremely simple hypervisor for experimental/educational use. +uml/ + - User Mode Linux, builds/runs Linux kernel as a userspace program. diff --git a/Documentation/kvm/api.txt b/Documentation/virtual/kvm/api.txt similarity index 100% rename from Documentation/kvm/api.txt rename to Documentation/virtual/kvm/api.txt diff --git a/Documentation/kvm/cpuid.txt b/Documentation/virtual/kvm/cpuid.txt similarity index 100% rename from Documentation/kvm/cpuid.txt rename to Documentation/virtual/kvm/cpuid.txt diff --git a/Documentation/kvm/locking.txt b/Documentation/virtual/kvm/locking.txt similarity index 100% rename from Documentation/kvm/locking.txt rename to Documentation/virtual/kvm/locking.txt diff --git a/Documentation/kvm/mmu.txt b/Documentation/virtual/kvm/mmu.txt similarity index 100% rename from Documentation/kvm/mmu.txt rename to Documentation/virtual/kvm/mmu.txt diff --git a/Documentation/kvm/msr.txt b/Documentation/virtual/kvm/msr.txt similarity index 100% rename from Documentation/kvm/msr.txt rename to Documentation/virtual/kvm/msr.txt diff --git a/Documentation/kvm/ppc-pv.txt b/Documentation/virtual/kvm/ppc-pv.txt similarity index 100% rename from Documentation/kvm/ppc-pv.txt rename to Documentation/virtual/kvm/ppc-pv.txt diff --git a/Documentation/kvm/review-checklist.txt b/Documentation/virtual/kvm/review-checklist.txt similarity index 95% rename from Documentation/kvm/review-checklist.txt rename to Documentation/virtual/kvm/review-checklist.txt index 730475ae1b8d..a850986ed684 100644 --- a/Documentation/kvm/review-checklist.txt +++ b/Documentation/virtual/kvm/review-checklist.txt @@ -7,7 +7,7 @@ Review checklist for kvm patches 2. Patches should be against kvm.git master branch. 3. If the patch introduces or modifies a new userspace API: - - the API must be documented in Documentation/kvm/api.txt + - the API must be documented in Documentation/virtual/kvm/api.txt - the API must be discoverable using KVM_CHECK_EXTENSION 4. New state must include support for save/restore. diff --git a/Documentation/kvm/timekeeping.txt b/Documentation/virtual/kvm/timekeeping.txt similarity index 100% rename from Documentation/kvm/timekeeping.txt rename to Documentation/virtual/kvm/timekeeping.txt diff --git a/Documentation/lguest/.gitignore b/Documentation/virtual/lguest/.gitignore similarity index 100% rename from Documentation/lguest/.gitignore rename to Documentation/virtual/lguest/.gitignore diff --git a/Documentation/lguest/Makefile b/Documentation/virtual/lguest/Makefile similarity index 100% rename from Documentation/lguest/Makefile rename to Documentation/virtual/lguest/Makefile diff --git a/Documentation/lguest/extract b/Documentation/virtual/lguest/extract similarity index 100% rename from Documentation/lguest/extract rename to Documentation/virtual/lguest/extract diff --git a/Documentation/lguest/lguest.c b/Documentation/virtual/lguest/lguest.c similarity index 100% rename from Documentation/lguest/lguest.c rename to Documentation/virtual/lguest/lguest.c diff --git a/Documentation/lguest/lguest.txt b/Documentation/virtual/lguest/lguest.txt similarity index 97% rename from Documentation/lguest/lguest.txt rename to Documentation/virtual/lguest/lguest.txt index dad99978a6a8..bff0c554485d 100644 --- a/Documentation/lguest/lguest.txt +++ b/Documentation/virtual/lguest/lguest.txt @@ -74,7 +74,8 @@ Running Lguest: - Run an lguest as root: - Documentation/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 --block=rootfile root=/dev/vda + Documentation/virtual/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 \ + --block=rootfile root=/dev/vda Explanation: 64: the amount of memory to use, in MB. diff --git a/Documentation/uml/UserModeLinux-HOWTO.txt b/Documentation/virtual/uml/UserModeLinux-HOWTO.txt similarity index 100% rename from Documentation/uml/UserModeLinux-HOWTO.txt rename to Documentation/virtual/uml/UserModeLinux-HOWTO.txt diff --git a/Documentation/workqueue.txt b/Documentation/workqueue.txt index 01c513fac40e..a0b577de918f 100644 --- a/Documentation/workqueue.txt +++ b/Documentation/workqueue.txt @@ -12,6 +12,7 @@ CONTENTS 4. Application Programming Interface (API) 5. Example Execution Scenarios 6. Guidelines +7. Debugging 1. Introduction @@ -379,3 +380,42 @@ If q1 has WQ_CPU_INTENSIVE set, * Unless work items are expected to consume a huge amount of CPU cycles, using a bound wq is usually beneficial due to the increased level of locality in wq operations and work item execution. + + +7. Debugging + +Because the work functions are executed by generic worker threads +there are a few tricks needed to shed some light on misbehaving +workqueue users. + +Worker threads show up in the process list as: + +root 5671 0.0 0.0 0 0 ? S 12:07 0:00 [kworker/0:1] +root 5672 0.0 0.0 0 0 ? S 12:07 0:00 [kworker/1:2] +root 5673 0.0 0.0 0 0 ? S 12:12 0:00 [kworker/0:0] +root 5674 0.0 0.0 0 0 ? S 12:13 0:00 [kworker/1:0] + +If kworkers are going crazy (using too much cpu), there are two types +of possible problems: + + 1. Something beeing scheduled in rapid succession + 2. A single work item that consumes lots of cpu cycles + +The first one can be tracked using tracing: + + $ echo workqueue:workqueue_queue_work > /sys/kernel/debug/tracing/set_event + $ cat /sys/kernel/debug/tracing/trace_pipe > out.txt + (wait a few secs) + ^C + +If something is busy looping on work queueing, it would be dominating +the output and the offender can be determined with the work item +function. + +For the second type of problems it should be possible to just check +the stack trace of the offending worker thread. + + $ cat /proc/THE_OFFENDING_KWORKER/stack + +The work item's function should be trivially visible in the stack +trace. diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt index 092e596a1301..c54b4f503e2a 100644 --- a/Documentation/x86/x86_64/boot-options.txt +++ b/Documentation/x86/x86_64/boot-options.txt @@ -206,7 +206,7 @@ IOMMU (input/output memory management unit) (e.g. because you have < 3 GB memory). Kernel boot message: "PCI-DMA: Disabling IOMMU" - 2. : AMD GART based hardware IOMMU. + 2. : AMD GART based hardware IOMMU. Kernel boot message: "PCI-DMA: using GART IOMMU" 3. : Software IOMMU implementation. Used diff --git a/Documentation/zh_CN/email-clients.txt b/Documentation/zh_CN/email-clients.txt new file mode 100644 index 000000000000..5d65e323d060 --- /dev/null +++ b/Documentation/zh_CN/email-clients.txt @@ -0,0 +1,210 @@ +锘?Chinese translated version of Documentation/email-clients.txt + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Chinese maintainer: Harry Wei +--------------------------------------------------------------------- +Documentation/email-clients.txt ???涓????缈昏?? + +濡??????宠??璁烘????存?版???????????瀹癸??璇风?存?ヨ??绯诲?????妗g??缁存?よ?????濡????浣?浣跨?ㄨ?辨?? +浜ゆ???????伴?剧??璇?锛?涔????浠ュ??涓???????缁存?よ??姹???┿??濡???????缈昏????存?颁???????舵?????缈? +璇?瀛???ㄩ??棰?锛?璇疯??绯讳腑??????缁存?よ????? + +涓???????缁存?よ??锛? 璐惧??濞? Harry Wei +涓???????缈昏?????锛? 璐惧??濞? Harry Wei +涓?????????¤?????锛? Yinglin Luan + Xiaochen Wang + yaxinsn + +浠ヤ??涓烘?f?? +--------------------------------------------------------------------- + +Linux???浠跺?㈡?风?????缃?淇℃?? +====================================================================== + +?????????缃? +---------------------------------------------------------------------- +Linux?????歌ˉ涓???????杩????浠惰?????浜ょ??锛????濂芥??琛ヤ??浣?涓洪??浠朵????????宓?????????????浜?缁存?よ?? +??ユ?堕??浠讹??浣???????浠剁?????瀹规?煎??搴?璇ユ??"text/plain"?????惰??锛????浠朵????????涓?璧???????锛? +???涓鸿??浼?浣胯ˉ涓????寮???ㄩ?ㄥ????ㄨ??璁鸿??绋?涓???????寰???伴?俱?? + +??ㄦ?ュ?????Linux?????歌ˉ涓???????浠跺?㈡?风????ㄥ?????琛ヤ????跺??璇ュ??浜?????????????濮???舵?????渚?濡?锛? +浠?浠?涓???芥?瑰?????????????ゅ?惰〃绗???????绌烘?硷???????虫????ㄦ??涓?琛????寮?澶存?????缁?灏俱?? + +涓?瑕????杩?"format=flowed"妯″????????琛ヤ?????杩???蜂??寮?璧蜂?????棰????浠ュ?????瀹崇?????琛???? + +涓?瑕?璁╀????????浠跺?㈡?风??杩?琛??????ㄦ?㈣?????杩???蜂??浼???村??浣????琛ヤ????? + +???浠跺?㈡?风??涓???芥?瑰???????????瀛?绗????缂??????瑰?????瑕??????????琛ヤ???????芥??ASCII??????UTF-8缂??????瑰??锛? +濡????浣?浣跨??UTF-8缂??????瑰???????????浠讹????d??浣?灏?浼???垮??涓?浜??????藉????????瀛?绗???????棰???? + +???浠跺?㈡?风??搴?璇ュ舰???骞朵??淇???? References: ?????? In-Reply-To: ???棰?锛???d?? +???浠惰??棰?灏变??浼?涓??????? + +澶???剁??甯?(?????????璐寸??甯?)???甯镐????界?ㄤ??琛ヤ??锛????涓哄?惰〃绗?浼?杞????涓虹┖??笺??浣跨??xclipboard, xclip +??????xcutsel涔?璁稿??浠ワ??浣???????濂芥??璇?涓?涓?????????垮??浣跨?ㄥ????剁??甯???? + +涓?瑕???ㄤ娇???PGP/GPG缃插????????浠朵腑??????琛ヤ?????杩???蜂??浣垮??寰?澶???????涓???借?诲??????????ㄤ??浣????琛ヤ????? +锛?杩?涓????棰?搴?璇ユ?????浠ヤ慨澶????锛? + +??ㄧ???????搁??浠跺??琛ㄥ?????琛ヤ??涔????锛?缁????宸卞?????涓?涓?琛ヤ?????涓?涓???????涓绘??锛?淇?瀛???ユ?跺?扮?? +???浠讹??灏?琛ヤ?????'patch'??戒护???涓?锛?濡??????????浜?锛????缁??????搁??浠跺??琛ㄥ???????? + + +涓?浜????浠跺?㈡?风?????绀? +---------------------------------------------------------------------- +杩????缁???轰??浜?璇?缁????MUA???缃????绀猴?????浠ョ?ㄤ??缁?Linux?????稿?????琛ヤ?????杩?浜?骞朵???????虫?? +?????????杞?浠跺?????缃???荤????? + +璇存??锛? +TUI = 浠ユ?????涓哄?虹???????ㄦ?锋?ュ?? +GUI = ??惧舰?????㈢?ㄦ?锋?ュ?? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Alpine (TUI) + +???缃????椤癸?? +???"Sending Preferences"??ㄥ??锛? + +- "Do Not Send Flowed Text"蹇?椤诲????? +- "Strip Whitespace Before Sending"蹇?椤诲?抽?? + +褰???????浠舵?讹????????搴?璇ユ?惧?ㄨˉ涓?浼???虹?扮????版?癸????跺?????涓?CTRL-R缁???????锛?浣挎??瀹???? +琛ヤ?????浠跺????ュ?伴??浠朵腑??? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Evolution (GUI) + +涓?浜?寮????????????????浣跨?ㄥ????????琛ヤ?? + +褰??????╅??浠堕??椤癸??Preformat + 浠?Format->Heading->Preformatted (Ctrl-7)??????宸ュ?锋?? + +??跺??浣跨??锛? + Insert->Text File... (Alt-n x)?????ヨˉ涓????浠躲?? + +浣?杩????浠?"diff -Nru old.c new.c | xclip"锛???????Preformat锛???跺??浣跨?ㄤ腑??撮??杩?琛?绮?甯???? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Kmail (GUI) + +涓?浜?寮????????????????浣跨?ㄥ????????琛ヤ????? + +榛?璁よ?剧疆涓?涓?HTML??煎??????????????锛?涓?瑕??????ㄥ????? + +褰?涔????涓?灏????浠剁????跺??锛???ㄩ??椤逛?????涓?瑕??????╄????ㄦ?㈣????????涓????缂虹?瑰氨???浣???ㄩ??浠朵腑杈???ョ??浠讳???????? +??戒??浼?琚??????ㄦ?㈣??锛????姝や??蹇?椤诲?ㄥ?????琛ヤ??涔?????????ㄦ?㈣????????绠?????????规??灏辨???????ㄨ????ㄦ?㈣????ヤ功??????浠讹?? +??跺?????瀹?淇?瀛?涓鸿??绋裤??涓????浣???ㄨ??绋夸腑???娆℃??寮?瀹?锛?瀹?宸茬????ㄩ?ㄨ????ㄦ?㈣??浜?锛???d??浣???????浠惰?界?舵病??? +?????╄????ㄦ?㈣??锛?浣????杩?涓?浼?澶卞?诲凡???????????ㄦ?㈣????? + +??ㄩ??浠剁??搴????锛??????ヨˉ涓?涔????锛???句??甯哥?ㄧ??琛ヤ??瀹????绗?锛?涓?涓?杩?瀛????(---)??? + +??跺?????"Message"????????$??锛??????╂????ユ??浠讹????ョ????????浣????琛ヤ?????浠躲??杩????涓?涓?棰?澶???????椤癸??浣????浠? +???杩?瀹????缃?浣???????浠跺缓绔?宸ュ?锋????????锛?杩????浠ュ甫涓?"insert file"??炬????? + +浣????浠ュ????ㄥ?伴??杩?GPG???璁伴??浠讹??浣???????宓?琛ヤ?????濂戒??瑕?浣跨??GPG???璁板??浠????浣?涓哄??宓??????????绛惧??琛ヤ??锛? +褰?浠?GPG涓???????7浣?缂??????朵??浣夸??浠?????????村??澶??????? + +濡????浣????瑕?浠ラ??浠剁??褰㈠????????琛ヤ??锛???d??灏卞?抽????瑰?婚??浠讹????跺?????涓?灞???э??绐????"Suggest automatic +display"锛?杩???峰??宓????浠舵?村?规??璁╄?昏???????般?? + +褰?浣?瑕?淇?瀛?灏?瑕?????????????宓???????琛ヤ??锛?浣????浠ヤ??娑???????琛ㄧ????奸????╁?????琛ヤ????????浠讹????跺????冲?婚????? +"save as"???浣????浠ヤ娇??ㄤ??涓?娌℃????存?圭????????琛ヤ????????浠讹??濡????瀹????浠ユ?g‘???褰㈠??缁???????褰?浣?姝g????ㄥ?? +???宸辩??绐???d??涓?瀵????锛???f?舵病??????椤瑰??浠ヤ??瀛????浠?--宸茬?????涓?涓?杩???风??bug琚?姹???ュ?颁??kmail???bugzilla +骞朵??甯????杩?灏?浼?琚?澶??????????浠舵??浠ュ?????瀵规??涓???ㄦ?峰??璇诲???????????琚?淇?瀛????锛????浠ュ?????浣???虫?????浠跺????跺?板?朵????版?癸?? +浣?涓?寰?涓????浠?浠????????????逛负缁?????????翠?????璇汇?? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Lotus Notes (GUI) + +涓?瑕?浣跨?ㄥ????? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Mutt (TUI) + +寰?澶?Linux寮????浜哄??浣跨??mutt瀹㈡?风??锛????浠ヨ?????瀹????瀹?宸ヤ????????甯告??浜???? + +Mutt涓????甯?缂?杈????锛????浠ヤ??绠′??浣跨?ㄤ??涔?缂?杈???ㄩ?戒??搴?璇ュ甫????????ㄦ??琛????澶у????扮??杈???ㄩ?藉甫??? +涓?涓?"insert file"???椤癸??瀹????浠ラ??杩?涓???瑰?????浠跺??瀹圭????瑰???????ユ??浠躲?? + +'vim'浣?涓?mutt???缂?杈????锛? + set editor="vi" + + 濡????浣跨??xclip锛???插?ヤ互涓???戒护 + :set paste + ???涓????涔??????????shift-insert??????浣跨?? + :r filename + +濡??????宠?????琛ヤ??浣?涓哄??宓?????????? +(a)ttach宸ヤ?????寰?濂斤??涓?甯????"set paste"??? + +???缃????椤癸?? +瀹?搴?璇ヤ互榛?璁よ?剧疆???褰㈠??宸ヤ????? +??惰??锛????"send_charset"璁剧疆涓?"us-ascii::utf-8"涔????涓?涓?涓???????涓绘????? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Pine (TUI) + +Pine杩???绘??涓?浜?绌烘?煎????????棰?锛?浣????杩?浜???板?ㄥ??璇ラ?借??淇?澶?浜???? + +濡???????浠ワ??璇蜂娇???alpine(pine???缁ф?胯??) + +???缃????椤癸?? +- ???杩?????????????瑕?娑???ゆ??绋??????? +- "no-strip-whitespace-before-send"???椤逛????????瑕??????? + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Sylpheed (GUI) + +- ???宓??????????浠ュ??濂界??宸ヤ??锛???????浣跨?ㄩ??浠讹????? +- ???璁镐娇??ㄥ????ㄧ??缂?杈???ㄣ?? +- 瀵逛?????褰?杈?澶???堕??甯告????? +- 濡???????杩?non-SSL杩???ワ?????娉?浣跨??TLS SMTP????????? +- ??ㄧ?????绐???d腑???涓?涓?寰??????ㄧ??ruler bar??? +- 缁???板?????涓?娣诲????板??灏变??浼?姝g‘???浜?瑙f?剧ず?????? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Thunderbird (GUI) + +榛?璁ゆ????典??锛?thunderbird寰?瀹规??????????????锛?浣????杩????涓?浜???规?????浠ュ己??跺?????寰???村ソ??? + +- ??ㄧ?ㄦ?峰????疯?剧疆???锛?缁???????瀵诲??锛?涓?瑕???????"Compose messages in HTML format"??? + +- 缂?杈?浣????Thunderbird???缃?璁剧疆??ヤ娇瀹?涓?瑕????琛?浣跨??锛?user_pref("mailnews.wraplength", 0); + +- 缂?杈?浣????Thunderbird???缃?璁剧疆锛?浣垮??涓?瑕?浣跨??"format=flowed"??煎??锛?user_pref("mailnews. + send_plaintext_flowed", false); + +- 浣????瑕?浣?Thunderbird???涓洪???????煎????瑰??锛? + 濡????榛?璁ゆ????典??浣?涔??????????HTML??煎??锛???d?????寰???俱??浠?浠?浠????棰???????涓????妗?涓???????"Preformat"??煎????? + 濡????榛?璁ゆ????典??浣?涔??????????????????煎??锛?浣?涓?寰????瀹???逛负HTML??煎??锛?浠?浠?浣?涓轰??娆℃?х??锛???ヤ功?????扮??娑????锛? + ??跺??寮哄?朵娇瀹??????版???????煎??锛???????瀹?灏变?????琛????瑕?瀹???板??锛???ㄥ??淇$????炬??涓?浣跨??shift?????ヤ娇瀹????涓?HTML + ??煎??锛???跺?????棰???????涓????妗?涓???????"Preformat"??煎????? + +- ???璁镐娇??ㄥ????ㄧ??缂?杈????锛? + ???瀵?Thunderbird???琛ヤ?????绠?????????规??灏辨??浣跨?ㄤ??涓?"external editor"??╁??锛???跺??浣跨?ㄤ????????娆㈢?? + $EDITOR??ヨ?诲???????????骞惰ˉ涓???版?????涓????瑕?瀹???板??锛????浠ヤ??杞藉苟涓?瀹?瑁?杩?涓???╁??锛???跺??娣诲??涓?涓?浣跨?ㄥ????? + ??????View->Toolbars->Customize...??????褰?浣?涔????淇℃???????跺??浠?浠???瑰?诲??灏卞??浠ヤ????? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +TkRat (GUI) + +???浠ヤ娇??ㄥ?????浣跨??"Insert file..."??????澶???ㄧ??缂?杈???ㄣ?? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Gmail (Web GUI) + +涓?瑕?浣跨?ㄥ????????琛ヤ????? + +Gmail缃?椤靛?㈡?风???????ㄥ?版????惰〃绗?杞????涓虹┖??笺?? + +??界?跺?惰〃绗?杞????涓虹┖??奸??棰????浠ヨ??澶???ㄧ??杈???ㄨВ??筹???????跺??杩?浼?浣跨?ㄥ??杞???㈣?????姣?琛???????涓?78涓?瀛?绗???? + +???涓?涓????棰????Gmail杩?浼????浠讳??涓????ASCII???瀛?绗????淇℃????逛负base64缂???????瀹????涓?瑗垮????????娆ф床浜虹?????瀛???? + + ### diff --git a/MAINTAINERS b/MAINTAINERS index ec3600306289..49a0bf3a5b97 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -151,6 +151,7 @@ S: Maintained F: drivers/net/hamradio/6pack.c 8169 10/100/1000 GIGABIT ETHERNET DRIVER +M: Realtek linux nic maintainers M: Francois Romieu L: netdev@vger.kernel.org S: Maintained @@ -404,8 +405,8 @@ S: Maintained F: sound/oss/aedsp16.c AFFS FILE SYSTEM -M: Roman Zippel -S: Maintained +L: linux-fsdevel@vger.kernel.org +S: Orphan F: Documentation/filesystems/affs.txt F: fs/affs/ @@ -1031,12 +1032,13 @@ W: http://www.fluff.org/ben/linux/ S: Maintained F: arch/arm/mach-s3c64xx/ -ARM/S5P ARM ARCHITECTURES +ARM/S5P EXYNOS ARM ARCHITECTURES M: Kukjin Kim L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-s5p*/ +F: arch/arm/mach-exynos*/ ARM/SAMSUNG MOBILE MACHINE SUPPORT M: Kyungmin Park @@ -1230,13 +1232,6 @@ W: http://wireless.kernel.org/en/users/Drivers/ath9k S: Supported F: drivers/net/wireless/ath/ath9k/ -ATHEROS AR9170 WIRELESS DRIVER -M: Christian Lamparter -L: linux-wireless@vger.kernel.org -W: http://wireless.kernel.org/en/users/Drivers/ar9170 -S: Obsolete -F: drivers/net/wireless/ath/ar9170/ - CARL9170 LINUX COMMUNITY WIRELESS DRIVER M: Christian Lamparter L: linux-wireless@vger.kernel.org @@ -2807,42 +2802,23 @@ GPIO SUBSYSTEM M: Grant Likely S: Maintained T: git git://git.secretlab.ca/git/linux-2.6.git -F: Documentation/gpio/gpio.txt +F: Documentation/gpio.txt F: drivers/gpio/ F: include/linux/gpio* +GRE DEMULTIPLEXER DRIVER +M: Dmitry Kozlov +L: netdev@vger.kernel.org +S: Maintained +F: net/ipv4/gre.c +F: include/net/gre.h + GRETH 10/100/1G Ethernet MAC device driver M: Kristoffer Glembo L: netdev@vger.kernel.org S: Maintained F: drivers/net/greth* -HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER -M: Frank Seidel -L: platform-driver-x86@vger.kernel.org -W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/ -S: Maintained -F: drivers/platform/x86/hdaps.c - -HWPOISON MEMORY FAILURE HANDLING -M: Andi Kleen -L: linux-mm@kvack.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison -S: Maintained -F: mm/memory-failure.c -F: mm/hwpoison-inject.c - -HYPERVISOR VIRTUAL CONSOLE DRIVER -L: linuxppc-dev@lists.ozlabs.org -S: Odd Fixes -F: drivers/tty/hvc/ - -iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER -M: Peter Jones -M: Konrad Rzeszutek Wilk -S: Maintained -F: drivers/firmware/iscsi_ibft* - GSPCA FINEPIX SUBDRIVER M: Frank Zago L: linux-media@vger.kernel.org @@ -2893,6 +2869,26 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git S: Maintained F: drivers/media/video/gspca/ +HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER +M: Frank Seidel +L: platform-driver-x86@vger.kernel.org +W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/ +S: Maintained +F: drivers/platform/x86/hdaps.c + +HWPOISON MEMORY FAILURE HANDLING +M: Andi Kleen +L: linux-mm@kvack.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison +S: Maintained +F: mm/memory-failure.c +F: mm/hwpoison-inject.c + +HYPERVISOR VIRTUAL CONSOLE DRIVER +L: linuxppc-dev@lists.ozlabs.org +S: Odd Fixes +F: drivers/tty/hvc/ + HARDWARE MONITORING M: Jean Delvare M: Guenter Roeck @@ -2943,8 +2939,8 @@ F: drivers/block/cciss* F: include/linux/cciss_ioctl.h HFS FILESYSTEM -M: Roman Zippel -S: Maintained +L: linux-fsdevel@vger.kernel.org +S: Orphan F: Documentation/filesystems/hfs.txt F: fs/hfs/ @@ -3360,6 +3356,12 @@ F: Documentation/wimax/README.i2400m F: drivers/net/wimax/i2400m/ F: include/linux/wimax/i2400m.h +INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy) +M: Stanislaw Gruszka +L: linux-wireless@vger.kernel.org +S: Supported +F: drivers/net/wireless/iwlegacy/ + INTEL WIRELESS WIFI LINK (iwlwifi) M: Wey-Yi Guy M: Intel Linux Wireless @@ -3476,6 +3478,12 @@ F: Documentation/isapnp.txt F: drivers/pnp/isapnp/ F: include/linux/isapnp.h +iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER +M: Peter Jones +M: Konrad Rzeszutek Wilk +S: Maintained +F: drivers/firmware/iscsi_ibft* + ISCSI M: Mike Christie L: open-iscsi@googlegroups.com @@ -3805,7 +3813,7 @@ M: Rusty Russell L: lguest@lists.ozlabs.org W: http://lguest.ozlabs.org/ S: Odd Fixes -F: Documentation/lguest/ +F: Documentation/virtual/lguest/ F: arch/x86/lguest/ F: drivers/lguest/ F: include/linux/lguest*.h @@ -3992,7 +4000,6 @@ F: arch/m32r/ M68K ARCHITECTURE M: Geert Uytterhoeven -M: Roman Zippel L: linux-m68k@lists.linux-m68k.org W: http://www.linux-m68k.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git @@ -4377,6 +4384,7 @@ S: Maintained F: net/ipv4/ F: net/ipv6/ F: include/net/ip* +F: arch/x86/net/* NETWORKING [LABELED] (NetLabel, CIPSO, Labeled IPsec, SECMARK) M: Paul Moore @@ -4987,6 +4995,13 @@ F: Documentation/pps/ F: drivers/pps/ F: include/linux/pps*.h +PPTP DRIVER +M: Dmitry Kozlov +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/pptp.c +W: http://sourceforge.net/projects/accel-pptp + PREEMPTIBLE KERNEL M: Robert Love L: kpreempt-tech@lists.sourceforge.net @@ -5395,7 +5410,7 @@ F: drivers/media/video/*7146* F: include/media/*7146* SAMSUNG AUDIO (ASoC) DRIVERS -M: Jassi Brar +M: Jassi Brar L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Supported F: sound/soc/samsung @@ -5416,6 +5431,7 @@ F: include/linux/timex.h F: kernel/time/clocksource.c F: kernel/time/time*.c F: kernel/time/ntp.c +F: drivers/clocksource TLG2300 VIDEO4LINUX-2 DRIVER M: Huang Shijie @@ -5596,9 +5612,9 @@ F: include/linux/ata.h F: include/linux/libata.h SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER -M: Jayamohan Kallickal +M: Jayamohan Kallickal L: linux-scsi@vger.kernel.org -W: http://www.serverengines.com +W: http://www.emulex.com S: Supported F: drivers/scsi/be2iscsi/ @@ -5816,6 +5832,13 @@ S: Maintained F: drivers/ssb/ F: include/linux/ssb/ +BROADCOM SPECIFIC AMBA DRIVER (BCMA) +M: Rafał Miłecki +L: linux-wireless@vger.kernel.org +S: Maintained +F: drivers/bcma/ +F: include/linux/bcma/ + SONY VAIO CONTROL DEVICE DRIVER M: Mattia Dongili L: platform-driver-x86@vger.kernel.org @@ -6554,7 +6577,7 @@ S: Maintained F: drivers/usb/host/uhci* USB "USBNET" DRIVER FRAMEWORK -M: David Brownell +M: Oliver Neukum L: netdev@vger.kernel.org W: http://www.linux-usb.org/usbnet S: Maintained @@ -6616,7 +6639,7 @@ L: user-mode-linux-devel@lists.sourceforge.net L: user-mode-linux-user@lists.sourceforge.net W: http://user-mode-linux.sourceforge.net S: Maintained -F: Documentation/uml/ +F: Documentation/virtual/uml/ F: arch/um/ F: fs/hostfs/ F: fs/hppfs/ @@ -6920,6 +6943,18 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86. S: Maintained F: drivers/platform/x86 +XEN HYPERVISOR INTERFACE +M: Jeremy Fitzhardinge +M: Konrad Rzeszutek Wilk +L: xen-devel@lists.xensource.com (moderated for non-subscribers) +L: virtualization@lists.linux-foundation.org +S: Supported +F: arch/x86/xen/ +F: drivers/*/xen-*front.c +F: drivers/xen/ +F: arch/x86/include/asm/xen/ +F: include/xen/ + XEN NETWORK BACKEND DRIVER M: Ian Campbell L: xen-devel@lists.xensource.com (moderated for non-subscribers) @@ -6941,18 +6976,6 @@ S: Supported F: arch/x86/xen/*swiotlb* F: drivers/xen/*swiotlb* -XEN HYPERVISOR INTERFACE -M: Jeremy Fitzhardinge -M: Konrad Rzeszutek Wilk -L: xen-devel@lists.xensource.com (moderated for non-subscribers) -L: virtualization@lists.linux-foundation.org -S: Supported -F: arch/x86/xen/ -F: drivers/*/xen-*front.c -F: drivers/xen/ -F: arch/x86/include/asm/xen/ -F: include/xen/ - XFS FILESYSTEM P: Silicon Graphics Inc M: Alex Elder @@ -7022,20 +7045,6 @@ M: "Maciej W. Rozycki" S: Maintained F: drivers/tty/serial/zs.* -GRE DEMULTIPLEXER DRIVER -M: Dmitry Kozlov -L: netdev@vger.kernel.org -S: Maintained -F: net/ipv4/gre.c -F: include/net/gre.h - -PPTP DRIVER -M: Dmitry Kozlov -L: netdev@vger.kernel.org -S: Maintained -F: drivers/net/pptp.c -W: http://sourceforge.net/projects/accel-pptp - THE REST M: Linus Torvalds L: linux-kernel@vger.kernel.org diff --git a/Makefile b/Makefile index 322e7334ccb9..a0344a81a893 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 39 -EXTRAVERSION = -rc3 +EXTRAVERSION = NAME = Flesh-Eating Bats with Fangs # *DOCUMENTATION* @@ -1268,6 +1268,7 @@ help: @echo ' make C=1 [targets] Check all c source with $$CHECK (sparse by default)' @echo ' make C=2 [targets] Force check of all c source with $$CHECK' @echo ' make W=1 [targets] Enable extra gcc checks' + @echo ' make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections' @echo '' @echo 'Execute "make" or "make all" to build all targets marked with [*] ' @echo 'For further info see the ./README file' diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h index 058937bf5a77..b1834166922d 100644 --- a/arch/alpha/include/asm/unistd.h +++ b/arch/alpha/include/asm/unistd.h @@ -452,10 +452,14 @@ #define __NR_fanotify_init 494 #define __NR_fanotify_mark 495 #define __NR_prlimit64 496 +#define __NR_name_to_handle_at 497 +#define __NR_open_by_handle_at 498 +#define __NR_clock_adjtime 499 +#define __NR_syncfs 500 #ifdef __KERNEL__ -#define NR_SYSCALLS 497 +#define NR_SYSCALLS 501 #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 42aa078a5e4d..5a621c6d22ab 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -585,8 +585,7 @@ handle_ipi(struct pt_regs *regs) switch (which) { case IPI_RESCHEDULE: - /* Reschedule callback. Everything to be done - is done by the interrupt return path. */ + scheduler_ipi(); break; case IPI_CALL_FUNC: diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S index a6a1de9db16f..15f999d41c75 100644 --- a/arch/alpha/kernel/systbls.S +++ b/arch/alpha/kernel/systbls.S @@ -498,23 +498,27 @@ sys_call_table: .quad sys_ni_syscall /* sys_timerfd */ .quad sys_eventfd .quad sys_recvmmsg - .quad sys_fallocate /* 480 */ + .quad sys_fallocate /* 480 */ .quad sys_timerfd_create .quad sys_timerfd_settime .quad sys_timerfd_gettime .quad sys_signalfd4 - .quad sys_eventfd2 /* 485 */ + .quad sys_eventfd2 /* 485 */ .quad sys_epoll_create1 .quad sys_dup3 .quad sys_pipe2 .quad sys_inotify_init1 - .quad sys_preadv /* 490 */ + .quad sys_preadv /* 490 */ .quad sys_pwritev .quad sys_rt_tgsigqueueinfo .quad sys_perf_event_open .quad sys_fanotify_init - .quad sys_fanotify_mark /* 495 */ + .quad sys_fanotify_mark /* 495 */ .quad sys_prlimit64 + .quad sys_name_to_handle_at + .quad sys_open_by_handle_at + .quad sys_clock_adjtime + .quad sys_syncfs /* 500 */ .size sys_call_table, . - sys_call_table .type sys_call_table, @object diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index 918e8e0b72ff..818e74ed45dc 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -375,8 +375,7 @@ static struct clocksource clocksource_rpcc = { static inline void register_rpcc_clocksource(long cycle_freq) { - clocksource_calc_mult_shift(&clocksource_rpcc, cycle_freq, 4); - clocksource_register(&clocksource_rpcc); + clocksource_register_hz(&clocksource_rpcc, cycle_freq); } #else /* !CONFIG_SMP */ static inline void register_rpcc_clocksource(long cycle_freq) diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S index 433be2a24f31..3d890a98a08b 100644 --- a/arch/alpha/kernel/vmlinux.lds.S +++ b/arch/alpha/kernel/vmlinux.lds.S @@ -46,6 +46,7 @@ SECTIONS __init_end = .; /* Freed after init ends here */ + _sdata = .; /* Start of rw data section */ _data = .; RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 8ebbb511c783..0c6852d93506 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -74,7 +74,7 @@ ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT) ZBSSADDR := $(CONFIG_ZBOOT_ROM_BSS) else ZTEXTADDR := 0 -ZBSSADDR := ALIGN(4) +ZBSSADDR := ALIGN(8) endif SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/ diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index adf583cd0c35..49f5b2eaaa87 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -179,15 +179,14 @@ not_angel: bl cache_on restart: adr r0, LC0 - ldmia r0, {r1, r2, r3, r5, r6, r9, r11, r12} - ldr sp, [r0, #32] + ldmia r0, {r1, r2, r3, r6, r9, r11, r12} + ldr sp, [r0, #28] /* * We might be running at a different address. We need * to fix up various pointers. */ sub r0, r0, r1 @ calculate the delta offset - add r5, r5, r0 @ _start add r6, r6, r0 @ _edata #ifndef CONFIG_ZBOOT_ROM @@ -206,31 +205,40 @@ restart: adr r0, LC0 /* * Check to see if we will overwrite ourselves. * r4 = final kernel address - * r5 = start of this image * r9 = size of decompressed image * r10 = end of this image, including bss/stack/malloc space if non XIP * We basically want: - * r4 >= r10 -> OK - * r4 + image length <= r5 -> OK + * r4 - 16k page directory >= r10 -> OK + * r4 + image length <= current position (pc) -> OK */ + add r10, r10, #16384 cmp r4, r10 bhs wont_overwrite add r10, r4, r9 - cmp r10, r5 + ARM( cmp r10, pc ) + THUMB( mov lr, pc ) + THUMB( cmp r10, lr ) bls wont_overwrite /* * Relocate ourselves past the end of the decompressed kernel. - * r5 = start of this image * r6 = _edata * r10 = end of the decompressed kernel * Because we always copy ahead, we need to do it from the end and go * backward in case the source and destination overlap. */ - /* Round up to next 256-byte boundary. */ - add r10, r10, #256 + /* + * Bump to the next 256-byte boundary with the size of + * the relocation code added. This avoids overwriting + * ourself when the offset is small. + */ + add r10, r10, #((reloc_code_end - restart + 256) & ~255) bic r10, r10, #255 + /* Get start of code we want to copy and align it down. */ + adr r5, restart + bic r5, r5, #31 + sub r9, r6, r5 @ size to copy add r9, r9, #31 @ rounded up to a multiple bic r9, r9, #31 @ ... of 32 bytes @@ -245,6 +253,11 @@ restart: adr r0, LC0 /* Preserve offset to relocated code. */ sub r6, r9, r6 +#ifndef CONFIG_ZBOOT_ROM + /* cache_clean_flush may use the stack, so relocate it */ + add sp, sp, r6 +#endif + bl cache_clean_flush adr r0, BSYM(restart) @@ -333,7 +346,6 @@ not_relocated: mov r0, #0 LC0: .word LC0 @ r1 .word __bss_start @ r2 .word _end @ r3 - .word _start @ r5 .word _edata @ r6 .word _image_size @ r9 .word _got_start @ r11 @@ -1062,6 +1074,7 @@ memdump: mov r12, r0 #endif .ltorg +reloc_code_end: .align .section ".stack", "aw", %nobits diff --git a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in index 5309909d7282..ea80abe78844 100644 --- a/arch/arm/boot/compressed/vmlinux.lds.in +++ b/arch/arm/boot/compressed/vmlinux.lds.in @@ -54,6 +54,7 @@ SECTIONS .bss : { *(.bss) } _end = .; + . = ALIGN(8); /* the stack must be 64-bit aligned */ .stack : { *(.stack) } .stab 0 : { *(.stab) } diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index 113085a77123..7aa4262ada7a 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c @@ -22,17 +22,16 @@ #include #include #include -#include +#include #include #include #include #include -#if defined(CONFIG_PM) +#ifdef CONFIG_PM /** * struct vic_device - VIC PM device - * @sysdev: The system device which is registered. * @irq: The IRQ number for the base of the VIC. * @base: The register base for the VIC. * @resume_sources: A bitmask of interrupts for resume. @@ -43,8 +42,6 @@ * @protect: Save for VIC_PROTECT. */ struct vic_device { - struct sys_device sysdev; - void __iomem *base; int irq; u32 resume_sources; @@ -59,11 +56,6 @@ struct vic_device { static struct vic_device vic_devices[CONFIG_ARM_VIC_NR]; static int vic_id; - -static inline struct vic_device *to_vic(struct sys_device *sys) -{ - return container_of(sys, struct vic_device, sysdev); -} #endif /* CONFIG_PM */ /** @@ -85,10 +77,9 @@ static void vic_init2(void __iomem *base) writel(32, base + VIC_PL190_DEF_VECT_ADDR); } -#if defined(CONFIG_PM) -static int vic_class_resume(struct sys_device *dev) +#ifdef CONFIG_PM +static void resume_one_vic(struct vic_device *vic) { - struct vic_device *vic = to_vic(dev); void __iomem *base = vic->base; printk(KERN_DEBUG "%s: resuming vic at %p\n", __func__, base); @@ -107,13 +98,18 @@ static int vic_class_resume(struct sys_device *dev) writel(vic->soft_int, base + VIC_INT_SOFT); writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR); - - return 0; } -static int vic_class_suspend(struct sys_device *dev, pm_message_t state) +static void vic_resume(void) +{ + int id; + + for (id = vic_id - 1; id >= 0; id--) + resume_one_vic(vic_devices + id); +} + +static void suspend_one_vic(struct vic_device *vic) { - struct vic_device *vic = to_vic(dev); void __iomem *base = vic->base; printk(KERN_DEBUG "%s: suspending vic at %p\n", __func__, base); @@ -128,14 +124,21 @@ static int vic_class_suspend(struct sys_device *dev, pm_message_t state) writel(vic->resume_irqs, base + VIC_INT_ENABLE); writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR); +} + +static int vic_suspend(void) +{ + int id; + + for (id = 0; id < vic_id; id++) + suspend_one_vic(vic_devices + id); return 0; } -struct sysdev_class vic_class = { - .name = "vic", - .suspend = vic_class_suspend, - .resume = vic_class_resume, +struct syscore_ops vic_syscore_ops = { + .suspend = vic_suspend, + .resume = vic_resume, }; /** @@ -147,30 +150,8 @@ struct sysdev_class vic_class = { */ static int __init vic_pm_init(void) { - struct vic_device *dev = vic_devices; - int err; - int id; - - if (vic_id == 0) - return 0; - - err = sysdev_class_register(&vic_class); - if (err) { - printk(KERN_ERR "%s: cannot register class\n", __func__); - return err; - } - - for (id = 0; id < vic_id; id++, dev++) { - dev->sysdev.id = id; - dev->sysdev.cls = &vic_class; - - err = sysdev_register(&dev->sysdev); - if (err) { - printk(KERN_ERR "%s: failed to register device\n", - __func__); - return err; - } - } + if (vic_id > 0) + register_syscore_ops(&vic_syscore_ops); return 0; } diff --git a/arch/arm/configs/at91x40_defconfig b/arch/arm/configs/at91x40_defconfig new file mode 100644 index 000000000000..c55e9212fcbb --- /dev/null +++ b/arch/arm/configs/at91x40_defconfig @@ -0,0 +1,48 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_EMBEDDED=y +# CONFIG_HOTPLUG is not set +# CONFIG_ELF_CORE is not set +# CONFIG_FUTEX is not set +# CONFIG_TIMERFD is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB=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_MMU is not set +CONFIG_ARCH_AT91=y +CONFIG_ARCH_AT91X40=y +CONFIG_MACH_AT91EB01=y +CONFIG_AT91_EARLY_USART0=y +CONFIG_CPU_ARM7TDMI=y +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x01000000 +CONFIG_DRAM_SIZE=0x00400000 +CONFIG_FLASH_MEM_BASE=0x01400000 +CONFIG_PROCESSOR_ID=0x14000040 +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_BINFMT_FLAT=y +# CONFIG_SUSPEND is not set +# CONFIG_FW_LOADER is not set +CONFIG_MTD=y +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_RAM=y +CONFIG_MTD_ROM=y +CONFIG_BLK_DEV_RAM=y +# CONFIG_INPUT is not set +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_DEVKMEM is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_HWMON is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_EXT2_FS=y +# CONFIG_DNOTIFY is not set +CONFIG_ROMFS_FS=y +# CONFIG_ENABLE_MUST_CHECK is not set diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index ed5bc9e05a4e..cd4458f64171 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h @@ -2,6 +2,7 @@ #define __ASM_ARM_CPUTYPE_H #include +#include #define CPUID_ID 0 #define CPUID_CACHETYPE 1 diff --git a/arch/arm/include/asm/i8253.h b/arch/arm/include/asm/i8253.h new file mode 100644 index 000000000000..70656b69d5ce --- /dev/null +++ b/arch/arm/include/asm/i8253.h @@ -0,0 +1,15 @@ +#ifndef __ASMARM_I8253_H +#define __ASMARM_I8253_H + +/* i8253A PIT registers */ +#define PIT_MODE 0x43 +#define PIT_CH0 0x40 + +#define PIT_LATCH ((PIT_TICK_RATE + HZ / 2) / HZ) + +extern raw_spinlock_t i8253_lock; + +#define outb_pit outb_p +#define inb_pit inb_p + +#endif diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index bb8a19bd5822..e46bdd0097eb 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h @@ -39,10 +39,13 @@ typedef u32 kprobe_opcode_t; struct kprobe; typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); +typedef unsigned long (kprobe_check_cc)(unsigned long); + /* Architecture specific copy of original instruction. */ struct arch_specific_insn { kprobe_opcode_t *insn; kprobe_insn_handler_t *insn_handler; + kprobe_check_cc *insn_check_cc; }; struct prev_kprobe { diff --git a/arch/arm/include/asm/mach/time.h b/arch/arm/include/asm/mach/time.h index 883f6be5117a..d5adaae5ee2c 100644 --- a/arch/arm/include/asm/mach/time.h +++ b/arch/arm/include/asm/mach/time.h @@ -34,7 +34,6 @@ * timer interrupt which may be pending. */ struct sys_timer { - struct sys_device dev; void (*init)(void); void (*suspend)(void); void (*resume)(void); diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 885be097769d..832888d0c20c 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -159,7 +159,7 @@ extern unsigned int user_debug; #include #elif defined(CONFIG_ARM_DMA_MEM_BUFFERABLE) || defined(CONFIG_SMP) #define mb() do { dsb(); outer_sync(); } while (0) -#define rmb() dmb() +#define rmb() dsb() #define wmb() mb() #else #include diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index c891eb76c0e3..87dbe3e21970 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -396,6 +396,10 @@ #define __NR_fanotify_init (__NR_SYSCALL_BASE+367) #define __NR_fanotify_mark (__NR_SYSCALL_BASE+368) #define __NR_prlimit64 (__NR_SYSCALL_BASE+369) +#define __NR_name_to_handle_at (__NR_SYSCALL_BASE+370) +#define __NR_open_by_handle_at (__NR_SYSCALL_BASE+371) +#define __NR_clock_adjtime (__NR_SYSCALL_BASE+372) +#define __NR_syncfs (__NR_SYSCALL_BASE+373) /* * The following SWIs are ARM private. diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 5c26eccef998..7fbf28c35bb2 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -379,6 +379,10 @@ CALL(sys_fanotify_init) CALL(sys_fanotify_mark) CALL(sys_prlimit64) +/* 370 */ CALL(sys_name_to_handle_at) + CALL(sys_open_by_handle_at) + CALL(sys_clock_adjtime) + CALL(sys_syncfs) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 23891317dc4b..15eeff6aea0e 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -34,9 +34,6 @@ * * *) If the PC is written to by the instruction, the * instruction must be fully simulated in software. - * If it is a conditional instruction, the handler - * will use insn[0] to copy its condition code to - * set r0 to 1 and insn[1] to "mov pc, lr" to return. * * *) Otherwise, a modified form of the instruction is * directly executed. Its handler calls the @@ -68,13 +65,17 @@ #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) +#define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos)) + +/* + * Test if load/store instructions writeback the address register. + * if P (bit 24) == 0 or W (bit 21) == 1 + */ +#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000) + #define PSR_fs (PSR_f|PSR_s) #define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ -#define SET_R0_TRUE_INSTRUCTION 0xe3a00001 /* mov r0, #1 */ - -#define truecc_insn(insn) (((insn) & 0xf0000000) | \ - (SET_R0_TRUE_INSTRUCTION & 0x0fffffff)) typedef long (insn_0arg_fn_t)(void); typedef long (insn_1arg_fn_t)(long); @@ -419,14 +420,10 @@ insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) { - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; long iaddr = (long)p->addr; int disp = branch_displacement(insn); - if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) - return; - if (insn & (1 << 24)) regs->ARM_lr = iaddr + 4; @@ -446,14 +443,10 @@ static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) { - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; int rm = insn & 0xf; long rmv = regs->uregs[rm]; - if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) - return; - if (insn & (1 << 5)) regs->ARM_lr = (long)p->addr + 4; @@ -463,9 +456,16 @@ static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr |= PSR_T_BIT; } +static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + unsigned long mask = 0xf8ff03df; /* Mask out execution state */ + regs->uregs[rd] = regs->ARM_cpsr & mask; +} + static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) { - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; int rn = (insn >> 16) & 0xf; int lbit = insn & (1 << 20); @@ -476,9 +476,6 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) int reg_bit_vector; int reg_count; - if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) - return; - reg_count = 0; reg_bit_vector = insn & 0xffff; while (reg_bit_vector) { @@ -510,11 +507,6 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs) { - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - - if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) - return; - regs->ARM_pc = (long)p->addr + str_pc_offset; simulate_ldm1stm1(p, regs); regs->ARM_pc = (long)p->addr + 4; @@ -525,24 +517,16 @@ static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) regs->uregs[12] = regs->uregs[13]; } -static void __kprobes emulate_ldcstc(struct kprobe *p, struct pt_regs *regs) -{ - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rn = (insn >> 16) & 0xf; - long rnv = regs->uregs[rn]; - - /* Save Rn in case of writeback. */ - regs->uregs[rn] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); -} - static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) { insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; int rd = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; /* rm may be invalid, don't care. */ + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; /* Not following the C calling convention here, so need asm(). */ __asm__ __volatile__ ( @@ -554,29 +538,36 @@ static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) "str r0, %[rn] \n\t" /* in case of writeback */ "str r2, %[rd0] \n\t" "str r3, %[rd1] \n\t" - : [rn] "+m" (regs->uregs[rn]), + : [rn] "+m" (rnv), [rd0] "=m" (regs->uregs[rd]), [rd1] "=m" (regs->uregs[rd+1]) - : [rm] "m" (regs->uregs[rm]), + : [rm] "m" (rmv), [cpsr] "r" (regs->ARM_cpsr), [i_fn] "r" (i_fn) : "r0", "r1", "r2", "r3", "lr", "cc" ); + if (is_writeback(insn)) + regs->uregs[rn] = rnv; } static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) { insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; int rd = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; - long rnv = regs->uregs[rn]; - long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; + /* rm/rmv may be invalid, don't care. */ + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; + long rnv_wb; - regs->uregs[rn] = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], + rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], regs->uregs[rd+1], regs->ARM_cpsr, i_fn); + if (is_writeback(insn)) + regs->uregs[rn] = rnv_wb; } static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) @@ -630,31 +621,6 @@ static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ } -static void __kprobes emulate_mrrc(struct kprobe *p, struct pt_regs *regs) -{ - insn_llret_0arg_fn_t *i_fn = (insn_llret_0arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - union reg_pair fnr; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - - fnr.dr = insnslot_llret_0arg_rflags(regs->ARM_cpsr, i_fn); - regs->uregs[rn] = fnr.r0; - regs->uregs[rd] = fnr.r1; -} - -static void __kprobes emulate_mcrr(struct kprobe *p, struct pt_regs *regs) -{ - insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - long rnv = regs->uregs[rn]; - long rdv = regs->uregs[rd]; - - insnslot_2arg_rflags(rnv, rdv, regs->ARM_cpsr, i_fn); -} - static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) { insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; @@ -688,32 +654,32 @@ static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs) insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); } -static void __kprobes emulate_rd12(struct kprobe *p, struct pt_regs *regs) +static void __kprobes emulate_nop(struct kprobe *p, struct pt_regs *regs) { - insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; +} + +static void __kprobes +emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs) +{ + insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; int rd = (insn >> 12) & 0xf; + long rdv = regs->uregs[rd]; - regs->uregs[rd] = insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); + regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn); } -static void __kprobes emulate_ird12(struct kprobe *p, struct pt_regs *regs) +static void __kprobes +emulate_rd12rn0_modify(struct kprobe *p, struct pt_regs *regs) { - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; + insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; - int ird = (insn >> 12) & 0xf; - - insnslot_1arg_rflags(regs->uregs[ird], regs->ARM_cpsr, i_fn); -} - -static void __kprobes emulate_rn16(struct kprobe *p, struct pt_regs *regs) -{ - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rn = (insn >> 16) & 0xf; + int rd = (insn >> 12) & 0xf; + int rn = insn & 0xf; + long rdv = regs->uregs[rd]; long rnv = regs->uregs[rn]; - insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); + regs->uregs[rd] = insnslot_2arg_rflags(rdv, rnv, regs->ARM_cpsr, i_fn); } static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) @@ -818,6 +784,17 @@ emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); } +static void __kprobes +emulate_alu_tests_imm(struct kprobe *p, struct pt_regs *regs) +{ + insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rn = (insn >> 16) & 0xf; + long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; + + insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); +} + static void __kprobes emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs) { @@ -854,14 +831,34 @@ emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs) insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); } +static void __kprobes +emulate_alu_tests(struct kprobe *p, struct pt_regs *regs) +{ + insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; + int rn = (insn >> 16) & 0xf; + int rs = (insn >> 8) & 0xf; /* rs/rsv may be invalid, don't care. */ + int rm = insn & 0xf; + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; + long rsv = regs->uregs[rs]; + + insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); +} + static enum kprobe_insn __kprobes prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) { - int ibit = (insn & (1 << 26)) ? 25 : 22; + int not_imm = (insn & (1 << 26)) ? (insn & (1 << 25)) + : (~insn & (1 << 22)); + + if (is_writeback(insn) && is_r15(insn, 16)) + return INSN_REJECTED; /* Writeback to PC */ insn &= 0xfff00fff; insn |= 0x00001000; /* Rn = r0, Rd = r1 */ - if (insn & (1 << ibit)) { + if (not_imm) { insn &= ~0xf; insn |= 2; /* Rm = r2 */ } @@ -870,28 +867,51 @@ prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD; } +static enum kprobe_insn __kprobes +prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + + insn &= 0xffff0fff; /* Rd = r0 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_rd12_modify; + return INSN_GOOD; +} + +static enum kprobe_insn __kprobes +prep_emulate_rd12rn0_modify(kprobe_opcode_t insn, + struct arch_specific_insn *asi) +{ + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + + insn &= 0xffff0ff0; /* Rd = r0 */ + insn |= 0x00000001; /* Rn = r1 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_rd12rn0_modify; + return INSN_GOOD; +} + static enum kprobe_insn __kprobes prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ asi->insn[0] = insn; asi->insn_handler = emulate_rd12rm0; return INSN_GOOD; } -static enum kprobe_insn __kprobes -prep_emulate_rd12(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - insn &= 0xffff0fff; /* Rd = r0 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_rd12; - return INSN_GOOD; -} - static enum kprobe_insn __kprobes prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ insn |= 0x00000001; /* Rm = r1 */ asi->insn[0] = insn; @@ -903,6 +923,9 @@ static enum kprobe_insn __kprobes prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + if (is_r15(insn, 16)) + return INSN_REJECTED; /* Rd is PC */ + insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ insn |= 0x00000001; /* Rm = r1 */ asi->insn[0] = insn; @@ -914,6 +937,9 @@ static enum kprobe_insn __kprobes prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + if (is_r15(insn, 16)) + return INSN_REJECTED; /* Rd is PC */ + insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ insn |= 0x00000102; /* Rs = r1, Rm = r2 */ asi->insn[0] = insn; @@ -925,6 +951,9 @@ static enum kprobe_insn __kprobes prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + if (is_r15(insn, 16) || is_r15(insn, 12)) + return INSN_REJECTED; /* RdHi or RdLo is PC */ + insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ insn |= 0x00001203; /* Rs = r2, Rm = r3 */ asi->insn[0] = insn; @@ -945,20 +974,13 @@ prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, static enum kprobe_insn __kprobes space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) { - /* CPS mmod == 1 : 1111 0001 0000 xx10 xxxx xxxx xx0x xxxx */ - /* RFE : 1111 100x x0x1 xxxx xxxx 1010 xxxx xxxx */ - /* SRS : 1111 100x x1x0 1101 xxxx 0101 xxxx xxxx */ - if ((insn & 0xfff30020) == 0xf1020000 || - (insn & 0xfe500f00) == 0xf8100a00 || - (insn & 0xfe5f0f00) == 0xf84d0500) - return INSN_REJECTED; - - /* PLD : 1111 01x1 x101 xxxx xxxx xxxx xxxx xxxx : */ - if ((insn & 0xfd700000) == 0xf4500000) { - insn &= 0xfff0ffff; /* Rn = r0 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_rn16; - return INSN_GOOD; + /* memory hint : 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx : */ + /* PLDI : 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx : */ + /* PLDW : 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx : */ + /* PLD : 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx : */ + if ((insn & 0xfe300000) == 0xf4100000) { + asi->insn_handler = emulate_nop; + return INSN_GOOD_NO_SLOT; } /* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */ @@ -967,41 +989,22 @@ space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD_NO_SLOT; } - /* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ - /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ - if ((insn & 0xffff00f0) == 0xf1010000 || - (insn & 0xff000010) == 0xfe000000) { - asi->insn[0] = insn; - asi->insn_handler = emulate_none; - return INSN_GOOD; - } + /* CPS : 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ + /* SETEND: 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ + /* SRS : 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ + /* RFE : 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ + + /* Coprocessor instructions... */ /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ - if ((insn & 0xffe00000) == 0xfc400000) { - insn &= 0xfff00fff; /* Rn = r0 */ - insn |= 0x00001000; /* Rd = r1 */ - asi->insn[0] = insn; - asi->insn_handler = - (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr; - return INSN_GOOD; - } + /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ + /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ + /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ + /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ + /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ - /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ - /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ - if ((insn & 0xfe000000) == 0xfc000000) { - insn &= 0xfff0ffff; /* Rn = r0 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_ldcstc; - return INSN_GOOD; - } - - /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ - /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ - insn &= 0xffff0fff; /* Rd = r0 */ - asi->insn[0] = insn; - asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12; - return INSN_GOOD; + return INSN_REJECTED; } static enum kprobe_insn __kprobes @@ -1010,19 +1013,18 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */ if ((insn & 0x0f900010) == 0x01000000) { - /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ - /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ - if ((insn & 0x0ff000f0) == 0x01200020 || - (insn & 0x0fb000f0) == 0x01200000) - return INSN_REJECTED; - - /* MRS : cccc 0001 0x00 xxxx xxxx xxxx 0000 xxxx */ - if ((insn & 0x0fb00010) == 0x01000000) - return prep_emulate_rd12(insn, asi); + /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ + if ((insn & 0x0ff000f0) == 0x01000000) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + asi->insn_handler = simulate_mrs; + return INSN_GOOD_NO_SLOT; + } /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ if ((insn & 0x0ff00090) == 0x01400080) - return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); + return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, + asi); /* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ /* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ @@ -1031,24 +1033,29 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) return prep_emulate_rd16rs8rm0_wflags(insn, asi); /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */ - /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 0x00 xxxx : Q */ - return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx : Q */ + if ((insn & 0x0ff00090) == 0x01000080 || + (insn & 0x0ff000b0) == 0x01200080) + return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ + /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ + /* MRS spsr : cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ + + /* Other instruction encodings aren't yet defined */ + return INSN_REJECTED; } /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */ else if ((insn & 0x0f900090) == 0x01000010) { - /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ - if ((insn & 0xfff000f0) == 0xe1200070) - return INSN_REJECTED; - /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ if ((insn & 0x0ff000d0) == 0x01200010) { - asi->insn[0] = truecc_insn(insn); + if ((insn & 0x0ff000ff) == 0x0120003f) + return INSN_REJECTED; /* BLX pc */ asi->insn_handler = simulate_blx2bx; - return INSN_GOOD; + return INSN_GOOD_NO_SLOT; } /* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ @@ -1059,17 +1066,27 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* QSUB : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */ /* QDADD : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */ /* QDSUB : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */ - return prep_emulate_rd12rn16rm0_wflags(insn, asi); + if ((insn & 0x0f9000f0) == 0x01000050) + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + + /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ + /* SMC : cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ + + /* Other instruction encodings aren't yet defined */ + return INSN_REJECTED; } /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */ - else if ((insn & 0x0f000090) == 0x00000090) { + else if ((insn & 0x0f0000f0) == 0x00000090) { /* MUL : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx : */ /* MULS : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */ /* MLA : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx : */ /* MLAS : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */ /* UMAAL : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx : */ + /* undef : cccc 0000 0101 xxxx xxxx xxxx 1001 xxxx : */ + /* MLS : cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx : */ + /* undef : cccc 0000 0111 xxxx xxxx xxxx 1001 xxxx : */ /* UMULL : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx : */ /* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */ /* UMLAL : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx : */ @@ -1078,13 +1095,15 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */ /* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */ /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */ - if ((insn & 0x0fe000f0) == 0x00000090) { - return prep_emulate_rd16rs8rm0_wflags(insn, asi); - } else if ((insn & 0x0fe000f0) == 0x00200090) { - return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); - } else { - return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); - } + if ((insn & 0x00d00000) == 0x00500000) + return INSN_REJECTED; + else if ((insn & 0x00e00000) == 0x00000000) + return prep_emulate_rd16rs8rm0_wflags(insn, asi); + else if ((insn & 0x00a00000) == 0x00200000) + return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + else + return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, + asi); } /* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */ @@ -1092,23 +1111,45 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* SWP : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */ /* SWPB : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */ - /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */ - /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */ + /* ??? : cccc 0001 0x01 xxxx xxxx xxxx 1001 xxxx */ + /* ??? : cccc 0001 0x10 xxxx xxxx xxxx 1001 xxxx */ + /* ??? : cccc 0001 0x11 xxxx xxxx xxxx 1001 xxxx */ /* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */ /* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */ + /* STREXD: cccc 0001 1010 xxxx xxxx xxxx 1001 xxxx */ + /* LDREXD: cccc 0001 1011 xxxx xxxx xxxx 1001 xxxx */ + /* STREXB: cccc 0001 1100 xxxx xxxx xxxx 1001 xxxx */ + /* LDREXB: cccc 0001 1101 xxxx xxxx xxxx 1001 xxxx */ + /* STREXH: cccc 0001 1110 xxxx xxxx xxxx 1001 xxxx */ + /* LDREXH: cccc 0001 1111 xxxx xxxx xxxx 1001 xxxx */ + + /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */ + /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */ /* LDRH : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */ /* STRH : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */ /* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */ /* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */ - if ((insn & 0x0fb000f0) == 0x01000090) { - /* SWP/SWPB */ - return prep_emulate_rd12rn16rm0_wflags(insn, asi); + if ((insn & 0x0f0000f0) == 0x01000090) { + if ((insn & 0x0fb000f0) == 0x01000090) { + /* SWP/SWPB */ + return prep_emulate_rd12rn16rm0_wflags(insn, + asi); + } else { + /* STREX/LDREX variants and unallocaed space */ + return INSN_REJECTED; + } + } else if ((insn & 0x0e1000d0) == 0x00000d0) { /* STRD/LDRD */ + if ((insn & 0x0000e000) == 0x0000e000) + return INSN_REJECTED; /* Rd is LR or PC */ + if (is_writeback(insn) && is_r15(insn, 16)) + return INSN_REJECTED; /* Writeback to PC */ + insn &= 0xfff00fff; insn |= 0x00002000; /* Rn = r0, Rd = r2 */ - if (insn & (1 << 22)) { - /* I bit */ + if (!(insn & (1 << 22))) { + /* Register index */ insn &= ~0xf; insn |= 1; /* Rm = r1 */ } @@ -1118,6 +1159,9 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD; } + /* LDRH/STRH/LDRSB/LDRSH */ + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ return prep_emulate_ldr_str(insn, asi); } @@ -1125,7 +1169,7 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* * ALU op with S bit and Rd == 15 : - * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx + * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */ if ((insn & 0x0e10f000) == 0x0010f000) return INSN_REJECTED; @@ -1154,22 +1198,61 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) insn |= 0x00000200; /* Rs = r2 */ } asi->insn[0] = insn; - asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ + + if ((insn & 0x0f900000) == 0x01100000) { + /* + * TST : cccc 0001 0001 xxxx xxxx xxxx xxxx xxxx + * TEQ : cccc 0001 0011 xxxx xxxx xxxx xxxx xxxx + * CMP : cccc 0001 0101 xxxx xxxx xxxx xxxx xxxx + * CMN : cccc 0001 0111 xxxx xxxx xxxx xxxx xxxx + */ + asi->insn_handler = emulate_alu_tests; + } else { + /* ALU ops which write to Rd */ + asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ emulate_alu_rwflags : emulate_alu_rflags; + } return INSN_GOOD; } static enum kprobe_insn __kprobes space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + /* MOVW : cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ + /* MOVT : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ + if ((insn & 0x0fb00000) == 0x03000000) + return prep_emulate_rd12_modify(insn, asi); + + /* hints : cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ + if ((insn & 0x0fff0000) == 0x03200000) { + unsigned op2 = insn & 0x000000ff; + if (op2 == 0x01 || op2 == 0x04) { + /* YIELD : cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ + /* SEV : cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_none; + return INSN_GOOD; + } else if (op2 <= 0x03) { + /* NOP : cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ + /* WFE : cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ + /* WFI : cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ + /* + * We make WFE and WFI true NOPs to avoid stalls due + * to missing events whilst processing the probe. + */ + asi->insn_handler = emulate_nop; + return INSN_GOOD_NO_SLOT; + } + /* For DBG and unallocated hints it's safest to reject them */ + return INSN_REJECTED; + } + /* * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx - * Undef : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx * ALU op with S bit and Rd == 15 : * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */ if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */ - (insn & 0x0ff00000) == 0x03400000 || /* Undef */ (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */ return INSN_REJECTED; @@ -1180,10 +1263,22 @@ space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) * *S (bit 20) updates condition codes * ADC/SBC/RSC reads the C flag */ - insn &= 0xffff0fff; /* Rd = r0 */ + insn &= 0xfff00fff; /* Rn = r0 and Rd = r0 */ asi->insn[0] = insn; - asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ + + if ((insn & 0x0f900000) == 0x03100000) { + /* + * TST : cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx + * TEQ : cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx + * CMP : cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx + * CMN : cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx + */ + asi->insn_handler = emulate_alu_tests_imm; + } else { + /* ALU ops which write to Rd */ + asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ emulate_alu_imm_rwflags : emulate_alu_imm_rflags; + } return INSN_GOOD; } @@ -1192,6 +1287,8 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) { /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */ if ((insn & 0x0ff000f0) == 0x068000b0) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ insn |= 0x00000001; /* Rm = r1 */ asi->insn[0] = insn; @@ -1205,6 +1302,8 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */ if ((insn & 0x0fa00030) == 0x06a00010 || (insn & 0x0fb000f0) == 0x06a00030) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ asi->insn[0] = insn; asi->insn_handler = emulate_sat; @@ -1213,57 +1312,101 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* REV : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ /* REV16 : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ + /* RBIT : cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ /* REVSH : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ if ((insn & 0x0ff00070) == 0x06b00030 || - (insn & 0x0ff000f0) == 0x06f000b0) + (insn & 0x0ff00070) == 0x06f00030) return prep_emulate_rd12rm0(insn, asi); + /* ??? : cccc 0110 0000 xxxx xxxx xxxx xxx1 xxxx : */ /* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */ /* SADDSUBX : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */ /* SSUBADDX : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */ /* SSUB16 : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */ /* SADD8 : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */ + /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1101 xxxx : */ /* SSUB8 : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */ /* QADD16 : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx : */ /* QADDSUBX : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx : */ /* QSUBADDX : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx : */ /* QSUB16 : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx : */ /* QADD8 : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx : */ + /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1101 xxxx : */ /* QSUB8 : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx : */ /* SHADD16 : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx : */ /* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx : */ /* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx : */ /* SHSUB16 : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx : */ /* SHADD8 : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx : */ + /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1101 xxxx : */ /* SHSUB8 : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx : */ + /* ??? : cccc 0110 0100 xxxx xxxx xxxx xxx1 xxxx : */ /* UADD16 : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */ /* UADDSUBX : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */ /* USUBADDX : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */ /* USUB16 : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */ /* UADD8 : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */ + /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1101 xxxx : */ /* USUB8 : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */ /* UQADD16 : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx : */ /* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx : */ /* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx : */ /* UQSUB16 : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx : */ /* UQADD8 : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx : */ + /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1101 xxxx : */ /* UQSUB8 : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx : */ /* UHADD16 : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx : */ /* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx : */ /* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx : */ /* UHSUB16 : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx : */ /* UHADD8 : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx : */ + /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1101 xxxx : */ /* UHSUB8 : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx : */ + if ((insn & 0x0f800010) == 0x06000010) { + if ((insn & 0x00300000) == 0x00000000 || + (insn & 0x000000e0) == 0x000000a0 || + (insn & 0x000000e0) == 0x000000c0) + return INSN_REJECTED; /* Unallocated space */ + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + } + /* PKHBT : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx : */ /* PKHTB : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx : */ + if ((insn & 0x0ff00030) == 0x06800010) + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + /* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */ - /* SXTB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ + /* SXTB16 : cccc 0110 1000 1111 xxxx xxxx 0111 xxxx : */ + /* ??? : cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx : */ /* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ + /* SXTB : cccc 0110 1010 1111 xxxx xxxx 0111 xxxx : */ /* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */ + /* SXTH : cccc 0110 1011 1111 xxxx xxxx 0111 xxxx : */ /* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */ + /* UXTB16 : cccc 0110 1100 1111 xxxx xxxx 0111 xxxx : */ + /* ??? : cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx : */ /* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */ + /* UXTB : cccc 0110 1110 1111 xxxx xxxx 0111 xxxx : */ /* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */ - return prep_emulate_rd12rn16rm0_wflags(insn, asi); + /* UXTH : cccc 0110 1111 1111 xxxx xxxx 0111 xxxx : */ + if ((insn & 0x0f8000f0) == 0x06800070) { + if ((insn & 0x00300000) == 0x00100000) + return INSN_REJECTED; /* Unallocated space */ + + if ((insn & 0x000f0000) == 0x000f0000) + return prep_emulate_rd12rm0(insn, asi); + else + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + } + + /* Other instruction encodings aren't yet defined */ + return INSN_REJECTED; } static enum kprobe_insn __kprobes @@ -1273,29 +1416,49 @@ space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) if ((insn & 0x0ff000f0) == 0x03f000f0) return INSN_REJECTED; - /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ - /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ - if ((insn & 0x0ff000f0) == 0x07800010) - return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); - /* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ /* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ if ((insn & 0x0ff00090) == 0x07400010) return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); /* SMLAD : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */ + /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */ /* SMLSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */ + /* SMUSD : cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx : */ /* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */ - /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ + /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ + /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx : */ + /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx : */ if ((insn & 0x0ff00090) == 0x07000010 || (insn & 0x0ff000d0) == 0x07500010 || - (insn & 0x0ff000d0) == 0x075000d0) + (insn & 0x0ff000f0) == 0x07800010) { + + if ((insn & 0x0000f000) == 0x0000f000) + return prep_emulate_rd16rs8rm0_wflags(insn, asi); + else + return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + } + + /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ + if ((insn & 0x0ff000d0) == 0x075000d0) return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); - /* SMUSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx : */ - /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */ - /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ - return prep_emulate_rd16rs8rm0_wflags(insn, asi); + /* SBFX : cccc 0111 101x xxxx xxxx xxxx x101 xxxx : */ + /* UBFX : cccc 0111 111x xxxx xxxx xxxx x101 xxxx : */ + if ((insn & 0x0fa00070) == 0x07a00050) + return prep_emulate_rd12rm0(insn, asi); + + /* BFI : cccc 0111 110x xxxx xxxx xxxx x001 xxxx : */ + /* BFC : cccc 0111 110x xxxx xxxx xxxx x001 1111 : */ + if ((insn & 0x0fe00070) == 0x07c00010) { + + if ((insn & 0x0000000f) == 0x0000000f) + return prep_emulate_rd12_modify(insn, asi); + else + return prep_emulate_rd12rn0_modify(insn, asi); + } + + return INSN_REJECTED; } static enum kprobe_insn __kprobes @@ -1309,6 +1472,10 @@ space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* STRB : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */ /* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ /* STRT : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ + + if ((insn & 0x00500000) == 0x00500000 && is_r15(insn, 12)) + return INSN_REJECTED; /* LDRB into PC */ + return prep_emulate_ldr_str(insn, asi); } @@ -1323,10 +1490,9 @@ space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ - asi->insn[0] = truecc_insn(insn); asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */ simulate_stm1_pc : simulate_ldm1stm1; - return INSN_GOOD; + return INSN_GOOD_NO_SLOT; } static enum kprobe_insn __kprobes @@ -1334,58 +1500,117 @@ space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi) { /* B : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ /* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ - asi->insn[0] = truecc_insn(insn); asi->insn_handler = simulate_bbl; - return INSN_GOOD; + return INSN_GOOD_NO_SLOT; } static enum kprobe_insn __kprobes -space_cccc_1100_010x(kprobe_opcode_t insn, struct arch_specific_insn *asi) +space_cccc_11xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + /* Coprocessor instructions... */ /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ - insn &= 0xfff00fff; - insn |= 0x00001000; /* Rn = r0, Rd = r1 */ - asi->insn[0] = insn; - asi->insn_handler = (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr; - return INSN_GOOD; + /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ + /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ + /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ + /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ + /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ + + /* SVC : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ + + return INSN_REJECTED; } -static enum kprobe_insn __kprobes -space_cccc_110x(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static unsigned long __kprobes __check_eq(unsigned long cpsr) { - /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ - /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ - insn &= 0xfff0ffff; /* Rn = r0 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_ldcstc; - return INSN_GOOD; + return cpsr & PSR_Z_BIT; } -static enum kprobe_insn __kprobes -space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static unsigned long __kprobes __check_ne(unsigned long cpsr) { - /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ - /* SWI : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ - if ((insn & 0xfff000f0) == 0xe1200070 || - (insn & 0x0f000000) == 0x0f000000) - return INSN_REJECTED; - - /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ - if ((insn & 0x0f000010) == 0x0e000000) { - asi->insn[0] = insn; - asi->insn_handler = emulate_none; - return INSN_GOOD; - } - - /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ - /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ - insn &= 0xffff0fff; /* Rd = r0 */ - asi->insn[0] = insn; - asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12; - return INSN_GOOD; + return (~cpsr) & PSR_Z_BIT; } +static unsigned long __kprobes __check_cs(unsigned long cpsr) +{ + return cpsr & PSR_C_BIT; +} + +static unsigned long __kprobes __check_cc(unsigned long cpsr) +{ + return (~cpsr) & PSR_C_BIT; +} + +static unsigned long __kprobes __check_mi(unsigned long cpsr) +{ + return cpsr & PSR_N_BIT; +} + +static unsigned long __kprobes __check_pl(unsigned long cpsr) +{ + return (~cpsr) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_vs(unsigned long cpsr) +{ + return cpsr & PSR_V_BIT; +} + +static unsigned long __kprobes __check_vc(unsigned long cpsr) +{ + return (~cpsr) & PSR_V_BIT; +} + +static unsigned long __kprobes __check_hi(unsigned long cpsr) +{ + cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return cpsr & PSR_C_BIT; +} + +static unsigned long __kprobes __check_ls(unsigned long cpsr) +{ + cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return (~cpsr) & PSR_C_BIT; +} + +static unsigned long __kprobes __check_ge(unsigned long cpsr) +{ + cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return (~cpsr) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_lt(unsigned long cpsr) +{ + cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return cpsr & PSR_N_BIT; +} + +static unsigned long __kprobes __check_gt(unsigned long cpsr) +{ + unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ + return (~temp) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_le(unsigned long cpsr) +{ + unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ + return temp & PSR_N_BIT; +} + +static unsigned long __kprobes __check_al(unsigned long cpsr) +{ + return true; +} + +static kprobe_check_cc * const condition_checks[16] = { + &__check_eq, &__check_ne, &__check_cs, &__check_cc, + &__check_mi, &__check_pl, &__check_vs, &__check_vc, + &__check_hi, &__check_ls, &__check_ge, &__check_lt, + &__check_gt, &__check_le, &__check_al, &__check_al +}; + /* Return: * INSN_REJECTED If instruction is one not allowed to kprobe, * INSN_GOOD If instruction is supported and uses instruction slot, @@ -1401,133 +1626,45 @@ space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi) enum kprobe_insn __kprobes arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + asi->insn_check_cc = condition_checks[insn>>28]; asi->insn[1] = KPROBE_RETURN_INSTRUCTION; - if ((insn & 0xf0000000) == 0xf0000000) { + if ((insn & 0xf0000000) == 0xf0000000) return space_1111(insn, asi); - } else if ((insn & 0x0e000000) == 0x00000000) { + else if ((insn & 0x0e000000) == 0x00000000) return space_cccc_000x(insn, asi); - } else if ((insn & 0x0e000000) == 0x02000000) { + else if ((insn & 0x0e000000) == 0x02000000) return space_cccc_001x(insn, asi); - } else if ((insn & 0x0f000010) == 0x06000010) { + else if ((insn & 0x0f000010) == 0x06000010) return space_cccc_0110__1(insn, asi); - } else if ((insn & 0x0f000010) == 0x07000010) { + else if ((insn & 0x0f000010) == 0x07000010) return space_cccc_0111__1(insn, asi); - } else if ((insn & 0x0c000000) == 0x04000000) { + else if ((insn & 0x0c000000) == 0x04000000) return space_cccc_01xx(insn, asi); - } else if ((insn & 0x0e000000) == 0x08000000) { + else if ((insn & 0x0e000000) == 0x08000000) return space_cccc_100x(insn, asi); - } else if ((insn & 0x0e000000) == 0x0a000000) { + else if ((insn & 0x0e000000) == 0x0a000000) return space_cccc_101x(insn, asi); - } else if ((insn & 0x0fe00000) == 0x0c400000) { - - return space_cccc_1100_010x(insn, asi); - - } else if ((insn & 0x0e000000) == 0x0c000000) { - - return space_cccc_110x(insn, asi); - - } - - return space_cccc_111x(insn, asi); + return space_cccc_11xx(insn, asi); } void __init arm_kprobe_decode_init(void) { find_str_pc_offset(); } - - -/* - * All ARM instructions listed below. - * - * Instructions and their general purpose registers are given. - * If a particular register may not use R15, it is prefixed with a "!". - * If marked with a "*" means the value returned by reading R15 - * is implementation defined. - * - * ADC/ADD/AND/BIC/CMN/CMP/EOR/MOV/MVN/ORR/RSB/RSC/SBC/SUB/TEQ - * TST: Rd, Rn, Rm, !Rs - * BX: Rm - * BLX(2): !Rm - * BX: Rm (R15 legal, but discouraged) - * BXJ: !Rm, - * CLZ: !Rd, !Rm - * CPY: Rd, Rm - * LDC/2,STC/2 immediate offset & unindex: Rn - * LDC/2,STC/2 immediate pre/post-indexed: !Rn - * LDM(1/3): !Rn, register_list - * LDM(2): !Rn, !register_list - * LDR,STR,PLD immediate offset: Rd, Rn - * LDR,STR,PLD register offset: Rd, Rn, !Rm - * LDR,STR,PLD scaled register offset: Rd, !Rn, !Rm - * LDR,STR immediate pre/post-indexed: Rd, !Rn - * LDR,STR register pre/post-indexed: Rd, !Rn, !Rm - * LDR,STR scaled register pre/post-indexed: Rd, !Rn, !Rm - * LDRB,STRB immediate offset: !Rd, Rn - * LDRB,STRB register offset: !Rd, Rn, !Rm - * LDRB,STRB scaled register offset: !Rd, !Rn, !Rm - * LDRB,STRB immediate pre/post-indexed: !Rd, !Rn - * LDRB,STRB register pre/post-indexed: !Rd, !Rn, !Rm - * LDRB,STRB scaled register pre/post-indexed: !Rd, !Rn, !Rm - * LDRT,LDRBT,STRBT immediate pre/post-indexed: !Rd, !Rn - * LDRT,LDRBT,STRBT register pre/post-indexed: !Rd, !Rn, !Rm - * LDRT,LDRBT,STRBT scaled register pre/post-indexed: !Rd, !Rn, !Rm - * LDRH/SH/SB/D,STRH/SH/SB/D immediate offset: !Rd, Rn - * LDRH/SH/SB/D,STRH/SH/SB/D register offset: !Rd, Rn, !Rm - * LDRH/SH/SB/D,STRH/SH/SB/D immediate pre/post-indexed: !Rd, !Rn - * LDRH/SH/SB/D,STRH/SH/SB/D register pre/post-indexed: !Rd, !Rn, !Rm - * LDREX: !Rd, !Rn - * MCR/2: !Rd - * MCRR/2,MRRC/2: !Rd, !Rn - * MLA: !Rd, !Rn, !Rm, !Rs - * MOV: Rd - * MRC/2: !Rd (if Rd==15, only changes cond codes, not the register) - * MRS,MSR: !Rd - * MUL: !Rd, !Rm, !Rs - * PKH{BT,TB}: !Rd, !Rn, !Rm - * QDADD,[U]QADD/16/8/SUBX: !Rd, !Rm, !Rn - * QDSUB,[U]QSUB/16/8/ADDX: !Rd, !Rm, !Rn - * REV/16/SH: !Rd, !Rm - * RFE: !Rn - * {S,U}[H]ADD{16,8,SUBX},{S,U}[H]SUB{16,8,ADDX}: !Rd, !Rn, !Rm - * SEL: !Rd, !Rn, !Rm - * SMLA,SMLA{D,W},SMLSD,SMML{A,S}: !Rd, !Rn, !Rm, !Rs - * SMLAL,SMLA{D,LD},SMLSLD,SMMULL,SMULW: !RdHi, !RdLo, !Rm, !Rs - * SMMUL,SMUAD,SMUL,SMUSD: !Rd, !Rm, !Rs - * SSAT/16: !Rd, !Rm - * STM(1/2): !Rn, register_list* (R15 in reg list not recommended) - * STRT immediate pre/post-indexed: Rd*, !Rn - * STRT register pre/post-indexed: Rd*, !Rn, !Rm - * STRT scaled register pre/post-indexed: Rd*, !Rn, !Rm - * STREX: !Rd, !Rn, !Rm - * SWP/B: !Rd, !Rn, !Rm - * {S,U}XTA{B,B16,H}: !Rd, !Rn, !Rm - * {S,U}XT{B,B16,H}: !Rd, !Rm - * UM{AA,LA,UL}L: !RdHi, !RdLo, !Rm, !Rs - * USA{D8,A8,T,T16}: !Rd, !Rm, !Rs - * - * May transfer control by writing R15 (possible mode changes or alternate - * mode accesses marked by "*"): - * ALU op (* with s-bit), B, BL, BKPT, BLX(1/2), BX, BXJ, CPS*, CPY, - * LDM(1), LDM(2/3)*, LDR, MOV, RFE*, SWI* - * - * Instructions that do not take general registers, nor transfer control: - * CDP/2, SETEND, SRS* - */ diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 2ba7deb3072e..1656c87501c0 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -134,7 +134,8 @@ static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { regs->ARM_pc += 4; - p->ainsn.insn_handler(p, regs); + if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) + p->ainsn.insn_handler(p, regs); } /* diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c index 31a316c1777b..0f107dcb0347 100644 --- a/arch/arm/kernel/leds.c +++ b/arch/arm/kernel/leds.c @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -69,29 +70,8 @@ static ssize_t leds_store(struct sys_device *dev, static SYSDEV_ATTR(event, 0200, NULL, leds_store); -static int leds_suspend(struct sys_device *dev, pm_message_t state) -{ - leds_event(led_stop); - return 0; -} - -static int leds_resume(struct sys_device *dev) -{ - leds_event(led_start); - return 0; -} - -static int leds_shutdown(struct sys_device *dev) -{ - leds_event(led_halted); - return 0; -} - static struct sysdev_class leds_sysclass = { .name = "leds", - .shutdown = leds_shutdown, - .suspend = leds_suspend, - .resume = leds_resume, }; static struct sys_device leds_device = { @@ -99,6 +79,28 @@ static struct sys_device leds_device = { .cls = &leds_sysclass, }; +static int leds_suspend(void) +{ + leds_event(led_stop); + return 0; +} + +static void leds_resume(void) +{ + leds_event(led_start); +} + +static void leds_shutdown(void) +{ + leds_event(led_halted); +} + +static struct syscore_ops leds_syscore_ops = { + .shutdown = leds_shutdown, + .suspend = leds_suspend, + .resume = leds_resume, +}; + static int __init leds_init(void) { int ret; @@ -107,6 +109,8 @@ static int __init leds_init(void) ret = sysdev_register(&leds_device); if (ret == 0) ret = sysdev_create_file(&leds_device, &attr_event); + if (ret == 0) + register_syscore_ops(&leds_syscore_ops); return ret; } diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 979da3947f42..139e3c827369 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -746,7 +746,8 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) tail = (struct frame_tail __user *)regs->ARM_fp - 1; - while (tail && !((unsigned long)tail & 0x3)) + while ((entry->nr < PERF_MAX_STACK_DEPTH) && + tail && !((unsigned long)tail & 0x3)) tail = user_backtrace(tail, entry); } diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 2bf27f364d09..8182f45ca493 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -767,12 +767,20 @@ long arch_ptrace(struct task_struct *child, long request, #ifdef CONFIG_HAVE_HW_BREAKPOINT case PTRACE_GETHBPREGS: + if (ptrace_get_breakpoints(child) < 0) + return -ESRCH; + ret = ptrace_gethbpregs(child, addr, (unsigned long __user *)data); + ptrace_put_breakpoints(child); break; case PTRACE_SETHBPREGS: + if (ptrace_get_breakpoints(child) < 0) + return -ESRCH; + ret = ptrace_sethbpregs(child, addr, (unsigned long __user *)data); + ptrace_put_breakpoints(child); break; #endif diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index cb8398317644..0340224cf73c 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -597,45 +597,19 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, return err; } -static inline void setup_syscall_restart(struct pt_regs *regs) -{ - regs->ARM_r0 = regs->ARM_ORIG_r0; - regs->ARM_pc -= thumb_mode(regs) ? 2 : 4; -} - /* * OK, we're invoking a handler */ static int handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs, int syscall) + struct pt_regs * regs) { struct thread_info *thread = current_thread_info(); struct task_struct *tsk = current; int usig = sig; int ret; - /* - * If we were from a system call, check for system call restarting... - */ - if (syscall) { - switch (regs->ARM_r0) { - case -ERESTART_RESTARTBLOCK: - case -ERESTARTNOHAND: - regs->ARM_r0 = -EINTR; - break; - case -ERESTARTSYS: - if (!(ka->sa.sa_flags & SA_RESTART)) { - regs->ARM_r0 = -EINTR; - break; - } - /* fallthrough */ - case -ERESTARTNOINTR: - setup_syscall_restart(regs); - } - } - /* * translate the signal */ @@ -685,6 +659,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, */ static void do_signal(struct pt_regs *regs, int syscall) { + unsigned int retval = 0, continue_addr = 0, restart_addr = 0; struct k_sigaction ka; siginfo_t info; int signr; @@ -698,18 +673,61 @@ static void do_signal(struct pt_regs *regs, int syscall) if (!user_mode(regs)) return; + /* + * If we were from a system call, check for system call restarting... + */ + if (syscall) { + continue_addr = regs->ARM_pc; + restart_addr = continue_addr - (thumb_mode(regs) ? 2 : 4); + retval = regs->ARM_r0; + + /* + * Prepare for system call restart. We do this here so that a + * debugger will see the already changed PSW. + */ + switch (retval) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + regs->ARM_r0 = regs->ARM_ORIG_r0; + regs->ARM_pc = restart_addr; + break; + case -ERESTART_RESTARTBLOCK: + regs->ARM_r0 = -EINTR; + break; + } + } + if (try_to_freeze()) goto no_signal; + /* + * Get the signal to deliver. When running under ptrace, at this + * point the debugger may change all our registers ... + */ signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { sigset_t *oldset; + /* + * Depending on the signal settings we may need to revert the + * decision to restart the system call. But skip this if a + * debugger has chosen to restart at a different PC. + */ + if (regs->ARM_pc == restart_addr) { + if (retval == -ERESTARTNOHAND + || (retval == -ERESTARTSYS + && !(ka.sa.sa_flags & SA_RESTART))) { + regs->ARM_r0 = -EINTR; + regs->ARM_pc = continue_addr; + } + } + if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; else oldset = ¤t->blocked; - if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) { + if (handle_signal(signr, &ka, &info, oldset, regs) == 0) { /* * A signal was successfully delivered; the saved * sigmask will have been stored in the signal frame, @@ -723,11 +741,14 @@ static void do_signal(struct pt_regs *regs, int syscall) } no_signal: - /* - * No signal to deliver to the process - restart the syscall. - */ if (syscall) { - if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) { + /* + * Handle restarting a different system call. As above, + * if a debugger has chosen to restart at a different PC, + * ignore the restart. + */ + if (retval == -ERESTART_RESTARTBLOCK + && regs->ARM_pc == continue_addr) { if (thumb_mode(regs)) { regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; regs->ARM_pc -= 2; @@ -750,11 +771,6 @@ static void do_signal(struct pt_regs *regs, int syscall) #endif } } - if (regs->ARM_r0 == -ERESTARTNOHAND || - regs->ARM_r0 == -ERESTARTSYS || - regs->ARM_r0 == -ERESTARTNOINTR) { - setup_syscall_restart(regs); - } /* If there's no signal to deliver, we just put the saved sigmask * back. diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 8fe05ad932e4..007a0a950e75 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -479,7 +479,7 @@ static void broadcast_timer_set_mode(enum clock_event_mode mode, { } -static void broadcast_timer_setup(struct clock_event_device *evt) +static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt) { evt->name = "dummy_timer"; evt->features = CLOCK_EVT_FEAT_ONESHOT | @@ -560,10 +560,7 @@ asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs) break; case IPI_RESCHEDULE: - /* - * nothing more to do - eveything is - * done on the interrupt return path - */ + scheduler_ipi(); break; case IPI_CALL_FUNC: diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 4ad8da15ef2b..af0aaebf4de6 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -311,7 +311,7 @@ asmlinkage long sys_oabi_semtimedop(int semid, long err; int i; - if (nsops < 1) + if (nsops < 1 || nsops > SEMOPM) return -EINVAL; sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL); if (!sops) diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 1ff46cabc7ef..cb634c3e28e9 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -115,48 +115,37 @@ void timer_tick(void) #endif #if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS) -static int timer_suspend(struct sys_device *dev, pm_message_t state) +static int timer_suspend(void) { - struct sys_timer *timer = container_of(dev, struct sys_timer, dev); - - if (timer->suspend != NULL) - timer->suspend(); + if (system_timer->suspend) + system_timer->suspend(); return 0; } -static int timer_resume(struct sys_device *dev) +static void timer_resume(void) { - struct sys_timer *timer = container_of(dev, struct sys_timer, dev); - - if (timer->resume != NULL) - timer->resume(); - - return 0; + if (system_timer->resume) + system_timer->resume(); } #else #define timer_suspend NULL #define timer_resume NULL #endif -static struct sysdev_class timer_sysclass = { - .name = "timer", +static struct syscore_ops timer_syscore_ops = { .suspend = timer_suspend, .resume = timer_resume, }; -static int __init timer_init_sysfs(void) +static int __init timer_init_syscore_ops(void) { - int ret = sysdev_class_register(&timer_sysclass); - if (ret == 0) { - system_timer->dev.cls = &timer_sysclass; - ret = sysdev_register(&system_timer->dev); - } + register_syscore_ops(&timer_syscore_ops); - return ret; + return 0; } -device_initcall(timer_init_sysfs); +device_initcall(timer_init_syscore_ops); void __init time_init(void) { diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 3b54ad19d489..d52eec268b47 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -234,7 +234,6 @@ static int __die(const char *str, int err, struct thread_info *thread, struct pt printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n", str, err, ++die_counter); - sysfs_printk_last_file(); /* trap and error numbers are mostly meaningless on ARM */ ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV); diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 19390231a0e9..2d299bf5d72f 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -83,6 +83,7 @@ config ARCH_AT91CAP9 select CPU_ARM926T select GENERIC_CLOCKEVENTS select HAVE_FB_ATMEL + select HAVE_NET_MACB config ARCH_AT572D940HF bool "AT572D940HF" diff --git a/arch/arm/mach-at91/board-eb01.c b/arch/arm/mach-at91/board-eb01.c index 1f9d3cb64c50..d8df59a3426d 100644 --- a/arch/arm/mach-at91/board-eb01.c +++ b/arch/arm/mach-at91/board-eb01.c @@ -30,6 +30,11 @@ #include #include "generic.h" +static void __init at91eb01_init_irq(void) +{ + at91x40_init_interrupts(NULL); +} + static void __init at91eb01_map_io(void) { at91x40_initialize(40000000); @@ -38,7 +43,7 @@ static void __init at91eb01_map_io(void) MACHINE_START(AT91EB01, "Atmel AT91 EB01") /* Maintainer: Greg Ungerer */ .timer = &at91x40_timer, - .init_irq = at91x40_init_interrupts, + .init_irq = at91eb01_init_irq, .map_io = at91eb01_map_io, MACHINE_END diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h index 3bef931d0b1c..0700f2125305 100644 --- a/arch/arm/mach-at91/include/mach/cpu.h +++ b/arch/arm/mach-at91/include/mach/cpu.h @@ -27,6 +27,7 @@ #define ARCH_ID_AT91SAM9G45 0x819b05a0 #define ARCH_ID_AT91SAM9G45MRL 0x819b05a2 /* aka 9G45-ES2 & non ES lots */ #define ARCH_ID_AT91SAM9G45ES 0x819b05a1 /* 9G45-ES (Engineering Sample) */ +#define ARCH_ID_AT91SAM9X5 0x819a05a0 #define ARCH_ID_AT91CAP9 0x039A03A0 #define ARCH_ID_AT91SAM9XE128 0x329973a0 @@ -55,6 +56,12 @@ static inline unsigned long at91_cpu_fully_identify(void) #define ARCH_EXID_AT91SAM9G46 0x00000003 #define ARCH_EXID_AT91SAM9G45 0x00000004 +#define ARCH_EXID_AT91SAM9G15 0x00000000 +#define ARCH_EXID_AT91SAM9G35 0x00000001 +#define ARCH_EXID_AT91SAM9X35 0x00000002 +#define ARCH_EXID_AT91SAM9G25 0x00000003 +#define ARCH_EXID_AT91SAM9X25 0x00000004 + static inline unsigned long at91_exid_identify(void) { return at91_sys_read(AT91_DBGU_EXID); @@ -143,6 +150,27 @@ static inline unsigned long at91cap9_rev_identify(void) #define cpu_is_at91sam9m11() (0) #endif +#ifdef CONFIG_ARCH_AT91SAM9X5 +#define cpu_is_at91sam9x5() (at91_cpu_identify() == ARCH_ID_AT91SAM9X5) +#define cpu_is_at91sam9g15() (cpu_is_at91sam9x5() && \ + (at91_exid_identify() == ARCH_EXID_AT91SAM9G15)) +#define cpu_is_at91sam9g35() (cpu_is_at91sam9x5() && \ + (at91_exid_identify() == ARCH_EXID_AT91SAM9G35)) +#define cpu_is_at91sam9x35() (cpu_is_at91sam9x5() && \ + (at91_exid_identify() == ARCH_EXID_AT91SAM9X35)) +#define cpu_is_at91sam9g25() (cpu_is_at91sam9x5() && \ + (at91_exid_identify() == ARCH_EXID_AT91SAM9G25)) +#define cpu_is_at91sam9x25() (cpu_is_at91sam9x5() && \ + (at91_exid_identify() == ARCH_EXID_AT91SAM9X25)) +#else +#define cpu_is_at91sam9x5() (0) +#define cpu_is_at91sam9g15() (0) +#define cpu_is_at91sam9g35() (0) +#define cpu_is_at91sam9x35() (0) +#define cpu_is_at91sam9g25() (0) +#define cpu_is_at91sam9x25() (0) +#endif + #ifdef CONFIG_ARCH_AT91CAP9 #define cpu_is_at91cap9() (at91_cpu_identify() == ARCH_ID_AT91CAP9) #define cpu_is_at91cap9_revB() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_B) diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index 32f147998cd9..c0deacae778d 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -63,6 +63,7 @@ config MACH_DAVINCI_EVM depends on ARCH_DAVINCI_DM644x select MISC_DEVICES select EEPROM_AT24 + select I2C help Configure this option to specify the whether the board used for development is a DM644x EVM @@ -72,6 +73,7 @@ config MACH_SFFSDR depends on ARCH_DAVINCI_DM644x select MISC_DEVICES select EEPROM_AT24 + select I2C help Say Y here to select the Lyrtech Small Form Factor Software Defined Radio (SFFSDR) board. @@ -105,6 +107,7 @@ config MACH_DAVINCI_DM6467_EVM select MACH_DAVINCI_DM6467TEVM select MISC_DEVICES select EEPROM_AT24 + select I2C help Configure this option to specify the whether the board used for development is a DM6467 EVM @@ -118,6 +121,7 @@ config MACH_DAVINCI_DM365_EVM depends on ARCH_DAVINCI_DM365 select MISC_DEVICES select EEPROM_AT24 + select I2C help Configure this option to specify whether the board used for development is a DM365 EVM @@ -129,6 +133,7 @@ config MACH_DAVINCI_DA830_EVM select GPIO_PCF857X select MISC_DEVICES select EEPROM_AT24 + select I2C help Say Y here to select the TI DA830/OMAP-L137/AM17x Evaluation Module. @@ -205,6 +210,7 @@ config MACH_MITYOMAPL138 depends on ARCH_DAVINCI_DA850 select MISC_DEVICES select EEPROM_AT24 + select I2C help Say Y here to select the Critical Link MityDSP-L138/MityARM-1808 System on Module. Information on this SoM may be found at diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 2aa79c54f98e..606a6f27ed6c 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -29,7 +29,7 @@ #include #include -#define MITYOMAPL138_PHY_ID "0:03" +#define MITYOMAPL138_PHY_ID "" #define FACTORY_CONFIG_MAGIC 0x012C0138 #define FACTORY_CONFIG_VERSION 0x00010001 @@ -414,7 +414,7 @@ static struct resource mityomapl138_nandflash_resource[] = { static struct platform_device mityomapl138_nandflash_device = { .name = "davinci_nand", - .id = 0, + .id = 1, .dev = { .platform_data = &mityomapl138_nandflash_data, }, diff --git a/arch/arm/mach-davinci/cpufreq.c b/arch/arm/mach-davinci/cpufreq.c index 0a95be1512bb..41669ecc1f91 100644 --- a/arch/arm/mach-davinci/cpufreq.c +++ b/arch/arm/mach-davinci/cpufreq.c @@ -94,9 +94,7 @@ static int davinci_target(struct cpufreq_policy *policy, if (freqs.old == freqs.new) return ret; - cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, - dev_driver_string(cpufreq.dev), - "transition: %u --> %u\n", freqs.old, freqs.new); + dev_dbg(&cpufreq.dev, "transition: %u --> %u\n", freqs.old, freqs.new); ret = cpufreq_frequency_table_target(policy, pdata->freq_table, freqs.new, relation, &idx); diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 625d4b66718b..58a02dc7b15a 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -39,7 +39,8 @@ #define DA8XX_GPIO_BASE 0x01e26000 #define DA8XX_I2C1_BASE 0x01e28000 #define DA8XX_SPI0_BASE 0x01c41000 -#define DA8XX_SPI1_BASE 0x01f0e000 +#define DA830_SPI1_BASE 0x01e12000 +#define DA850_SPI1_BASE 0x01f0e000 #define DA8XX_EMAC_CTRL_REG_OFFSET 0x3000 #define DA8XX_EMAC_MOD_REG_OFFSET 0x2000 @@ -762,8 +763,8 @@ static struct resource da8xx_spi0_resources[] = { static struct resource da8xx_spi1_resources[] = { [0] = { - .start = DA8XX_SPI1_BASE, - .end = DA8XX_SPI1_BASE + SZ_4K - 1, + .start = DA830_SPI1_BASE, + .end = DA830_SPI1_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -832,5 +833,10 @@ int __init da8xx_register_spi(int instance, struct spi_board_info *info, da8xx_spi_pdata[instance].num_chipselect = len; + if (instance == 1 && cpu_is_davinci_da850()) { + da8xx_spi1_resources[0].start = DA850_SPI1_BASE; + da8xx_spi1_resources[0].end = DA850_SPI1_BASE + SZ_4K - 1; + } + return platform_device_register(&da8xx_spi_device[instance]); } diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index f68012239641..a3a94e9c9378 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -314,7 +314,7 @@ static struct clk timer2_clk = { .name = "timer2", .parent = &pll1_aux_clk, .lpsc = DAVINCI_LPSC_TIMER2, - .usecount = 1, /* REVISIT: why can't' this be disabled? */ + .usecount = 1, /* REVISIT: why can't this be disabled? */ }; static struct clk timer3_clk = { diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 5f8a65424184..4c82c2716293 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -274,7 +274,7 @@ static struct clk timer2_clk = { .name = "timer2", .parent = &pll1_aux_clk, .lpsc = DAVINCI_LPSC_TIMER2, - .usecount = 1, /* REVISIT: why can't' this be disabled? */ + .usecount = 1, /* REVISIT: why can't this be disabled? */ }; static struct clk_lookup dm644x_clks[] = { diff --git a/arch/arm/mach-davinci/include/mach/debug-macro.S b/arch/arm/mach-davinci/include/mach/debug-macro.S index 9f1befc5ac38..f8b7ea4f6235 100644 --- a/arch/arm/mach-davinci/include/mach/debug-macro.S +++ b/arch/arm/mach-davinci/include/mach/debug-macro.S @@ -24,6 +24,9 @@ #define UART_SHIFT 2 +#define davinci_uart_v2p(x) ((x) - PAGE_OFFSET + PLAT_PHYS_OFFSET) +#define davinci_uart_p2v(x) ((x) - PLAT_PHYS_OFFSET + PAGE_OFFSET) + .pushsection .data davinci_uart_phys: .word 0 davinci_uart_virt: .word 0 @@ -34,7 +37,7 @@ davinci_uart_virt: .word 0 /* Use davinci_uart_phys/virt if already configured */ 10: mrc p15, 0, \rp, c1, c0 tst \rp, #1 @ MMU enabled? - ldreq \rp, =__virt_to_phys(davinci_uart_phys) + ldreq \rp, =davinci_uart_v2p(davinci_uart_phys) ldrne \rp, =davinci_uart_phys add \rv, \rp, #4 @ davinci_uart_virt ldr \rp, [\rp, #0] @@ -48,18 +51,18 @@ davinci_uart_virt: .word 0 tst \rp, #1 @ MMU enabled? /* Copy uart phys address from decompressor uart info */ - ldreq \rv, =__virt_to_phys(davinci_uart_phys) + ldreq \rv, =davinci_uart_v2p(davinci_uart_phys) ldrne \rv, =davinci_uart_phys ldreq \rp, =DAVINCI_UART_INFO - ldrne \rp, =__phys_to_virt(DAVINCI_UART_INFO) + ldrne \rp, =davinci_uart_p2v(DAVINCI_UART_INFO) ldr \rp, [\rp, #0] str \rp, [\rv] /* Copy uart virt address from decompressor uart info */ - ldreq \rv, =__virt_to_phys(davinci_uart_virt) + ldreq \rv, =davinci_uart_v2p(davinci_uart_virt) ldrne \rv, =davinci_uart_virt ldreq \rp, =DAVINCI_UART_INFO - ldrne \rp, =__phys_to_virt(DAVINCI_UART_INFO) + ldrne \rp, =davinci_uart_p2v(DAVINCI_UART_INFO) ldr \rp, [\rp, #4] str \rp, [\rv] diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h index 8051110b8ac3..c9e6ce185a66 100644 --- a/arch/arm/mach-davinci/include/mach/serial.h +++ b/arch/arm/mach-davinci/include/mach/serial.h @@ -22,7 +22,7 @@ * * This area sits just below the page tables (see arch/arm/kernel/head.S). */ -#define DAVINCI_UART_INFO (PHYS_OFFSET + 0x3ff8) +#define DAVINCI_UART_INFO (PLAT_PHYS_OFFSET + 0x3ff8) #define DAVINCI_UART0_BASE (IO_PHYS + 0x20000) #define DAVINCI_UART1_BASE (IO_PHYS + 0x20400) diff --git a/arch/arm/mach-exynos4/pm.c b/arch/arm/mach-exynos4/pm.c index 10d917d9e3ad..8755ca8dd48d 100644 --- a/arch/arm/mach-exynos4/pm.c +++ b/arch/arm/mach-exynos4/pm.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -372,7 +373,27 @@ void exynos4_scu_enable(void __iomem *scu_base) flush_cache_all(); } -static int exynos4_pm_resume(struct sys_device *dev) +static struct sysdev_driver exynos4_pm_driver = { + .add = exynos4_pm_add, +}; + +static __init int exynos4_pm_drvinit(void) +{ + unsigned int tmp; + + s3c_pm_init(); + + /* All wakeup disable */ + + tmp = __raw_readl(S5P_WAKEUP_MASK); + tmp |= ((0xFF << 8) | (0x1F << 1)); + __raw_writel(tmp, S5P_WAKEUP_MASK); + + return sysdev_driver_register(&exynos4_sysclass, &exynos4_pm_driver); +} +arch_initcall(exynos4_pm_drvinit); + +static void exynos4_pm_resume(void) { /* For release retention */ @@ -394,27 +415,15 @@ static int exynos4_pm_resume(struct sys_device *dev) /* enable L2X0*/ writel_relaxed(1, S5P_VA_L2CC + L2X0_CTRL); #endif - - return 0; } -static struct sysdev_driver exynos4_pm_driver = { - .add = exynos4_pm_add, +static struct syscore_ops exynos4_pm_syscore_ops = { .resume = exynos4_pm_resume, }; -static __init int exynos4_pm_drvinit(void) +static __init int exynos4_pm_syscore_init(void) { - unsigned int tmp; - - s3c_pm_init(); - - /* All wakeup disable */ - - tmp = __raw_readl(S5P_WAKEUP_MASK); - tmp |= ((0xFF << 8) | (0x1F << 1)); - __raw_writel(tmp, S5P_WAKEUP_MASK); - - return sysdev_driver_register(&exynos4_sysclass, &exynos4_pm_driver); + register_syscore_ops(&exynos4_pm_syscore_ops); + return 0; } -arch_initcall(exynos4_pm_drvinit); +arch_initcall(exynos4_pm_syscore_init); diff --git a/arch/arm/mach-footbridge/Kconfig b/arch/arm/mach-footbridge/Kconfig index bdd257921cfb..46adca068f2c 100644 --- a/arch/arm/mach-footbridge/Kconfig +++ b/arch/arm/mach-footbridge/Kconfig @@ -4,6 +4,7 @@ menu "Footbridge Implementations" config ARCH_CATS bool "CATS" + select CLKSRC_I8253 select FOOTBRIDGE_HOST select ISA select ISA_DMA @@ -59,6 +60,7 @@ config ARCH_EBSA285_HOST config ARCH_NETWINDER bool "NetWinder" + select CLKSRC_I8253 select FOOTBRIDGE_HOST select ISA select ISA_DMA diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c index 441c6ce0d555..7020f1a3feca 100644 --- a/arch/arm/mach-footbridge/isa-timer.c +++ b/arch/arm/mach-footbridge/isa-timer.c @@ -10,53 +10,16 @@ #include #include #include +#include #include #include - +#include #include #include "common.h" -#define PIT_MODE 0x43 -#define PIT_CH0 0x40 - -#define PIT_LATCH ((PIT_TICK_RATE + HZ / 2) / HZ) - -static cycle_t pit_read(struct clocksource *cs) -{ - unsigned long flags; - static int old_count; - static u32 old_jifs; - int count; - u32 jifs; - - raw_local_irq_save(flags); - - jifs = jiffies; - outb_p(0x00, PIT_MODE); /* latch the count */ - count = inb_p(PIT_CH0); /* read the latched count */ - count |= inb_p(PIT_CH0) << 8; - - if (count > old_count && jifs == old_jifs) - count = old_count; - - old_count = count; - old_jifs = jifs; - - raw_local_irq_restore(flags); - - count = (PIT_LATCH - 1) - count; - - return (cycle_t)(jifs * PIT_LATCH) + count; -} - -static struct clocksource pit_cs = { - .name = "pit", - .rating = 110, - .read = pit_read, - .mask = CLOCKSOURCE_MASK(32), -}; +DEFINE_RAW_SPINLOCK(i8253_lock); static void pit_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) @@ -121,7 +84,7 @@ static void __init isa_timer_init(void) pit_ce.max_delta_ns = clockevent_delta2ns(0x7fff, &pit_ce); pit_ce.min_delta_ns = clockevent_delta2ns(0x000f, &pit_ce); - clocksource_register_hz(&pit_cs, PIT_TICK_RATE); + clocksource_i8253_init(); setup_irq(pit_ce.irq, &pit_timer_irq); clockevents_register_device(&pit_ce); diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 980803ff348c..d3e96451529c 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -180,13 +180,13 @@ static void __init ap_init_irq(void) #ifdef CONFIG_PM static unsigned long ic_irq_enable; -static int irq_suspend(struct sys_device *dev, pm_message_t state) +static int irq_suspend(void) { ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE); return 0; } -static int irq_resume(struct sys_device *dev) +static void irq_resume(void) { /* disable all irq sources */ writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); @@ -194,33 +194,25 @@ static int irq_resume(struct sys_device *dev) writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET); - return 0; } #else #define irq_suspend NULL #define irq_resume NULL #endif -static struct sysdev_class irq_class = { - .name = "irq", +static struct syscore_ops irq_syscore_ops = { .suspend = irq_suspend, .resume = irq_resume, }; -static struct sys_device irq_device = { - .id = 0, - .cls = &irq_class, -}; - -static int __init irq_init_sysfs(void) +static int __init irq_syscore_init(void) { - int ret = sysdev_class_register(&irq_class); - if (ret == 0) - ret = sysdev_register(&irq_device); - return ret; + register_syscore_ops(&irq_syscore_ops); + + return 0; } -device_initcall(irq_init_sysfs); +device_initcall(irq_syscore_init); /* * Flash handling. diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 7f568611547e..6a96911b0ad5 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -160,10 +160,7 @@ static struct msm_mmc_platform_data qsd8x50_sdc1_data = { static void __init qsd8x50_init_mmc(void) { - if (machine_is_qsd8x50_ffa() || machine_is_qsd8x50a_ffa()) - vreg_mmc = vreg_get(NULL, "gp6"); - else - vreg_mmc = vreg_get(NULL, "gp5"); + vreg_mmc = vreg_get(NULL, "gp5"); if (IS_ERR(vreg_mmc)) { pr_err("vreg get for vreg_mmc failed (%ld)\n", diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 56f920c55b6a..38b95e949d13 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -269,7 +269,7 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt) /* Use existing clock_event for cpu 0 */ if (!smp_processor_id()) - return; + return 0; writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); diff --git a/arch/arm/mach-mx3/mach-vpr200.c b/arch/arm/mach-mx3/mach-vpr200.c index 2cf390fbd980..47a69cbc31a8 100644 --- a/arch/arm/mach-mx3/mach-vpr200.c +++ b/arch/arm/mach-mx3/mach-vpr200.c @@ -257,11 +257,16 @@ static const struct fsl_usb2_platform_data otg_device_pdata __initconst = { .workaround = FLS_USB2_WORKAROUND_ENGCM09152, }; +static int vpr200_usbh_init(struct platform_device *pdev) +{ + return mx35_initialize_usb_hw(pdev->id, + MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY); +} + /* USB HOST config */ static const struct mxc_usbh_platform_data usb_host_pdata __initconst = { - .portsc = MXC_EHCI_MODE_SERIAL, - .flags = MXC_EHCI_INTERFACE_SINGLE_UNI | - MXC_EHCI_INTERNAL_PHY, + .init = vpr200_usbh_init, + .portsc = MXC_EHCI_MODE_SERIAL, }; static struct platform_device *devices[] __initdata = { diff --git a/arch/arm/mach-mx5/board-mx53_loco.c b/arch/arm/mach-mx5/board-mx53_loco.c index 10a1bea10548..6206b1191fe8 100644 --- a/arch/arm/mach-mx5/board-mx53_loco.c +++ b/arch/arm/mach-mx5/board-mx53_loco.c @@ -193,7 +193,7 @@ static iomux_v3_cfg_t mx53_loco_pads[] = { .wakeup = wake, \ } -static const struct gpio_keys_button loco_buttons[] __initconst = { +static struct gpio_keys_button loco_buttons[] = { GPIO_BUTTON(MX53_LOCO_POWER, KEY_POWER, 1, "power", 0), GPIO_BUTTON(MX53_LOCO_UI1, KEY_VOLUMEUP, 1, "volume-up", 0), GPIO_BUTTON(MX53_LOCO_UI2, KEY_VOLUMEDOWN, 1, "volume-down", 0), diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c index 1ad97fed1e94..5dcc59d5b9ec 100644 --- a/arch/arm/mach-mxs/clock-mx28.c +++ b/arch/arm/mach-mxs/clock-mx28.c @@ -295,11 +295,11 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ unsigned long diff, parent_rate, calc_rate; \ int i; \ \ - parent_rate = clk_get_rate(clk->parent); \ div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ bm_busy = BM_CLKCTRL_##dr##_BUSY; \ \ if (clk->parent == &ref_xtal_clk) { \ + parent_rate = clk_get_rate(clk->parent); \ div = DIV_ROUND_UP(parent_rate, rate); \ if (clk == &cpu_clk) { \ div_max = BM_CLKCTRL_CPU_DIV_XTAL >> \ @@ -309,6 +309,11 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ if (div == 0 || div > div_max) \ return -EINVAL; \ } else { \ + /* \ + * hack alert: this block modifies clk->parent, too, \ + * so the base to use it the grand parent. \ + */ \ + parent_rate = clk_get_rate(clk->parent->parent); \ rate >>= PARENT_RATE_SHIFT; \ parent_rate >>= PARENT_RATE_SHIFT; \ diff = parent_rate; \ diff --git a/arch/arm/mach-omap1/pm_bus.c b/arch/arm/mach-omap1/pm_bus.c index 6588c22b8a64..fe31d933f0ed 100644 --- a/arch/arm/mach-omap1/pm_bus.c +++ b/arch/arm/mach-omap1/pm_bus.c @@ -24,75 +24,50 @@ #ifdef CONFIG_PM_RUNTIME static int omap1_pm_runtime_suspend(struct device *dev) { - struct clk *iclk, *fclk; - int ret = 0; + int ret; dev_dbg(dev, "%s\n", __func__); ret = pm_generic_runtime_suspend(dev); + if (ret) + return ret; - fclk = clk_get(dev, "fck"); - if (!IS_ERR(fclk)) { - clk_disable(fclk); - clk_put(fclk); - } - - iclk = clk_get(dev, "ick"); - if (!IS_ERR(iclk)) { - clk_disable(iclk); - clk_put(iclk); + ret = pm_runtime_clk_suspend(dev); + if (ret) { + pm_generic_runtime_resume(dev); + return ret; } return 0; -}; +} static int omap1_pm_runtime_resume(struct device *dev) { - struct clk *iclk, *fclk; - dev_dbg(dev, "%s\n", __func__); - iclk = clk_get(dev, "ick"); - if (!IS_ERR(iclk)) { - clk_enable(iclk); - clk_put(iclk); - } - - fclk = clk_get(dev, "fck"); - if (!IS_ERR(fclk)) { - clk_enable(fclk); - clk_put(fclk); - } - + pm_runtime_clk_resume(dev); return pm_generic_runtime_resume(dev); +} + +static struct dev_power_domain default_power_domain = { + .ops = { + .runtime_suspend = omap1_pm_runtime_suspend, + .runtime_resume = omap1_pm_runtime_resume, + USE_PLATFORM_PM_SLEEP_OPS + }, +}; + +static struct pm_clk_notifier_block platform_bus_notifier = { + .pwr_domain = &default_power_domain, + .con_ids = { "ick", "fck", NULL, }, }; static int __init omap1_pm_runtime_init(void) { - const struct dev_pm_ops *pm; - struct dev_pm_ops *omap_pm; - if (!cpu_class_is_omap1()) return -ENODEV; - pm = platform_bus_get_pm_ops(); - if (!pm) { - pr_err("%s: unable to get dev_pm_ops from platform_bus\n", - __func__); - return -ENODEV; - } - - omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL); - if (!omap_pm) { - pr_err("%s: unable to alloc memory for new dev_pm_ops\n", - __func__); - return -ENOMEM; - } - - omap_pm->runtime_suspend = omap1_pm_runtime_suspend; - omap_pm->runtime_resume = omap1_pm_runtime_resume; - - platform_bus_set_pm_ops(omap_pm); + pm_runtime_clk_add_notifier(&platform_bus_type, &platform_bus_notifier); return 0; } diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index a45cd6409686..66dfbccacd25 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -59,16 +59,16 @@ endif # Power Management ifeq ($(CONFIG_PM),y) obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o -obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o pm_bus.o +obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o \ - cpuidle34xx.o pm_bus.o -obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o pm_bus.o + cpuidle34xx.o +obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o obj-$(CONFIG_PM_DEBUG) += pm-debug.o obj-$(CONFIG_OMAP_SMARTREFLEX) += sr_device.o smartreflex.o obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o AFLAGS_sleep24xx.o :=-Wa,-march=armv6 -AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a +AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a$(plus_sec) ifeq ($(CONFIG_PM_VERBOSE),y) CFLAGS_pm_bus.o += -DDEBUG diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c index e964895b80e8..f8ba20a14e62 100644 --- a/arch/arm/mach-omap2/board-rx51.c +++ b/arch/arm/mach-omap2/board-rx51.c @@ -141,14 +141,19 @@ static void __init rx51_init(void) static void __init rx51_map_io(void) { omap2_set_globals_3xxx(); - rx51_video_mem_init(); omap34xx_map_common_io(); } +static void __init rx51_reserve(void) +{ + rx51_video_mem_init(); + omap_reserve(); +} + MACHINE_START(NOKIA_RX51, "Nokia RX-51 board") /* Maintainer: Lauri Leukkunen */ .boot_params = 0x80000100, - .reserve = omap_reserve, + .reserve = rx51_reserve, .map_io = rx51_map_io, .init_early = rx51_init_early, .init_irq = omap_init_irq, diff --git a/arch/arm/mach-omap2/clkt34xx_dpll3m2.c b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c index b2b1e37bb6bb..d6e34dd9e7e7 100644 --- a/arch/arm/mach-omap2/clkt34xx_dpll3m2.c +++ b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c @@ -115,6 +115,7 @@ int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, sdrc_cs0->actim_ctrlb, sdrc_cs0->mr, 0, 0, 0, 0); + clk->rate = rate; return 0; } diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 276992d3b7fb..8c965671b4d4 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -3116,14 +3116,9 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "dsp_fck", &dsp_fck, CK_443X), CLK("omapdss_dss", "sys_clk", &dss_sys_clk, CK_443X), CLK("omapdss_dss", "tv_clk", &dss_tv_clk, CK_443X), - CLK("omapdss_dss", "dss_clk", &dss_dss_clk, CK_443X), CLK("omapdss_dss", "video_clk", &dss_48mhz_clk, CK_443X), - CLK("omapdss_dss", "fck", &dss_fck, CK_443X), - /* - * On OMAP4, DSS ick is a dummy clock; this is needed for compatibility - * with OMAP2/3. - */ - CLK("omapdss_dss", "ick", &dummy_ck, CK_443X), + CLK("omapdss_dss", "fck", &dss_dss_clk, CK_443X), + CLK("omapdss_dss", "ick", &dss_fck, CK_443X), CLK(NULL, "efuse_ctrl_cust_fck", &efuse_ctrl_cust_fck, CK_443X), CLK(NULL, "emif1_fck", &emif1_fck, CK_443X), CLK(NULL, "emif2_fck", &emif2_fck, CK_443X), diff --git a/arch/arm/mach-omap2/cm2xxx_3xxx.c b/arch/arm/mach-omap2/cm2xxx_3xxx.c index 9d0dec806e92..38830d8d4783 100644 --- a/arch/arm/mach-omap2/cm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/cm2xxx_3xxx.c @@ -247,6 +247,7 @@ struct omap3_cm_regs { u32 per_cm_clksel; u32 emu_cm_clksel; u32 emu_cm_clkstctrl; + u32 pll_cm_autoidle; u32 pll_cm_autoidle2; u32 pll_cm_clksel4; u32 pll_cm_clksel5; @@ -319,6 +320,15 @@ void omap3_cm_save_context(void) omap2_cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSEL1); cm_context.emu_cm_clkstctrl = omap2_cm_read_mod_reg(OMAP3430_EMU_MOD, OMAP2_CM_CLKSTCTRL); + /* + * As per erratum i671, ROM code does not respect the PER DPLL + * programming scheme if CM_AUTOIDLE_PLL.AUTO_PERIPH_DPLL == 1. + * In this case, even though this register has been saved in + * scratchpad contents, we need to restore AUTO_PERIPH_DPLL + * by ourselves. So, we need to save it anyway. + */ + cm_context.pll_cm_autoidle = + omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE); cm_context.pll_cm_autoidle2 = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE2); cm_context.pll_cm_clksel4 = @@ -441,6 +451,13 @@ void omap3_cm_restore_context(void) CM_CLKSEL1); omap2_cm_write_mod_reg(cm_context.emu_cm_clkstctrl, OMAP3430_EMU_MOD, OMAP2_CM_CLKSTCTRL); + /* + * As per erratum i671, ROM code does not respect the PER DPLL + * programming scheme if CM_AUTOIDLE_PLL.AUTO_PERIPH_DPLL == 1. + * In this case, we need to restore AUTO_PERIPH_DPLL by ourselves. + */ + omap2_cm_write_mod_reg(cm_context.pll_cm_autoidle, PLL_MOD, + CM_AUTOIDLE); omap2_cm_write_mod_reg(cm_context.pll_cm_autoidle2, PLL_MOD, CM_AUTOIDLE2); omap2_cm_write_mod_reg(cm_context.pll_cm_clksel4, PLL_MOD, diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index 695279419020..da53ba3917ca 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -316,8 +316,14 @@ void omap3_save_scratchpad_contents(void) omap2_cm_read_mod_reg(WKUP_MOD, CM_CLKSEL); prcm_block_contents.cm_clken_pll = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKEN); + /* + * As per erratum i671, ROM code does not respect the PER DPLL + * programming scheme if CM_AUTOIDLE_PLL..AUTO_PERIPH_DPLL == 1. + * Then, in anycase, clear these bits to avoid extra latencies. + */ prcm_block_contents.cm_autoidle_pll = - omap2_cm_read_mod_reg(PLL_MOD, OMAP3430_CM_AUTOIDLE_PLL); + omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE) & + ~OMAP3430_AUTO_PERIPH_DPLL_MASK; prcm_block_contents.cm_clksel1_pll = omap2_cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL1_PLL); prcm_block_contents.cm_clksel2_pll = diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index 8eb3ce1bbfbe..c4d0ae87d62a 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -1639,6 +1639,7 @@ static struct omap_hwmod_ocp_if *omap2420_gpio1_slaves[] = { static struct omap_hwmod omap2420_gpio1_hwmod = { .name = "gpio1", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap242x_gpio1_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap242x_gpio1_irqs), .main_clk = "gpios_fck", @@ -1669,6 +1670,7 @@ static struct omap_hwmod_ocp_if *omap2420_gpio2_slaves[] = { static struct omap_hwmod omap2420_gpio2_hwmod = { .name = "gpio2", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap242x_gpio2_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap242x_gpio2_irqs), .main_clk = "gpios_fck", @@ -1699,6 +1701,7 @@ static struct omap_hwmod_ocp_if *omap2420_gpio3_slaves[] = { static struct omap_hwmod omap2420_gpio3_hwmod = { .name = "gpio3", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap242x_gpio3_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap242x_gpio3_irqs), .main_clk = "gpios_fck", @@ -1729,6 +1732,7 @@ static struct omap_hwmod_ocp_if *omap2420_gpio4_slaves[] = { static struct omap_hwmod omap2420_gpio4_hwmod = { .name = "gpio4", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap242x_gpio4_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap242x_gpio4_irqs), .main_clk = "gpios_fck", @@ -1782,7 +1786,7 @@ static struct omap_hwmod_irq_info omap2420_dma_system_irqs[] = { static struct omap_hwmod_addr_space omap2420_dma_system_addrs[] = { { .pa_start = 0x48056000, - .pa_end = 0x4a0560ff, + .pa_end = 0x48056fff, .flags = ADDR_TYPE_RT }, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index e6e3810db77f..9682dd519f8d 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -1742,6 +1742,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio1_slaves[] = { static struct omap_hwmod omap2430_gpio1_hwmod = { .name = "gpio1", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap243x_gpio1_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap243x_gpio1_irqs), .main_clk = "gpios_fck", @@ -1772,6 +1773,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio2_slaves[] = { static struct omap_hwmod omap2430_gpio2_hwmod = { .name = "gpio2", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap243x_gpio2_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap243x_gpio2_irqs), .main_clk = "gpios_fck", @@ -1802,6 +1804,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio3_slaves[] = { static struct omap_hwmod omap2430_gpio3_hwmod = { .name = "gpio3", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap243x_gpio3_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap243x_gpio3_irqs), .main_clk = "gpios_fck", @@ -1832,6 +1835,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio4_slaves[] = { static struct omap_hwmod omap2430_gpio4_hwmod = { .name = "gpio4", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap243x_gpio4_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap243x_gpio4_irqs), .main_clk = "gpios_fck", @@ -1862,6 +1866,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio5_slaves[] = { static struct omap_hwmod omap2430_gpio5_hwmod = { .name = "gpio5", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap243x_gpio5_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap243x_gpio5_irqs), .main_clk = "gpio5_fck", @@ -1915,7 +1920,7 @@ static struct omap_hwmod_irq_info omap2430_dma_system_irqs[] = { static struct omap_hwmod_addr_space omap2430_dma_system_addrs[] = { { .pa_start = 0x48056000, - .pa_end = 0x4a0560ff, + .pa_end = 0x48056fff, .flags = ADDR_TYPE_RT }, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index b98e2dfcba28..909a84de6682 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -2141,6 +2141,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio1_slaves[] = { static struct omap_hwmod omap3xxx_gpio1_hwmod = { .name = "gpio1", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap3xxx_gpio1_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_gpio1_irqs), .main_clk = "gpio1_ick", @@ -2177,6 +2178,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio2_slaves[] = { static struct omap_hwmod omap3xxx_gpio2_hwmod = { .name = "gpio2", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap3xxx_gpio2_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_gpio2_irqs), .main_clk = "gpio2_ick", @@ -2213,6 +2215,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio3_slaves[] = { static struct omap_hwmod omap3xxx_gpio3_hwmod = { .name = "gpio3", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap3xxx_gpio3_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_gpio3_irqs), .main_clk = "gpio3_ick", @@ -2249,6 +2252,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio4_slaves[] = { static struct omap_hwmod omap3xxx_gpio4_hwmod = { .name = "gpio4", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap3xxx_gpio4_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_gpio4_irqs), .main_clk = "gpio4_ick", @@ -2285,6 +2289,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio5_slaves[] = { static struct omap_hwmod omap3xxx_gpio5_hwmod = { .name = "gpio5", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap3xxx_gpio5_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_gpio5_irqs), .main_clk = "gpio5_ick", @@ -2321,6 +2326,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio6_slaves[] = { static struct omap_hwmod omap3xxx_gpio6_hwmod = { .name = "gpio6", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap3xxx_gpio6_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_gpio6_irqs), .main_clk = "gpio6_ick", @@ -2386,7 +2392,7 @@ static struct omap_hwmod_irq_info omap3xxx_dma_system_irqs[] = { static struct omap_hwmod_addr_space omap3xxx_dma_system_addrs[] = { { .pa_start = 0x48056000, - .pa_end = 0x4a0560ff, + .pa_end = 0x48056fff, .flags = ADDR_TYPE_RT }, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 3e88dd3f8ef3..abc548a0c98d 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -885,7 +885,7 @@ static struct omap_hwmod_ocp_if *omap44xx_dma_system_masters[] = { static struct omap_hwmod_addr_space omap44xx_dma_system_addrs[] = { { .pa_start = 0x4a056000, - .pa_end = 0x4a0560ff, + .pa_end = 0x4a056fff, .flags = ADDR_TYPE_RT }, }; diff --git a/arch/arm/mach-omap2/omap_l3_smx.c b/arch/arm/mach-omap2/omap_l3_smx.c index 5f2da7565b68..4321e7938929 100644 --- a/arch/arm/mach-omap2/omap_l3_smx.c +++ b/arch/arm/mach-omap2/omap_l3_smx.c @@ -196,11 +196,11 @@ static irqreturn_t omap3_l3_app_irq(int irq, void *_l3) /* No timeout error for debug sources */ } - base = ((l3->rt) + (*(omap3_l3_bases[int_type] + err_source))); - /* identify the error source */ for (err_source = 0; !(status & (1 << err_source)); err_source++) ; + + base = l3->rt + *(omap3_l3_bases[int_type] + err_source); error = omap3_l3_readll(base, L3_ERROR_LOG); if (error) { diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 30af3351c2d6..49486f522dca 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -89,6 +89,7 @@ static void omap2_init_processor_devices(void) if (cpu_is_omap44xx()) { _init_omap_device("l3_main_1", &l3_dev); _init_omap_device("dsp", &dsp_dev); + _init_omap_device("iva", &iva_dev); } else { _init_omap_device("l3_main", &l3_dev); } diff --git a/arch/arm/mach-omap2/pm_bus.c b/arch/arm/mach-omap2/pm_bus.c deleted file mode 100644 index 5acd2ab298b1..000000000000 --- a/arch/arm/mach-omap2/pm_bus.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Runtime PM support code for OMAP - * - * Author: Kevin Hilman, Deep Root Systems, LLC - * - * Copyright (C) 2010 Texas Instruments, Inc. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef CONFIG_PM_RUNTIME -static int omap_pm_runtime_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - int r, ret = 0; - - dev_dbg(dev, "%s\n", __func__); - - ret = pm_generic_runtime_suspend(dev); - - if (!ret && dev->parent == &omap_device_parent) { - r = omap_device_idle(pdev); - WARN_ON(r); - } - - return ret; -}; - -static int omap_pm_runtime_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - int r; - - dev_dbg(dev, "%s\n", __func__); - - if (dev->parent == &omap_device_parent) { - r = omap_device_enable(pdev); - WARN_ON(r); - } - - return pm_generic_runtime_resume(dev); -}; -#else -#define omap_pm_runtime_suspend NULL -#define omap_pm_runtime_resume NULL -#endif /* CONFIG_PM_RUNTIME */ - -static int __init omap_pm_runtime_init(void) -{ - const struct dev_pm_ops *pm; - struct dev_pm_ops *omap_pm; - - pm = platform_bus_get_pm_ops(); - if (!pm) { - pr_err("%s: unable to get dev_pm_ops from platform_bus\n", - __func__); - return -ENODEV; - } - - omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL); - if (!omap_pm) { - pr_err("%s: unable to alloc memory for new dev_pm_ops\n", - __func__); - return -ENOMEM; - } - - omap_pm->runtime_suspend = omap_pm_runtime_suspend; - omap_pm->runtime_resume = omap_pm_runtime_resume; - - platform_bus_set_pm_ops(omap_pm); - - return 0; -} -core_initcall(omap_pm_runtime_init); diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c index 6fb520999b6e..0c1552d9d995 100644 --- a/arch/arm/mach-omap2/voltage.c +++ b/arch/arm/mach-omap2/voltage.c @@ -114,7 +114,6 @@ static int __init _config_common_vdd_data(struct omap_vdd_info *vdd) sys_clk_speed /= 1000; /* Generic voltage parameters */ - vdd->curr_volt = 1200000; vdd->volt_scale = vp_forceupdate_scale_voltage; vdd->vp_enabled = false; diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c index bfbecec6d05f..810a982a66f8 100644 --- a/arch/arm/mach-pxa/balloon3.c +++ b/arch/arm/mach-pxa/balloon3.c @@ -15,7 +15,6 @@ #include #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/clock-pxa2xx.c b/arch/arm/mach-pxa/clock-pxa2xx.c index 1ce090448493..1d5859d9a0e3 100644 --- a/arch/arm/mach-pxa/clock-pxa2xx.c +++ b/arch/arm/mach-pxa/clock-pxa2xx.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include @@ -33,32 +33,22 @@ const struct clkops clk_pxa2xx_cken_ops = { #ifdef CONFIG_PM static uint32_t saved_cken; -static int pxa2xx_clock_suspend(struct sys_device *d, pm_message_t state) +static int pxa2xx_clock_suspend(void) { saved_cken = CKEN; return 0; } -static int pxa2xx_clock_resume(struct sys_device *d) +static void pxa2xx_clock_resume(void) { CKEN = saved_cken; - return 0; } #else #define pxa2xx_clock_suspend NULL #define pxa2xx_clock_resume NULL #endif -struct sysdev_class pxa2xx_clock_sysclass = { - .name = "pxa2xx-clock", +struct syscore_ops pxa2xx_clock_syscore_ops = { .suspend = pxa2xx_clock_suspend, .resume = pxa2xx_clock_resume, }; - -static int __init pxa2xx_clock_init(void) -{ - if (cpu_is_pxa2xx()) - return sysdev_class_register(&pxa2xx_clock_sysclass); - return 0; -} -postcore_initcall(pxa2xx_clock_init); diff --git a/arch/arm/mach-pxa/clock-pxa3xx.c b/arch/arm/mach-pxa/clock-pxa3xx.c index 3f864cd0bd28..2a37a9a8f621 100644 --- a/arch/arm/mach-pxa/clock-pxa3xx.c +++ b/arch/arm/mach-pxa/clock-pxa3xx.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -182,7 +183,7 @@ const struct clkops clk_pxa3xx_pout_ops = { static uint32_t cken[2]; static uint32_t accr; -static int pxa3xx_clock_suspend(struct sys_device *d, pm_message_t state) +static int pxa3xx_clock_suspend(void) { cken[0] = CKENA; cken[1] = CKENB; @@ -190,28 +191,18 @@ static int pxa3xx_clock_suspend(struct sys_device *d, pm_message_t state) return 0; } -static int pxa3xx_clock_resume(struct sys_device *d) +static void pxa3xx_clock_resume(void) { ACCR = accr; CKENA = cken[0]; CKENB = cken[1]; - return 0; } #else #define pxa3xx_clock_suspend NULL #define pxa3xx_clock_resume NULL #endif -struct sysdev_class pxa3xx_clock_sysclass = { - .name = "pxa3xx-clock", +struct syscore_ops pxa3xx_clock_syscore_ops = { .suspend = pxa3xx_clock_suspend, .resume = pxa3xx_clock_resume, }; - -static int __init pxa3xx_clock_init(void) -{ - if (cpu_is_pxa3xx() || cpu_is_pxa95x()) - return sysdev_class_register(&pxa3xx_clock_sysclass); - return 0; -} -postcore_initcall(pxa3xx_clock_init); diff --git a/arch/arm/mach-pxa/clock.h b/arch/arm/mach-pxa/clock.h index f9f349a21b54..1f2fb9c43f06 100644 --- a/arch/arm/mach-pxa/clock.h +++ b/arch/arm/mach-pxa/clock.h @@ -1,5 +1,5 @@ #include -#include +#include struct clkops { void (*enable)(struct clk *); @@ -54,7 +54,7 @@ extern const struct clkops clk_pxa2xx_cken_ops; void clk_pxa2xx_cken_enable(struct clk *clk); void clk_pxa2xx_cken_disable(struct clk *clk); -extern struct sysdev_class pxa2xx_clock_sysclass; +extern struct syscore_ops pxa2xx_clock_syscore_ops; #if defined(CONFIG_PXA3xx) || defined(CONFIG_PXA95x) #define DEFINE_PXA3_CKEN(_name, _cken, _rate, _delay) \ @@ -74,5 +74,6 @@ extern const struct clkops clk_pxa3xx_smemc_ops; extern void clk_pxa3xx_cken_enable(struct clk *); extern void clk_pxa3xx_cken_disable(struct clk *); -extern struct sysdev_class pxa3xx_clock_sysclass; +extern struct syscore_ops pxa3xx_clock_syscore_ops; + #endif diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c index b88d601a8090..13518a705399 100644 --- a/arch/arm/mach-pxa/cm-x270.c +++ b/arch/arm/mach-pxa/cm-x270.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/cm-x2xx.c b/arch/arm/mach-pxa/cm-x2xx.c index 8225e2e58c6e..a10996782476 100644 --- a/arch/arm/mach-pxa/cm-x2xx.c +++ b/arch/arm/mach-pxa/cm-x2xx.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include #include @@ -388,7 +388,7 @@ static inline void cmx2xx_init_display(void) {} #ifdef CONFIG_PM static unsigned long sleep_save_msc[10]; -static int cmx2xx_suspend(struct sys_device *dev, pm_message_t state) +static int cmx2xx_suspend(void) { cmx2xx_pci_suspend(); @@ -412,7 +412,7 @@ static int cmx2xx_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int cmx2xx_resume(struct sys_device *dev) +static void cmx2xx_resume(void) { cmx2xx_pci_resume(); @@ -420,27 +420,18 @@ static int cmx2xx_resume(struct sys_device *dev) __raw_writel(sleep_save_msc[0], MSC0); __raw_writel(sleep_save_msc[1], MSC1); __raw_writel(sleep_save_msc[2], MSC2); - - return 0; } -static struct sysdev_class cmx2xx_pm_sysclass = { - .name = "pm", +static struct syscore_ops cmx2xx_pm_syscore_ops = { .resume = cmx2xx_resume, .suspend = cmx2xx_suspend, }; -static struct sys_device cmx2xx_pm_device = { - .cls = &cmx2xx_pm_sysclass, -}; - static int __init cmx2xx_pm_init(void) { - int error; - error = sysdev_class_register(&cmx2xx_pm_sysclass); - if (error == 0) - error = sysdev_register(&cmx2xx_pm_device); - return error; + register_syscore_ops(&cmx2xx_pm_syscore_ops); + + return 0; } #else static int __init cmx2xx_pm_init(void) { return 0; } diff --git a/arch/arm/mach-pxa/colibri-evalboard.c b/arch/arm/mach-pxa/colibri-evalboard.c index 81c3c433e2d6..d28e802e2448 100644 --- a/arch/arm/mach-pxa/colibri-evalboard.c +++ b/arch/arm/mach-pxa/colibri-evalboard.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/colibri-pxa270-income.c b/arch/arm/mach-pxa/colibri-pxa270-income.c index 44c1b77ece67..80538b8806ed 100644 --- a/arch/arm/mach-pxa/colibri-pxa270-income.c +++ b/arch/arm/mach-pxa/colibri-pxa270-income.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-pxa/colibri-pxa270.c b/arch/arm/mach-pxa/colibri-pxa270.c index 6fc5d328ba7f..7545a48ed88b 100644 --- a/arch/arm/mach-pxa/colibri-pxa270.c +++ b/arch/arm/mach-pxa/colibri-pxa270.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h index a079d8baa45a..e6c9344a95ae 100644 --- a/arch/arm/mach-pxa/generic.h +++ b/arch/arm/mach-pxa/generic.h @@ -61,10 +61,10 @@ extern unsigned pxa3xx_get_clk_frequency_khz(int); #define pxa3xx_get_clk_frequency_khz(x) (0) #endif -extern struct sysdev_class pxa_irq_sysclass; -extern struct sysdev_class pxa_gpio_sysclass; -extern struct sysdev_class pxa2xx_mfp_sysclass; -extern struct sysdev_class pxa3xx_mfp_sysclass; +extern struct syscore_ops pxa_irq_syscore_ops; +extern struct syscore_ops pxa_gpio_syscore_ops; +extern struct syscore_ops pxa2xx_mfp_syscore_ops; +extern struct syscore_ops pxa3xx_mfp_syscore_ops; void __init pxa_set_ffuart_info(void *info); void __init pxa_set_btuart_info(void *info); diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c index 6de0ad0eea65..9cdcca597924 100644 --- a/arch/arm/mach-pxa/hx4700.c +++ b/arch/arm/mach-pxa/hx4700.c @@ -711,7 +711,7 @@ static struct regulator_consumer_supply bq24022_consumers[] = { static struct regulator_init_data bq24022_init_data = { .constraints = { .max_uA = 500000, - .valid_ops_mask = REGULATOR_CHANGE_CURRENT, + .valid_ops_mask = REGULATOR_CHANGE_CURRENT|REGULATOR_CHANGE_STATUS, }, .num_consumer_supplies = ARRAY_SIZE(bq24022_consumers), .consumer_supplies = bq24022_consumers, diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 6251e3f5c62c..32ed551bf9c5 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -183,7 +183,7 @@ void __init pxa_init_irq(int irq_nr, set_wake_t fn) static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32]; static unsigned long saved_ipr[MAX_INTERNAL_IRQS]; -static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state) +static int pxa_irq_suspend(void) { int i; @@ -202,7 +202,7 @@ static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int pxa_irq_resume(struct sys_device *dev) +static void pxa_irq_resume(void) { int i; @@ -218,22 +218,13 @@ static int pxa_irq_resume(struct sys_device *dev) __raw_writel(saved_ipr[i], IRQ_BASE + IPR(i)); __raw_writel(1, IRQ_BASE + ICCR); - return 0; } #else #define pxa_irq_suspend NULL #define pxa_irq_resume NULL #endif -struct sysdev_class pxa_irq_sysclass = { - .name = "irq", +struct syscore_ops pxa_irq_syscore_ops = { .suspend = pxa_irq_suspend, .resume = pxa_irq_resume, }; - -static int __init pxa_irq_init(void) -{ - return sysdev_class_register(&pxa_irq_sysclass); -} - -core_initcall(pxa_irq_init); diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c index f5de541725b1..6cf8180bf5bd 100644 --- a/arch/arm/mach-pxa/lpd270.c +++ b/arch/arm/mach-pxa/lpd270.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include @@ -159,30 +159,22 @@ static void __init lpd270_init_irq(void) #ifdef CONFIG_PM -static int lpd270_irq_resume(struct sys_device *dev) +static void lpd270_irq_resume(void) { __raw_writew(lpd270_irq_enabled, LPD270_INT_MASK); - return 0; } -static struct sysdev_class lpd270_irq_sysclass = { - .name = "cpld_irq", +static struct syscore_ops lpd270_irq_syscore_ops = { .resume = lpd270_irq_resume, }; -static struct sys_device lpd270_irq_device = { - .cls = &lpd270_irq_sysclass, -}; - static int __init lpd270_irq_device_init(void) { - int ret = -ENODEV; if (machine_is_logicpd_pxa270()) { - ret = sysdev_class_register(&lpd270_irq_sysclass); - if (ret == 0) - ret = sysdev_register(&lpd270_irq_device); + register_syscore_ops(&lpd270_irq_syscore_ops); + return 0; } - return ret; + return -ENODEV; } device_initcall(lpd270_irq_device_init); diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 3ede978c83d9..e10ddb827147 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -176,31 +176,22 @@ static void __init lubbock_init_irq(void) #ifdef CONFIG_PM -static int lubbock_irq_resume(struct sys_device *dev) +static void lubbock_irq_resume(void) { LUB_IRQ_MASK_EN = lubbock_irq_enabled; - return 0; } -static struct sysdev_class lubbock_irq_sysclass = { - .name = "cpld_irq", +static struct syscore_ops lubbock_irq_syscore_ops = { .resume = lubbock_irq_resume, }; -static struct sys_device lubbock_irq_device = { - .cls = &lubbock_irq_sysclass, -}; - static int __init lubbock_irq_device_init(void) { - int ret = -ENODEV; - if (machine_is_lubbock()) { - ret = sysdev_class_register(&lubbock_irq_sysclass); - if (ret == 0) - ret = sysdev_register(&lubbock_irq_device); + register_syscore_ops(&lubbock_irq_syscore_ops); + return 0; } - return ret; + return -ENODEV; } device_initcall(lubbock_irq_device_init); diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index a72993dde2b3..9984ef70bd79 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -599,7 +599,7 @@ static struct regulator_consumer_supply bq24022_consumers[] = { static struct regulator_init_data bq24022_init_data = { .constraints = { .max_uA = 500000, - .valid_ops_mask = REGULATOR_CHANGE_CURRENT, + .valid_ops_mask = REGULATOR_CHANGE_CURRENT | REGULATOR_CHANGE_STATUS, }, .num_consumer_supplies = ARRAY_SIZE(bq24022_consumers), .consumer_supplies = bq24022_consumers, diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 95163baca29e..3479e2b3b511 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include @@ -185,31 +185,21 @@ static void __init mainstone_init_irq(void) #ifdef CONFIG_PM -static int mainstone_irq_resume(struct sys_device *dev) +static void mainstone_irq_resume(void) { MST_INTMSKENA = mainstone_irq_enabled; - return 0; } -static struct sysdev_class mainstone_irq_sysclass = { - .name = "cpld_irq", +static struct syscore_ops mainstone_irq_syscore_ops = { .resume = mainstone_irq_resume, }; -static struct sys_device mainstone_irq_device = { - .cls = &mainstone_irq_sysclass, -}; - static int __init mainstone_irq_device_init(void) { - int ret = -ENODEV; + if (machine_is_mainstone()) + register_syscore_ops(&mainstone_irq_syscore_ops); - if (machine_is_mainstone()) { - ret = sysdev_class_register(&mainstone_irq_sysclass); - if (ret == 0) - ret = sysdev_register(&mainstone_irq_device); - } - return ret; + return 0; } device_initcall(mainstone_irq_device_init); diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c index 1d1419b73457..87ae3129f4f7 100644 --- a/arch/arm/mach-pxa/mfp-pxa2xx.c +++ b/arch/arm/mach-pxa/mfp-pxa2xx.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -338,7 +338,7 @@ static unsigned long saved_gafr[2][4]; static unsigned long saved_gpdr[4]; static unsigned long saved_pgsr[4]; -static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state) +static int pxa2xx_mfp_suspend(void) { int i; @@ -365,7 +365,7 @@ static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state) return 0; } -static int pxa2xx_mfp_resume(struct sys_device *d) +static void pxa2xx_mfp_resume(void) { int i; @@ -376,15 +376,13 @@ static int pxa2xx_mfp_resume(struct sys_device *d) PGSR(i) = saved_pgsr[i]; } PSSR = PSSR_RDH | PSSR_PH; - return 0; } #else #define pxa2xx_mfp_suspend NULL #define pxa2xx_mfp_resume NULL #endif -struct sysdev_class pxa2xx_mfp_sysclass = { - .name = "mfp", +struct syscore_ops pxa2xx_mfp_syscore_ops = { .suspend = pxa2xx_mfp_suspend, .resume = pxa2xx_mfp_resume, }; @@ -409,6 +407,6 @@ static int __init pxa2xx_mfp_init(void) for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++) gpdr_lpm[i] = GPDR(i * 32); - return sysdev_class_register(&pxa2xx_mfp_sysclass); + return 0; } postcore_initcall(pxa2xx_mfp_init); diff --git a/arch/arm/mach-pxa/mfp-pxa3xx.c b/arch/arm/mach-pxa/mfp-pxa3xx.c index 7a270eecd480..89863a01ecd7 100644 --- a/arch/arm/mach-pxa/mfp-pxa3xx.c +++ b/arch/arm/mach-pxa/mfp-pxa3xx.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include @@ -31,13 +31,13 @@ * a pull-down mode if they're an active low chip select, and we're * just entering standby. */ -static int pxa3xx_mfp_suspend(struct sys_device *d, pm_message_t state) +static int pxa3xx_mfp_suspend(void) { mfp_config_lpm(); return 0; } -static int pxa3xx_mfp_resume(struct sys_device *d) +static void pxa3xx_mfp_resume(void) { mfp_config_run(); @@ -47,24 +47,13 @@ static int pxa3xx_mfp_resume(struct sys_device *d) * preserve them here in case they will be referenced later */ ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S); - return 0; } #else #define pxa3xx_mfp_suspend NULL #define pxa3xx_mfp_resume NULL #endif -struct sysdev_class pxa3xx_mfp_sysclass = { - .name = "mfp", +struct syscore_ops pxa3xx_mfp_syscore_ops = { .suspend = pxa3xx_mfp_suspend, - .resume = pxa3xx_mfp_resume, + .resume = pxa3xx_mfp_resume, }; - -static int __init mfp_init_devicefs(void) -{ - if (cpu_is_pxa3xx()) - return sysdev_class_register(&pxa3xx_mfp_sysclass); - - return 0; -} -postcore_initcall(mfp_init_devicefs); diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c index 23925db8ff74..e3470137c934 100644 --- a/arch/arm/mach-pxa/mioa701.c +++ b/arch/arm/mach-pxa/mioa701.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -488,7 +488,7 @@ static void install_bootstrap(void) } -static int mioa701_sys_suspend(struct sys_device *sysdev, pm_message_t state) +static int mioa701_sys_suspend(void) { int i = 0, is_bt_on; u32 *mem_resume_vector = phys_to_virt(RESUME_VECTOR_ADDR); @@ -514,7 +514,7 @@ static int mioa701_sys_suspend(struct sys_device *sysdev, pm_message_t state) return 0; } -static int mioa701_sys_resume(struct sys_device *sysdev) +static void mioa701_sys_resume(void) { int i = 0; u32 *mem_resume_vector = phys_to_virt(RESUME_VECTOR_ADDR); @@ -527,43 +527,18 @@ static int mioa701_sys_resume(struct sys_device *sysdev) *mem_resume_enabler = save_buffer[i++]; *mem_resume_bt = save_buffer[i++]; *mem_resume_unknown = save_buffer[i++]; - - return 0; } -static struct sysdev_class mioa701_sysclass = { - .name = "mioa701", -}; - -static struct sys_device sysdev_bootstrap = { - .cls = &mioa701_sysclass, -}; - -static struct sysdev_driver driver_bootstrap = { - .suspend = &mioa701_sys_suspend, - .resume = &mioa701_sys_resume, +static struct syscore_ops mioa701_syscore_ops = { + .suspend = mioa701_sys_suspend, + .resume = mioa701_sys_resume, }; static int __init bootstrap_init(void) { - int rc; int save_size = mioa701_bootstrap_lg + (sizeof(u32) * 3); - rc = sysdev_class_register(&mioa701_sysclass); - if (rc) { - printk(KERN_ERR "Failed registering mioa701 sys class\n"); - return -ENODEV; - } - rc = sysdev_register(&sysdev_bootstrap); - if (rc) { - printk(KERN_ERR "Failed registering mioa701 sys device\n"); - return -ENODEV; - } - rc = sysdev_driver_register(&mioa701_sysclass, &driver_bootstrap); - if (rc) { - printk(KERN_ERR "Failed registering PMU sys driver\n"); - return -ENODEV; - } + register_syscore_ops(&mioa701_syscore_ops); save_buffer = kmalloc(save_size, GFP_KERNEL); if (!save_buffer) @@ -576,9 +551,7 @@ static int __init bootstrap_init(void) static void bootstrap_exit(void) { kfree(save_buffer); - sysdev_driver_unregister(&mioa701_sysclass, &driver_bootstrap); - sysdev_unregister(&sysdev_bootstrap); - sysdev_class_unregister(&mioa701_sysclass); + unregister_syscore_ops(&mioa701_syscore_ops); printk(KERN_CRIT "Unregistering mioa701 suspend will hang next" "resume !!!\n"); diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c index a6f898cbfac9..4061ecddee70 100644 --- a/arch/arm/mach-pxa/palmld.c +++ b/arch/arm/mach-pxa/palmld.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/palmtreo.c b/arch/arm/mach-pxa/palmtreo.c index 8aadad55fbe4..20d1b18b1733 100644 --- a/arch/arm/mach-pxa/palmtreo.c +++ b/arch/arm/mach-pxa/palmtreo.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c index 3b8a4f37dbbe..65f24f0b77e8 100644 --- a/arch/arm/mach-pxa/palmz72.c +++ b/arch/arm/mach-pxa/palmz72.c @@ -19,7 +19,7 @@ */ #include -#include +#include #include #include #include @@ -233,9 +233,9 @@ static struct palmz72_resume_info palmz72_resume_info = { static unsigned long store_ptr; -/* sys_device for Palm Zire 72 PM */ +/* syscore_ops for Palm Zire 72 PM */ -static int palmz72_pm_suspend(struct sys_device *dev, pm_message_t msg) +static int palmz72_pm_suspend(void) { /* setup the resume_info struct for the original bootloader */ palmz72_resume_info.resume_addr = (u32) cpu_resume; @@ -249,31 +249,23 @@ static int palmz72_pm_suspend(struct sys_device *dev, pm_message_t msg) return 0; } -static int palmz72_pm_resume(struct sys_device *dev) +static void palmz72_pm_resume(void) { *PALMZ72_SAVE_DWORD = store_ptr; - return 0; } -static struct sysdev_class palmz72_pm_sysclass = { - .name = "palmz72_pm", +static struct syscore_ops palmz72_pm_syscore_ops = { .suspend = palmz72_pm_suspend, .resume = palmz72_pm_resume, }; -static struct sys_device palmz72_pm_device = { - .cls = &palmz72_pm_sysclass, -}; - static int __init palmz72_pm_init(void) { - int ret = -ENODEV; if (machine_is_palmz72()) { - ret = sysdev_class_register(&palmz72_pm_sysclass); - if (ret == 0) - ret = sysdev_register(&palmz72_pm_device); + register_syscore_ops(&palmz72_pm_syscore_ops); + return 0; } - return ret; + return -ENODEV; } device_initcall(palmz72_pm_init); diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index a4af8c52d7ee..fed363cec9c6 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -350,21 +350,9 @@ static struct platform_device *pxa25x_devices[] __initdata = { &pxa_device_asoc_platform, }; -static struct sys_device pxa25x_sysdev[] = { - { - .cls = &pxa_irq_sysclass, - }, { - .cls = &pxa2xx_mfp_sysclass, - }, { - .cls = &pxa_gpio_sysclass, - }, { - .cls = &pxa2xx_clock_sysclass, - } -}; - static int __init pxa25x_init(void) { - int i, ret = 0; + int ret = 0; if (cpu_is_pxa25x()) { @@ -377,11 +365,10 @@ static int __init pxa25x_init(void) pxa25x_init_pm(); - for (i = 0; i < ARRAY_SIZE(pxa25x_sysdev); i++) { - ret = sysdev_register(&pxa25x_sysdev[i]); - if (ret) - pr_err("failed to register sysdev[%d]\n", i); - } + register_syscore_ops(&pxa_irq_syscore_ops); + register_syscore_ops(&pxa2xx_mfp_syscore_ops); + register_syscore_ops(&pxa_gpio_syscore_ops); + register_syscore_ops(&pxa2xx_clock_syscore_ops); ret = platform_add_devices(pxa25x_devices, ARRAY_SIZE(pxa25x_devices)); diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 909756eaf4b7..2fecbec58d88 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -428,21 +428,9 @@ static struct platform_device *devices[] __initdata = { &pxa27x_device_pwm1, }; -static struct sys_device pxa27x_sysdev[] = { - { - .cls = &pxa_irq_sysclass, - }, { - .cls = &pxa2xx_mfp_sysclass, - }, { - .cls = &pxa_gpio_sysclass, - }, { - .cls = &pxa2xx_clock_sysclass, - } -}; - static int __init pxa27x_init(void) { - int i, ret = 0; + int ret = 0; if (cpu_is_pxa27x()) { @@ -455,11 +443,10 @@ static int __init pxa27x_init(void) pxa27x_init_pm(); - for (i = 0; i < ARRAY_SIZE(pxa27x_sysdev); i++) { - ret = sysdev_register(&pxa27x_sysdev[i]); - if (ret) - pr_err("failed to register sysdev[%d]\n", i); - } + register_syscore_ops(&pxa_irq_syscore_ops); + register_syscore_ops(&pxa2xx_mfp_syscore_ops); + register_syscore_ops(&pxa_gpio_syscore_ops); + register_syscore_ops(&pxa2xx_clock_syscore_ops); ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 8dd107391157..8521d7d6f1da 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -427,21 +427,9 @@ static struct platform_device *devices[] __initdata = { &pxa27x_device_pwm1, }; -static struct sys_device pxa3xx_sysdev[] = { - { - .cls = &pxa_irq_sysclass, - }, { - .cls = &pxa3xx_mfp_sysclass, - }, { - .cls = &pxa_gpio_sysclass, - }, { - .cls = &pxa3xx_clock_sysclass, - } -}; - static int __init pxa3xx_init(void) { - int i, ret = 0; + int ret = 0; if (cpu_is_pxa3xx()) { @@ -462,11 +450,10 @@ static int __init pxa3xx_init(void) pxa3xx_init_pm(); - for (i = 0; i < ARRAY_SIZE(pxa3xx_sysdev); i++) { - ret = sysdev_register(&pxa3xx_sysdev[i]); - if (ret) - pr_err("failed to register sysdev[%d]\n", i); - } + register_syscore_ops(&pxa_irq_syscore_ops); + register_syscore_ops(&pxa3xx_mfp_syscore_ops); + register_syscore_ops(&pxa_gpio_syscore_ops); + register_syscore_ops(&pxa3xx_clock_syscore_ops); ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-pxa/pxa95x.c b/arch/arm/mach-pxa/pxa95x.c index 23b229bd06e9..ecc82a330fad 100644 --- a/arch/arm/mach-pxa/pxa95x.c +++ b/arch/arm/mach-pxa/pxa95x.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include @@ -260,16 +260,6 @@ static struct platform_device *devices[] __initdata = { &pxa27x_device_pwm1, }; -static struct sys_device pxa95x_sysdev[] = { - { - .cls = &pxa_irq_sysclass, - }, { - .cls = &pxa_gpio_sysclass, - }, { - .cls = &pxa3xx_clock_sysclass, - } -}; - static int __init pxa95x_init(void) { int ret = 0, i; @@ -293,11 +283,9 @@ static int __init pxa95x_init(void) if ((ret = pxa_init_dma(IRQ_DMA, 32))) return ret; - for (i = 0; i < ARRAY_SIZE(pxa95x_sysdev); i++) { - ret = sysdev_register(&pxa95x_sysdev[i]); - if (ret) - pr_err("failed to register sysdev[%d]\n", i); - } + register_syscore_ops(&pxa_irq_syscore_ops); + register_syscore_ops(&pxa_gpio_syscore_ops); + register_syscore_ops(&pxa3xx_clock_syscore_ops); ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index cd1861351f75..d130f77b6d11 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/smemc.c b/arch/arm/mach-pxa/smemc.c index 232b7316ec08..79923058d10f 100644 --- a/arch/arm/mach-pxa/smemc.c +++ b/arch/arm/mach-pxa/smemc.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -16,7 +16,7 @@ static unsigned long msc[2]; static unsigned long sxcnfg, memclkcfg; static unsigned long csadrcfg[4]; -static int pxa3xx_smemc_suspend(struct sys_device *dev, pm_message_t state) +static int pxa3xx_smemc_suspend(void) { msc[0] = __raw_readl(MSC0); msc[1] = __raw_readl(MSC1); @@ -30,7 +30,7 @@ static int pxa3xx_smemc_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int pxa3xx_smemc_resume(struct sys_device *dev) +static void pxa3xx_smemc_resume(void) { __raw_writel(msc[0], MSC0); __raw_writel(msc[1], MSC1); @@ -40,34 +40,19 @@ static int pxa3xx_smemc_resume(struct sys_device *dev) __raw_writel(csadrcfg[1], CSADRCFG1); __raw_writel(csadrcfg[2], CSADRCFG2); __raw_writel(csadrcfg[3], CSADRCFG3); - - return 0; } -static struct sysdev_class smemc_sysclass = { - .name = "smemc", +static struct syscore_ops smemc_syscore_ops = { .suspend = pxa3xx_smemc_suspend, .resume = pxa3xx_smemc_resume, }; -static struct sys_device smemc_sysdev = { - .id = 0, - .cls = &smemc_sysclass, -}; - static int __init smemc_init(void) { - int ret = 0; + if (cpu_is_pxa3xx()) + register_syscore_ops(&smemc_syscore_ops); - if (cpu_is_pxa3xx()) { - ret = sysdev_class_register(&smemc_sysclass); - if (ret) - return ret; - - ret = sysdev_register(&smemc_sysdev); - } - - return ret; + return 0; } subsys_initcall(smemc_init); #endif diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index b9cfbebdfe9c..687417a93698 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c index b523f119e0f0..903218eab56d 100644 --- a/arch/arm/mach-pxa/viper.c +++ b/arch/arm/mach-pxa/viper.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -130,20 +131,19 @@ static u8 viper_hw_version(void) return v1; } -/* CPU sysdev */ -static int viper_cpu_suspend(struct sys_device *sysdev, pm_message_t state) +/* CPU system core operations. */ +static int viper_cpu_suspend(void) { viper_icr_set_bit(VIPER_ICR_R_DIS); return 0; } -static int viper_cpu_resume(struct sys_device *sysdev) +static void viper_cpu_resume(void) { viper_icr_clear_bit(VIPER_ICR_R_DIS); - return 0; } -static struct sysdev_driver viper_cpu_sysdev_driver = { +static struct syscore_ops viper_cpu_syscore_ops = { .suspend = viper_cpu_suspend, .resume = viper_cpu_resume, }; @@ -945,7 +945,7 @@ static void __init viper_init(void) viper_init_vcore_gpios(); viper_init_cpufreq(); - sysdev_driver_register(&cpu_sysdev_class, &viper_cpu_sysdev_driver); + register_syscore_ops(&viper_cpu_syscore_ops); if (version) { pr_info("viper: hardware v%di%d detected. " diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c index f71d377c8640..67bd41488bf8 100644 --- a/arch/arm/mach-pxa/vpac270.c +++ b/arch/arm/mach-pxa/vpac270.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-realview/include/mach/barriers.h b/arch/arm/mach-realview/include/mach/barriers.h index 0c5d749d7b5f..9a732195aa1c 100644 --- a/arch/arm/mach-realview/include/mach/barriers.h +++ b/arch/arm/mach-realview/include/mach/barriers.h @@ -4,5 +4,5 @@ * operation to deadlock the system. */ #define mb() dsb() -#define rmb() dmb() +#define rmb() dsb() #define wmb() mb() diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c index 5e2f35332056..2854129f8cc7 100644 --- a/arch/arm/mach-s3c2410/irq.c +++ b/arch/arm/mach-s3c2410/irq.c @@ -23,38 +23,12 @@ #include #include #include -#include +#include #include #include -static int s3c2410_irq_add(struct sys_device *sysdev) -{ - return 0; -} - -static struct sysdev_driver s3c2410_irq_driver = { - .add = s3c2410_irq_add, +struct syscore_ops s3c24xx_irq_syscore_ops = { .suspend = s3c24xx_irq_suspend, .resume = s3c24xx_irq_resume, }; - -static int __init s3c2410_irq_init(void) -{ - return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver); -} - -arch_initcall(s3c2410_irq_init); - -static struct sysdev_driver s3c2410a_irq_driver = { - .add = s3c2410_irq_add, - .suspend = s3c24xx_irq_suspend, - .resume = s3c24xx_irq_resume, -}; - -static int __init s3c2410a_irq_init(void) -{ - return sysdev_driver_register(&s3c2410a_sysclass, &s3c2410a_irq_driver); -} - -arch_initcall(s3c2410a_irq_init); diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index 2970ea9f7c2b..1e2d536adda9 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -214,17 +214,16 @@ static struct s3c2410_uartcfg bast_uartcfgs[] __initdata = { /* NAND Flash on BAST board */ #ifdef CONFIG_PM -static int bast_pm_suspend(struct sys_device *sd, pm_message_t state) +static int bast_pm_suspend(void) { /* ensure that an nRESET is not generated on resume. */ gpio_direction_output(S3C2410_GPA(21), 1); return 0; } -static int bast_pm_resume(struct sys_device *sd) +static void bast_pm_resume(void) { s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT); - return 0; } #else @@ -232,16 +231,11 @@ static int bast_pm_resume(struct sys_device *sd) #define bast_pm_resume NULL #endif -static struct sysdev_class bast_pm_sysclass = { - .name = "mach-bast", +static struct syscore_ops bast_pm_syscore_ops = { .suspend = bast_pm_suspend, .resume = bast_pm_resume, }; -static struct sys_device bast_pm_sysdev = { - .cls = &bast_pm_sysclass, -}; - static int smartmedia_map[] = { 0 }; static int chip0_map[] = { 1 }; static int chip1_map[] = { 2 }; @@ -642,8 +636,7 @@ static void __init bast_map_io(void) static void __init bast_init(void) { - sysdev_class_register(&bast_pm_sysclass); - sysdev_register(&bast_pm_sysdev); + register_syscore_ops(&bast_pm_syscore_ops); s3c_i2c0_set_platdata(&bast_i2c_info); s3c_nand_set_platdata(&bast_nand_info); diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c index 725636fc4dc3..4728f9aa7df1 100644 --- a/arch/arm/mach-s3c2410/pm.c +++ b/arch/arm/mach-s3c2410/pm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -92,7 +93,7 @@ static void s3c2410_pm_prepare(void) } } -static int s3c2410_pm_resume(struct sys_device *dev) +static void s3c2410_pm_resume(void) { unsigned long tmp; @@ -104,10 +105,12 @@ static int s3c2410_pm_resume(struct sys_device *dev) if ( machine_is_aml_m5900() ) s3c2410_gpio_setpin(S3C2410_GPF(2), 0); - - return 0; } +struct syscore_ops s3c2410_pm_syscore_ops = { + .resume = s3c2410_pm_resume, +}; + static int s3c2410_pm_add(struct sys_device *dev) { pm_cpu_prep = s3c2410_pm_prepare; @@ -119,7 +122,6 @@ static int s3c2410_pm_add(struct sys_device *dev) #if defined(CONFIG_CPU_S3C2410) static struct sysdev_driver s3c2410_pm_driver = { .add = s3c2410_pm_add, - .resume = s3c2410_pm_resume, }; /* register ourselves */ @@ -133,7 +135,6 @@ arch_initcall(s3c2410_pm_drvinit); static struct sysdev_driver s3c2410a_pm_driver = { .add = s3c2410_pm_add, - .resume = s3c2410_pm_resume, }; static int __init s3c2410a_pm_drvinit(void) @@ -147,7 +148,6 @@ arch_initcall(s3c2410a_pm_drvinit); #if defined(CONFIG_CPU_S3C2440) static struct sysdev_driver s3c2440_pm_driver = { .add = s3c2410_pm_add, - .resume = s3c2410_pm_resume, }; static int __init s3c2440_pm_drvinit(void) @@ -161,7 +161,6 @@ arch_initcall(s3c2440_pm_drvinit); #if defined(CONFIG_CPU_S3C2442) static struct sysdev_driver s3c2442_pm_driver = { .add = s3c2410_pm_add, - .resume = s3c2410_pm_resume, }; static int __init s3c2442_pm_drvinit(void) diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c index adc90a3c5890..f1d3bd8f6f17 100644 --- a/arch/arm/mach-s3c2410/s3c2410.c +++ b/arch/arm/mach-s3c2410/s3c2410.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include #include @@ -168,6 +170,9 @@ int __init s3c2410_init(void) { printk("S3C2410: Initialising architecture\n"); + register_syscore_ops(&s3c2410_pm_syscore_ops); + register_syscore_ops(&s3c24xx_irq_syscore_ops); + return sysdev_register(&s3c2410_sysdev); } diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c2412/irq.c index f3355d2ec634..1a1aa220972b 100644 --- a/arch/arm/mach-s3c2412/irq.c +++ b/arch/arm/mach-s3c2412/irq.c @@ -202,8 +202,6 @@ static int s3c2412_irq_add(struct sys_device *sysdev) static struct sysdev_driver s3c2412_irq_driver = { .add = s3c2412_irq_add, - .suspend = s3c24xx_irq_suspend, - .resume = s3c24xx_irq_resume, }; static int s3c2412_irq_init(void) diff --git a/arch/arm/mach-s3c2412/mach-jive.c b/arch/arm/mach-s3c2412/mach-jive.c index 923e01bdf017..85dcaeb9e62f 100644 --- a/arch/arm/mach-s3c2412/mach-jive.c +++ b/arch/arm/mach-s3c2412/mach-jive.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -486,7 +486,7 @@ static struct s3c2410_udc_mach_info jive_udc_cfg __initdata = { /* Jive power management device */ #ifdef CONFIG_PM -static int jive_pm_suspend(struct sys_device *sd, pm_message_t state) +static int jive_pm_suspend(void) { /* Write the magic value u-boot uses to check for resume into * the INFORM0 register, and ensure INFORM1 is set to the @@ -498,10 +498,9 @@ static int jive_pm_suspend(struct sys_device *sd, pm_message_t state) return 0; } -static int jive_pm_resume(struct sys_device *sd) +static void jive_pm_resume(void) { __raw_writel(0x0, S3C2412_INFORM0); - return 0; } #else @@ -509,16 +508,11 @@ static int jive_pm_resume(struct sys_device *sd) #define jive_pm_resume NULL #endif -static struct sysdev_class jive_pm_sysclass = { - .name = "jive-pm", +static struct syscore_ops jive_pm_syscore_ops = { .suspend = jive_pm_suspend, .resume = jive_pm_resume, }; -static struct sys_device jive_pm_sysdev = { - .cls = &jive_pm_sysclass, -}; - static void __init jive_map_io(void) { s3c24xx_init_io(jive_iodesc, ARRAY_SIZE(jive_iodesc)); @@ -536,10 +530,9 @@ static void jive_power_off(void) static void __init jive_machine_init(void) { - /* register system devices for managing low level suspend */ + /* register system core operations for managing low level suspend */ - sysdev_class_register(&jive_pm_sysclass); - sysdev_register(&jive_pm_sysdev); + register_syscore_ops(&jive_pm_syscore_ops); /* write our sleep configurations for the IO. Pull down all unused * IO, ensure that we have turned off all peripherals we do not diff --git a/arch/arm/mach-s3c2412/pm.c b/arch/arm/mach-s3c2412/pm.c index a7417c479ffe..752b13a7b3db 100644 --- a/arch/arm/mach-s3c2412/pm.c +++ b/arch/arm/mach-s3c2412/pm.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -86,13 +87,24 @@ static struct sleep_save s3c2412_sleep[] = { SAVE_ITEM(S3C2413_GPJSLPCON), }; -static int s3c2412_pm_suspend(struct sys_device *dev, pm_message_t state) +static struct sysdev_driver s3c2412_pm_driver = { + .add = s3c2412_pm_add, +}; + +static __init int s3c2412_pm_init(void) +{ + return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_pm_driver); +} + +arch_initcall(s3c2412_pm_init); + +static int s3c2412_pm_suspend(void) { s3c_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep)); return 0; } -static int s3c2412_pm_resume(struct sys_device *dev) +static void s3c2412_pm_resume(void) { unsigned long tmp; @@ -102,18 +114,9 @@ static int s3c2412_pm_resume(struct sys_device *dev) __raw_writel(tmp, S3C2412_PWRCFG); s3c_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep)); - return 0; } -static struct sysdev_driver s3c2412_pm_driver = { - .add = s3c2412_pm_add, +struct syscore_ops s3c2412_pm_syscore_ops = { .suspend = s3c2412_pm_suspend, .resume = s3c2412_pm_resume, }; - -static __init int s3c2412_pm_init(void) -{ - return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_pm_driver); -} - -arch_initcall(s3c2412_pm_init); diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c index 4c6df51ddf33..ef0958d3e5c6 100644 --- a/arch/arm/mach-s3c2412/s3c2412.c +++ b/arch/arm/mach-s3c2412/s3c2412.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -244,5 +245,8 @@ int __init s3c2412_init(void) { printk("S3C2412: Initialising architecture\n"); + register_syscore_ops(&s3c2412_pm_syscore_ops); + register_syscore_ops(&s3c24xx_irq_syscore_ops); + return sysdev_register(&s3c2412_sysdev); } diff --git a/arch/arm/mach-s3c2416/irq.c b/arch/arm/mach-s3c2416/irq.c index 77b38f2381c1..28ad20d42445 100644 --- a/arch/arm/mach-s3c2416/irq.c +++ b/arch/arm/mach-s3c2416/irq.c @@ -236,8 +236,6 @@ static int __init s3c2416_irq_add(struct sys_device *sysdev) static struct sysdev_driver s3c2416_irq_driver = { .add = s3c2416_irq_add, - .suspend = s3c24xx_irq_suspend, - .resume = s3c24xx_irq_resume, }; static int __init s3c2416_irq_init(void) diff --git a/arch/arm/mach-s3c2416/pm.c b/arch/arm/mach-s3c2416/pm.c index 4a04205b04d5..41db2b21e213 100644 --- a/arch/arm/mach-s3c2416/pm.c +++ b/arch/arm/mach-s3c2416/pm.c @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -55,25 +56,8 @@ static int s3c2416_pm_add(struct sys_device *sysdev) return 0; } -static int s3c2416_pm_suspend(struct sys_device *dev, pm_message_t state) -{ - return 0; -} - -static int s3c2416_pm_resume(struct sys_device *dev) -{ - /* unset the return-from-sleep amd inform flags */ - __raw_writel(0x0, S3C2443_PWRMODE); - __raw_writel(0x0, S3C2412_INFORM0); - __raw_writel(0x0, S3C2412_INFORM1); - - return 0; -} - static struct sysdev_driver s3c2416_pm_driver = { .add = s3c2416_pm_add, - .suspend = s3c2416_pm_suspend, - .resume = s3c2416_pm_resume, }; static __init int s3c2416_pm_init(void) @@ -82,3 +66,16 @@ static __init int s3c2416_pm_init(void) } arch_initcall(s3c2416_pm_init); + + +static void s3c2416_pm_resume(void) +{ + /* unset the return-from-sleep amd inform flags */ + __raw_writel(0x0, S3C2443_PWRMODE); + __raw_writel(0x0, S3C2412_INFORM0); + __raw_writel(0x0, S3C2412_INFORM1); +} + +struct syscore_ops s3c2416_pm_syscore_ops = { + .resume = s3c2416_pm_resume, +}; diff --git a/arch/arm/mach-s3c2416/s3c2416.c b/arch/arm/mach-s3c2416/s3c2416.c index ba7fd8737434..494ce913dc95 100644 --- a/arch/arm/mach-s3c2416/s3c2416.c +++ b/arch/arm/mach-s3c2416/s3c2416.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,7 @@ #include #include #include +#include #include #include @@ -95,6 +97,9 @@ int __init s3c2416_init(void) s3c_fb_setname("s3c2443-fb"); + register_syscore_ops(&s3c2416_pm_syscore_ops); + register_syscore_ops(&s3c24xx_irq_syscore_ops); + return sysdev_register(&s3c2416_sysdev); } diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c index 0db2411ef4bb..716662008ce2 100644 --- a/arch/arm/mach-s3c2440/mach-gta02.c +++ b/arch/arm/mach-s3c2440/mach-gta02.c @@ -409,6 +409,10 @@ struct platform_device s3c24xx_pwm_device = { .num_resources = 0, }; +static struct platform_device gta02_dfbmcs320_device = { + .name = "dfbmcs320", +}; + static struct i2c_board_info gta02_i2c_devs[] __initdata = { { I2C_BOARD_INFO("pcf50633", 0x73), @@ -523,6 +527,7 @@ static struct platform_device *gta02_devices[] __initdata = { &s3c_device_iis, &samsung_asoc_dma, &s3c_device_i2c0, + >a02_dfbmcs320_device, >a02_buttons_device, &s3c_device_adc, &s3c_device_ts, diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c index 14dc67897757..d88536393310 100644 --- a/arch/arm/mach-s3c2440/mach-osiris.c +++ b/arch/arm/mach-s3c2440/mach-osiris.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -284,7 +284,7 @@ static struct platform_device osiris_pcmcia = { #ifdef CONFIG_PM static unsigned char pm_osiris_ctrl0; -static int osiris_pm_suspend(struct sys_device *sd, pm_message_t state) +static int osiris_pm_suspend(void) { unsigned int tmp; @@ -304,7 +304,7 @@ static int osiris_pm_suspend(struct sys_device *sd, pm_message_t state) return 0; } -static int osiris_pm_resume(struct sys_device *sd) +static void osiris_pm_resume(void) { if (pm_osiris_ctrl0 & OSIRIS_CTRL0_FIX8) __raw_writeb(OSIRIS_CTRL1_FIX8, OSIRIS_VA_CTRL1); @@ -312,8 +312,6 @@ static int osiris_pm_resume(struct sys_device *sd) __raw_writeb(pm_osiris_ctrl0, OSIRIS_VA_CTRL0); s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT); - - return 0; } #else @@ -321,16 +319,11 @@ static int osiris_pm_resume(struct sys_device *sd) #define osiris_pm_resume NULL #endif -static struct sysdev_class osiris_pm_sysclass = { - .name = "mach-osiris", +static struct syscore_ops osiris_pm_syscore_ops = { .suspend = osiris_pm_suspend, .resume = osiris_pm_resume, }; -static struct sys_device osiris_pm_sysdev = { - .cls = &osiris_pm_sysclass, -}; - /* Link for DVS driver to TPS65011 */ static void osiris_tps_release(struct device *dev) @@ -439,8 +432,7 @@ static void __init osiris_map_io(void) static void __init osiris_init(void) { - sysdev_class_register(&osiris_pm_sysclass); - sysdev_register(&osiris_pm_sysdev); + register_syscore_ops(&osiris_pm_syscore_ops); s3c_i2c0_set_platdata(NULL); s3c_nand_set_platdata(&osiris_nand_info); diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c index f7663f731ea0..ce99ff72838d 100644 --- a/arch/arm/mach-s3c2440/s3c2440.c +++ b/arch/arm/mach-s3c2440/s3c2440.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include #include @@ -51,6 +53,12 @@ int __init s3c2440_init(void) s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT; s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT; + /* register suspend/resume handlers */ + + register_syscore_ops(&s3c2410_pm_syscore_ops); + register_syscore_ops(&s3c244x_pm_syscore_ops); + register_syscore_ops(&s3c24xx_irq_syscore_ops); + /* register our system device for everything else */ return sysdev_register(&s3c2440_sysdev); diff --git a/arch/arm/mach-s3c2440/s3c2442.c b/arch/arm/mach-s3c2440/s3c2442.c index ecf813546554..6224bad4d604 100644 --- a/arch/arm/mach-s3c2440/s3c2442.c +++ b/arch/arm/mach-s3c2440/s3c2442.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,7 @@ #include #include #include +#include #include #include @@ -167,6 +169,10 @@ int __init s3c2442_init(void) { printk("S3C2442: Initialising architecture\n"); + register_syscore_ops(&s3c2410_pm_syscore_ops); + register_syscore_ops(&s3c244x_pm_syscore_ops); + register_syscore_ops(&s3c24xx_irq_syscore_ops); + return sysdev_register(&s3c2442_sysdev); } diff --git a/arch/arm/mach-s3c2440/s3c244x-irq.c b/arch/arm/mach-s3c2440/s3c244x-irq.c index de07c2feaa32..c63e8f26d901 100644 --- a/arch/arm/mach-s3c2440/s3c244x-irq.c +++ b/arch/arm/mach-s3c2440/s3c244x-irq.c @@ -116,8 +116,6 @@ static int s3c244x_irq_add(struct sys_device *sysdev) static struct sysdev_driver s3c2440_irq_driver = { .add = s3c244x_irq_add, - .suspend = s3c24xx_irq_suspend, - .resume = s3c24xx_irq_resume, }; static int s3c2440_irq_init(void) @@ -129,8 +127,6 @@ arch_initcall(s3c2440_irq_init); static struct sysdev_driver s3c2442_irq_driver = { .add = s3c244x_irq_add, - .suspend = s3c24xx_irq_suspend, - .resume = s3c24xx_irq_resume, }; diff --git a/arch/arm/mach-s3c2440/s3c244x.c b/arch/arm/mach-s3c2440/s3c244x.c index 90c1707b9c95..7e8a23d2098a 100644 --- a/arch/arm/mach-s3c2440/s3c244x.c +++ b/arch/arm/mach-s3c2440/s3c244x.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -134,45 +135,14 @@ void __init s3c244x_init_clocks(int xtal) s3c2410_baseclk_add(); } -#ifdef CONFIG_PM - -static struct sleep_save s3c244x_sleep[] = { - SAVE_ITEM(S3C2440_DSC0), - SAVE_ITEM(S3C2440_DSC1), - SAVE_ITEM(S3C2440_GPJDAT), - SAVE_ITEM(S3C2440_GPJCON), - SAVE_ITEM(S3C2440_GPJUP) -}; - -static int s3c244x_suspend(struct sys_device *dev, pm_message_t state) -{ - s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep)); - return 0; -} - -static int s3c244x_resume(struct sys_device *dev) -{ - s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep)); - return 0; -} - -#else -#define s3c244x_suspend NULL -#define s3c244x_resume NULL -#endif - /* Since the S3C2442 and S3C2440 share items, put both sysclasses here */ struct sysdev_class s3c2440_sysclass = { .name = "s3c2440-core", - .suspend = s3c244x_suspend, - .resume = s3c244x_resume }; struct sysdev_class s3c2442_sysclass = { .name = "s3c2442-core", - .suspend = s3c244x_suspend, - .resume = s3c244x_resume }; /* need to register class before we actually register the device, and @@ -194,3 +164,33 @@ static int __init s3c2442_core_init(void) } core_initcall(s3c2442_core_init); + + +#ifdef CONFIG_PM +static struct sleep_save s3c244x_sleep[] = { + SAVE_ITEM(S3C2440_DSC0), + SAVE_ITEM(S3C2440_DSC1), + SAVE_ITEM(S3C2440_GPJDAT), + SAVE_ITEM(S3C2440_GPJCON), + SAVE_ITEM(S3C2440_GPJUP) +}; + +static int s3c244x_suspend(void) +{ + s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep)); + return 0; +} + +static void s3c244x_resume(void) +{ + s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep)); +} +#else +#define s3c244x_suspend NULL +#define s3c244x_resume NULL +#endif + +struct syscore_ops s3c244x_pm_syscore_ops = { + .suspend = s3c244x_suspend, + .resume = s3c244x_resume, +}; diff --git a/arch/arm/mach-s3c64xx/irq-pm.c b/arch/arm/mach-s3c64xx/irq-pm.c index da1bec64b9da..8bec61e242c7 100644 --- a/arch/arm/mach-s3c64xx/irq-pm.c +++ b/arch/arm/mach-s3c64xx/irq-pm.c @@ -13,7 +13,7 @@ */ #include -#include +#include #include #include #include @@ -54,7 +54,7 @@ static struct irq_grp_save { static u32 irq_uart_mask[CONFIG_SERIAL_SAMSUNG_UARTS]; -static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state) +static int s3c64xx_irq_pm_suspend(void) { struct irq_grp_save *grp = eint_grp_save; int i; @@ -75,7 +75,7 @@ static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int s3c64xx_irq_pm_resume(struct sys_device *dev) +static void s3c64xx_irq_pm_resume(void) { struct irq_grp_save *grp = eint_grp_save; int i; @@ -94,18 +94,18 @@ static int s3c64xx_irq_pm_resume(struct sys_device *dev) } S3C_PMDBG("%s: IRQ configuration restored\n", __func__); - return 0; } -static struct sysdev_driver s3c64xx_irq_driver = { +struct syscore_ops s3c64xx_irq_syscore_ops = { .suspend = s3c64xx_irq_pm_suspend, .resume = s3c64xx_irq_pm_resume, }; -static int __init s3c64xx_irq_pm_init(void) +static __init int s3c64xx_syscore_init(void) { - return sysdev_driver_register(&s3c64xx_sysclass, &s3c64xx_irq_driver); + register_syscore_ops(&s3c64xx_irq_syscore_ops); + + return 0; } -arch_initcall(s3c64xx_irq_pm_init); - +core_initcall(s3c64xx_syscore_init); diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c index 549d7924fd4c..24febae3d4c0 100644 --- a/arch/arm/mach-s5pv210/pm.c +++ b/arch/arm/mach-s5pv210/pm.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -140,7 +141,17 @@ static int s5pv210_pm_add(struct sys_device *sysdev) return 0; } -static int s5pv210_pm_resume(struct sys_device *dev) +static struct sysdev_driver s5pv210_pm_driver = { + .add = s5pv210_pm_add, +}; + +static __init int s5pv210_pm_drvinit(void) +{ + return sysdev_driver_register(&s5pv210_sysclass, &s5pv210_pm_driver); +} +arch_initcall(s5pv210_pm_drvinit); + +static void s5pv210_pm_resume(void) { u32 tmp; @@ -150,17 +161,15 @@ static int s5pv210_pm_resume(struct sys_device *dev) __raw_writel(tmp , S5P_OTHERS); s3c_pm_do_restore_core(s5pv210_core_save, ARRAY_SIZE(s5pv210_core_save)); - - return 0; } -static struct sysdev_driver s5pv210_pm_driver = { - .add = s5pv210_pm_add, +static struct syscore_ops s5pv210_pm_syscore_ops = { .resume = s5pv210_pm_resume, }; -static __init int s5pv210_pm_drvinit(void) +static __init int s5pv210_pm_syscore_init(void) { - return sysdev_driver_register(&s5pv210_sysclass, &s5pv210_pm_driver); + register_syscore_ops(&s5pv210_pm_syscore_ops); + return 0; } -arch_initcall(s5pv210_pm_drvinit); +arch_initcall(s5pv210_pm_syscore_init); diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c index 423ddb3d65e9..dfbf824a69fa 100644 --- a/arch/arm/mach-sa1100/irq.c +++ b/arch/arm/mach-sa1100/irq.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -234,7 +234,7 @@ static struct sa1100irq_state { unsigned int iccr; } sa1100irq_state; -static int sa1100irq_suspend(struct sys_device *dev, pm_message_t state) +static int sa1100irq_suspend(void) { struct sa1100irq_state *st = &sa1100irq_state; @@ -264,7 +264,7 @@ static int sa1100irq_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int sa1100irq_resume(struct sys_device *dev) +static void sa1100irq_resume(void) { struct sa1100irq_state *st = &sa1100irq_state; @@ -277,24 +277,17 @@ static int sa1100irq_resume(struct sys_device *dev) ICMR = st->icmr; } - return 0; } -static struct sysdev_class sa1100irq_sysclass = { - .name = "sa11x0-irq", +static struct syscore_ops sa1100irq_syscore_ops = { .suspend = sa1100irq_suspend, .resume = sa1100irq_resume, }; -static struct sys_device sa1100irq_device = { - .id = 0, - .cls = &sa1100irq_sysclass, -}; - static int __init sa1100irq_init_devicefs(void) { - sysdev_class_register(&sa1100irq_sysclass); - return sysdev_register(&sa1100irq_device); + register_syscore_ops(&sa1100irq_syscore_ops); + return 0; } device_initcall(sa1100irq_init_devicefs); diff --git a/arch/arm/mach-shmobile/pm_runtime.c b/arch/arm/mach-shmobile/pm_runtime.c index 94912d3944d3..2d1b67a59e4a 100644 --- a/arch/arm/mach-shmobile/pm_runtime.c +++ b/arch/arm/mach-shmobile/pm_runtime.c @@ -18,152 +18,41 @@ #include #include #include +#include #ifdef CONFIG_PM_RUNTIME -#define BIT_ONCE 0 -#define BIT_ACTIVE 1 -#define BIT_CLK_ENABLED 2 -struct pm_runtime_data { - unsigned long flags; - struct clk *clk; -}; - -static void __devres_release(struct device *dev, void *res) -{ - struct pm_runtime_data *prd = res; - - dev_dbg(dev, "__devres_release()\n"); - - if (test_bit(BIT_CLK_ENABLED, &prd->flags)) - clk_disable(prd->clk); - - if (test_bit(BIT_ACTIVE, &prd->flags)) - clk_put(prd->clk); -} - -static struct pm_runtime_data *__to_prd(struct device *dev) -{ - return devres_find(dev, __devres_release, NULL, NULL); -} - -static void platform_pm_runtime_init(struct device *dev, - struct pm_runtime_data *prd) -{ - if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) { - prd->clk = clk_get(dev, NULL); - if (!IS_ERR(prd->clk)) { - set_bit(BIT_ACTIVE, &prd->flags); - dev_info(dev, "clocks managed by runtime pm\n"); - } - } -} - -static void platform_pm_runtime_bug(struct device *dev, - struct pm_runtime_data *prd) -{ - if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) - dev_err(dev, "runtime pm suspend before resume\n"); -} - -int platform_pm_runtime_suspend(struct device *dev) -{ - struct pm_runtime_data *prd = __to_prd(dev); - - dev_dbg(dev, "platform_pm_runtime_suspend()\n"); - - platform_pm_runtime_bug(dev, prd); - - if (prd && test_bit(BIT_ACTIVE, &prd->flags)) { - clk_disable(prd->clk); - clear_bit(BIT_CLK_ENABLED, &prd->flags); - } - - return 0; -} - -int platform_pm_runtime_resume(struct device *dev) -{ - struct pm_runtime_data *prd = __to_prd(dev); - - dev_dbg(dev, "platform_pm_runtime_resume()\n"); - - platform_pm_runtime_init(dev, prd); - - if (prd && test_bit(BIT_ACTIVE, &prd->flags)) { - clk_enable(prd->clk); - set_bit(BIT_CLK_ENABLED, &prd->flags); - } - - return 0; -} - -int platform_pm_runtime_idle(struct device *dev) +static int default_platform_runtime_idle(struct device *dev) { /* suspend synchronously to disable clocks immediately */ return pm_runtime_suspend(dev); } -static int platform_bus_notify(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct device *dev = data; - struct pm_runtime_data *prd; +static struct dev_power_domain default_power_domain = { + .ops = { + .runtime_suspend = pm_runtime_clk_suspend, + .runtime_resume = pm_runtime_clk_resume, + .runtime_idle = default_platform_runtime_idle, + USE_PLATFORM_PM_SLEEP_OPS + }, +}; - dev_dbg(dev, "platform_bus_notify() %ld !\n", action); +#define DEFAULT_PWR_DOMAIN_PTR (&default_power_domain) - if (action == BUS_NOTIFY_BIND_DRIVER) { - prd = devres_alloc(__devres_release, sizeof(*prd), GFP_KERNEL); - if (prd) - devres_add(dev, prd); - else - dev_err(dev, "unable to alloc memory for runtime pm\n"); - } +#else - return 0; -} - -#else /* CONFIG_PM_RUNTIME */ - -static int platform_bus_notify(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct device *dev = data; - struct clk *clk; - - dev_dbg(dev, "platform_bus_notify() %ld !\n", action); - - switch (action) { - case BUS_NOTIFY_BIND_DRIVER: - clk = clk_get(dev, NULL); - if (!IS_ERR(clk)) { - clk_enable(clk); - clk_put(clk); - dev_info(dev, "runtime pm disabled, clock forced on\n"); - } - break; - case BUS_NOTIFY_UNBOUND_DRIVER: - clk = clk_get(dev, NULL); - if (!IS_ERR(clk)) { - clk_disable(clk); - clk_put(clk); - dev_info(dev, "runtime pm disabled, clock forced off\n"); - } - break; - } - - return 0; -} +#define DEFAULT_PWR_DOMAIN_PTR NULL #endif /* CONFIG_PM_RUNTIME */ -static struct notifier_block platform_bus_notifier = { - .notifier_call = platform_bus_notify +static struct pm_clk_notifier_block platform_bus_notifier = { + .pwr_domain = DEFAULT_PWR_DOMAIN_PTR, + .con_ids = { NULL, }, }; static int __init sh_pm_runtime_init(void) { - bus_register_notifier(&platform_bus_type, &platform_bus_notifier); + pm_runtime_clk_add_notifier(&platform_bus_type, &platform_bus_notifier); return 0; } core_initcall(sh_pm_runtime_init); diff --git a/arch/arm/mach-tegra/include/mach/barriers.h b/arch/arm/mach-tegra/include/mach/barriers.h index cc115174899b..425b42e91ef6 100644 --- a/arch/arm/mach-tegra/include/mach/barriers.h +++ b/arch/arm/mach-tegra/include/mach/barriers.h @@ -23,7 +23,7 @@ #include -#define rmb() dmb() +#define rmb() dsb() #define wmb() do { dsb(); outer_sync(); } while (0) #define mb() wmb() diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index af913741e6ec..6e1907fa94f0 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -178,16 +178,15 @@ static struct i2c_board_info __initdata mop500_i2c0_devices[] = { .irq = NOMADIK_GPIO_TO_IRQ(217), .platform_data = &mop500_tc35892_data, }, -}; - -/* I2C0 devices only available prior to HREFv60 */ -static struct i2c_board_info __initdata mop500_i2c0_old_devices[] = { + /* I2C0 devices only available prior to HREFv60 */ { I2C_BOARD_INFO("tps61052", 0x33), .platform_data = &mop500_tps61052_data, }, }; +#define NUM_PRE_V60_I2C0_DEVICES 1 + static struct i2c_board_info __initdata mop500_i2c2_devices[] = { { /* lp5521 LED driver, 1st device */ @@ -425,6 +424,8 @@ static void __init mop500_uart_init(void) static void __init mop500_init_machine(void) { + int i2c0_devs; + /* * The HREFv60 board removed a GPIO expander and routed * all these GPIO pins to the internal GPIO controller @@ -448,11 +449,11 @@ static void __init mop500_init_machine(void) platform_device_register(&ab8500_device); - i2c_register_board_info(0, mop500_i2c0_devices, - ARRAY_SIZE(mop500_i2c0_devices)); - if (!machine_is_hrefv60()) - i2c_register_board_info(0, mop500_i2c0_old_devices, - ARRAY_SIZE(mop500_i2c0_old_devices)); + i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices); + if (machine_is_hrefv60()) + i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES; + + i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs); i2c_register_board_info(2, mop500_i2c2_devices, ARRAY_SIZE(mop500_i2c2_devices)); } diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index e5f6fc428348..e591513bb53e 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -392,7 +392,7 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn) * Convert start_pfn/end_pfn to a struct page pointer. */ start_pg = pfn_to_page(start_pfn - 1) + 1; - end_pg = pfn_to_page(end_pfn); + end_pg = pfn_to_page(end_pfn - 1) + 1; /* * Convert to physical addresses, and @@ -426,6 +426,14 @@ static void __init free_unused_memmap(struct meminfo *mi) bank_start = bank_pfn_start(bank); +#ifdef CONFIG_SPARSEMEM + /* + * Take care not to free memmap entries that don't exist + * due to SPARSEMEM sections which aren't present. + */ + bank_start = min(bank_start, + ALIGN(prev_bank_end, PAGES_PER_SECTION)); +#endif /* * If we had a previous bank, and there is a space * between the current bank and the previous, free it. @@ -440,6 +448,12 @@ static void __init free_unused_memmap(struct meminfo *mi) */ prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES); } + +#ifdef CONFIG_SPARSEMEM + if (!IS_ALIGNED(prev_bank_end, PAGES_PER_SECTION)) + free_memmap(prev_bank_end, + ALIGN(prev_bank_end, PAGES_PER_SECTION)); +#endif } static void __init free_highpages(void) diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index ce233bcbf506..42af97664c9d 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -395,7 +395,7 @@ ENTRY(xscale_dma_a0_map_area) teq r2, #DMA_TO_DEVICE beq xscale_dma_clean_range b xscale_dma_flush_range -ENDPROC(xscsale_dma_a0_map_area) +ENDPROC(xscale_dma_a0_map_area) /* * dma_unmap_area(start, size, dir) diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c index 7a107246fd98..6cd6d7f686f6 100644 --- a/arch/arm/plat-mxc/gpio.c +++ b/arch/arm/plat-mxc/gpio.c @@ -295,6 +295,12 @@ static int mxc_gpio_direction_output(struct gpio_chip *chip, return 0; } +/* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt) { int i, j; @@ -311,6 +317,7 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt) __raw_writel(~0, port[i].base + GPIO_ISR); for (j = port[i].virtual_irq_start; j < port[i].virtual_irq_start + 32; j++) { + irq_set_lockdep_class(j, &gpio_lock_class); irq_set_chip_and_handler(j, &gpio_irq_chip, handle_level_irq); set_irq_flags(j, IRQF_VALID); diff --git a/arch/arm/plat-mxc/ssi-fiq.S b/arch/arm/plat-mxc/ssi-fiq.S index 4ddce565b353..8397a2dd19f2 100644 --- a/arch/arm/plat-mxc/ssi-fiq.S +++ b/arch/arm/plat-mxc/ssi-fiq.S @@ -124,6 +124,8 @@ imx_ssi_fiq_start: 1: @ return from FIQ subs pc, lr, #4 + + .align imx_ssi_fiq_base: .word 0x0 imx_ssi_fiq_rx_buffer: diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index d2adcdda23cf..bd9e32187eab 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -1372,9 +1372,7 @@ static const struct dev_pm_ops omap_mpuio_dev_pm_ops = { .resume_noirq = omap_mpuio_resume_noirq, }; -/* use platform_driver for this, now that there's no longer any - * point to sys_device (other than not disturbing old code). - */ +/* use platform_driver for this. */ static struct platform_driver omap_mpuio_driver = { .driver = { .name = "mpuio", @@ -1745,7 +1743,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) } #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) -static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) +static int omap_gpio_suspend(void) { int i; @@ -1795,12 +1793,12 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) return 0; } -static int omap_gpio_resume(struct sys_device *dev) +static void omap_gpio_resume(void) { int i; if (!cpu_class_is_omap2() && !cpu_is_omap16xx()) - return 0; + return; for (i = 0; i < gpio_bank_count; i++) { struct gpio_bank *bank = &gpio_bank[i]; @@ -1836,21 +1834,13 @@ static int omap_gpio_resume(struct sys_device *dev) __raw_writel(bank->saved_wakeup, wake_set); spin_unlock_irqrestore(&bank->lock, flags); } - - return 0; } -static struct sysdev_class omap_gpio_sysclass = { - .name = "gpio", +static struct syscore_ops omap_gpio_syscore_ops = { .suspend = omap_gpio_suspend, .resume = omap_gpio_resume, }; -static struct sys_device omap_gpio_device = { - .id = 0, - .cls = &omap_gpio_sysclass, -}; - #endif #ifdef CONFIG_ARCH_OMAP2PLUS @@ -2108,21 +2098,14 @@ postcore_initcall(omap_gpio_drv_reg); static int __init omap_gpio_sysinit(void) { - int ret = 0; - mpuio_init(); #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) - if (cpu_is_omap16xx() || cpu_class_is_omap2()) { - if (ret == 0) { - ret = sysdev_class_register(&omap_gpio_sysclass); - if (ret == 0) - ret = sysdev_register(&omap_gpio_device); - } - } + if (cpu_is_omap16xx() || cpu_class_is_omap2()) + register_syscore_ops(&omap_gpio_syscore_ops); #endif - return ret; + return 0; } arch_initcall(omap_gpio_sysinit); diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c index 8a51fd58f656..34fc31ee9081 100644 --- a/arch/arm/plat-omap/iommu.c +++ b/arch/arm/plat-omap/iommu.c @@ -793,6 +793,8 @@ static irqreturn_t iommu_fault_handler(int irq, void *data) clk_enable(obj->clk); errs = iommu_report_fault(obj, &da); clk_disable(obj->clk); + if (errs == 0) + return IRQ_HANDLED; /* Fault callback or TLB/PTE Dynamic loading */ if (obj->isr && !obj->isr(obj, da, errs, obj->isr_priv)) diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index 9bbda9acb73b..a37b8eb65b76 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -536,6 +536,28 @@ int omap_early_device_register(struct omap_device *od) return 0; } +static int _od_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + return omap_device_idle(pdev); +} + +static int _od_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + return omap_device_enable(pdev); +} + +static struct dev_power_domain omap_device_power_domain = { + .ops = { + .runtime_suspend = _od_runtime_suspend, + .runtime_resume = _od_runtime_resume, + USE_PLATFORM_PM_SLEEP_OPS + } +}; + /** * omap_device_register - register an omap_device with one omap_hwmod * @od: struct omap_device * to register @@ -549,6 +571,7 @@ int omap_device_register(struct omap_device *od) pr_debug("omap_device: %s: registering\n", od->pdev.name); od->pdev.dev.parent = &omap_device_parent; + od->pdev.dev.pwr_domain = &omap_device_power_domain; return platform_device_register(&od->pdev); } diff --git a/arch/arm/plat-pxa/gpio.c b/arch/arm/plat-pxa/gpio.c index dce088f45678..48ebb9479b61 100644 --- a/arch/arm/plat-pxa/gpio.c +++ b/arch/arm/plat-pxa/gpio.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -295,7 +295,7 @@ void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn) } #ifdef CONFIG_PM -static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state) +static int pxa_gpio_suspend(void) { struct pxa_gpio_chip *c; int gpio; @@ -312,7 +312,7 @@ static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int pxa_gpio_resume(struct sys_device *dev) +static void pxa_gpio_resume(void) { struct pxa_gpio_chip *c; int gpio; @@ -326,22 +326,13 @@ static int pxa_gpio_resume(struct sys_device *dev) __raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET); __raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET); } - return 0; } #else #define pxa_gpio_suspend NULL #define pxa_gpio_resume NULL #endif -struct sysdev_class pxa_gpio_sysclass = { - .name = "gpio", +struct syscore_ops pxa_gpio_syscore_ops = { .suspend = pxa_gpio_suspend, .resume = pxa_gpio_resume, }; - -static int __init pxa_gpio_init(void) -{ - return sysdev_class_register(&pxa_gpio_sysclass); -} - -core_initcall(pxa_gpio_init); diff --git a/arch/arm/plat-pxa/mfp.c b/arch/arm/plat-pxa/mfp.c index a9aa5ad3f4eb..be12eadcce20 100644 --- a/arch/arm/plat-pxa/mfp.c +++ b/arch/arm/plat-pxa/mfp.c @@ -17,7 +17,6 @@ #include #include #include -#include #include diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c index 27ea852e3370..c10d10c56e2e 100644 --- a/arch/arm/plat-s3c24xx/dma.c +++ b/arch/arm/plat-s3c24xx/dma.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -1195,19 +1195,12 @@ int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *d EXPORT_SYMBOL(s3c2410_dma_getposition); -static inline struct s3c2410_dma_chan *to_dma_chan(struct sys_device *dev) -{ - return container_of(dev, struct s3c2410_dma_chan, dev); -} - -/* system device class */ +/* system core operations */ #ifdef CONFIG_PM -static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state) +static void s3c2410_dma_suspend_chan(s3c2410_dma_chan *cp) { - struct s3c2410_dma_chan *cp = to_dma_chan(dev); - printk(KERN_DEBUG "suspending dma channel %d\n", cp->number); if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) { @@ -1222,13 +1215,21 @@ static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state) s3c2410_dma_dostop(cp); } +} + +static int s3c2410_dma_suspend(void) +{ + struct s3c2410_dma_chan *cp = s3c2410_chans; + int channel; + + for (channel = 0; channel < dma_channels; cp++, channel++) + s3c2410_dma_suspend_chan(cp); return 0; } -static int s3c2410_dma_resume(struct sys_device *dev) +static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp) { - struct s3c2410_dma_chan *cp = to_dma_chan(dev); unsigned int no = cp->number | DMACH_LOW_LEVEL; /* restore channel's hardware configuration */ @@ -1249,13 +1250,21 @@ static int s3c2410_dma_resume(struct sys_device *dev) return 0; } +static void s3c2410_dma_resume(void) +{ + struct s3c2410_dma_chan *cp = s3c2410_chans + dma_channels - 1; + int channel; + + for (channel = dma_channels - 1; channel >= 0; cp++, channel--) + s3c2410_dma_resume_chan(cp); +} + #else #define s3c2410_dma_suspend NULL #define s3c2410_dma_resume NULL #endif /* CONFIG_PM */ -struct sysdev_class dma_sysclass = { - .name = "s3c24xx-dma", +struct syscore_ops dma_syscore_ops = { .suspend = s3c2410_dma_suspend, .resume = s3c2410_dma_resume, }; @@ -1269,39 +1278,14 @@ static void s3c2410_dma_cache_ctor(void *p) /* initialisation code */ -static int __init s3c24xx_dma_sysclass_init(void) +static int __init s3c24xx_dma_syscore_init(void) { - int ret = sysdev_class_register(&dma_sysclass); - - if (ret != 0) - printk(KERN_ERR "dma sysclass registration failed\n"); - - return ret; -} - -core_initcall(s3c24xx_dma_sysclass_init); - -static int __init s3c24xx_dma_sysdev_register(void) -{ - struct s3c2410_dma_chan *cp = s3c2410_chans; - int channel, ret; - - for (channel = 0; channel < dma_channels; cp++, channel++) { - cp->dev.cls = &dma_sysclass; - cp->dev.id = channel; - ret = sysdev_register(&cp->dev); - - if (ret) { - printk(KERN_ERR "error registering dev for dma %d\n", - channel); - return ret; - } - } + register_syscore_ops(&dma_syscore_ops); return 0; } -late_initcall(s3c24xx_dma_sysdev_register); +late_initcall(s3c24xx_dma_syscore_init); int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq, unsigned int stride) diff --git a/arch/arm/plat-s3c24xx/irq-pm.c b/arch/arm/plat-s3c24xx/irq-pm.c index c3624d898630..0efb2e2848c8 100644 --- a/arch/arm/plat-s3c24xx/irq-pm.c +++ b/arch/arm/plat-s3c24xx/irq-pm.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -65,7 +64,7 @@ static unsigned long save_extint[3]; static unsigned long save_eintflt[4]; static unsigned long save_eintmask; -int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state) +int s3c24xx_irq_suspend(void) { unsigned int i; @@ -81,7 +80,7 @@ int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state) return 0; } -int s3c24xx_irq_resume(struct sys_device *dev) +void s3c24xx_irq_resume(void) { unsigned int i; @@ -93,6 +92,4 @@ int s3c24xx_irq_resume(struct sys_device *dev) s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); __raw_writel(save_eintmask, S3C24XX_EINTMASK); - - return 0; } diff --git a/arch/arm/plat-s5p/irq-pm.c b/arch/arm/plat-s5p/irq-pm.c index 5259ad458bc8..327acb3a4464 100644 --- a/arch/arm/plat-s5p/irq-pm.c +++ b/arch/arm/plat-s5p/irq-pm.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -77,17 +76,15 @@ static struct sleep_save eint_save[] = { SAVE_ITEM(S5P_EINT_MASK(3)), }; -int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state) +int s3c24xx_irq_suspend(void) { s3c_pm_do_save(eint_save, ARRAY_SIZE(eint_save)); return 0; } -int s3c24xx_irq_resume(struct sys_device *dev) +void s3c24xx_irq_resume(void) { s3c_pm_do_restore(eint_save, ARRAY_SIZE(eint_save)); - - return 0; } diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h index cedfff51c82b..3aedac0034ba 100644 --- a/arch/arm/plat-samsung/include/plat/cpu.h +++ b/arch/arm/plat-samsung/include/plat/cpu.h @@ -68,6 +68,12 @@ extern void s3c24xx_init_uartdevs(char *name, struct sys_timer; extern struct sys_timer s3c24xx_timer; +extern struct syscore_ops s3c2410_pm_syscore_ops; +extern struct syscore_ops s3c2412_pm_syscore_ops; +extern struct syscore_ops s3c2416_pm_syscore_ops; +extern struct syscore_ops s3c244x_pm_syscore_ops; +extern struct syscore_ops s3c64xx_irq_syscore_ops; + /* system device classes */ extern struct sysdev_class s3c2410_sysclass; diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h index 937cc2ace517..7fb6f6be8c81 100644 --- a/arch/arm/plat-samsung/include/plat/pm.h +++ b/arch/arm/plat-samsung/include/plat/pm.h @@ -103,14 +103,16 @@ extern void s3c_pm_do_restore_core(struct sleep_save *ptr, int count); #ifdef CONFIG_PM extern int s3c_irqext_wake(struct irq_data *data, unsigned int state); -extern int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state); -extern int s3c24xx_irq_resume(struct sys_device *dev); +extern int s3c24xx_irq_suspend(void); +extern void s3c24xx_irq_resume(void); #else #define s3c_irqext_wake NULL #define s3c24xx_irq_suspend NULL #define s3c24xx_irq_resume NULL #endif +extern struct syscore_ops s3c24xx_irq_syscore_ops; + /* PM debug functions */ #ifdef CONFIG_SAMSUNG_PM_DEBUG diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index f74695075e64..f25e7ec89416 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -398,9 +398,9 @@ static void vfp_enable(void *unused) } #ifdef CONFIG_PM -#include +#include -static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state) +static int vfp_pm_suspend(void) { struct thread_info *ti = current_thread_info(); u32 fpexc = fmrx(FPEXC); @@ -420,34 +420,25 @@ static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int vfp_pm_resume(struct sys_device *dev) +static void vfp_pm_resume(void) { /* ensure we have access to the vfp */ vfp_enable(NULL); /* and disable it to ensure the next usage restores the state */ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); - - return 0; } -static struct sysdev_class vfp_pm_sysclass = { - .name = "vfp", +static struct syscore_ops vfp_pm_syscore_ops = { .suspend = vfp_pm_suspend, .resume = vfp_pm_resume, }; -static struct sys_device vfp_pm_sysdev = { - .cls = &vfp_pm_sysclass, -}; - static void vfp_pm_init(void) { - sysdev_class_register(&vfp_pm_sysclass); - sysdev_register(&vfp_pm_sysdev); + register_syscore_ops(&vfp_pm_syscore_ops); } - #else static inline void vfp_pm_init(void) { } #endif /* CONFIG_PM */ diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c index 21ce35f33aa5..3e3646186c9f 100644 --- a/arch/avr32/mach-at32ap/intc.c +++ b/arch/avr32/mach-at32ap/intc.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include @@ -21,7 +21,6 @@ struct intc { void __iomem *regs; struct irq_chip chip; - struct sys_device sysdev; #ifdef CONFIG_PM unsigned long suspend_ipr; unsigned long saved_ipr[64]; @@ -146,9 +145,8 @@ void intc_set_suspend_handler(unsigned long offset) intc0.suspend_ipr = offset; } -static int intc_suspend(struct sys_device *sdev, pm_message_t state) +static int intc_suspend(void) { - struct intc *intc = container_of(sdev, struct intc, sysdev); int i; if (unlikely(!irqs_disabled())) { @@ -156,28 +154,25 @@ static int intc_suspend(struct sys_device *sdev, pm_message_t state) return -EINVAL; } - if (unlikely(!intc->suspend_ipr)) { + if (unlikely(!intc0.suspend_ipr)) { pr_err("intc_suspend: suspend_ipr not initialized\n"); return -EINVAL; } for (i = 0; i < 64; i++) { - intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i); - intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr); + intc0.saved_ipr[i] = intc_readl(&intc0, INTPR0 + 4 * i); + intc_writel(&intc0, INTPR0 + 4 * i, intc0.suspend_ipr); } return 0; } -static int intc_resume(struct sys_device *sdev) +static int intc_resume(void) { - struct intc *intc = container_of(sdev, struct intc, sysdev); int i; - WARN_ON(!irqs_disabled()); - for (i = 0; i < 64; i++) - intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]); + intc_writel(&intc0, INTPR0 + 4 * i, intc0.saved_ipr[i]); return 0; } @@ -186,27 +181,18 @@ static int intc_resume(struct sys_device *sdev) #define intc_resume NULL #endif -static struct sysdev_class intc_class = { - .name = "intc", +static struct syscore_ops intc_syscore_ops = { .suspend = intc_suspend, .resume = intc_resume, }; -static int __init intc_init_sysdev(void) +static int __init intc_init_syscore(void) { - int ret; + register_syscore_ops(&intc_syscore_ops); - ret = sysdev_class_register(&intc_class); - if (ret) - return ret; - - intc0.sysdev.id = 0; - intc0.sysdev.cls = &intc_class; - ret = sysdev_register(&intc0.sysdev); - - return ret; + return 0; } -device_initcall(intc_init_sysdev); +device_initcall(intc_init_syscore); unsigned long intc_get_pending(unsigned int group) { diff --git a/arch/blackfin/kernel/nmi.c b/arch/blackfin/kernel/nmi.c index 0b5f72f17fd0..401eb1d8e3b4 100644 --- a/arch/blackfin/kernel/nmi.c +++ b/arch/blackfin/kernel/nmi.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include @@ -196,43 +196,31 @@ void touch_nmi_watchdog(void) /* Suspend/resume support */ #ifdef CONFIG_PM -static int nmi_wdt_suspend(struct sys_device *dev, pm_message_t state) +static int nmi_wdt_suspend(void) { nmi_wdt_stop(); return 0; } -static int nmi_wdt_resume(struct sys_device *dev) +static void nmi_wdt_resume(void) { if (nmi_active) nmi_wdt_start(); - return 0; } -static struct sysdev_class nmi_sysclass = { - .name = DRV_NAME, +static struct syscore_ops nmi_syscore_ops = { .resume = nmi_wdt_resume, .suspend = nmi_wdt_suspend, }; -static struct sys_device device_nmi_wdt = { - .id = 0, - .cls = &nmi_sysclass, -}; - -static int __init init_nmi_wdt_sysfs(void) +static int __init init_nmi_wdt_syscore(void) { - int error; + if (nmi_active) + register_syscore_ops(&nmi_syscore_ops); - if (!nmi_active) - return 0; - - error = sysdev_class_register(&nmi_sysclass); - if (!error) - error = sysdev_register(&device_nmi_wdt); - return error; + return 0; } -late_initcall(init_nmi_wdt_sysfs); +late_initcall(init_nmi_wdt_syscore); #endif /* CONFIG_PM */ diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c index cdb4beb6bc8f..9e9b60d969dc 100644 --- a/arch/blackfin/kernel/time-ts.c +++ b/arch/blackfin/kernel/time-ts.c @@ -23,29 +23,6 @@ #include #include -/* Accelerators for sched_clock() - * convert from cycles(64bits) => nanoseconds (64bits) - * basic equation: - * ns = cycles / (freq / ns_per_sec) - * ns = cycles * (ns_per_sec / freq) - * ns = cycles * (10^9 / (cpu_khz * 10^3)) - * ns = cycles * (10^6 / cpu_khz) - * - * Then we use scaling math (suggested by george@mvista.com) to get: - * ns = cycles * (10^6 * SC / cpu_khz) / SC - * ns = cycles * cyc2ns_scale / SC - * - * And since SC is a constant power of two, we can convert the div - * into a shift. - * - * We can use khz divisor instead of mhz to keep a better precision, since - * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits. - * (mathieu.desnoyers@polymtl.ca) - * - * -johnstul@us.ibm.com "math is hard, lets go shopping!" - */ - -#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ #if defined(CONFIG_CYCLES_CLOCKSOURCE) @@ -63,7 +40,6 @@ static struct clocksource bfin_cs_cycles = { .rating = 400, .read = bfin_read_cycles, .mask = CLOCKSOURCE_MASK(64), - .shift = CYC2NS_SCALE_FACTOR, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -75,10 +51,7 @@ static inline unsigned long long bfin_cs_cycles_sched_clock(void) static int __init bfin_cs_cycles_init(void) { - bfin_cs_cycles.mult = \ - clocksource_hz2mult(get_cclk(), bfin_cs_cycles.shift); - - if (clocksource_register(&bfin_cs_cycles)) + if (clocksource_register_hz(&bfin_cs_cycles, get_cclk())) panic("failed to register clocksource"); return 0; @@ -111,7 +84,6 @@ static struct clocksource bfin_cs_gptimer0 = { .rating = 350, .read = bfin_read_gptimer0, .mask = CLOCKSOURCE_MASK(32), - .shift = CYC2NS_SCALE_FACTOR, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -125,10 +97,7 @@ static int __init bfin_cs_gptimer0_init(void) { setup_gptimer0(); - bfin_cs_gptimer0.mult = \ - clocksource_hz2mult(get_sclk(), bfin_cs_gptimer0.shift); - - if (clocksource_register(&bfin_cs_gptimer0)) + if (clocksource_register_hz(&bfin_cs_gptimer0, get_sclk())) panic("failed to register clocksource"); return 0; diff --git a/arch/blackfin/mach-common/dpmc.c b/arch/blackfin/mach-common/dpmc.c index 382099fd5561..5e4112e518a9 100644 --- a/arch/blackfin/mach-common/dpmc.c +++ b/arch/blackfin/mach-common/dpmc.c @@ -19,9 +19,6 @@ #define DRIVER_NAME "bfin dpmc" -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, DRIVER_NAME, msg) - struct bfin_dpmc_platform_data *pdata; /** diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index 8bce5ed031e4..1fbd94c44457 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -177,6 +177,9 @@ static irqreturn_t ipi_handler_int1(int irq, void *dev_instance) while (msg_queue->count) { msg = &msg_queue->ipi_message[msg_queue->head]; switch (msg->type) { + case BFIN_IPI_RESCHEDULE: + scheduler_ipi(); + break; case BFIN_IPI_CALL_FUNC: spin_unlock_irqrestore(&msg_queue->lock, flags); ipi_call_function(cpu, msg); diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c index 4c9e3e1ba5d1..66cc75657e2f 100644 --- a/arch/cris/arch-v32/kernel/smp.c +++ b/arch/cris/arch-v32/kernel/smp.c @@ -342,15 +342,18 @@ irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id) ipi = REG_RD(intr_vect, irq_regs[smp_processor_id()], rw_ipi); + if (ipi.vector & IPI_SCHEDULE) { + scheduler_ipi(); + } if (ipi.vector & IPI_CALL) { - func(info); + func(info); } if (ipi.vector & IPI_FLUSH_TLB) { - if (flush_mm == FLUSH_ALL) - __flush_tlb_all(); - else if (flush_vma == FLUSH_ALL) + if (flush_mm == FLUSH_ALL) + __flush_tlb_all(); + else if (flush_vma == FLUSH_ALL) __flush_tlb_mm(flush_mm); - else + else __flush_tlb_page(flush_vma, flush_addr); } diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 4ce8d1358fee..c04dd576f333 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -37,6 +37,7 @@ #include #include #include +#include #include /* ia64_get_itc() */ #include diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c index 22f61526a8e1..f09b174244d5 100644 --- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c +++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c @@ -23,8 +23,6 @@ #include #include -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg) - MODULE_AUTHOR("Venkatesh Pallipadi"); MODULE_DESCRIPTION("ACPI Processor P-States Driver"); MODULE_LICENSE("GPL"); @@ -47,12 +45,12 @@ processor_set_pstate ( { s64 retval; - dprintk("processor_set_pstate\n"); + pr_debug("processor_set_pstate\n"); retval = ia64_pal_set_pstate((u64)value); if (retval) { - dprintk("Failed to set freq to 0x%x, with error 0x%lx\n", + pr_debug("Failed to set freq to 0x%x, with error 0x%lx\n", value, retval); return -ENODEV; } @@ -67,14 +65,14 @@ processor_get_pstate ( u64 pstate_index = 0; s64 retval; - dprintk("processor_get_pstate\n"); + pr_debug("processor_get_pstate\n"); retval = ia64_pal_get_pstate(&pstate_index, PAL_GET_PSTATE_TYPE_INSTANT); *value = (u32) pstate_index; if (retval) - dprintk("Failed to get current freq with " + pr_debug("Failed to get current freq with " "error 0x%lx, idx 0x%x\n", retval, *value); return (int)retval; @@ -90,7 +88,7 @@ extract_clock ( { unsigned long i; - dprintk("extract_clock\n"); + pr_debug("extract_clock\n"); for (i = 0; i < data->acpi_data.state_count; i++) { if (value == data->acpi_data.states[i].status) @@ -110,7 +108,7 @@ processor_get_freq ( cpumask_t saved_mask; unsigned long clock_freq; - dprintk("processor_get_freq\n"); + pr_debug("processor_get_freq\n"); saved_mask = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -148,7 +146,7 @@ processor_set_freq ( cpumask_t saved_mask; int retval; - dprintk("processor_set_freq\n"); + pr_debug("processor_set_freq\n"); saved_mask = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -159,16 +157,16 @@ processor_set_freq ( if (state == data->acpi_data.state) { if (unlikely(data->resume)) { - dprintk("Called after resume, resetting to P%d\n", state); + pr_debug("Called after resume, resetting to P%d\n", state); data->resume = 0; } else { - dprintk("Already at target state (P%d)\n", state); + pr_debug("Already at target state (P%d)\n", state); retval = 0; goto migrate_end; } } - dprintk("Transitioning from P%d to P%d\n", + pr_debug("Transitioning from P%d to P%d\n", data->acpi_data.state, state); /* cpufreq frequency struct */ @@ -186,7 +184,7 @@ processor_set_freq ( value = (u32) data->acpi_data.states[state].control; - dprintk("Transitioning to state: 0x%08x\n", value); + pr_debug("Transitioning to state: 0x%08x\n", value); ret = processor_set_pstate(value); if (ret) { @@ -219,7 +217,7 @@ acpi_cpufreq_get ( { struct cpufreq_acpi_io *data = acpi_io_data[cpu]; - dprintk("acpi_cpufreq_get\n"); + pr_debug("acpi_cpufreq_get\n"); return processor_get_freq(data, cpu); } @@ -235,7 +233,7 @@ acpi_cpufreq_target ( unsigned int next_state = 0; unsigned int result = 0; - dprintk("acpi_cpufreq_setpolicy\n"); + pr_debug("acpi_cpufreq_setpolicy\n"); result = cpufreq_frequency_table_target(policy, data->freq_table, target_freq, relation, &next_state); @@ -255,7 +253,7 @@ acpi_cpufreq_verify ( unsigned int result = 0; struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; - dprintk("acpi_cpufreq_verify\n"); + pr_debug("acpi_cpufreq_verify\n"); result = cpufreq_frequency_table_verify(policy, data->freq_table); @@ -273,7 +271,7 @@ acpi_cpufreq_cpu_init ( struct cpufreq_acpi_io *data; unsigned int result = 0; - dprintk("acpi_cpufreq_cpu_init\n"); + pr_debug("acpi_cpufreq_cpu_init\n"); data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); if (!data) @@ -288,7 +286,7 @@ acpi_cpufreq_cpu_init ( /* capability check */ if (data->acpi_data.state_count <= 1) { - dprintk("No P-States\n"); + pr_debug("No P-States\n"); result = -ENODEV; goto err_unreg; } @@ -297,7 +295,7 @@ acpi_cpufreq_cpu_init ( ACPI_ADR_SPACE_FIXED_HARDWARE) || (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { - dprintk("Unsupported address space [%d, %d]\n", + pr_debug("Unsupported address space [%d, %d]\n", (u32) (data->acpi_data.control_register.space_id), (u32) (data->acpi_data.status_register.space_id)); result = -ENODEV; @@ -348,7 +346,7 @@ acpi_cpufreq_cpu_init ( "activated.\n", cpu); for (i = 0; i < data->acpi_data.state_count; i++) - dprintk(" %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n", + pr_debug(" %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n", (i == data->acpi_data.state?'*':' '), i, (u32) data->acpi_data.states[i].core_frequency, (u32) data->acpi_data.states[i].power, @@ -383,7 +381,7 @@ acpi_cpufreq_cpu_exit ( { struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; - dprintk("acpi_cpufreq_cpu_exit\n"); + pr_debug("acpi_cpufreq_cpu_exit\n"); if (data) { cpufreq_frequency_table_put_attr(policy->cpu); @@ -418,7 +416,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = { static int __init acpi_cpufreq_init (void) { - dprintk("acpi_cpufreq_init\n"); + pr_debug("acpi_cpufreq_init\n"); return cpufreq_register_driver(&acpi_cpufreq_driver); } @@ -427,7 +425,7 @@ acpi_cpufreq_init (void) static void __exit acpi_cpufreq_exit (void) { - dprintk("acpi_cpufreq_exit\n"); + pr_debug("acpi_cpufreq_exit\n"); cpufreq_unregister_driver(&acpi_cpufreq_driver); return; diff --git a/arch/ia64/kernel/cyclone.c b/arch/ia64/kernel/cyclone.c index 1b811c61bdc6..f64097b5118a 100644 --- a/arch/ia64/kernel/cyclone.c +++ b/arch/ia64/kernel/cyclone.c @@ -31,8 +31,6 @@ static struct clocksource clocksource_cyclone = { .rating = 300, .read = read_cyclone, .mask = (1LL << 40) - 1, - .mult = 0, /*to be calculated*/ - .shift = 16, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -118,9 +116,7 @@ int __init init_cyclone_clock(void) /* initialize last tick */ cyclone_mc = cyclone_timer; clocksource_cyclone.fsys_mmio = cyclone_timer; - clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ, - clocksource_cyclone.shift); - clocksource_register(&clocksource_cyclone); + clocksource_register_hz(&clocksource_cyclone, CYCLONE_TIMER_FREQ); return 0; } diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 5b704740f160..782c3a357f24 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -496,6 +497,7 @@ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs) smp_local_flush_tlb(); kstat_incr_irqs_this_cpu(irq, desc); } else if (unlikely(IS_RESCHEDULE(vector))) { + scheduler_ipi(); kstat_incr_irqs_this_cpu(irq, desc); } else { ia64_setreg(_IA64_REG_CR_TPR, vector); diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 156ad803d5b7..04440cc09b40 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -73,8 +73,6 @@ static struct clocksource clocksource_itc = { .rating = 350, .read = itc_get_cycles, .mask = CLOCKSOURCE_MASK(64), - .mult = 0, /*to be calculated*/ - .shift = 16, .flags = CLOCK_SOURCE_IS_CONTINUOUS, #ifdef CONFIG_PARAVIRT .resume = paravirt_clocksource_resume, @@ -365,11 +363,8 @@ ia64_init_itm (void) ia64_cpu_local_tick(); if (!itc_clocksource) { - /* Sort out mult/shift values: */ - clocksource_itc.mult = - clocksource_hz2mult(local_cpu_data->itc_freq, - clocksource_itc.shift); - clocksource_register(&clocksource_itc); + clocksource_register_hz(&clocksource_itc, + local_cpu_data->itc_freq); itc_clocksource = &clocksource_itc; } } diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 787de4a77d82..53c0ba004e9e 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -209,6 +209,7 @@ SECTIONS { data : { } :data .data : AT(ADDR(.data) - LOAD_OFFSET) { + _sdata = .; INIT_TASK_DATA(PAGE_SIZE) CACHELINE_ALIGNED_DATA(SMP_CACHE_BYTES) READ_MOSTLY_DATA(SMP_CACHE_BYTES) diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index 0799fea4c588..20b359376128 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include diff --git a/arch/ia64/oprofile/backtrace.c b/arch/ia64/oprofile/backtrace.c index 5cdd7e4a597c..f7b798993cea 100644 --- a/arch/ia64/oprofile/backtrace.c +++ b/arch/ia64/oprofile/backtrace.c @@ -29,7 +29,7 @@ typedef struct unsigned int depth; struct pt_regs *regs; struct unw_frame_info frame; - u64 *prev_pfs_loc; /* state for WAR for old spinlock ool code */ + unsigned long *prev_pfs_loc; /* state for WAR for old spinlock ool code */ } ia64_backtrace_t; /* Returns non-zero if the PC is in the Interrupt Vector Table */ diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c index 21d6f09e3447..c34efda122e1 100644 --- a/arch/ia64/sn/kernel/sn2/timer.c +++ b/arch/ia64/sn/kernel/sn2/timer.c @@ -33,8 +33,6 @@ static struct clocksource clocksource_sn2 = { .rating = 450, .read = read_sn2, .mask = (1LL << 55) - 1, - .mult = 0, - .shift = 10, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -57,9 +55,7 @@ ia64_sn_udelay (unsigned long usecs) void __init sn_timer_init(void) { clocksource_sn2.fsys_mmio = RTC_COUNTER_ADDR; - clocksource_sn2.mult = clocksource_hz2mult(sn_rtc_cycles_per_second, - clocksource_sn2.shift); - clocksource_register(&clocksource_sn2); + clocksource_register_hz(&clocksource_sn2, sn_rtc_cycles_per_second); ia64_udelay = &ia64_sn_udelay; } diff --git a/arch/ia64/xen/irq_xen.c b/arch/ia64/xen/irq_xen.c index 108bb858acf2..b279e142c633 100644 --- a/arch/ia64/xen/irq_xen.c +++ b/arch/ia64/xen/irq_xen.c @@ -92,6 +92,8 @@ static unsigned short saved_irq_cnt; static int xen_slab_ready; #ifdef CONFIG_SMP +#include + /* Dummy stub. Though we may check XEN_RESCHEDULE_VECTOR before __do_IRQ, * it ends up to issue several memory accesses upon percpu data and * thus adds unnecessary traffic to other paths. @@ -99,7 +101,13 @@ static int xen_slab_ready; static irqreturn_t xen_dummy_handler(int irq, void *dev_id) { + return IRQ_HANDLED; +} +static irqreturn_t +xen_resched_handler(int irq, void *dev_id) +{ + scheduler_ipi(); return IRQ_HANDLED; } @@ -110,7 +118,7 @@ static struct irqaction xen_ipi_irqaction = { }; static struct irqaction xen_resched_irqaction = { - .handler = xen_dummy_handler, + .handler = xen_resched_handler, .flags = IRQF_DISABLED, .name = "resched" }; diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c index 31cef20b2996..fc10b39893d4 100644 --- a/arch/m32r/kernel/smp.c +++ b/arch/m32r/kernel/smp.c @@ -122,8 +122,6 @@ void smp_send_reschedule(int cpu_id) * * Description: This routine executes on CPU which received * 'RESCHEDULE_IPI'. - * Rescheduling is processed at the exit of interrupt - * operation. * * Born on Date: 2002.02.05 * @@ -138,7 +136,7 @@ void smp_send_reschedule(int cpu_id) *==========================================================================*/ void smp_reschedule_interrupt(void) { - /* nothing to do */ + scheduler_ipi(); } /*==========================================================================* diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S index c194d64cdbb9..cf95aec77460 100644 --- a/arch/m32r/kernel/vmlinux.lds.S +++ b/arch/m32r/kernel/vmlinux.lds.S @@ -44,6 +44,7 @@ SECTIONS EXCEPTION_TABLE(16) NOTES + _sdata = .; /* Start of data section */ RODATA RW_DATA_SECTION(32, PAGE_SIZE, THREAD_SIZE) _edata = .; /* End of data section */ diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index b995513d527f..95022b04b62d 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -36,13 +36,10 @@ /* Hook for MIDI serial driver */ void (*atari_MIDI_interrupt_hook) (void); -/* Hook for mouse driver */ -void (*atari_mouse_interrupt_hook) (char *); /* Hook for keyboard inputdev driver */ void (*atari_input_keyboard_interrupt_hook) (unsigned char, char); /* Hook for mouse inputdev driver */ void (*atari_input_mouse_interrupt_hook) (char *); -EXPORT_SYMBOL(atari_mouse_interrupt_hook); EXPORT_SYMBOL(atari_input_keyboard_interrupt_hook); EXPORT_SYMBOL(atari_input_mouse_interrupt_hook); @@ -263,8 +260,8 @@ static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy) kb_state.buf[kb_state.len++] = scancode; if (kb_state.len == 3) { kb_state.state = KEYBOARD; - if (atari_mouse_interrupt_hook) - atari_mouse_interrupt_hook(kb_state.buf); + if (atari_input_mouse_interrupt_hook) + atari_input_mouse_interrupt_hook(kb_state.buf); } break; @@ -575,7 +572,7 @@ int atari_keyb_init(void) kb_state.len = 0; error = request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, - IRQ_TYPE_SLOW, "keyboard/mouse/MIDI", + IRQ_TYPE_SLOW, "keyboard,mouse,MIDI", atari_keyboard_interrupt); if (error) return error; diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index 604329fafbb8..ddbf43ca8858 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -180,7 +180,7 @@ void __init stdma_init(void) { stdma_isr = NULL; if (request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW | IRQF_SHARED, - "ST-DMA: floppy/ACSI/IDE/Falcon-SCSI", stdma_int)) + "ST-DMA floppy,ACSI,IDE,Falcon-SCSI", stdma_int)) pr_err("Couldn't register ST-DMA interrupt\n"); } diff --git a/arch/m68k/include/asm/atarikb.h b/arch/m68k/include/asm/atarikb.h index 546e7da5804f..68f3622bf591 100644 --- a/arch/m68k/include/asm/atarikb.h +++ b/arch/m68k/include/asm/atarikb.h @@ -34,8 +34,6 @@ void ikbd_joystick_disable(void); /* Hook for MIDI serial driver */ extern void (*atari_MIDI_interrupt_hook) (void); -/* Hook for mouse driver */ -extern void (*atari_mouse_interrupt_hook) (char *); /* Hook for keyboard inputdev driver */ extern void (*atari_input_keyboard_interrupt_hook) (unsigned char, char); /* Hook for mouse inputdev driver */ diff --git a/arch/m68k/include/asm/bitops_mm.h b/arch/m68k/include/asm/bitops_mm.h index 9d69f6e62365..e9020f88a748 100644 --- a/arch/m68k/include/asm/bitops_mm.h +++ b/arch/m68k/include/asm/bitops_mm.h @@ -181,14 +181,15 @@ static inline int find_first_zero_bit(const unsigned long *vaddr, { const unsigned long *p = vaddr; int res = 32; + unsigned int words; unsigned long num; if (!size) return 0; - size = (size + 31) >> 5; + words = (size + 31) >> 5; while (!(num = ~*p++)) { - if (!--size) + if (!--words) goto out; } @@ -196,7 +197,8 @@ static inline int find_first_zero_bit(const unsigned long *vaddr, : "=d" (res) : "d" (num & -num)); res ^= 31; out: - return ((long)p - (long)vaddr - 4) * 8 + res; + res += ((long)p - (long)vaddr - 4) * 8; + return res < size ? res : size; } static inline int find_next_zero_bit(const unsigned long *vaddr, int size, @@ -215,27 +217,32 @@ static inline int find_next_zero_bit(const unsigned long *vaddr, int size, /* Look for zero in first longword */ __asm__ __volatile__ ("bfffo %1{#0,#0},%0" : "=d" (res) : "d" (num & -num)); - if (res < 32) - return offset + (res ^ 31); + if (res < 32) { + offset += res ^ 31; + return offset < size ? offset : size; + } offset += 32; + + if (offset >= size) + return size; } /* No zero yet, search remaining full bytes for a zero */ - res = find_first_zero_bit(p, size - ((long)p - (long)vaddr) * 8); - return offset + res; + return offset + find_first_zero_bit(p, size - offset); } static inline int find_first_bit(const unsigned long *vaddr, unsigned size) { const unsigned long *p = vaddr; int res = 32; + unsigned int words; unsigned long num; if (!size) return 0; - size = (size + 31) >> 5; + words = (size + 31) >> 5; while (!(num = *p++)) { - if (!--size) + if (!--words) goto out; } @@ -243,7 +250,8 @@ static inline int find_first_bit(const unsigned long *vaddr, unsigned size) : "=d" (res) : "d" (num & -num)); res ^= 31; out: - return ((long)p - (long)vaddr - 4) * 8 + res; + res += ((long)p - (long)vaddr - 4) * 8; + return res < size ? res : size; } static inline int find_next_bit(const unsigned long *vaddr, int size, @@ -262,13 +270,17 @@ static inline int find_next_bit(const unsigned long *vaddr, int size, /* Look for one in first longword */ __asm__ __volatile__ ("bfffo %1{#0,#0},%0" : "=d" (res) : "d" (num & -num)); - if (res < 32) - return offset + (res ^ 31); + if (res < 32) { + offset += res ^ 31; + return offset < size ? offset : size; + } offset += 32; + + if (offset >= size) + return size; } /* No one yet, search remaining full bytes for a one */ - res = find_first_bit(p, size - ((long)p - (long)vaddr) * 8); - return offset + res; + return offset + find_first_bit(p, size - offset); } /* @@ -366,23 +378,25 @@ static inline int test_bit_le(int nr, const void *vaddr) static inline int find_first_zero_bit_le(const void *vaddr, unsigned size) { const unsigned long *p = vaddr, *addr = vaddr; - int res; + int res = 0; + unsigned int words; if (!size) return 0; - size = (size >> 5) + ((size & 31) > 0); - while (*p++ == ~0UL) - { - if (--size == 0) - return (p - addr) << 5; + words = (size >> 5) + ((size & 31) > 0); + while (*p++ == ~0UL) { + if (--words == 0) + goto out; } --p; for (res = 0; res < 32; res++) if (!test_bit_le(res, p)) break; - return (p - addr) * 32 + res; +out: + res += (p - addr) * 32; + return res < size ? res : size; } static inline unsigned long find_next_zero_bit_le(const void *addr, @@ -400,10 +414,15 @@ static inline unsigned long find_next_zero_bit_le(const void *addr, offset -= bit; /* Look for zero in first longword */ for (res = bit; res < 32; res++) - if (!test_bit_le(res, p)) - return offset + res; + if (!test_bit_le(res, p)) { + offset += res; + return offset < size ? offset : size; + } p++; offset += 32; + + if (offset >= size) + return size; } /* No zero yet, search remaining full bytes for a zero */ return offset + find_first_zero_bit_le(p, size - offset); @@ -412,22 +431,25 @@ static inline unsigned long find_next_zero_bit_le(const void *addr, static inline int find_first_bit_le(const void *vaddr, unsigned size) { const unsigned long *p = vaddr, *addr = vaddr; - int res; + int res = 0; + unsigned int words; if (!size) return 0; - size = (size >> 5) + ((size & 31) > 0); + words = (size >> 5) + ((size & 31) > 0); while (*p++ == 0UL) { - if (--size == 0) - return (p - addr) << 5; + if (--words == 0) + goto out; } --p; for (res = 0; res < 32; res++) if (test_bit_le(res, p)) break; - return (p - addr) * 32 + res; +out: + res += (p - addr) * 32; + return res < size ? res : size; } static inline unsigned long find_next_bit_le(const void *addr, @@ -445,10 +467,15 @@ static inline unsigned long find_next_bit_le(const void *addr, offset -= bit; /* Look for one in first longword */ for (res = bit; res < 32; res++) - if (test_bit_le(res, p)) - return offset + res; + if (test_bit_le(res, p)) { + offset += res; + return offset < size ? offset : size; + } p++; offset += 32; + + if (offset >= size) + return size; } /* No set bit yet, search remaining full bytes for a set bit */ return offset + find_first_bit_le(p, size - offset); diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index 29e17907d9f2..f3b649de2a1b 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h @@ -22,7 +22,7 @@ #define __NR_mknod 14 #define __NR_chmod 15 #define __NR_chown 16 -#define __NR_break 17 +/*#define __NR_break 17*/ #define __NR_oldstat 18 #define __NR_lseek 19 #define __NR_getpid 20 @@ -36,11 +36,11 @@ #define __NR_oldfstat 28 #define __NR_pause 29 #define __NR_utime 30 -#define __NR_stty 31 -#define __NR_gtty 32 +/*#define __NR_stty 31*/ +/*#define __NR_gtty 32*/ #define __NR_access 33 #define __NR_nice 34 -#define __NR_ftime 35 +/*#define __NR_ftime 35*/ #define __NR_sync 36 #define __NR_kill 37 #define __NR_rename 38 @@ -49,7 +49,7 @@ #define __NR_dup 41 #define __NR_pipe 42 #define __NR_times 43 -#define __NR_prof 44 +/*#define __NR_prof 44*/ #define __NR_brk 45 #define __NR_setgid 46 #define __NR_getgid 47 @@ -58,13 +58,13 @@ #define __NR_getegid 50 #define __NR_acct 51 #define __NR_umount2 52 -#define __NR_lock 53 +/*#define __NR_lock 53*/ #define __NR_ioctl 54 #define __NR_fcntl 55 -#define __NR_mpx 56 +/*#define __NR_mpx 56*/ #define __NR_setpgid 57 -#define __NR_ulimit 58 -#define __NR_oldolduname 59 +/*#define __NR_ulimit 58*/ +/*#define __NR_oldolduname 59*/ #define __NR_umask 60 #define __NR_chroot 61 #define __NR_ustat 62 @@ -103,10 +103,10 @@ #define __NR_fchown 95 #define __NR_getpriority 96 #define __NR_setpriority 97 -#define __NR_profil 98 +/*#define __NR_profil 98*/ #define __NR_statfs 99 #define __NR_fstatfs 100 -#define __NR_ioperm 101 +/*#define __NR_ioperm 101*/ #define __NR_socketcall 102 #define __NR_syslog 103 #define __NR_setitimer 104 @@ -114,11 +114,11 @@ #define __NR_stat 106 #define __NR_lstat 107 #define __NR_fstat 108 -#define __NR_olduname 109 -#define __NR_iopl /* 110 */ not supported +/*#define __NR_olduname 109*/ +/*#define __NR_iopl 110*/ /* not supported */ #define __NR_vhangup 111 -#define __NR_idle /* 112 */ Obsolete -#define __NR_vm86 /* 113 */ not supported +/*#define __NR_idle 112*/ /* Obsolete */ +/*#define __NR_vm86 113*/ /* not supported */ #define __NR_wait4 114 #define __NR_swapoff 115 #define __NR_sysinfo 116 @@ -132,17 +132,17 @@ #define __NR_adjtimex 124 #define __NR_mprotect 125 #define __NR_sigprocmask 126 -#define __NR_create_module 127 +/*#define __NR_create_module 127*/ #define __NR_init_module 128 #define __NR_delete_module 129 -#define __NR_get_kernel_syms 130 +/*#define __NR_get_kernel_syms 130*/ #define __NR_quotactl 131 #define __NR_getpgid 132 #define __NR_fchdir 133 #define __NR_bdflush 134 #define __NR_sysfs 135 #define __NR_personality 136 -#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ +/*#define __NR_afs_syscall 137*/ /* Syscall for Andrew File System */ #define __NR_setfsuid 138 #define __NR_setfsgid 139 #define __NR__llseek 140 @@ -172,7 +172,7 @@ #define __NR_setresuid 164 #define __NR_getresuid 165 #define __NR_getpagesize 166 -#define __NR_query_module 167 +/*#define __NR_query_module 167*/ #define __NR_poll 168 #define __NR_nfsservctl 169 #define __NR_setresgid 170 @@ -193,8 +193,8 @@ #define __NR_capset 185 #define __NR_sigaltstack 186 #define __NR_sendfile 187 -#define __NR_getpmsg 188 /* some people actually want streams */ -#define __NR_putpmsg 189 /* some people actually want streams */ +/*#define __NR_getpmsg 188*/ /* some people actually want streams */ +/*#define __NR_putpmsg 189*/ /* some people actually want streams */ #define __NR_vfork 190 #define __NR_ugetrlimit 191 #define __NR_mmap2 192 @@ -223,6 +223,8 @@ #define __NR_setfsuid32 215 #define __NR_setfsgid32 216 #define __NR_pivot_root 217 +/* 218*/ +/* 219*/ #define __NR_getdents64 220 #define __NR_gettid 221 #define __NR_tkill 222 @@ -281,7 +283,7 @@ #define __NR_mq_notify 275 #define __NR_mq_getsetattr 276 #define __NR_waitid 277 -#define __NR_vserver 278 +/*#define __NR_vserver 278*/ #define __NR_add_key 279 #define __NR_request_key 280 #define __NR_keyctl 281 diff --git a/arch/m68k/kernel/Makefile_mm b/arch/m68k/kernel/Makefile_mm index 55d5d6b680a2..aced67804579 100644 --- a/arch/m68k/kernel/Makefile_mm +++ b/arch/m68k/kernel/Makefile_mm @@ -10,7 +10,7 @@ endif extra-y += vmlinux.lds obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \ - sys_m68k.o time.o setup.o m68k_ksyms.o devres.o + sys_m68k.o time.o setup.o m68k_ksyms.o devres.o syscalltable.o devres-y = ../../../kernel/irq/devres.o diff --git a/arch/m68k/kernel/entry_mm.S b/arch/m68k/kernel/entry_mm.S index 1359ee659574..bd0ec05263b2 100644 --- a/arch/m68k/kernel/entry_mm.S +++ b/arch/m68k/kernel/entry_mm.S @@ -407,351 +407,3 @@ resume: rts -.data -ALIGN -sys_call_table: - .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ - .long sys_exit - .long sys_fork - .long sys_read - .long sys_write - .long sys_open /* 5 */ - .long sys_close - .long sys_waitpid - .long sys_creat - .long sys_link - .long sys_unlink /* 10 */ - .long sys_execve - .long sys_chdir - .long sys_time - .long sys_mknod - .long sys_chmod /* 15 */ - .long sys_chown16 - .long sys_ni_syscall /* old break syscall holder */ - .long sys_stat - .long sys_lseek - .long sys_getpid /* 20 */ - .long sys_mount - .long sys_oldumount - .long sys_setuid16 - .long sys_getuid16 - .long sys_stime /* 25 */ - .long sys_ptrace - .long sys_alarm - .long sys_fstat - .long sys_pause - .long sys_utime /* 30 */ - .long sys_ni_syscall /* old stty syscall holder */ - .long sys_ni_syscall /* old gtty syscall holder */ - .long sys_access - .long sys_nice - .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ - .long sys_sync - .long sys_kill - .long sys_rename - .long sys_mkdir - .long sys_rmdir /* 40 */ - .long sys_dup - .long sys_pipe - .long sys_times - .long sys_ni_syscall /* old prof syscall holder */ - .long sys_brk /* 45 */ - .long sys_setgid16 - .long sys_getgid16 - .long sys_signal - .long sys_geteuid16 - .long sys_getegid16 /* 50 */ - .long sys_acct - .long sys_umount /* recycled never used phys() */ - .long sys_ni_syscall /* old lock syscall holder */ - .long sys_ioctl - .long sys_fcntl /* 55 */ - .long sys_ni_syscall /* old mpx syscall holder */ - .long sys_setpgid - .long sys_ni_syscall /* old ulimit syscall holder */ - .long sys_ni_syscall - .long sys_umask /* 60 */ - .long sys_chroot - .long sys_ustat - .long sys_dup2 - .long sys_getppid - .long sys_getpgrp /* 65 */ - .long sys_setsid - .long sys_sigaction - .long sys_sgetmask - .long sys_ssetmask - .long sys_setreuid16 /* 70 */ - .long sys_setregid16 - .long sys_sigsuspend - .long sys_sigpending - .long sys_sethostname - .long sys_setrlimit /* 75 */ - .long sys_old_getrlimit - .long sys_getrusage - .long sys_gettimeofday - .long sys_settimeofday - .long sys_getgroups16 /* 80 */ - .long sys_setgroups16 - .long sys_old_select - .long sys_symlink - .long sys_lstat - .long sys_readlink /* 85 */ - .long sys_uselib - .long sys_swapon - .long sys_reboot - .long sys_old_readdir - .long sys_old_mmap /* 90 */ - .long sys_munmap - .long sys_truncate - .long sys_ftruncate - .long sys_fchmod - .long sys_fchown16 /* 95 */ - .long sys_getpriority - .long sys_setpriority - .long sys_ni_syscall /* old profil syscall holder */ - .long sys_statfs - .long sys_fstatfs /* 100 */ - .long sys_ni_syscall /* ioperm for i386 */ - .long sys_socketcall - .long sys_syslog - .long sys_setitimer - .long sys_getitimer /* 105 */ - .long sys_newstat - .long sys_newlstat - .long sys_newfstat - .long sys_ni_syscall - .long sys_ni_syscall /* 110 */ /* iopl for i386 */ - .long sys_vhangup - .long sys_ni_syscall /* obsolete idle() syscall */ - .long sys_ni_syscall /* vm86old for i386 */ - .long sys_wait4 - .long sys_swapoff /* 115 */ - .long sys_sysinfo - .long sys_ipc - .long sys_fsync - .long sys_sigreturn - .long sys_clone /* 120 */ - .long sys_setdomainname - .long sys_newuname - .long sys_cacheflush /* modify_ldt for i386 */ - .long sys_adjtimex - .long sys_mprotect /* 125 */ - .long sys_sigprocmask - .long sys_ni_syscall /* old "create_module" */ - .long sys_init_module - .long sys_delete_module - .long sys_ni_syscall /* 130 - old "get_kernel_syms" */ - .long sys_quotactl - .long sys_getpgid - .long sys_fchdir - .long sys_bdflush - .long sys_sysfs /* 135 */ - .long sys_personality - .long sys_ni_syscall /* for afs_syscall */ - .long sys_setfsuid16 - .long sys_setfsgid16 - .long sys_llseek /* 140 */ - .long sys_getdents - .long sys_select - .long sys_flock - .long sys_msync - .long sys_readv /* 145 */ - .long sys_writev - .long sys_getsid - .long sys_fdatasync - .long sys_sysctl - .long sys_mlock /* 150 */ - .long sys_munlock - .long sys_mlockall - .long sys_munlockall - .long sys_sched_setparam - .long sys_sched_getparam /* 155 */ - .long sys_sched_setscheduler - .long sys_sched_getscheduler - .long sys_sched_yield - .long sys_sched_get_priority_max - .long sys_sched_get_priority_min /* 160 */ - .long sys_sched_rr_get_interval - .long sys_nanosleep - .long sys_mremap - .long sys_setresuid16 - .long sys_getresuid16 /* 165 */ - .long sys_getpagesize - .long sys_ni_syscall /* old sys_query_module */ - .long sys_poll - .long sys_nfsservctl - .long sys_setresgid16 /* 170 */ - .long sys_getresgid16 - .long sys_prctl - .long sys_rt_sigreturn - .long sys_rt_sigaction - .long sys_rt_sigprocmask /* 175 */ - .long sys_rt_sigpending - .long sys_rt_sigtimedwait - .long sys_rt_sigqueueinfo - .long sys_rt_sigsuspend - .long sys_pread64 /* 180 */ - .long sys_pwrite64 - .long sys_lchown16; - .long sys_getcwd - .long sys_capget - .long sys_capset /* 185 */ - .long sys_sigaltstack - .long sys_sendfile - .long sys_ni_syscall /* streams1 */ - .long sys_ni_syscall /* streams2 */ - .long sys_vfork /* 190 */ - .long sys_getrlimit - .long sys_mmap2 - .long sys_truncate64 - .long sys_ftruncate64 - .long sys_stat64 /* 195 */ - .long sys_lstat64 - .long sys_fstat64 - .long sys_chown - .long sys_getuid - .long sys_getgid /* 200 */ - .long sys_geteuid - .long sys_getegid - .long sys_setreuid - .long sys_setregid - .long sys_getgroups /* 205 */ - .long sys_setgroups - .long sys_fchown - .long sys_setresuid - .long sys_getresuid - .long sys_setresgid /* 210 */ - .long sys_getresgid - .long sys_lchown - .long sys_setuid - .long sys_setgid - .long sys_setfsuid /* 215 */ - .long sys_setfsgid - .long sys_pivot_root - .long sys_ni_syscall - .long sys_ni_syscall - .long sys_getdents64 /* 220 */ - .long sys_gettid - .long sys_tkill - .long sys_setxattr - .long sys_lsetxattr - .long sys_fsetxattr /* 225 */ - .long sys_getxattr - .long sys_lgetxattr - .long sys_fgetxattr - .long sys_listxattr - .long sys_llistxattr /* 230 */ - .long sys_flistxattr - .long sys_removexattr - .long sys_lremovexattr - .long sys_fremovexattr - .long sys_futex /* 235 */ - .long sys_sendfile64 - .long sys_mincore - .long sys_madvise - .long sys_fcntl64 - .long sys_readahead /* 240 */ - .long sys_io_setup - .long sys_io_destroy - .long sys_io_getevents - .long sys_io_submit - .long sys_io_cancel /* 245 */ - .long sys_fadvise64 - .long sys_exit_group - .long sys_lookup_dcookie - .long sys_epoll_create - .long sys_epoll_ctl /* 250 */ - .long sys_epoll_wait - .long sys_remap_file_pages - .long sys_set_tid_address - .long sys_timer_create - .long sys_timer_settime /* 255 */ - .long sys_timer_gettime - .long sys_timer_getoverrun - .long sys_timer_delete - .long sys_clock_settime - .long sys_clock_gettime /* 260 */ - .long sys_clock_getres - .long sys_clock_nanosleep - .long sys_statfs64 - .long sys_fstatfs64 - .long sys_tgkill /* 265 */ - .long sys_utimes - .long sys_fadvise64_64 - .long sys_mbind - .long sys_get_mempolicy - .long sys_set_mempolicy /* 270 */ - .long sys_mq_open - .long sys_mq_unlink - .long sys_mq_timedsend - .long sys_mq_timedreceive - .long sys_mq_notify /* 275 */ - .long sys_mq_getsetattr - .long sys_waitid - .long sys_ni_syscall /* for sys_vserver */ - .long sys_add_key - .long sys_request_key /* 280 */ - .long sys_keyctl - .long sys_ioprio_set - .long sys_ioprio_get - .long sys_inotify_init - .long sys_inotify_add_watch /* 285 */ - .long sys_inotify_rm_watch - .long sys_migrate_pages - .long sys_openat - .long sys_mkdirat - .long sys_mknodat /* 290 */ - .long sys_fchownat - .long sys_futimesat - .long sys_fstatat64 - .long sys_unlinkat - .long sys_renameat /* 295 */ - .long sys_linkat - .long sys_symlinkat - .long sys_readlinkat - .long sys_fchmodat - .long sys_faccessat /* 300 */ - .long sys_ni_syscall /* Reserved for pselect6 */ - .long sys_ni_syscall /* Reserved for ppoll */ - .long sys_unshare - .long sys_set_robust_list - .long sys_get_robust_list /* 305 */ - .long sys_splice - .long sys_sync_file_range - .long sys_tee - .long sys_vmsplice - .long sys_move_pages /* 310 */ - .long sys_sched_setaffinity - .long sys_sched_getaffinity - .long sys_kexec_load - .long sys_getcpu - .long sys_epoll_pwait /* 315 */ - .long sys_utimensat - .long sys_signalfd - .long sys_timerfd_create - .long sys_eventfd - .long sys_fallocate /* 320 */ - .long sys_timerfd_settime - .long sys_timerfd_gettime - .long sys_signalfd4 - .long sys_eventfd2 - .long sys_epoll_create1 /* 325 */ - .long sys_dup3 - .long sys_pipe2 - .long sys_inotify_init1 - .long sys_preadv - .long sys_pwritev /* 330 */ - .long sys_rt_tgsigqueueinfo - .long sys_perf_event_open - .long sys_get_thread_area - .long sys_set_thread_area - .long sys_atomic_cmpxchg_32 /* 335 */ - .long sys_atomic_barrier - .long sys_fanotify_init - .long sys_fanotify_mark - .long sys_prlimit64 - .long sys_name_to_handle_at /* 340 */ - .long sys_open_by_handle_at - .long sys_clock_adjtime - .long sys_syncfs - diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S index 9b8393d8adb8..5909e392cb1e 100644 --- a/arch/m68k/kernel/syscalltable.S +++ b/arch/m68k/kernel/syscalltable.S @@ -1,6 +1,4 @@ /* - * linux/arch/m68knommu/kernel/syscalltable.S - * * Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com) * * Based on older entry.S files, the following copyrights apply: @@ -9,171 +7,176 @@ * Kenneth Albanowski , * Copyright (C) 2000 Lineo Inc. (www.lineo.com) * Copyright (C) 1991, 1992 Linus Torvalds + * + * Linux/m68k support by Hamish Macdonald */ #include #include -#include -.text +#ifndef CONFIG_MMU +#define sys_mmap2 sys_mmap_pgoff +#endif + +.section .rodata ALIGN ENTRY(sys_call_table) - .long sys_restart_syscall /* 0 - old "setup()" system call */ + .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ .long sys_exit .long sys_fork .long sys_read .long sys_write - .long sys_open /* 5 */ + .long sys_open /* 5 */ .long sys_close .long sys_waitpid .long sys_creat .long sys_link - .long sys_unlink /* 10 */ + .long sys_unlink /* 10 */ .long sys_execve .long sys_chdir .long sys_time .long sys_mknod - .long sys_chmod /* 15 */ + .long sys_chmod /* 15 */ .long sys_chown16 - .long sys_ni_syscall /* old break syscall holder */ + .long sys_ni_syscall /* old break syscall holder */ .long sys_stat .long sys_lseek - .long sys_getpid /* 20 */ + .long sys_getpid /* 20 */ .long sys_mount .long sys_oldumount .long sys_setuid16 .long sys_getuid16 - .long sys_stime /* 25 */ + .long sys_stime /* 25 */ .long sys_ptrace .long sys_alarm .long sys_fstat .long sys_pause - .long sys_utime /* 30 */ - .long sys_ni_syscall /* old stty syscall holder */ - .long sys_ni_syscall /* old gtty syscall holder */ + .long sys_utime /* 30 */ + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ .long sys_access .long sys_nice - .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + .long sys_ni_syscall /* 35 - old ftime syscall holder */ .long sys_sync .long sys_kill .long sys_rename .long sys_mkdir - .long sys_rmdir /* 40 */ + .long sys_rmdir /* 40 */ .long sys_dup .long sys_pipe .long sys_times - .long sys_ni_syscall /* old prof syscall holder */ - .long sys_brk /* 45 */ + .long sys_ni_syscall /* old prof syscall holder */ + .long sys_brk /* 45 */ .long sys_setgid16 .long sys_getgid16 .long sys_signal .long sys_geteuid16 - .long sys_getegid16 /* 50 */ + .long sys_getegid16 /* 50 */ .long sys_acct - .long sys_umount /* recycled never used phys() */ - .long sys_ni_syscall /* old lock syscall holder */ + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ .long sys_ioctl - .long sys_fcntl /* 55 */ - .long sys_ni_syscall /* old mpx syscall holder */ + .long sys_fcntl /* 55 */ + .long sys_ni_syscall /* old mpx syscall holder */ .long sys_setpgid - .long sys_ni_syscall /* old ulimit syscall holder */ + .long sys_ni_syscall /* old ulimit syscall holder */ .long sys_ni_syscall - .long sys_umask /* 60 */ + .long sys_umask /* 60 */ .long sys_chroot .long sys_ustat .long sys_dup2 .long sys_getppid - .long sys_getpgrp /* 65 */ + .long sys_getpgrp /* 65 */ .long sys_setsid .long sys_sigaction .long sys_sgetmask .long sys_ssetmask - .long sys_setreuid16 /* 70 */ + .long sys_setreuid16 /* 70 */ .long sys_setregid16 .long sys_sigsuspend .long sys_sigpending .long sys_sethostname - .long sys_setrlimit /* 75 */ + .long sys_setrlimit /* 75 */ .long sys_old_getrlimit .long sys_getrusage .long sys_gettimeofday .long sys_settimeofday - .long sys_getgroups16 /* 80 */ + .long sys_getgroups16 /* 80 */ .long sys_setgroups16 .long sys_old_select .long sys_symlink .long sys_lstat - .long sys_readlink /* 85 */ + .long sys_readlink /* 85 */ .long sys_uselib - .long sys_ni_syscall /* sys_swapon */ + .long sys_swapon .long sys_reboot .long sys_old_readdir - .long sys_old_mmap /* 90 */ + .long sys_old_mmap /* 90 */ .long sys_munmap .long sys_truncate .long sys_ftruncate .long sys_fchmod - .long sys_fchown16 /* 95 */ + .long sys_fchown16 /* 95 */ .long sys_getpriority .long sys_setpriority - .long sys_ni_syscall /* old profil syscall holder */ + .long sys_ni_syscall /* old profil syscall holder */ .long sys_statfs - .long sys_fstatfs /* 100 */ - .long sys_ni_syscall /* ioperm for i386 */ + .long sys_fstatfs /* 100 */ + .long sys_ni_syscall /* ioperm for i386 */ .long sys_socketcall .long sys_syslog .long sys_setitimer - .long sys_getitimer /* 105 */ + .long sys_getitimer /* 105 */ .long sys_newstat .long sys_newlstat .long sys_newfstat .long sys_ni_syscall - .long sys_ni_syscall /* iopl for i386 */ /* 110 */ + .long sys_ni_syscall /* 110 - iopl for i386 */ .long sys_vhangup - .long sys_ni_syscall /* obsolete idle() syscall */ - .long sys_ni_syscall /* vm86old for i386 */ + .long sys_ni_syscall /* obsolete idle() syscall */ + .long sys_ni_syscall /* vm86old for i386 */ .long sys_wait4 - .long sys_ni_syscall /* 115 */ /* sys_swapoff */ + .long sys_swapoff /* 115 */ .long sys_sysinfo .long sys_ipc .long sys_fsync .long sys_sigreturn - .long sys_clone /* 120 */ + .long sys_clone /* 120 */ .long sys_setdomainname .long sys_newuname - .long sys_cacheflush /* modify_ldt for i386 */ + .long sys_cacheflush /* modify_ldt for i386 */ .long sys_adjtimex - .long sys_ni_syscall /* 125 */ /* sys_mprotect */ + .long sys_mprotect /* 125 */ .long sys_sigprocmask - .long sys_ni_syscall /* old "creat_module" */ + .long sys_ni_syscall /* old "create_module" */ .long sys_init_module .long sys_delete_module - .long sys_ni_syscall /* 130: old "get_kernel_syms" */ + .long sys_ni_syscall /* 130 - old "get_kernel_syms" */ .long sys_quotactl .long sys_getpgid .long sys_fchdir .long sys_bdflush - .long sys_sysfs /* 135 */ + .long sys_sysfs /* 135 */ .long sys_personality - .long sys_ni_syscall /* for afs_syscall */ + .long sys_ni_syscall /* for afs_syscall */ .long sys_setfsuid16 .long sys_setfsgid16 - .long sys_llseek /* 140 */ + .long sys_llseek /* 140 */ .long sys_getdents .long sys_select .long sys_flock - .long sys_ni_syscall /* sys_msync */ - .long sys_readv /* 145 */ + .long sys_msync + .long sys_readv /* 145 */ .long sys_writev .long sys_getsid .long sys_fdatasync .long sys_sysctl - .long sys_ni_syscall /* 150 */ /* sys_mlock */ - .long sys_ni_syscall /* sys_munlock */ - .long sys_ni_syscall /* sys_mlockall */ - .long sys_ni_syscall /* sys_munlockall */ + .long sys_mlock /* 150 */ + .long sys_munlock + .long sys_mlockall + .long sys_munlockall .long sys_sched_setparam - .long sys_sched_getparam /* 155 */ + .long sys_sched_getparam /* 155 */ .long sys_sched_setscheduler .long sys_sched_getscheduler .long sys_sched_yield @@ -181,124 +184,124 @@ ENTRY(sys_call_table) .long sys_sched_get_priority_min /* 160 */ .long sys_sched_rr_get_interval .long sys_nanosleep - .long sys_ni_syscall /* sys_mremap */ + .long sys_mremap .long sys_setresuid16 - .long sys_getresuid16 /* 165 */ - .long sys_getpagesize /* sys_getpagesize */ - .long sys_ni_syscall /* old "query_module" */ + .long sys_getresuid16 /* 165 */ + .long sys_getpagesize + .long sys_ni_syscall /* old "query_module" */ .long sys_poll - .long sys_ni_syscall /* sys_nfsservctl */ - .long sys_setresgid16 /* 170 */ + .long sys_nfsservctl + .long sys_setresgid16 /* 170 */ .long sys_getresgid16 .long sys_prctl .long sys_rt_sigreturn .long sys_rt_sigaction - .long sys_rt_sigprocmask /* 175 */ + .long sys_rt_sigprocmask /* 175 */ .long sys_rt_sigpending .long sys_rt_sigtimedwait .long sys_rt_sigqueueinfo .long sys_rt_sigsuspend - .long sys_pread64 /* 180 */ + .long sys_pread64 /* 180 */ .long sys_pwrite64 .long sys_lchown16 .long sys_getcwd .long sys_capget - .long sys_capset /* 185 */ + .long sys_capset /* 185 */ .long sys_sigaltstack .long sys_sendfile - .long sys_ni_syscall /* streams1 */ - .long sys_ni_syscall /* streams2 */ - .long sys_vfork /* 190 */ + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ + .long sys_vfork /* 190 */ .long sys_getrlimit - .long sys_mmap_pgoff + .long sys_mmap2 .long sys_truncate64 .long sys_ftruncate64 - .long sys_stat64 /* 195 */ + .long sys_stat64 /* 195 */ .long sys_lstat64 .long sys_fstat64 .long sys_chown .long sys_getuid - .long sys_getgid /* 200 */ + .long sys_getgid /* 200 */ .long sys_geteuid .long sys_getegid .long sys_setreuid .long sys_setregid - .long sys_getgroups /* 205 */ + .long sys_getgroups /* 205 */ .long sys_setgroups .long sys_fchown .long sys_setresuid .long sys_getresuid - .long sys_setresgid /* 210 */ + .long sys_setresgid /* 210 */ .long sys_getresgid .long sys_lchown .long sys_setuid .long sys_setgid - .long sys_setfsuid /* 215 */ + .long sys_setfsuid /* 215 */ .long sys_setfsgid .long sys_pivot_root .long sys_ni_syscall .long sys_ni_syscall - .long sys_getdents64 /* 220 */ + .long sys_getdents64 /* 220 */ .long sys_gettid .long sys_tkill .long sys_setxattr .long sys_lsetxattr - .long sys_fsetxattr /* 225 */ + .long sys_fsetxattr /* 225 */ .long sys_getxattr .long sys_lgetxattr .long sys_fgetxattr .long sys_listxattr - .long sys_llistxattr /* 230 */ + .long sys_llistxattr /* 230 */ .long sys_flistxattr .long sys_removexattr .long sys_lremovexattr .long sys_fremovexattr - .long sys_futex /* 235 */ + .long sys_futex /* 235 */ .long sys_sendfile64 - .long sys_ni_syscall /* sys_mincore */ - .long sys_ni_syscall /* sys_madvise */ + .long sys_mincore + .long sys_madvise .long sys_fcntl64 - .long sys_readahead /* 240 */ + .long sys_readahead /* 240 */ .long sys_io_setup .long sys_io_destroy .long sys_io_getevents .long sys_io_submit - .long sys_io_cancel /* 245 */ + .long sys_io_cancel /* 245 */ .long sys_fadvise64 .long sys_exit_group .long sys_lookup_dcookie .long sys_epoll_create - .long sys_epoll_ctl /* 250 */ + .long sys_epoll_ctl /* 250 */ .long sys_epoll_wait - .long sys_ni_syscall /* sys_remap_file_pages */ + .long sys_remap_file_pages .long sys_set_tid_address .long sys_timer_create - .long sys_timer_settime /* 255 */ + .long sys_timer_settime /* 255 */ .long sys_timer_gettime .long sys_timer_getoverrun .long sys_timer_delete .long sys_clock_settime - .long sys_clock_gettime /* 260 */ + .long sys_clock_gettime /* 260 */ .long sys_clock_getres .long sys_clock_nanosleep .long sys_statfs64 .long sys_fstatfs64 - .long sys_tgkill /* 265 */ + .long sys_tgkill /* 265 */ .long sys_utimes .long sys_fadvise64_64 - .long sys_mbind + .long sys_mbind .long sys_get_mempolicy - .long sys_set_mempolicy /* 270 */ + .long sys_set_mempolicy /* 270 */ .long sys_mq_open .long sys_mq_unlink .long sys_mq_timedsend .long sys_mq_timedreceive - .long sys_mq_notify /* 275 */ + .long sys_mq_notify /* 275 */ .long sys_mq_getsetattr .long sys_waitid - .long sys_ni_syscall /* for sys_vserver */ + .long sys_ni_syscall /* for sys_vserver */ .long sys_add_key - .long sys_request_key /* 280 */ + .long sys_request_key /* 280 */ .long sys_keyctl .long sys_ioprio_set .long sys_ioprio_get @@ -319,8 +322,8 @@ ENTRY(sys_call_table) .long sys_readlinkat .long sys_fchmodat .long sys_faccessat /* 300 */ - .long sys_ni_syscall /* Reserved for pselect6 */ - .long sys_ni_syscall /* Reserved for ppoll */ + .long sys_pselect6 + .long sys_ppoll .long sys_unshare .long sys_set_robust_list .long sys_get_robust_list /* 305 */ @@ -363,7 +366,3 @@ ENTRY(sys_call_table) .long sys_clock_adjtime .long sys_syncfs - .rept NR_syscalls-(.-sys_call_table)/4 - .long sys_ni_syscall - .endr - diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds index 878be5f38cad..d0993594f558 100644 --- a/arch/m68k/kernel/vmlinux-std.lds +++ b/arch/m68k/kernel/vmlinux-std.lds @@ -25,6 +25,8 @@ SECTIONS EXCEPTION_TABLE(16) + _sdata = .; /* Start of data section */ + RODATA RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds index 1ad6b7ad2c17..8080469ee6c1 100644 --- a/arch/m68k/kernel/vmlinux-sun3.lds +++ b/arch/m68k/kernel/vmlinux-sun3.lds @@ -25,6 +25,7 @@ SECTIONS _etext = .; /* End of text section */ EXCEPTION_TABLE(16) :data + _sdata = .; /* Start of rw data section */ RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) :data /* End of data goes *here* so that freeing init code works properly. */ _edata = .; diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c index 02b7a03e4226..8b3db1c587fc 100644 --- a/arch/m68k/mm/motorola.c +++ b/arch/m68k/mm/motorola.c @@ -300,6 +300,8 @@ void __init paging_init(void) zones_size[ZONE_DMA] = m68k_memory[i].size >> PAGE_SHIFT; free_area_init_node(i, zones_size, m68k_memory[i].addr >> PAGE_SHIFT, NULL); + if (node_present_pages(i)) + node_set_state(i, N_NORMAL_MEMORY); } } diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index d8a214f11ac2..e5550ce4e0eb 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -217,16 +217,12 @@ static struct clocksource clocksource_microblaze = { .rating = 300, .read = microblaze_read, .mask = CLOCKSOURCE_MASK(32), - .shift = 8, /* I can shift it */ .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static int __init microblaze_clocksource_init(void) { - clocksource_microblaze.mult = - clocksource_hz2mult(timer_clock_freq, - clocksource_microblaze.shift); - if (clocksource_register(&clocksource_microblaze)) + if (clocksource_register_hz(&clocksource_microblaze, timer_clock_freq)) panic("failed to register clocksource"); /* stop timer1 */ diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index 7ff9b5492041..aef6c917b45a 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -11,6 +11,7 @@ platforms += dec platforms += emma platforms += jazz platforms += jz4740 +platforms += lantiq platforms += lasat platforms += loongson platforms += mipssim diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 8e256cc5dcd9..cef1a854487d 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -212,6 +212,24 @@ config MACH_JZ4740 select HAVE_PWM select HAVE_CLK +config LANTIQ + bool "Lantiq based platforms" + select DMA_NONCOHERENT + select IRQ_CPU + select CEVT_R4K + select CSRC_R4K + select SYS_HAS_CPU_MIPS32_R1 + select SYS_HAS_CPU_MIPS32_R2 + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_MULTITHREADING + select SYS_HAS_EARLY_PRINTK + select ARCH_REQUIRE_GPIOLIB + select SWAP_IO_SPACE + select BOOT_RAW + select HAVE_CLK + select MIPS_MACHINE + config LASAT bool "LASAT Networks platforms" select CEVT_R4K @@ -736,6 +754,33 @@ config CAVIUM_OCTEON_REFERENCE_BOARD Hikari Say Y here for most Octeon reference boards. +config NLM_XLR_BOARD + bool "Netlogic XLR/XLS based systems" + depends on EXPERIMENTAL + select BOOT_ELF32 + select NLM_COMMON + select NLM_XLR + select SYS_HAS_CPU_XLR + select SYS_SUPPORTS_SMP + select HW_HAS_PCI + select SWAP_IO_SPACE + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL + select 64BIT_PHYS_ADDR + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_HIGHMEM + select DMA_COHERENT + select NR_CPUS_DEFAULT_32 + select CEVT_R4K + select CSRC_R4K + select IRQ_CPU + select ZONE_DMA if 64BIT + select SYNC_R4K + select SYS_HAS_EARLY_PRINTK + help + Support for systems based on Netlogic XLR and XLS processors. + Say Y here if you have a XLR or XLS based board. + endchoice source "arch/mips/alchemy/Kconfig" @@ -743,6 +788,7 @@ source "arch/mips/ath79/Kconfig" source "arch/mips/bcm63xx/Kconfig" source "arch/mips/jazz/Kconfig" source "arch/mips/jz4740/Kconfig" +source "arch/mips/lantiq/Kconfig" source "arch/mips/lasat/Kconfig" source "arch/mips/pmc-sierra/Kconfig" source "arch/mips/powertv/Kconfig" @@ -752,6 +798,7 @@ source "arch/mips/txx9/Kconfig" source "arch/mips/vr41xx/Kconfig" source "arch/mips/cavium-octeon/Kconfig" source "arch/mips/loongson/Kconfig" +source "arch/mips/netlogic/Kconfig" endmenu @@ -997,9 +1044,6 @@ config IRQ_GT641XX config IRQ_GIC bool -config IRQ_CPU_OCTEON - bool - config MIPS_BOARDS_GEN bool @@ -1359,8 +1403,6 @@ config CPU_SB1 config CPU_CAVIUM_OCTEON bool "Cavium Octeon processor" depends on SYS_HAS_CPU_CAVIUM_OCTEON - select IRQ_CPU - select IRQ_CPU_OCTEON select CPU_HAS_PREFETCH select CPU_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_SMP @@ -1425,6 +1467,17 @@ config CPU_BMIPS5000 help Broadcom BMIPS5000 processors. +config CPU_XLR + bool "Netlogic XLR SoC" + depends on SYS_HAS_CPU_XLR + select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_64BIT_KERNEL + select CPU_SUPPORTS_HIGHMEM + select WEAK_ORDERING + select WEAK_REORDERING_BEYOND_LLSC + select CPU_SUPPORTS_HUGEPAGES + help + Netlogic Microsystems XLR/XLS processors. endchoice if CPU_LOONGSON2F @@ -1555,6 +1608,9 @@ config SYS_HAS_CPU_BMIPS4380 config SYS_HAS_CPU_BMIPS5000 bool +config SYS_HAS_CPU_XLR + bool + # # CPU may reorder R->R, R->W, W->R, W->W # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC @@ -2339,6 +2395,7 @@ config MMU config I8253 bool + select CLKSRC_I8253 select MIPS_EXTERNAL_TIMER config ZONE_DMA32 diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 53e3514ba10e..884819cd0607 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -191,6 +191,18 @@ endif # include $(srctree)/arch/mips/Kbuild.platforms +# +# NETLOGIC SOC Common (common) +# +cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/mach-netlogic +cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/netlogic + +# +# NETLOGIC XLR/XLS SoC, Simulator and boards +# +core-$(CONFIG_NLM_XLR) += arch/mips/netlogic/xlr/ +load-$(CONFIG_NLM_XLR_BOARD) += 0xffffffff84000000 + cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic drivers-$(CONFIG_PCI) += arch/mips/pci/ diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c index ca0506a8585a..3a5abb54d505 100644 --- a/arch/mips/alchemy/common/dbdma.c +++ b/arch/mips/alchemy/common/dbdma.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include @@ -58,7 +58,8 @@ static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock); /* I couldn't find a macro that did this... */ #define ALIGN_ADDR(x, a) ((((u32)(x)) + (a-1)) & ~(a-1)) -static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE; +static dbdma_global_t *dbdma_gptr = + (dbdma_global_t *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR); static int dbdma_initialized; static dbdev_tab_t dbdev_tab[] = { @@ -299,7 +300,7 @@ u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, if (ctp != NULL) { memset(ctp, 0, sizeof(chan_tab_t)); ctp->chan_index = chan = i; - dcp = DDMA_CHANNEL_BASE; + dcp = KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR); dcp += (0x0100 * chan); ctp->chan_ptr = (au1x_dma_chan_t *)dcp; cp = (au1x_dma_chan_t *)dcp; @@ -958,105 +959,75 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr) } -struct alchemy_dbdma_sysdev { - struct sys_device sysdev; - u32 pm_regs[NUM_DBDMA_CHANS + 1][6]; -}; +static unsigned long alchemy_dbdma_pm_data[NUM_DBDMA_CHANS + 1][6]; -static int alchemy_dbdma_suspend(struct sys_device *dev, - pm_message_t state) +static int alchemy_dbdma_suspend(void) { - struct alchemy_dbdma_sysdev *sdev = - container_of(dev, struct alchemy_dbdma_sysdev, sysdev); int i; - u32 addr; + void __iomem *addr; - addr = DDMA_GLOBAL_BASE; - sdev->pm_regs[0][0] = au_readl(addr + 0x00); - sdev->pm_regs[0][1] = au_readl(addr + 0x04); - sdev->pm_regs[0][2] = au_readl(addr + 0x08); - sdev->pm_regs[0][3] = au_readl(addr + 0x0c); + addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR); + alchemy_dbdma_pm_data[0][0] = __raw_readl(addr + 0x00); + alchemy_dbdma_pm_data[0][1] = __raw_readl(addr + 0x04); + alchemy_dbdma_pm_data[0][2] = __raw_readl(addr + 0x08); + alchemy_dbdma_pm_data[0][3] = __raw_readl(addr + 0x0c); /* save channel configurations */ - for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) { - sdev->pm_regs[i][0] = au_readl(addr + 0x00); - sdev->pm_regs[i][1] = au_readl(addr + 0x04); - sdev->pm_regs[i][2] = au_readl(addr + 0x08); - sdev->pm_regs[i][3] = au_readl(addr + 0x0c); - sdev->pm_regs[i][4] = au_readl(addr + 0x10); - sdev->pm_regs[i][5] = au_readl(addr + 0x14); + addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR); + for (i = 1; i <= NUM_DBDMA_CHANS; i++) { + alchemy_dbdma_pm_data[i][0] = __raw_readl(addr + 0x00); + alchemy_dbdma_pm_data[i][1] = __raw_readl(addr + 0x04); + alchemy_dbdma_pm_data[i][2] = __raw_readl(addr + 0x08); + alchemy_dbdma_pm_data[i][3] = __raw_readl(addr + 0x0c); + alchemy_dbdma_pm_data[i][4] = __raw_readl(addr + 0x10); + alchemy_dbdma_pm_data[i][5] = __raw_readl(addr + 0x14); /* halt channel */ - au_writel(sdev->pm_regs[i][0] & ~1, addr + 0x00); - au_sync(); - while (!(au_readl(addr + 0x14) & 1)) - au_sync(); + __raw_writel(alchemy_dbdma_pm_data[i][0] & ~1, addr + 0x00); + wmb(); + while (!(__raw_readl(addr + 0x14) & 1)) + wmb(); addr += 0x100; /* next channel base */ } /* disable channel interrupts */ - au_writel(0, DDMA_GLOBAL_BASE + 0x0c); - au_sync(); + addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR); + __raw_writel(0, addr + 0x0c); + wmb(); return 0; } -static int alchemy_dbdma_resume(struct sys_device *dev) +static void alchemy_dbdma_resume(void) { - struct alchemy_dbdma_sysdev *sdev = - container_of(dev, struct alchemy_dbdma_sysdev, sysdev); int i; - u32 addr; + void __iomem *addr; - addr = DDMA_GLOBAL_BASE; - au_writel(sdev->pm_regs[0][0], addr + 0x00); - au_writel(sdev->pm_regs[0][1], addr + 0x04); - au_writel(sdev->pm_regs[0][2], addr + 0x08); - au_writel(sdev->pm_regs[0][3], addr + 0x0c); + addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR); + __raw_writel(alchemy_dbdma_pm_data[0][0], addr + 0x00); + __raw_writel(alchemy_dbdma_pm_data[0][1], addr + 0x04); + __raw_writel(alchemy_dbdma_pm_data[0][2], addr + 0x08); + __raw_writel(alchemy_dbdma_pm_data[0][3], addr + 0x0c); /* restore channel configurations */ - for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) { - au_writel(sdev->pm_regs[i][0], addr + 0x00); - au_writel(sdev->pm_regs[i][1], addr + 0x04); - au_writel(sdev->pm_regs[i][2], addr + 0x08); - au_writel(sdev->pm_regs[i][3], addr + 0x0c); - au_writel(sdev->pm_regs[i][4], addr + 0x10); - au_writel(sdev->pm_regs[i][5], addr + 0x14); - au_sync(); + addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR); + for (i = 1; i <= NUM_DBDMA_CHANS; i++) { + __raw_writel(alchemy_dbdma_pm_data[i][0], addr + 0x00); + __raw_writel(alchemy_dbdma_pm_data[i][1], addr + 0x04); + __raw_writel(alchemy_dbdma_pm_data[i][2], addr + 0x08); + __raw_writel(alchemy_dbdma_pm_data[i][3], addr + 0x0c); + __raw_writel(alchemy_dbdma_pm_data[i][4], addr + 0x10); + __raw_writel(alchemy_dbdma_pm_data[i][5], addr + 0x14); + wmb(); addr += 0x100; /* next channel base */ } - - return 0; } -static struct sysdev_class alchemy_dbdma_sysdev_class = { - .name = "dbdma", +static struct syscore_ops alchemy_dbdma_syscore_ops = { .suspend = alchemy_dbdma_suspend, .resume = alchemy_dbdma_resume, }; -static int __init alchemy_dbdma_sysdev_init(void) -{ - struct alchemy_dbdma_sysdev *sdev; - int ret; - - ret = sysdev_class_register(&alchemy_dbdma_sysdev_class); - if (ret) - return ret; - - sdev = kzalloc(sizeof(struct alchemy_dbdma_sysdev), GFP_KERNEL); - if (!sdev) - return -ENOMEM; - - sdev->sysdev.id = -1; - sdev->sysdev.cls = &alchemy_dbdma_sysdev_class; - ret = sysdev_register(&sdev->sysdev); - if (ret) - kfree(sdev); - - return ret; -} - static int __init au1xxx_dbdma_init(void) { int irq_nr, ret; @@ -1084,11 +1055,7 @@ static int __init au1xxx_dbdma_init(void) else { dbdma_initialized = 1; printk(KERN_INFO "Alchemy DBDMA initialized\n"); - ret = alchemy_dbdma_sysdev_init(); - if (ret) { - printk(KERN_ERR "DBDMA PM init failed\n"); - ret = 0; - } + register_syscore_ops(&alchemy_dbdma_syscore_ops); } return ret; diff --git a/arch/mips/alchemy/common/dma.c b/arch/mips/alchemy/common/dma.c index d5278877891d..347980e79a89 100644 --- a/arch/mips/alchemy/common/dma.c +++ b/arch/mips/alchemy/common/dma.c @@ -58,6 +58,9 @@ * returned from request_dma. */ +/* DMA Channel register block spacing */ +#define DMA_CHANNEL_LEN 0x00000100 + DEFINE_SPINLOCK(au1000_dma_spin_lock); struct dma_chan au1000_dma_table[NUM_AU1000_DMA_CHANNELS] = { @@ -77,22 +80,23 @@ static const struct dma_dev { unsigned int fifo_addr; unsigned int dma_mode; } dma_dev_table[DMA_NUM_DEV] = { - {UART0_ADDR + UART_TX, 0}, - {UART0_ADDR + UART_RX, 0}, - {0, 0}, - {0, 0}, - {AC97C_DATA, DMA_DW16 }, /* coherent */ - {AC97C_DATA, DMA_DR | DMA_DW16 }, /* coherent */ - {UART3_ADDR + UART_TX, DMA_DW8 | DMA_NC}, - {UART3_ADDR + UART_RX, DMA_DR | DMA_DW8 | DMA_NC}, - {USBD_EP0RD, DMA_DR | DMA_DW8 | DMA_NC}, - {USBD_EP0WR, DMA_DW8 | DMA_NC}, - {USBD_EP2WR, DMA_DW8 | DMA_NC}, - {USBD_EP3WR, DMA_DW8 | DMA_NC}, - {USBD_EP4RD, DMA_DR | DMA_DW8 | DMA_NC}, - {USBD_EP5RD, DMA_DR | DMA_DW8 | DMA_NC}, - {I2S_DATA, DMA_DW32 | DMA_NC}, - {I2S_DATA, DMA_DR | DMA_DW32 | DMA_NC} + { AU1000_UART0_PHYS_ADDR + 0x04, DMA_DW8 }, /* UART0_TX */ + { AU1000_UART0_PHYS_ADDR + 0x00, DMA_DW8 | DMA_DR }, /* UART0_RX */ + { 0, 0 }, /* DMA_REQ0 */ + { 0, 0 }, /* DMA_REQ1 */ + { AU1000_AC97_PHYS_ADDR + 0x08, DMA_DW16 }, /* AC97 TX c */ + { AU1000_AC97_PHYS_ADDR + 0x08, DMA_DW16 | DMA_DR }, /* AC97 RX c */ + { AU1000_UART3_PHYS_ADDR + 0x04, DMA_DW8 | DMA_NC }, /* UART3_TX */ + { AU1000_UART3_PHYS_ADDR + 0x00, DMA_DW8 | DMA_NC | DMA_DR }, /* UART3_RX */ + { AU1000_USBD_PHYS_ADDR + 0x00, DMA_DW8 | DMA_NC | DMA_DR }, /* EP0RD */ + { AU1000_USBD_PHYS_ADDR + 0x04, DMA_DW8 | DMA_NC }, /* EP0WR */ + { AU1000_USBD_PHYS_ADDR + 0x08, DMA_DW8 | DMA_NC }, /* EP2WR */ + { AU1000_USBD_PHYS_ADDR + 0x0c, DMA_DW8 | DMA_NC }, /* EP3WR */ + { AU1000_USBD_PHYS_ADDR + 0x10, DMA_DW8 | DMA_NC | DMA_DR }, /* EP4RD */ + { AU1000_USBD_PHYS_ADDR + 0x14, DMA_DW8 | DMA_NC | DMA_DR }, /* EP5RD */ + /* on Au1500, these 2 are DMA_REQ2/3 (GPIO208/209) instead! */ + { AU1000_I2S_PHYS_ADDR + 0x00, DMA_DW32 | DMA_NC}, /* I2S TX */ + { AU1000_I2S_PHYS_ADDR + 0x00, DMA_DW32 | DMA_NC | DMA_DR}, /* I2S RX */ }; int au1000_dma_read_proc(char *buf, char **start, off_t fpos, @@ -123,10 +127,10 @@ int au1000_dma_read_proc(char *buf, char **start, off_t fpos, /* Device FIFO addresses and default DMA modes - 2nd bank */ static const struct dma_dev dma_dev_table_bank2[DMA_NUM_DEV_BANK2] = { - { SD0_XMIT_FIFO, DMA_DS | DMA_DW8 }, /* coherent */ - { SD0_RECV_FIFO, DMA_DS | DMA_DR | DMA_DW8 }, /* coherent */ - { SD1_XMIT_FIFO, DMA_DS | DMA_DW8 }, /* coherent */ - { SD1_RECV_FIFO, DMA_DS | DMA_DR | DMA_DW8 } /* coherent */ + { AU1100_SD0_PHYS_ADDR + 0x00, DMA_DS | DMA_DW8 }, /* coherent */ + { AU1100_SD0_PHYS_ADDR + 0x04, DMA_DS | DMA_DW8 | DMA_DR }, /* coherent */ + { AU1100_SD1_PHYS_ADDR + 0x00, DMA_DS | DMA_DW8 }, /* coherent */ + { AU1100_SD1_PHYS_ADDR + 0x04, DMA_DS | DMA_DW8 | DMA_DR } /* coherent */ }; void dump_au1000_dma_channel(unsigned int dmanr) @@ -202,7 +206,7 @@ int request_au1000_dma(int dev_id, const char *dev_str, } /* fill it in */ - chan->io = DMA_CHANNEL_BASE + i * DMA_CHANNEL_LEN; + chan->io = KSEG1ADDR(AU1000_DMA_PHYS_ADDR) + i * DMA_CHANNEL_LEN; chan->dev_id = dev_id; chan->dev_str = dev_str; chan->fifo_addr = dev->fifo_addr; diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c index 55dd7c888517..8b60ba0675e2 100644 --- a/arch/mips/alchemy/common/irq.c +++ b/arch/mips/alchemy/common/irq.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include @@ -39,6 +39,36 @@ #include #endif +/* Interrupt Controller register offsets */ +#define IC_CFG0RD 0x40 +#define IC_CFG0SET 0x40 +#define IC_CFG0CLR 0x44 +#define IC_CFG1RD 0x48 +#define IC_CFG1SET 0x48 +#define IC_CFG1CLR 0x4C +#define IC_CFG2RD 0x50 +#define IC_CFG2SET 0x50 +#define IC_CFG2CLR 0x54 +#define IC_REQ0INT 0x54 +#define IC_SRCRD 0x58 +#define IC_SRCSET 0x58 +#define IC_SRCCLR 0x5C +#define IC_REQ1INT 0x5C +#define IC_ASSIGNRD 0x60 +#define IC_ASSIGNSET 0x60 +#define IC_ASSIGNCLR 0x64 +#define IC_WAKERD 0x68 +#define IC_WAKESET 0x68 +#define IC_WAKECLR 0x6C +#define IC_MASKRD 0x70 +#define IC_MASKSET 0x70 +#define IC_MASKCLR 0x74 +#define IC_RISINGRD 0x78 +#define IC_RISINGCLR 0x78 +#define IC_FALLINGRD 0x7C +#define IC_FALLINGCLR 0x7C +#define IC_TESTBIT 0x80 + static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type); /* NOTE on interrupt priorities: The original writers of this code said: @@ -221,89 +251,101 @@ struct au1xxx_irqmap au1200_irqmap[] __initdata = { static void au1x_ic0_unmask(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; - au_writel(1 << bit, IC0_MASKSET); - au_writel(1 << bit, IC0_WAKESET); - au_sync(); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); + + __raw_writel(1 << bit, base + IC_MASKSET); + __raw_writel(1 << bit, base + IC_WAKESET); + wmb(); } static void au1x_ic1_unmask(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; - au_writel(1 << bit, IC1_MASKSET); - au_writel(1 << bit, IC1_WAKESET); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); + + __raw_writel(1 << bit, base + IC_MASKSET); + __raw_writel(1 << bit, base + IC_WAKESET); /* very hacky. does the pb1000 cpld auto-disable this int? * nowhere in the current kernel sources is it disabled. --mlau */ #if defined(CONFIG_MIPS_PB1000) if (d->irq == AU1000_GPIO15_INT) - au_writel(0x4000, PB1000_MDR); /* enable int */ + __raw_writel(0x4000, (void __iomem *)PB1000_MDR); /* enable int */ #endif - au_sync(); + wmb(); } static void au1x_ic0_mask(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; - au_writel(1 << bit, IC0_MASKCLR); - au_writel(1 << bit, IC0_WAKECLR); - au_sync(); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); + + __raw_writel(1 << bit, base + IC_MASKCLR); + __raw_writel(1 << bit, base + IC_WAKECLR); + wmb(); } static void au1x_ic1_mask(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; - au_writel(1 << bit, IC1_MASKCLR); - au_writel(1 << bit, IC1_WAKECLR); - au_sync(); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); + + __raw_writel(1 << bit, base + IC_MASKCLR); + __raw_writel(1 << bit, base + IC_WAKECLR); + wmb(); } static void au1x_ic0_ack(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); /* * This may assume that we don't get interrupts from * both edges at once, or if we do, that we don't care. */ - au_writel(1 << bit, IC0_FALLINGCLR); - au_writel(1 << bit, IC0_RISINGCLR); - au_sync(); + __raw_writel(1 << bit, base + IC_FALLINGCLR); + __raw_writel(1 << bit, base + IC_RISINGCLR); + wmb(); } static void au1x_ic1_ack(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); /* * This may assume that we don't get interrupts from * both edges at once, or if we do, that we don't care. */ - au_writel(1 << bit, IC1_FALLINGCLR); - au_writel(1 << bit, IC1_RISINGCLR); - au_sync(); + __raw_writel(1 << bit, base + IC_FALLINGCLR); + __raw_writel(1 << bit, base + IC_RISINGCLR); + wmb(); } static void au1x_ic0_maskack(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); - au_writel(1 << bit, IC0_WAKECLR); - au_writel(1 << bit, IC0_MASKCLR); - au_writel(1 << bit, IC0_RISINGCLR); - au_writel(1 << bit, IC0_FALLINGCLR); - au_sync(); + __raw_writel(1 << bit, base + IC_WAKECLR); + __raw_writel(1 << bit, base + IC_MASKCLR); + __raw_writel(1 << bit, base + IC_RISINGCLR); + __raw_writel(1 << bit, base + IC_FALLINGCLR); + wmb(); } static void au1x_ic1_maskack(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); - au_writel(1 << bit, IC1_WAKECLR); - au_writel(1 << bit, IC1_MASKCLR); - au_writel(1 << bit, IC1_RISINGCLR); - au_writel(1 << bit, IC1_FALLINGCLR); - au_sync(); + __raw_writel(1 << bit, base + IC_WAKECLR); + __raw_writel(1 << bit, base + IC_MASKCLR); + __raw_writel(1 << bit, base + IC_RISINGCLR); + __raw_writel(1 << bit, base + IC_FALLINGCLR); + wmb(); } static int au1x_ic1_setwake(struct irq_data *d, unsigned int on) @@ -318,13 +360,13 @@ static int au1x_ic1_setwake(struct irq_data *d, unsigned int on) return -EINVAL; local_irq_save(flags); - wakemsk = au_readl(SYS_WAKEMSK); + wakemsk = __raw_readl((void __iomem *)SYS_WAKEMSK); if (on) wakemsk |= 1 << bit; else wakemsk &= ~(1 << bit); - au_writel(wakemsk, SYS_WAKEMSK); - au_sync(); + __raw_writel(wakemsk, (void __iomem *)SYS_WAKEMSK); + wmb(); local_irq_restore(flags); return 0; @@ -356,81 +398,74 @@ static struct irq_chip au1x_ic1_chip = { static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type) { struct irq_chip *chip; - unsigned long icr[6]; - unsigned int bit, ic, irq = d->irq; + unsigned int bit, irq = d->irq; irq_flow_handler_t handler = NULL; unsigned char *name = NULL; + void __iomem *base; int ret; if (irq >= AU1000_INTC1_INT_BASE) { bit = irq - AU1000_INTC1_INT_BASE; chip = &au1x_ic1_chip; - ic = 1; + base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); } else { bit = irq - AU1000_INTC0_INT_BASE; chip = &au1x_ic0_chip; - ic = 0; + base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); } if (bit > 31) return -EINVAL; - icr[0] = ic ? IC1_CFG0SET : IC0_CFG0SET; - icr[1] = ic ? IC1_CFG1SET : IC0_CFG1SET; - icr[2] = ic ? IC1_CFG2SET : IC0_CFG2SET; - icr[3] = ic ? IC1_CFG0CLR : IC0_CFG0CLR; - icr[4] = ic ? IC1_CFG1CLR : IC0_CFG1CLR; - icr[5] = ic ? IC1_CFG2CLR : IC0_CFG2CLR; - ret = 0; switch (flow_type) { /* cfgregs 2:1:0 */ case IRQ_TYPE_EDGE_RISING: /* 0:0:1 */ - au_writel(1 << bit, icr[5]); - au_writel(1 << bit, icr[4]); - au_writel(1 << bit, icr[0]); + __raw_writel(1 << bit, base + IC_CFG2CLR); + __raw_writel(1 << bit, base + IC_CFG1CLR); + __raw_writel(1 << bit, base + IC_CFG0SET); handler = handle_edge_irq; name = "riseedge"; break; case IRQ_TYPE_EDGE_FALLING: /* 0:1:0 */ - au_writel(1 << bit, icr[5]); - au_writel(1 << bit, icr[1]); - au_writel(1 << bit, icr[3]); + __raw_writel(1 << bit, base + IC_CFG2CLR); + __raw_writel(1 << bit, base + IC_CFG1SET); + __raw_writel(1 << bit, base + IC_CFG0CLR); handler = handle_edge_irq; name = "falledge"; break; case IRQ_TYPE_EDGE_BOTH: /* 0:1:1 */ - au_writel(1 << bit, icr[5]); - au_writel(1 << bit, icr[1]); - au_writel(1 << bit, icr[0]); + __raw_writel(1 << bit, base + IC_CFG2CLR); + __raw_writel(1 << bit, base + IC_CFG1SET); + __raw_writel(1 << bit, base + IC_CFG0SET); handler = handle_edge_irq; name = "bothedge"; break; case IRQ_TYPE_LEVEL_HIGH: /* 1:0:1 */ - au_writel(1 << bit, icr[2]); - au_writel(1 << bit, icr[4]); - au_writel(1 << bit, icr[0]); + __raw_writel(1 << bit, base + IC_CFG2SET); + __raw_writel(1 << bit, base + IC_CFG1CLR); + __raw_writel(1 << bit, base + IC_CFG0SET); handler = handle_level_irq; name = "hilevel"; break; case IRQ_TYPE_LEVEL_LOW: /* 1:1:0 */ - au_writel(1 << bit, icr[2]); - au_writel(1 << bit, icr[1]); - au_writel(1 << bit, icr[3]); + __raw_writel(1 << bit, base + IC_CFG2SET); + __raw_writel(1 << bit, base + IC_CFG1SET); + __raw_writel(1 << bit, base + IC_CFG0CLR); handler = handle_level_irq; name = "lowlevel"; break; case IRQ_TYPE_NONE: /* 0:0:0 */ - au_writel(1 << bit, icr[5]); - au_writel(1 << bit, icr[4]); - au_writel(1 << bit, icr[3]); + __raw_writel(1 << bit, base + IC_CFG2CLR); + __raw_writel(1 << bit, base + IC_CFG1CLR); + __raw_writel(1 << bit, base + IC_CFG0CLR); break; default: ret = -EINVAL; } __irq_set_chip_handler_name_locked(d->irq, chip, handler, name); - au_sync(); + wmb(); return ret; } @@ -444,21 +479,21 @@ asmlinkage void plat_irq_dispatch(void) off = MIPS_CPU_IRQ_BASE + 7; goto handle; } else if (pending & CAUSEF_IP2) { - s = IC0_REQ0INT; + s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ0INT; off = AU1000_INTC0_INT_BASE; } else if (pending & CAUSEF_IP3) { - s = IC0_REQ1INT; + s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ1INT; off = AU1000_INTC0_INT_BASE; } else if (pending & CAUSEF_IP4) { - s = IC1_REQ0INT; + s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ0INT; off = AU1000_INTC1_INT_BASE; } else if (pending & CAUSEF_IP5) { - s = IC1_REQ1INT; + s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ1INT; off = AU1000_INTC1_INT_BASE; } else goto spurious; - s = au_readl(s); + s = __raw_readl((void __iomem *)s); if (unlikely(!s)) { spurious: spurious_interrupt(); @@ -469,48 +504,42 @@ asmlinkage void plat_irq_dispatch(void) do_IRQ(off); } + +static inline void ic_init(void __iomem *base) +{ + /* initialize interrupt controller to a safe state */ + __raw_writel(0xffffffff, base + IC_CFG0CLR); + __raw_writel(0xffffffff, base + IC_CFG1CLR); + __raw_writel(0xffffffff, base + IC_CFG2CLR); + __raw_writel(0xffffffff, base + IC_MASKCLR); + __raw_writel(0xffffffff, base + IC_ASSIGNCLR); + __raw_writel(0xffffffff, base + IC_WAKECLR); + __raw_writel(0xffffffff, base + IC_SRCSET); + __raw_writel(0xffffffff, base + IC_FALLINGCLR); + __raw_writel(0xffffffff, base + IC_RISINGCLR); + __raw_writel(0x00000000, base + IC_TESTBIT); + wmb(); +} + static void __init au1000_init_irq(struct au1xxx_irqmap *map) { unsigned int bit, irq_nr; - int i; - - /* - * Initialize interrupt controllers to a safe state. - */ - au_writel(0xffffffff, IC0_CFG0CLR); - au_writel(0xffffffff, IC0_CFG1CLR); - au_writel(0xffffffff, IC0_CFG2CLR); - au_writel(0xffffffff, IC0_MASKCLR); - au_writel(0xffffffff, IC0_ASSIGNCLR); - au_writel(0xffffffff, IC0_WAKECLR); - au_writel(0xffffffff, IC0_SRCSET); - au_writel(0xffffffff, IC0_FALLINGCLR); - au_writel(0xffffffff, IC0_RISINGCLR); - au_writel(0x00000000, IC0_TESTBIT); - - au_writel(0xffffffff, IC1_CFG0CLR); - au_writel(0xffffffff, IC1_CFG1CLR); - au_writel(0xffffffff, IC1_CFG2CLR); - au_writel(0xffffffff, IC1_MASKCLR); - au_writel(0xffffffff, IC1_ASSIGNCLR); - au_writel(0xffffffff, IC1_WAKECLR); - au_writel(0xffffffff, IC1_SRCSET); - au_writel(0xffffffff, IC1_FALLINGCLR); - au_writel(0xffffffff, IC1_RISINGCLR); - au_writel(0x00000000, IC1_TESTBIT); + void __iomem *base; + ic_init((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR)); + ic_init((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR)); mips_cpu_irq_init(); /* register all 64 possible IC0+IC1 irq sources as type "none". * Use set_irq_type() to set edge/level behaviour at runtime. */ - for (i = AU1000_INTC0_INT_BASE; - (i < AU1000_INTC0_INT_BASE + 32); i++) - au1x_ic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE); + for (irq_nr = AU1000_INTC0_INT_BASE; + (irq_nr < AU1000_INTC0_INT_BASE + 32); irq_nr++) + au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE); - for (i = AU1000_INTC1_INT_BASE; - (i < AU1000_INTC1_INT_BASE + 32); i++) - au1x_ic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE); + for (irq_nr = AU1000_INTC1_INT_BASE; + (irq_nr < AU1000_INTC1_INT_BASE + 32); irq_nr++) + au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE); /* * Initialize IC0, which is fixed per processor. @@ -520,13 +549,13 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map) if (irq_nr >= AU1000_INTC1_INT_BASE) { bit = irq_nr - AU1000_INTC1_INT_BASE; - if (map->im_request) - au_writel(1 << bit, IC1_ASSIGNSET); + base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); } else { bit = irq_nr - AU1000_INTC0_INT_BASE; - if (map->im_request) - au_writel(1 << bit, IC0_ASSIGNSET); + base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); } + if (map->im_request) + __raw_writel(1 << bit, base + IC_ASSIGNSET); au1x_ic_settype(irq_get_irq_data(irq_nr), map->im_type); ++map; @@ -556,90 +585,62 @@ void __init arch_init_irq(void) } } -struct alchemy_ic_sysdev { - struct sys_device sysdev; - void __iomem *base; - unsigned long pmdata[7]; -}; -static int alchemy_ic_suspend(struct sys_device *dev, pm_message_t state) +static unsigned long alchemy_ic_pmdata[7 * 2]; + +static inline void alchemy_ic_suspend_one(void __iomem *base, unsigned long *d) { - struct alchemy_ic_sysdev *icdev = - container_of(dev, struct alchemy_ic_sysdev, sysdev); + d[0] = __raw_readl(base + IC_CFG0RD); + d[1] = __raw_readl(base + IC_CFG1RD); + d[2] = __raw_readl(base + IC_CFG2RD); + d[3] = __raw_readl(base + IC_SRCRD); + d[4] = __raw_readl(base + IC_ASSIGNRD); + d[5] = __raw_readl(base + IC_WAKERD); + d[6] = __raw_readl(base + IC_MASKRD); + ic_init(base); /* shut it up too while at it */ +} - icdev->pmdata[0] = __raw_readl(icdev->base + IC_CFG0RD); - icdev->pmdata[1] = __raw_readl(icdev->base + IC_CFG1RD); - icdev->pmdata[2] = __raw_readl(icdev->base + IC_CFG2RD); - icdev->pmdata[3] = __raw_readl(icdev->base + IC_SRCRD); - icdev->pmdata[4] = __raw_readl(icdev->base + IC_ASSIGNRD); - icdev->pmdata[5] = __raw_readl(icdev->base + IC_WAKERD); - icdev->pmdata[6] = __raw_readl(icdev->base + IC_MASKRD); +static inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d) +{ + ic_init(base); + __raw_writel(d[0], base + IC_CFG0SET); + __raw_writel(d[1], base + IC_CFG1SET); + __raw_writel(d[2], base + IC_CFG2SET); + __raw_writel(d[3], base + IC_SRCSET); + __raw_writel(d[4], base + IC_ASSIGNSET); + __raw_writel(d[5], base + IC_WAKESET); + wmb(); + + __raw_writel(d[6], base + IC_MASKSET); + wmb(); +} + +static int alchemy_ic_suspend(void) +{ + alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), + alchemy_ic_pmdata); + alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), + &alchemy_ic_pmdata[7]); return 0; } -static int alchemy_ic_resume(struct sys_device *dev) +static void alchemy_ic_resume(void) { - struct alchemy_ic_sysdev *icdev = - container_of(dev, struct alchemy_ic_sysdev, sysdev); - - __raw_writel(0xffffffff, icdev->base + IC_MASKCLR); - __raw_writel(0xffffffff, icdev->base + IC_CFG0CLR); - __raw_writel(0xffffffff, icdev->base + IC_CFG1CLR); - __raw_writel(0xffffffff, icdev->base + IC_CFG2CLR); - __raw_writel(0xffffffff, icdev->base + IC_SRCCLR); - __raw_writel(0xffffffff, icdev->base + IC_ASSIGNCLR); - __raw_writel(0xffffffff, icdev->base + IC_WAKECLR); - __raw_writel(0xffffffff, icdev->base + IC_RISINGCLR); - __raw_writel(0xffffffff, icdev->base + IC_FALLINGCLR); - __raw_writel(0x00000000, icdev->base + IC_TESTBIT); - wmb(); - __raw_writel(icdev->pmdata[0], icdev->base + IC_CFG0SET); - __raw_writel(icdev->pmdata[1], icdev->base + IC_CFG1SET); - __raw_writel(icdev->pmdata[2], icdev->base + IC_CFG2SET); - __raw_writel(icdev->pmdata[3], icdev->base + IC_SRCSET); - __raw_writel(icdev->pmdata[4], icdev->base + IC_ASSIGNSET); - __raw_writel(icdev->pmdata[5], icdev->base + IC_WAKESET); - wmb(); - - __raw_writel(icdev->pmdata[6], icdev->base + IC_MASKSET); - wmb(); - - return 0; + alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), + &alchemy_ic_pmdata[7]); + alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), + alchemy_ic_pmdata); } -static struct sysdev_class alchemy_ic_sysdev_class = { - .name = "ic", +static struct syscore_ops alchemy_ic_syscore_ops = { .suspend = alchemy_ic_suspend, .resume = alchemy_ic_resume, }; -static int __init alchemy_ic_sysdev_init(void) +static int __init alchemy_ic_pm_init(void) { - struct alchemy_ic_sysdev *icdev; - unsigned long icbase[2] = { IC0_PHYS_ADDR, IC1_PHYS_ADDR }; - int err, i; - - err = sysdev_class_register(&alchemy_ic_sysdev_class); - if (err) - return err; - - for (i = 0; i < 2; i++) { - icdev = kzalloc(sizeof(struct alchemy_ic_sysdev), GFP_KERNEL); - if (!icdev) - return -ENOMEM; - - icdev->base = ioremap(icbase[i], 0x1000); - - icdev->sysdev.id = i; - icdev->sysdev.cls = &alchemy_ic_sysdev_class; - err = sysdev_register(&icdev->sysdev); - if (err) { - kfree(icdev); - return err; - } - } - + register_syscore_ops(&alchemy_ic_syscore_ops); return 0; } -device_initcall(alchemy_ic_sysdev_init); +device_initcall(alchemy_ic_pm_init); diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c index 9e7814db3d03..3b2c18b14341 100644 --- a/arch/mips/alchemy/common/platform.c +++ b/arch/mips/alchemy/common/platform.c @@ -13,9 +13,10 @@ #include #include +#include #include #include -#include +#include #include #include @@ -30,21 +31,12 @@ static void alchemy_8250_pm(struct uart_port *port, unsigned int state, #ifdef CONFIG_SERIAL_8250 switch (state) { case 0: - if ((__raw_readl(port->membase + UART_MOD_CNTRL) & 3) != 3) { - /* power-on sequence as suggested in the databooks */ - __raw_writel(0, port->membase + UART_MOD_CNTRL); - wmb(); - __raw_writel(1, port->membase + UART_MOD_CNTRL); - wmb(); - } - __raw_writel(3, port->membase + UART_MOD_CNTRL); /* full on */ - wmb(); + alchemy_uart_enable(CPHYSADDR(port->membase)); serial8250_do_pm(port, state, old_state); break; case 3: /* power off */ serial8250_do_pm(port, state, old_state); - __raw_writel(0, port->membase + UART_MOD_CNTRL); - wmb(); + alchemy_uart_disable(CPHYSADDR(port->membase)); break; default: serial8250_do_pm(port, state, old_state); @@ -65,38 +57,60 @@ static void alchemy_8250_pm(struct uart_port *port, unsigned int state, .pm = alchemy_8250_pm, \ } -static struct plat_serial8250_port au1x00_uart_data[] = { -#if defined(CONFIG_SOC_AU1000) - PORT(UART0_PHYS_ADDR, AU1000_UART0_INT), - PORT(UART1_PHYS_ADDR, AU1000_UART1_INT), - PORT(UART2_PHYS_ADDR, AU1000_UART2_INT), - PORT(UART3_PHYS_ADDR, AU1000_UART3_INT), -#elif defined(CONFIG_SOC_AU1500) - PORT(UART0_PHYS_ADDR, AU1500_UART0_INT), - PORT(UART3_PHYS_ADDR, AU1500_UART3_INT), -#elif defined(CONFIG_SOC_AU1100) - PORT(UART0_PHYS_ADDR, AU1100_UART0_INT), - PORT(UART1_PHYS_ADDR, AU1100_UART1_INT), - PORT(UART3_PHYS_ADDR, AU1100_UART3_INT), -#elif defined(CONFIG_SOC_AU1550) - PORT(UART0_PHYS_ADDR, AU1550_UART0_INT), - PORT(UART1_PHYS_ADDR, AU1550_UART1_INT), - PORT(UART3_PHYS_ADDR, AU1550_UART3_INT), -#elif defined(CONFIG_SOC_AU1200) - PORT(UART0_PHYS_ADDR, AU1200_UART0_INT), - PORT(UART1_PHYS_ADDR, AU1200_UART1_INT), -#endif - { }, +static struct plat_serial8250_port au1x00_uart_data[][4] __initdata = { + [ALCHEMY_CPU_AU1000] = { + PORT(AU1000_UART0_PHYS_ADDR, AU1000_UART0_INT), + PORT(AU1000_UART1_PHYS_ADDR, AU1000_UART1_INT), + PORT(AU1000_UART2_PHYS_ADDR, AU1000_UART2_INT), + PORT(AU1000_UART3_PHYS_ADDR, AU1000_UART3_INT), + }, + [ALCHEMY_CPU_AU1500] = { + PORT(AU1000_UART0_PHYS_ADDR, AU1500_UART0_INT), + PORT(AU1000_UART3_PHYS_ADDR, AU1500_UART3_INT), + }, + [ALCHEMY_CPU_AU1100] = { + PORT(AU1000_UART0_PHYS_ADDR, AU1100_UART0_INT), + PORT(AU1000_UART1_PHYS_ADDR, AU1100_UART1_INT), + PORT(AU1000_UART3_PHYS_ADDR, AU1100_UART3_INT), + }, + [ALCHEMY_CPU_AU1550] = { + PORT(AU1000_UART0_PHYS_ADDR, AU1550_UART0_INT), + PORT(AU1000_UART1_PHYS_ADDR, AU1550_UART1_INT), + PORT(AU1000_UART3_PHYS_ADDR, AU1550_UART3_INT), + }, + [ALCHEMY_CPU_AU1200] = { + PORT(AU1000_UART0_PHYS_ADDR, AU1200_UART0_INT), + PORT(AU1000_UART1_PHYS_ADDR, AU1200_UART1_INT), + }, }; static struct platform_device au1xx0_uart_device = { .name = "serial8250", .id = PLAT8250_DEV_AU1X00, - .dev = { - .platform_data = au1x00_uart_data, - }, }; +static void __init alchemy_setup_uarts(int ctype) +{ + unsigned int uartclk = get_au1x00_uart_baud_base() * 16; + int s = sizeof(struct plat_serial8250_port); + int c = alchemy_get_uarts(ctype); + struct plat_serial8250_port *ports; + + ports = kzalloc(s * (c + 1), GFP_KERNEL); + if (!ports) { + printk(KERN_INFO "Alchemy: no memory for UART data\n"); + return; + } + memcpy(ports, au1x00_uart_data[ctype], s * c); + au1xx0_uart_device.dev.platform_data = ports; + + /* Fill up uartclk. */ + for (s = 0; s < c; s++) + ports[s].uartclk = uartclk; + if (platform_device_register(&au1xx0_uart_device)) + printk(KERN_INFO "Alchemy: failed to register UARTs\n"); +} + /* OHCI (USB full speed host controller) */ static struct resource au1xxx_usb_ohci_resources[] = { [0] = { @@ -269,8 +283,8 @@ extern struct au1xmmc_platform_data au1xmmc_platdata[2]; static struct resource au1200_mmc0_resources[] = { [0] = { - .start = SD0_PHYS_ADDR, - .end = SD0_PHYS_ADDR + 0x7ffff, + .start = AU1100_SD0_PHYS_ADDR, + .end = AU1100_SD0_PHYS_ADDR + 0xfff, .flags = IORESOURCE_MEM, }, [1] = { @@ -305,8 +319,8 @@ static struct platform_device au1200_mmc0_device = { #ifndef CONFIG_MIPS_DB1200 static struct resource au1200_mmc1_resources[] = { [0] = { - .start = SD1_PHYS_ADDR, - .end = SD1_PHYS_ADDR + 0x7ffff, + .start = AU1100_SD1_PHYS_ADDR, + .end = AU1100_SD1_PHYS_ADDR + 0xfff, .flags = IORESOURCE_MEM, }, [1] = { @@ -359,15 +373,16 @@ static struct platform_device pbdb_smbus_device = { #endif /* Macro to help defining the Ethernet MAC resources */ +#define MAC_RES_COUNT 3 /* MAC regs base, MAC enable reg, MAC INT */ #define MAC_RES(_base, _enable, _irq) \ { \ - .start = CPHYSADDR(_base), \ - .end = CPHYSADDR(_base + 0xffff), \ + .start = _base, \ + .end = _base + 0xffff, \ .flags = IORESOURCE_MEM, \ }, \ { \ - .start = CPHYSADDR(_enable), \ - .end = CPHYSADDR(_enable + 0x3), \ + .start = _enable, \ + .end = _enable + 0x3, \ .flags = IORESOURCE_MEM, \ }, \ { \ @@ -376,19 +391,29 @@ static struct platform_device pbdb_smbus_device = { .flags = IORESOURCE_IRQ \ } -static struct resource au1xxx_eth0_resources[] = { -#if defined(CONFIG_SOC_AU1000) - MAC_RES(AU1000_ETH0_BASE, AU1000_MAC0_ENABLE, AU1000_MAC0_DMA_INT), -#elif defined(CONFIG_SOC_AU1100) - MAC_RES(AU1100_ETH0_BASE, AU1100_MAC0_ENABLE, AU1100_MAC0_DMA_INT), -#elif defined(CONFIG_SOC_AU1550) - MAC_RES(AU1550_ETH0_BASE, AU1550_MAC0_ENABLE, AU1550_MAC0_DMA_INT), -#elif defined(CONFIG_SOC_AU1500) - MAC_RES(AU1500_ETH0_BASE, AU1500_MAC0_ENABLE, AU1500_MAC0_DMA_INT), -#endif +static struct resource au1xxx_eth0_resources[][MAC_RES_COUNT] __initdata = { + [ALCHEMY_CPU_AU1000] = { + MAC_RES(AU1000_MAC0_PHYS_ADDR, + AU1000_MACEN_PHYS_ADDR, + AU1000_MAC0_DMA_INT) + }, + [ALCHEMY_CPU_AU1500] = { + MAC_RES(AU1500_MAC0_PHYS_ADDR, + AU1500_MACEN_PHYS_ADDR, + AU1500_MAC0_DMA_INT) + }, + [ALCHEMY_CPU_AU1100] = { + MAC_RES(AU1000_MAC0_PHYS_ADDR, + AU1000_MACEN_PHYS_ADDR, + AU1100_MAC0_DMA_INT) + }, + [ALCHEMY_CPU_AU1550] = { + MAC_RES(AU1000_MAC0_PHYS_ADDR, + AU1000_MACEN_PHYS_ADDR, + AU1550_MAC0_DMA_INT) + }, }; - static struct au1000_eth_platform_data au1xxx_eth0_platform_data = { .phy1_search_mac0 = 1, }; @@ -396,20 +421,26 @@ static struct au1000_eth_platform_data au1xxx_eth0_platform_data = { static struct platform_device au1xxx_eth0_device = { .name = "au1000-eth", .id = 0, - .num_resources = ARRAY_SIZE(au1xxx_eth0_resources), - .resource = au1xxx_eth0_resources, + .num_resources = MAC_RES_COUNT, .dev.platform_data = &au1xxx_eth0_platform_data, }; -#ifndef CONFIG_SOC_AU1100 -static struct resource au1xxx_eth1_resources[] = { -#if defined(CONFIG_SOC_AU1000) - MAC_RES(AU1000_ETH1_BASE, AU1000_MAC1_ENABLE, AU1000_MAC1_DMA_INT), -#elif defined(CONFIG_SOC_AU1550) - MAC_RES(AU1550_ETH1_BASE, AU1550_MAC1_ENABLE, AU1550_MAC1_DMA_INT), -#elif defined(CONFIG_SOC_AU1500) - MAC_RES(AU1500_ETH1_BASE, AU1500_MAC1_ENABLE, AU1500_MAC1_DMA_INT), -#endif +static struct resource au1xxx_eth1_resources[][MAC_RES_COUNT] __initdata = { + [ALCHEMY_CPU_AU1000] = { + MAC_RES(AU1000_MAC1_PHYS_ADDR, + AU1000_MACEN_PHYS_ADDR + 4, + AU1000_MAC1_DMA_INT) + }, + [ALCHEMY_CPU_AU1500] = { + MAC_RES(AU1500_MAC1_PHYS_ADDR, + AU1500_MACEN_PHYS_ADDR + 4, + AU1500_MAC1_DMA_INT) + }, + [ALCHEMY_CPU_AU1550] = { + MAC_RES(AU1000_MAC1_PHYS_ADDR, + AU1000_MACEN_PHYS_ADDR + 4, + AU1550_MAC1_DMA_INT) + }, }; static struct au1000_eth_platform_data au1xxx_eth1_platform_data = { @@ -419,11 +450,9 @@ static struct au1000_eth_platform_data au1xxx_eth1_platform_data = { static struct platform_device au1xxx_eth1_device = { .name = "au1000-eth", .id = 1, - .num_resources = ARRAY_SIZE(au1xxx_eth1_resources), - .resource = au1xxx_eth1_resources, + .num_resources = MAC_RES_COUNT, .dev.platform_data = &au1xxx_eth1_platform_data, }; -#endif void __init au1xxx_override_eth_cfg(unsigned int port, struct au1000_eth_platform_data *eth_data) @@ -434,15 +463,65 @@ void __init au1xxx_override_eth_cfg(unsigned int port, if (port == 0) memcpy(&au1xxx_eth0_platform_data, eth_data, sizeof(struct au1000_eth_platform_data)); -#ifndef CONFIG_SOC_AU1100 else memcpy(&au1xxx_eth1_platform_data, eth_data, sizeof(struct au1000_eth_platform_data)); -#endif +} + +static void __init alchemy_setup_macs(int ctype) +{ + int ret, i; + unsigned char ethaddr[6]; + struct resource *macres; + + /* Handle 1st MAC */ + if (alchemy_get_macs(ctype) < 1) + return; + + macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL); + if (!macres) { + printk(KERN_INFO "Alchemy: no memory for MAC0 resources\n"); + return; + } + memcpy(macres, au1xxx_eth0_resources[ctype], + sizeof(struct resource) * MAC_RES_COUNT); + au1xxx_eth0_device.resource = macres; + + i = prom_get_ethernet_addr(ethaddr); + if (!i && !is_valid_ether_addr(au1xxx_eth0_platform_data.mac)) + memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6); + + ret = platform_device_register(&au1xxx_eth0_device); + if (!ret) + printk(KERN_INFO "Alchemy: failed to register MAC0\n"); + + + /* Handle 2nd MAC */ + if (alchemy_get_macs(ctype) < 2) + return; + + macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL); + if (!macres) { + printk(KERN_INFO "Alchemy: no memory for MAC1 resources\n"); + return; + } + memcpy(macres, au1xxx_eth1_resources[ctype], + sizeof(struct resource) * MAC_RES_COUNT); + au1xxx_eth1_device.resource = macres; + + ethaddr[5] += 1; /* next addr for 2nd MAC */ + if (!i && !is_valid_ether_addr(au1xxx_eth1_platform_data.mac)) + memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6); + + /* Register second MAC if enabled in pinfunc */ + if (!(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2)) { + ret = platform_device_register(&au1xxx_eth1_device); + if (ret) + printk(KERN_INFO "Alchemy: failed to register MAC1\n"); + } } static struct platform_device *au1xxx_platform_devices[] __initdata = { - &au1xx0_uart_device, &au1xxx_usb_ohci_device, #ifdef CONFIG_FB_AU1100 &au1100_lcd_device, @@ -460,36 +539,17 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = { #ifdef SMBUS_PSC_BASE &pbdb_smbus_device, #endif - &au1xxx_eth0_device, }; static int __init au1xxx_platform_init(void) { - unsigned int uartclk = get_au1x00_uart_baud_base() * 16; - int err, i; - unsigned char ethaddr[6]; + int err, ctype = alchemy_get_cputype(); - /* Fill up uartclk. */ - for (i = 0; au1x00_uart_data[i].flags; i++) - au1x00_uart_data[i].uartclk = uartclk; - - /* use firmware-provided mac addr if available and necessary */ - i = prom_get_ethernet_addr(ethaddr); - if (!i && !is_valid_ether_addr(au1xxx_eth0_platform_data.mac)) - memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6); + alchemy_setup_uarts(ctype); + alchemy_setup_macs(ctype); err = platform_add_devices(au1xxx_platform_devices, ARRAY_SIZE(au1xxx_platform_devices)); -#ifndef CONFIG_SOC_AU1100 - ethaddr[5] += 1; /* next addr for 2nd MAC */ - if (!i && !is_valid_ether_addr(au1xxx_eth1_platform_data.mac)) - memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6); - - /* Register second MAC if enabled in pinfunc */ - if (!err && !(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2)) - err = platform_device_register(&au1xxx_eth1_device); -#endif - return err; } diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c index 561e5da2658b..1b887c868417 100644 --- a/arch/mips/alchemy/common/setup.c +++ b/arch/mips/alchemy/common/setup.c @@ -52,8 +52,6 @@ void __init plat_mem_setup(void) /* this is faster than wasting cycles trying to approximate it */ preset_lpj = (est_freq >> 1) / HZ; - board_setup(); /* board specific setup */ - if (au1xxx_cpu_needs_config_od()) /* Various early Au1xx0 errata corrected by this */ set_c0_config(1 << 19); /* Set Config[OD] */ @@ -61,6 +59,8 @@ void __init plat_mem_setup(void) /* Clear to obtain best system bus performance */ clear_c0_config(1 << 19); /* Clear Config[OD] */ + board_setup(); /* board specific setup */ + /* IO/MEM resources. */ set_io_port_base(0); ioport_resource.start = IOPORT_RESOURCE_START; diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c index 2aecb2fdf982..d5da6adbf634 100644 --- a/arch/mips/alchemy/common/time.c +++ b/arch/mips/alchemy/common/time.c @@ -141,8 +141,7 @@ static int __init alchemy_time_init(unsigned int m2int) goto cntr_err; /* register counter1 clocksource and event device */ - clocksource_set_clock(&au1x_counter1_clocksource, 32768); - clocksource_register(&au1x_counter1_clocksource); + clocksource_register_hz(&au1x_counter1_clocksource, 32768); cd->shift = 32; cd->mult = div_sc(32768, NSEC_PER_SEC, cd->shift); diff --git a/arch/mips/alchemy/devboards/db1200/setup.c b/arch/mips/alchemy/devboards/db1200/setup.c index 4a8980027ecf..1dac4f27d334 100644 --- a/arch/mips/alchemy/devboards/db1200/setup.c +++ b/arch/mips/alchemy/devboards/db1200/setup.c @@ -23,6 +23,13 @@ void __init board_setup(void) unsigned long freq0, clksrc, div, pfc; unsigned short whoami; + /* Set Config[OD] (disable overlapping bus transaction): + * This gets rid of a _lot_ of spurious interrupts (especially + * wrt. IDE); but incurs ~10% performance hit in some + * cpu-bound applications. + */ + set_c0_config(1 << 19); + bcsr_init(DB1200_BCSR_PHYS_ADDR, DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS); diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c index 05f120ff90f9..5c956fe8760f 100644 --- a/arch/mips/alchemy/devboards/db1x00/board_setup.c +++ b/arch/mips/alchemy/devboards/db1x00/board_setup.c @@ -127,13 +127,10 @@ const char *get_system_type(void) void __init board_setup(void) { unsigned long bcsr1, bcsr2; - u32 pin_func; bcsr1 = DB1000_BCSR_PHYS_ADDR; bcsr2 = DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS; - pin_func = 0; - #ifdef CONFIG_MIPS_DB1000 printk(KERN_INFO "AMD Alchemy Au1000/Db1000 Board\n"); #endif @@ -164,12 +161,16 @@ void __init board_setup(void) /* Not valid for Au1550 */ #if defined(CONFIG_IRDA) && \ (defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100)) - /* Set IRFIRSEL instead of GPIO15 */ - pin_func = au_readl(SYS_PINFUNC) | SYS_PF_IRF; - au_writel(pin_func, SYS_PINFUNC); - /* Power off until the driver is in use */ - bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK, - BCSR_RESETS_IRDA_MODE_OFF); + { + u32 pin_func; + + /* Set IRFIRSEL instead of GPIO15 */ + pin_func = au_readl(SYS_PINFUNC) | SYS_PF_IRF; + au_writel(pin_func, SYS_PINFUNC); + /* Power off until the driver is in use */ + bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK, + BCSR_RESETS_IRDA_MODE_OFF); + } #endif bcsr_write(BCSR_PCMCIA, 0); /* turn off PCMCIA power */ @@ -177,31 +178,35 @@ void __init board_setup(void) alchemy_gpio1_input_enable(); #ifdef CONFIG_MIPS_MIRAGE - /* GPIO[20] is output */ - alchemy_gpio_direction_output(20, 0); + { + u32 pin_func; - /* Set GPIO[210:208] instead of SSI_0 */ - pin_func = au_readl(SYS_PINFUNC) | SYS_PF_S0; + /* GPIO[20] is output */ + alchemy_gpio_direction_output(20, 0); - /* Set GPIO[215:211] for LEDs */ - pin_func |= 5 << 2; + /* Set GPIO[210:208] instead of SSI_0 */ + pin_func = au_readl(SYS_PINFUNC) | SYS_PF_S0; - /* Set GPIO[214:213] for more LEDs */ - pin_func |= 5 << 12; + /* Set GPIO[215:211] for LEDs */ + pin_func |= 5 << 2; - /* Set GPIO[207:200] instead of PCMCIA/LCD */ - pin_func |= SYS_PF_LCD | SYS_PF_PC; - au_writel(pin_func, SYS_PINFUNC); + /* Set GPIO[214:213] for more LEDs */ + pin_func |= 5 << 12; - /* - * Enable speaker amplifier. This should - * be part of the audio driver. - */ - alchemy_gpio_direction_output(209, 1); + /* Set GPIO[207:200] instead of PCMCIA/LCD */ + pin_func |= SYS_PF_LCD | SYS_PF_PC; + au_writel(pin_func, SYS_PINFUNC); - pm_power_off = mirage_power_off; - _machine_halt = mirage_power_off; - _machine_restart = (void(*)(char *))mips_softreset; + /* + * Enable speaker amplifier. This should + * be part of the audio driver. + */ + alchemy_gpio_direction_output(209, 1); + + pm_power_off = mirage_power_off; + _machine_halt = mirage_power_off; + _machine_restart = (void(*)(char *))mips_softreset; + } #endif #ifdef CONFIG_MIPS_BOSPORUS diff --git a/arch/mips/alchemy/devboards/pb1000/board_setup.c b/arch/mips/alchemy/devboards/pb1000/board_setup.c index 2d85c4b5be09..e64fdcbf75d0 100644 --- a/arch/mips/alchemy/devboards/pb1000/board_setup.c +++ b/arch/mips/alchemy/devboards/pb1000/board_setup.c @@ -65,7 +65,7 @@ void __init board_setup(void) /* Set AUX clock to 12 MHz * 8 = 96 MHz */ au_writel(8, SYS_AUXPLL); - au_writel(0, SYS_PINSTATERD); + alchemy_gpio1_input_enable(); udelay(100); #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) diff --git a/arch/mips/alchemy/devboards/pb1500/board_setup.c b/arch/mips/alchemy/devboards/pb1500/board_setup.c index 83f46215eb0c..3b4fa3206969 100644 --- a/arch/mips/alchemy/devboards/pb1500/board_setup.c +++ b/arch/mips/alchemy/devboards/pb1500/board_setup.c @@ -56,7 +56,7 @@ void __init board_setup(void) sys_clksrc = sys_freqctrl = pin_func = 0; /* Set AUX clock to 12 MHz * 8 = 96 MHz */ au_writel(8, SYS_AUXPLL); - au_writel(0, SYS_PINSTATERD); + alchemy_gpio1_input_enable(); udelay(100); /* GPIO201 is input for PCMCIA card detect */ diff --git a/arch/mips/alchemy/devboards/prom.c b/arch/mips/alchemy/devboards/prom.c index baeb21385058..e5306b56da6d 100644 --- a/arch/mips/alchemy/devboards/prom.c +++ b/arch/mips/alchemy/devboards/prom.c @@ -62,5 +62,5 @@ void __init prom_init(void) void prom_putchar(unsigned char c) { - alchemy_uart_putchar(UART0_PHYS_ADDR, c); + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); } diff --git a/arch/mips/alchemy/gpr/board_setup.c b/arch/mips/alchemy/gpr/board_setup.c index ad2e3f137933..5f8f0691ed2d 100644 --- a/arch/mips/alchemy/gpr/board_setup.c +++ b/arch/mips/alchemy/gpr/board_setup.c @@ -36,9 +36,6 @@ #include -#define UART1_ADDR KSEG1ADDR(UART1_PHYS_ADDR) -#define UART3_ADDR KSEG1ADDR(UART3_PHYS_ADDR) - char irq_tab_alchemy[][5] __initdata = { [0] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, }; @@ -67,18 +64,15 @@ static void gpr_power_off(void) void __init board_setup(void) { - printk(KERN_INFO "Tarpeze ITS GPR board\n"); + printk(KERN_INFO "Trapeze ITS GPR board\n"); pm_power_off = gpr_power_off; _machine_halt = gpr_power_off; _machine_restart = gpr_reset; - /* Enable UART3 */ - au_writel(0x1, UART3_ADDR + UART_MOD_CNTRL);/* clock enable (CE) */ - au_writel(0x3, UART3_ADDR + UART_MOD_CNTRL); /* CE and "enable" */ - /* Enable UART1 */ - au_writel(0x1, UART1_ADDR + UART_MOD_CNTRL); /* clock enable (CE) */ - au_writel(0x3, UART1_ADDR + UART_MOD_CNTRL); /* CE and "enable" */ + /* Enable UART1/3 */ + alchemy_uart_enable(AU1000_UART3_PHYS_ADDR); + alchemy_uart_enable(AU1000_UART1_PHYS_ADDR); /* Take away Reset of UMTS-card */ alchemy_gpio_direction_output(215, 1); diff --git a/arch/mips/alchemy/gpr/init.c b/arch/mips/alchemy/gpr/init.c index f044f4c541d7..229aafae680c 100644 --- a/arch/mips/alchemy/gpr/init.c +++ b/arch/mips/alchemy/gpr/init.c @@ -59,5 +59,5 @@ void __init prom_init(void) void prom_putchar(unsigned char c) { - alchemy_uart_putchar(UART0_PHYS_ADDR, c); + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); } diff --git a/arch/mips/alchemy/mtx-1/board_setup.c b/arch/mips/alchemy/mtx-1/board_setup.c index cf436ab679ae..3ae984cf98cf 100644 --- a/arch/mips/alchemy/mtx-1/board_setup.c +++ b/arch/mips/alchemy/mtx-1/board_setup.c @@ -87,7 +87,7 @@ void __init board_setup(void) au_writel(SYS_PF_NI2, SYS_PINFUNC); /* Initialize GPIO */ - au_writel(0xFFFFFFFF, SYS_TRIOUTCLR); + au_writel(~0, KSEG1ADDR(AU1000_SYS_PHYS_ADDR) + SYS_TRIOUTCLR); alchemy_gpio_direction_output(0, 0); /* Disable M66EN (PCI 66MHz) */ alchemy_gpio_direction_output(3, 1); /* Disable PCI CLKRUN# */ alchemy_gpio_direction_output(1, 1); /* Enable EXT_IO3 */ diff --git a/arch/mips/alchemy/mtx-1/init.c b/arch/mips/alchemy/mtx-1/init.c index f8d25575fa05..2e81cc7f3422 100644 --- a/arch/mips/alchemy/mtx-1/init.c +++ b/arch/mips/alchemy/mtx-1/init.c @@ -62,5 +62,5 @@ void __init prom_init(void) void prom_putchar(unsigned char c) { - alchemy_uart_putchar(UART0_PHYS_ADDR, c); + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); } diff --git a/arch/mips/alchemy/mtx-1/platform.c b/arch/mips/alchemy/mtx-1/platform.c index 956f946218c5..55628e390fd7 100644 --- a/arch/mips/alchemy/mtx-1/platform.c +++ b/arch/mips/alchemy/mtx-1/platform.c @@ -53,8 +53,8 @@ static struct platform_device mtx1_button = { static struct resource mtx1_wdt_res[] = { [0] = { - .start = 15, - .end = 15, + .start = 215, + .end = 215, .name = "mtx1-wdt-gpio", .flags = IORESOURCE_IRQ, } diff --git a/arch/mips/alchemy/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c index febfb0fb0896..81e57fad07ab 100644 --- a/arch/mips/alchemy/xxs1500/board_setup.c +++ b/arch/mips/alchemy/xxs1500/board_setup.c @@ -66,13 +66,10 @@ void __init board_setup(void) au_writel(pin_func, SYS_PINFUNC); /* Enable UART */ - au_writel(0x01, UART3_ADDR + UART_MOD_CNTRL); /* clock enable (CE) */ - mdelay(10); - au_writel(0x03, UART3_ADDR + UART_MOD_CNTRL); /* CE and "enable" */ - mdelay(10); - - /* Enable DTR = USB power up */ - au_writel(0x01, UART3_ADDR + UART_MCR); /* UART_MCR_DTR is 0x01??? */ + alchemy_uart_enable(AU1000_UART3_PHYS_ADDR); + /* Enable DTR (MCR bit 0) = USB power up */ + __raw_writel(1, (void __iomem *)KSEG1ADDR(AU1000_UART3_PHYS_ADDR + 0x18)); + wmb(); #ifdef CONFIG_PCI #if defined(__MIPSEB__) diff --git a/arch/mips/alchemy/xxs1500/init.c b/arch/mips/alchemy/xxs1500/init.c index 15125c2fda7d..0ee02cfa989d 100644 --- a/arch/mips/alchemy/xxs1500/init.c +++ b/arch/mips/alchemy/xxs1500/init.c @@ -51,14 +51,13 @@ void __init prom_init(void) prom_init_cmdline(); memsize_str = prom_getenv("memsize"); - if (!memsize_str) + if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize)) memsize = 0x04000000; - else - strict_strtoul(memsize_str, 0, &memsize); + add_memory_region(0, memsize, BOOT_MEM_RAM); } void prom_putchar(unsigned char c) { - alchemy_uart_putchar(UART0_PHYS_ADDR, c); + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); } diff --git a/arch/mips/ar7/gpio.c b/arch/mips/ar7/gpio.c index 425dfa5d6e12..bb571bcdb8f2 100644 --- a/arch/mips/ar7/gpio.c +++ b/arch/mips/ar7/gpio.c @@ -325,9 +325,7 @@ int __init ar7_gpio_init(void) size = 0x1f; } - gpch->regs = ioremap_nocache(AR7_REGS_GPIO, - AR7_REGS_GPIO + 0x10); - + gpch->regs = ioremap_nocache(AR7_REGS_GPIO, size); if (!gpch->regs) { printk(KERN_ERR "%s: failed to ioremap regs\n", gpch->chip.label); diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index e5b6615731e5..54db815bc86c 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -3,6 +3,7 @@ * * Copyright (C) 2005 Broadcom Corporation * Copyright (C) 2006 Felix Fietkau + * Copyright (C) 2010-2011 Hauke Mehrtens * * 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 @@ -23,7 +24,7 @@ static char nvram_buf[NVRAM_SPACE]; /* Probe for NVRAM header */ -static void __init early_nvram_init(void) +static void early_nvram_init(void) { struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; struct nvram_header *header; diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index c95f90bf734c..73b529b57433 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -3,6 +3,7 @@ * Copyright (C) 2006 Felix Fietkau * Copyright (C) 2006 Michael Buesch * Copyright (C) 2010 Waldemar Brodkorb + * Copyright (C) 2010-2011 Hauke Mehrtens * * 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 @@ -57,10 +58,49 @@ static void bcm47xx_machine_halt(void) } #define READ_FROM_NVRAM(_outvar, name, buf) \ - if (nvram_getenv(name, buf, sizeof(buf)) >= 0)\ + if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\ sprom->_outvar = simple_strtoul(buf, NULL, 0); -static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) +#define READ_FROM_NVRAM2(_outvar, name1, name2, buf) \ + if (nvram_getprefix(prefix, name1, buf, sizeof(buf)) >= 0 || \ + nvram_getprefix(prefix, name2, buf, sizeof(buf)) >= 0)\ + sprom->_outvar = simple_strtoul(buf, NULL, 0); + +static inline int nvram_getprefix(const char *prefix, char *name, + char *buf, int len) +{ + if (prefix) { + char key[100]; + + snprintf(key, sizeof(key), "%s%s", prefix, name); + return nvram_getenv(key, buf, len); + } + + return nvram_getenv(name, buf, len); +} + +static u32 nvram_getu32(const char *name, char *buf, int len) +{ + int rv; + char key[100]; + u16 var0, var1; + + snprintf(key, sizeof(key), "%s0", name); + rv = nvram_getenv(key, buf, len); + /* return 0 here so this looks like unset */ + if (rv < 0) + return 0; + var0 = simple_strtoul(buf, NULL, 0); + + snprintf(key, sizeof(key), "%s1", name); + rv = nvram_getenv(key, buf, len); + if (rv < 0) + return 0; + var1 = simple_strtoul(buf, NULL, 0); + return var1 << 16 | var0; +} + +static void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix) { char buf[100]; u32 boardflags; @@ -69,11 +109,12 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) sprom->revision = 1; /* Fallback: Old hardware does not define this. */ READ_FROM_NVRAM(revision, "sromrev", buf); - if (nvram_getenv("il0macaddr", buf, sizeof(buf)) >= 0) + if (nvram_getprefix(prefix, "il0macaddr", buf, sizeof(buf)) >= 0 || + nvram_getprefix(prefix, "macaddr", buf, sizeof(buf)) >= 0) nvram_parse_macaddr(buf, sprom->il0mac); - if (nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0) + if (nvram_getprefix(prefix, "et0macaddr", buf, sizeof(buf)) >= 0) nvram_parse_macaddr(buf, sprom->et0mac); - if (nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0) + if (nvram_getprefix(prefix, "et1macaddr", buf, sizeof(buf)) >= 0) nvram_parse_macaddr(buf, sprom->et1mac); READ_FROM_NVRAM(et0phyaddr, "et0phyaddr", buf); READ_FROM_NVRAM(et1phyaddr, "et1phyaddr", buf); @@ -95,20 +136,36 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) READ_FROM_NVRAM(pa1hib0, "pa1hib0", buf); READ_FROM_NVRAM(pa1hib2, "pa1hib1", buf); READ_FROM_NVRAM(pa1hib1, "pa1hib2", buf); - READ_FROM_NVRAM(gpio0, "wl0gpio0", buf); - READ_FROM_NVRAM(gpio1, "wl0gpio1", buf); - READ_FROM_NVRAM(gpio2, "wl0gpio2", buf); - READ_FROM_NVRAM(gpio3, "wl0gpio3", buf); - READ_FROM_NVRAM(maxpwr_bg, "pa0maxpwr", buf); - READ_FROM_NVRAM(maxpwr_al, "pa1lomaxpwr", buf); - READ_FROM_NVRAM(maxpwr_a, "pa1maxpwr", buf); - READ_FROM_NVRAM(maxpwr_ah, "pa1himaxpwr", buf); - READ_FROM_NVRAM(itssi_a, "pa1itssit", buf); - READ_FROM_NVRAM(itssi_bg, "pa0itssit", buf); + READ_FROM_NVRAM2(gpio0, "ledbh0", "wl0gpio0", buf); + READ_FROM_NVRAM2(gpio1, "ledbh1", "wl0gpio1", buf); + READ_FROM_NVRAM2(gpio2, "ledbh2", "wl0gpio2", buf); + READ_FROM_NVRAM2(gpio3, "ledbh3", "wl0gpio3", buf); + READ_FROM_NVRAM2(maxpwr_bg, "maxp2ga0", "pa0maxpwr", buf); + READ_FROM_NVRAM2(maxpwr_al, "maxp5gla0", "pa1lomaxpwr", buf); + READ_FROM_NVRAM2(maxpwr_a, "maxp5ga0", "pa1maxpwr", buf); + READ_FROM_NVRAM2(maxpwr_ah, "maxp5gha0", "pa1himaxpwr", buf); + READ_FROM_NVRAM2(itssi_bg, "itt5ga0", "pa0itssit", buf); + READ_FROM_NVRAM2(itssi_a, "itt2ga0", "pa1itssit", buf); READ_FROM_NVRAM(tri2g, "tri2g", buf); READ_FROM_NVRAM(tri5gl, "tri5gl", buf); READ_FROM_NVRAM(tri5g, "tri5g", buf); READ_FROM_NVRAM(tri5gh, "tri5gh", buf); + READ_FROM_NVRAM(txpid2g[0], "txpid2ga0", buf); + READ_FROM_NVRAM(txpid2g[1], "txpid2ga1", buf); + READ_FROM_NVRAM(txpid2g[2], "txpid2ga2", buf); + READ_FROM_NVRAM(txpid2g[3], "txpid2ga3", buf); + READ_FROM_NVRAM(txpid5g[0], "txpid5ga0", buf); + READ_FROM_NVRAM(txpid5g[1], "txpid5ga1", buf); + READ_FROM_NVRAM(txpid5g[2], "txpid5ga2", buf); + READ_FROM_NVRAM(txpid5g[3], "txpid5ga3", buf); + READ_FROM_NVRAM(txpid5gl[0], "txpid5gla0", buf); + READ_FROM_NVRAM(txpid5gl[1], "txpid5gla1", buf); + READ_FROM_NVRAM(txpid5gl[2], "txpid5gla2", buf); + READ_FROM_NVRAM(txpid5gl[3], "txpid5gla3", buf); + READ_FROM_NVRAM(txpid5gh[0], "txpid5gha0", buf); + READ_FROM_NVRAM(txpid5gh[1], "txpid5gha1", buf); + READ_FROM_NVRAM(txpid5gh[2], "txpid5gha2", buf); + READ_FROM_NVRAM(txpid5gh[3], "txpid5gha3", buf); READ_FROM_NVRAM(rxpo2g, "rxpo2g", buf); READ_FROM_NVRAM(rxpo5g, "rxpo5g", buf); READ_FROM_NVRAM(rssisav2g, "rssisav2g", buf); @@ -120,19 +177,27 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) READ_FROM_NVRAM(rssismf5g, "rssismf5g", buf); READ_FROM_NVRAM(bxa5g, "bxa5g", buf); READ_FROM_NVRAM(cck2gpo, "cck2gpo", buf); - READ_FROM_NVRAM(ofdm2gpo, "ofdm2gpo", buf); - READ_FROM_NVRAM(ofdm5glpo, "ofdm5glpo", buf); - READ_FROM_NVRAM(ofdm5gpo, "ofdm5gpo", buf); - READ_FROM_NVRAM(ofdm5ghpo, "ofdm5ghpo", buf); - if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0) { + sprom->ofdm2gpo = nvram_getu32("ofdm2gpo", buf, sizeof(buf)); + sprom->ofdm5glpo = nvram_getu32("ofdm5glpo", buf, sizeof(buf)); + sprom->ofdm5gpo = nvram_getu32("ofdm5gpo", buf, sizeof(buf)); + sprom->ofdm5ghpo = nvram_getu32("ofdm5ghpo", buf, sizeof(buf)); + + READ_FROM_NVRAM(antenna_gain.ghz24.a0, "ag0", buf); + READ_FROM_NVRAM(antenna_gain.ghz24.a1, "ag1", buf); + READ_FROM_NVRAM(antenna_gain.ghz24.a2, "ag2", buf); + READ_FROM_NVRAM(antenna_gain.ghz24.a3, "ag3", buf); + memcpy(&sprom->antenna_gain.ghz5, &sprom->antenna_gain.ghz24, + sizeof(sprom->antenna_gain.ghz5)); + + if (nvram_getprefix(prefix, "boardflags", buf, sizeof(buf)) >= 0) { boardflags = simple_strtoul(buf, NULL, 0); if (boardflags) { sprom->boardflags_lo = (boardflags & 0x0000FFFFU); sprom->boardflags_hi = (boardflags & 0xFFFF0000U) >> 16; } } - if (nvram_getenv("boardflags2", buf, sizeof(buf)) >= 0) { + if (nvram_getprefix(prefix, "boardflags2", buf, sizeof(buf)) >= 0) { boardflags = simple_strtoul(buf, NULL, 0); if (boardflags) { sprom->boardflags2_lo = (boardflags & 0x0000FFFFU); @@ -141,6 +206,22 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) } } +int bcm47xx_get_sprom(struct ssb_bus *bus, struct ssb_sprom *out) +{ + char prefix[10]; + + if (bus->bustype == SSB_BUSTYPE_PCI) { + snprintf(prefix, sizeof(prefix), "pci/%u/%u/", + bus->host_pci->bus->number + 1, + PCI_SLOT(bus->host_pci->devfn)); + bcm47xx_fill_sprom(out, prefix); + return 0; + } else { + printk(KERN_WARNING "bcm47xx: unable to fill SPROM for given bustype.\n"); + return -EINVAL; + } +} + static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv) { @@ -158,7 +239,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus, if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); - bcm47xx_fill_sprom(&iv->sprom); + bcm47xx_fill_sprom(&iv->sprom, NULL); if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10); @@ -172,6 +253,11 @@ void __init plat_mem_setup(void) char buf[100]; struct ssb_mipscore *mcore; + err = ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom); + if (err) + printk(KERN_WARNING "bcm47xx: someone else already registered" + " a ssb SPROM callback handler (err %d)\n", err); + err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE, bcm47xx_get_invariants); if (err) diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index 8dba8cfb752f..40b223b603be 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -643,6 +643,17 @@ static struct ssb_sprom bcm63xx_sprom = { .boardflags_lo = 0x2848, .boardflags_hi = 0x0000, }; + +int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out) +{ + if (bus->bustype == SSB_BUSTYPE_PCI) { + memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom)); + return 0; + } else { + printk(KERN_ERR PFX "unable to fill SPROM for given bustype.\n"); + return -EINVAL; + } +} #endif /* @@ -793,8 +804,9 @@ void __init board_prom_init(void) if (!board_get_mac_address(bcm63xx_sprom.il0mac)) { memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN); memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN); - if (ssb_arch_set_fallback_sprom(&bcm63xx_sprom) < 0) - printk(KERN_ERR "failed to register fallback SPROM\n"); + if (ssb_arch_register_fallback_sprom( + &bcm63xx_get_fallback_sprom) < 0) + printk(KERN_ERR PFX "failed to register fallback SPROM\n"); } #endif } diff --git a/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c b/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c index 88c9d963be88..9a6243676e22 100644 --- a/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c +++ b/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c @@ -16,8 +16,8 @@ int main(int argc, char *argv[]) { + unsigned long long vmlinux_size, vmlinux_load_addr, vmlinuz_load_addr; struct stat sb; - uint64_t vmlinux_size, vmlinux_load_addr, vmlinuz_load_addr; if (argc != 3) { fprintf(stderr, "Usage: %s \n", diff --git a/arch/mips/boot/compressed/uart-alchemy.c b/arch/mips/boot/compressed/uart-alchemy.c index 1bff22fa089b..eb063e6dead9 100644 --- a/arch/mips/boot/compressed/uart-alchemy.c +++ b/arch/mips/boot/compressed/uart-alchemy.c @@ -3,5 +3,5 @@ void putc(char c) { /* all current (Jan. 2010) in-kernel boards */ - alchemy_uart_putchar(UART0_PHYS_ADDR, c); + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); } diff --git a/arch/mips/cavium-octeon/Kconfig b/arch/mips/cavium-octeon/Kconfig index caae22858163..cad555ebeca3 100644 --- a/arch/mips/cavium-octeon/Kconfig +++ b/arch/mips/cavium-octeon/Kconfig @@ -1,11 +1,7 @@ -config CAVIUM_OCTEON_SPECIFIC_OPTIONS - bool "Enable Octeon specific options" - depends on CPU_CAVIUM_OCTEON - default "y" +if CPU_CAVIUM_OCTEON config CAVIUM_CN63XXP1 bool "Enable CN63XXP1 errata worarounds" - depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS default "n" help The CN63XXP1 chip requires build time workarounds to @@ -16,7 +12,6 @@ config CAVIUM_CN63XXP1 config CAVIUM_OCTEON_2ND_KERNEL bool "Build the kernel to be used as a 2nd kernel on the same chip" - depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS default "n" help This option configures this kernel to be linked at a different @@ -26,7 +21,6 @@ config CAVIUM_OCTEON_2ND_KERNEL config CAVIUM_OCTEON_HW_FIX_UNALIGNED bool "Enable hardware fixups of unaligned loads and stores" - depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS default "y" help Configure the Octeon hardware to automatically fix unaligned loads @@ -38,7 +32,6 @@ config CAVIUM_OCTEON_HW_FIX_UNALIGNED config CAVIUM_OCTEON_CVMSEG_SIZE int "Number of L1 cache lines reserved for CVMSEG memory" - depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS range 0 54 default 1 help @@ -50,7 +43,6 @@ config CAVIUM_OCTEON_CVMSEG_SIZE config CAVIUM_OCTEON_LOCK_L2 bool "Lock often used kernel code in the L2" - depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS default "y" help Enable locking parts of the kernel into the L2 cache. @@ -93,7 +85,6 @@ config CAVIUM_OCTEON_LOCK_L2_MEMCPY config ARCH_SPARSEMEM_ENABLE def_bool y select SPARSEMEM_STATIC - depends on CPU_CAVIUM_OCTEON config CAVIUM_OCTEON_HELPER def_bool y @@ -107,6 +98,8 @@ config NEED_SG_DMA_LENGTH config SWIOTLB def_bool y - depends on CPU_CAVIUM_OCTEON select IOMMU_HELPER select NEED_SG_DMA_LENGTH + + +endif # CPU_CAVIUM_OCTEON diff --git a/arch/mips/cavium-octeon/csrc-octeon.c b/arch/mips/cavium-octeon/csrc-octeon.c index 26bf71130bf8..29d56afbb02d 100644 --- a/arch/mips/cavium-octeon/csrc-octeon.c +++ b/arch/mips/cavium-octeon/csrc-octeon.c @@ -105,8 +105,7 @@ unsigned long long notrace sched_clock(void) void __init plat_time_init(void) { clocksource_mips.rating = 300; - clocksource_set_clock(&clocksource_mips, octeon_get_clock_rate()); - clocksource_register(&clocksource_mips); + clocksource_register_hz(&clocksource_mips, octeon_get_clock_rate()); } static u64 octeon_udelay_factor; diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 0707fae3f0ee..2d9028f1474c 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -288,7 +288,6 @@ void octeon_user_io_init(void) union octeon_cvmemctl cvmmemctl; union cvmx_iob_fau_timeout fau_timeout; union cvmx_pow_nw_tim nm_tim; - uint64_t cvmctl; /* Get the current settings for CP0_CVMMEMCTL_REG */ cvmmemctl.u64 = read_c0_cvmmemctl(); @@ -392,12 +391,6 @@ void octeon_user_io_init(void) CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128); - /* Move the performance counter interrupts to IRQ 6 */ - cvmctl = read_c0_cvmctl(); - cvmctl &= ~(7 << 7); - cvmctl |= 6 << 7; - write_c0_cvmctl(cvmctl); - /* Set a default for the hardware timeouts */ fau_timeout.u64 = 0; fau_timeout.s.tout_val = 0xfff; diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index ba78b21cc8d0..8b606423bbd7 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -37,13 +37,15 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id) uint64_t action; /* Load the mailbox register to figure out what we're supposed to do */ - action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid)); + action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid)) & 0xffff; /* Clear the mailbox to clear the interrupt */ cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action); if (action & SMP_CALL_FUNCTION) smp_call_function_interrupt(); + if (action & SMP_RESCHEDULE_YOURSELF) + scheduler_ipi(); /* Check if we've been told to flush the icache */ if (action & SMP_ICACHE_FLUSH) @@ -200,16 +202,15 @@ void octeon_prepare_cpus(unsigned int max_cpus) if (labi->labi_signature != LABI_SIGNATURE) panic("The bootloader version on this board is incorrect."); #endif - - cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffffffff); + /* + * Only the low order mailbox bits are used for IPIs, leave + * the other bits alone. + */ + cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffff); if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt, IRQF_DISABLED, - "mailbox0", mailbox_interrupt)) { + "SMP-IPI", mailbox_interrupt)) { panic("Cannot request_irq(OCTEON_IRQ_MBOX0)\n"); } - if (request_irq(OCTEON_IRQ_MBOX1, mailbox_interrupt, IRQF_DISABLED, - "mailbox1", mailbox_interrupt)) { - panic("Cannot request_irq(OCTEON_IRQ_MBOX1)\n"); - } } /** diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index 167c1d07b809..b6acd2f256b6 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -86,8 +86,8 @@ CONFIG_NET_SCHED=y CONFIG_NET_EMATCH=y CONFIG_NET_CLS_ACT=y CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m @@ -329,7 +329,7 @@ CONFIG_USB_LED=m CONFIG_USB_GADGET=m CONFIG_USB_GADGET_M66592=y CONFIG_MMC=m -CONFIG_LEDS_CLASS=m +CONFIG_LEDS_CLASS=y CONFIG_STAGING=y # CONFIG_STAGING_EXCLUDE_BUILD is not set CONFIG_FB_SM7XX=y diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index 7270f3183bda..5527abbb7dea 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -374,7 +374,7 @@ CONFIG_FB_CIRRUS=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_HID=m -CONFIG_LEDS_CLASS=m +CONFIG_LEDS_CLASS=y CONFIG_LEDS_TRIGGER_TIMER=m CONFIG_LEDS_TRIGGER_IDE_DISK=y CONFIG_LEDS_TRIGGER_HEARTBEAT=m diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index a97a42c6b2c8..37862b2ce363 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -225,8 +225,8 @@ CONFIG_TOSHIBA_FIR=m CONFIG_VLSI_FIR=m CONFIG_MCS_FIR=m CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig new file mode 100644 index 000000000000..e4b399fdaa61 --- /dev/null +++ b/arch/mips/configs/nlm_xlr_defconfig @@ -0,0 +1,574 @@ +CONFIG_NLM_XLR_BOARD=y +CONFIG_HIGHMEM=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_SMP=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_KEXEC=y +CONFIG_EXPERIMENTAL=y +CONFIG_CROSS_COMPILE="mips64-unknown-linux-gnu-" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_AUDIT=y +CONFIG_NAMESPACES=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs" +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_INITRAMFS_COMPRESSION_GZIP=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_ELF_CORE is not set +# CONFIG_PCSPKR_PLATFORM is not set +# CONFIG_PERF_EVENTS is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BINFMT_MISC=m +CONFIG_PM_RUNTIME=y +CONFIG_PM_DEBUG=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=m +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_NET_IPIP=m +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETLABEL=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_FTP=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_DECNET_NF_GRABULATOR=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_NFLOG=m +CONFIG_IP_DCCP=m +CONFIG_RDS=m +CONFIG_RDS_TCP=m +CONFIG_TIPC=m +CONFIG_ATM=m +CONFIG_ATM_CLIP=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_DECNET=m +CONFIG_LLC2=m +CONFIG_IPX=m +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m +CONFIG_PHONET=m +CONFIG_IEEE802154=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_DRR=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_FLOW=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_DCB=y +CONFIG_NET_PKTGEN=m +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +CONFIG_CONNECTOR=y +CONFIG_MTD=m +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_OSD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_CDROM_PKTCDVD=y +CONFIG_MISC_DEVICES=y +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=y +CONFIG_SCSI_TGT=m +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_ISCSI_TCP=m +CONFIG_LIBFCOE=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=m +CONFIG_SCSI_DH_HP_SW=m +CONFIG_SCSI_DH_EMC=m +CONFIG_SCSI_DH_ALUA=m +CONFIG_SCSI_OSD_INITIATOR=m +CONFIG_SCSI_OSD_ULD=m +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y +CONFIG_LEGACY_PTY_COUNT=0 +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_N_HDLC=m +# CONFIG_DEVKMEM is not set +CONFIG_STALDRV=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_TIMERIOMEM=m +CONFIG_RAW_DRIVER=m +# CONFIG_HWMON is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_UIO=y +CONFIG_UIO_PDRV=m +CONFIG_UIO_PDRV_GENIRQ=m +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=y +CONFIG_OCFS2_FS=m +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_NILFS2_FS=m +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=y +CONFIG_CUSE=m +CONFIG_FSCACHE=m +CONFIG_FSCACHE_STATS=y +CONFIG_FSCACHE_HISTOGRAM=y +CONFIG_CACHEFILES=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_NTFS_FS=m +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CONFIGFS_FS=y +CONFIG_ADFS_FS=m +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=y +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_CRAMFS=m +CONFIG_SQUASHFS=m +CONFIG_VXFS_FS=m +CONFIG_MINIX_FS=m +CONFIG_OMFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_ROMFS_FS=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +CONFIG_EXOFS_FS=m +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_FSCACHE=y +CONFIG_NFSD=m +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_CIFS=m +CONFIG_CIFS_WEAK_PW_HASH=y +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +CONFIG_CIFS_DFS_UPCALL=y +CONFIG_CIFS_EXPERIMENTAL=y +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +CONFIG_CODA_FS=m +CONFIG_AFS_FS=m +CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +CONFIG_ACORN_PARTITION_ICS=y +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_ATARI_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +CONFIG_SGI_PARTITION=y +CONFIG_ULTRIX_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_SYSV68_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_PRINTK_TIME=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_UNUSED_SYMBOLS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_SCHED_TRACER=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KGDB=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_LSM_MMAP_MIN_ADDR=0 +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SMACK=y +CONFIG_SECURITY_TOMOYO=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_RMD128=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_RMD256=m +CONFIG_CRYPTO_RMD320=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_ZLIB=m +CONFIG_CRYPTO_LZO=m +CONFIG_CRC_CCITT=m +CONFIG_CRC7=m diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h index 650ac9ba734c..b4db69fbc40c 100644 --- a/arch/mips/include/asm/cache.h +++ b/arch/mips/include/asm/cache.h @@ -17,6 +17,6 @@ #define SMP_CACHE_SHIFT L1_CACHE_SHIFT #define SMP_CACHE_BYTES L1_CACHE_BYTES -#define __read_mostly __attribute__((__section__(".data.read_mostly"))) +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) #endif /* _ASM_CACHE_H */ diff --git a/arch/mips/include/asm/cevt-r4k.h b/arch/mips/include/asm/cevt-r4k.h index fa4328f9124f..65f9bdd02f1f 100644 --- a/arch/mips/include/asm/cevt-r4k.h +++ b/arch/mips/include/asm/cevt-r4k.h @@ -14,6 +14,9 @@ #ifndef __ASM_CEVT_R4K_H #define __ASM_CEVT_R4K_H +#include +#include + DECLARE_PER_CPU(struct clock_event_device, mips_clockevent_device); void mips_event_handler(struct clock_event_device *dev); diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 86877539c6e8..34c0d3cb116f 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -33,6 +33,7 @@ #define PRID_COMP_TOSHIBA 0x070000 #define PRID_COMP_LSI 0x080000 #define PRID_COMP_LEXRA 0x0b0000 +#define PRID_COMP_NETLOGIC 0x0c0000 #define PRID_COMP_CAVIUM 0x0d0000 #define PRID_COMP_INGENIC 0xd00000 @@ -141,6 +142,31 @@ #define PRID_IMP_JZRISC 0x0200 +/* + * These are the PRID's for when 23:16 == PRID_COMP_NETLOGIC + */ +#define PRID_IMP_NETLOGIC_XLR732 0x0000 +#define PRID_IMP_NETLOGIC_XLR716 0x0200 +#define PRID_IMP_NETLOGIC_XLR532 0x0900 +#define PRID_IMP_NETLOGIC_XLR308 0x0600 +#define PRID_IMP_NETLOGIC_XLR532C 0x0800 +#define PRID_IMP_NETLOGIC_XLR516C 0x0a00 +#define PRID_IMP_NETLOGIC_XLR508C 0x0b00 +#define PRID_IMP_NETLOGIC_XLR308C 0x0f00 +#define PRID_IMP_NETLOGIC_XLS608 0x8000 +#define PRID_IMP_NETLOGIC_XLS408 0x8800 +#define PRID_IMP_NETLOGIC_XLS404 0x8c00 +#define PRID_IMP_NETLOGIC_XLS208 0x8e00 +#define PRID_IMP_NETLOGIC_XLS204 0x8f00 +#define PRID_IMP_NETLOGIC_XLS108 0xce00 +#define PRID_IMP_NETLOGIC_XLS104 0xcf00 +#define PRID_IMP_NETLOGIC_XLS616B 0x4000 +#define PRID_IMP_NETLOGIC_XLS608B 0x4a00 +#define PRID_IMP_NETLOGIC_XLS416B 0x4400 +#define PRID_IMP_NETLOGIC_XLS412B 0x4c00 +#define PRID_IMP_NETLOGIC_XLS408B 0x4e00 +#define PRID_IMP_NETLOGIC_XLS404B 0x4f00 + /* * Definitions for 7:0 on legacy processors */ @@ -234,6 +260,7 @@ enum cpu_type_enum { */ CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2, CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2, + CPU_XLR, CPU_LAST }; diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index 655f849bd08d..7aa37ddfca4b 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h @@ -5,7 +5,9 @@ #include #include +#ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */ #include +#endif extern struct dma_map_ops *mips_dma_map_ops; diff --git a/arch/mips/include/asm/hugetlb.h b/arch/mips/include/asm/hugetlb.h index f5e856015329..c565b7c3f0b5 100644 --- a/arch/mips/include/asm/hugetlb.h +++ b/arch/mips/include/asm/hugetlb.h @@ -70,6 +70,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) { + flush_tlb_mm(vma->vm_mm); } static inline int huge_pte_none(pte_t pte) diff --git a/arch/mips/include/asm/i8253.h b/arch/mips/include/asm/i8253.h index 48bb82372994..9ad011366f73 100644 --- a/arch/mips/include/asm/i8253.h +++ b/arch/mips/include/asm/i8253.h @@ -12,8 +12,13 @@ #define PIT_CH0 0x40 #define PIT_CH2 0x42 +#define PIT_LATCH LATCH + extern raw_spinlock_t i8253_lock; extern void setup_pit_timer(void); +#define inb_pit inb_p +#define outb_pit outb_p + #endif /* __ASM_I8253_H */ diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h index 7622ccf75076..1881b316ca45 100644 --- a/arch/mips/include/asm/jump_label.h +++ b/arch/mips/include/asm/jump_label.h @@ -20,16 +20,18 @@ #define WORD_INSN ".word" #endif -#define JUMP_LABEL(key, label) \ - do { \ - asm goto("1:\tnop\n\t" \ - "nop\n\t" \ - ".pushsection __jump_table, \"a\"\n\t" \ - WORD_INSN " 1b, %l[" #label "], %0\n\t" \ - ".popsection\n\t" \ - : : "i" (key) : : label); \ - } while (0) - +static __always_inline bool arch_static_branch(struct jump_label_key *key) +{ + asm goto("1:\tnop\n\t" + "nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + WORD_INSN " 1b, %l[l_yes], %0\n\t" + ".popsection\n\t" + : : "i" (key) : : l_yes); + return false; +l_yes: + return true; +} #endif /* __KERNEL__ */ diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h index a6976619160a..f260ebed713b 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000.h +++ b/arch/mips/include/asm/mach-au1x00/au1000.h @@ -161,6 +161,45 @@ static inline int alchemy_get_cputype(void) return ALCHEMY_CPU_UNKNOWN; } +/* return number of uarts on a given cputype */ +static inline int alchemy_get_uarts(int type) +{ + switch (type) { + case ALCHEMY_CPU_AU1000: + return 4; + case ALCHEMY_CPU_AU1500: + case ALCHEMY_CPU_AU1200: + return 2; + case ALCHEMY_CPU_AU1100: + case ALCHEMY_CPU_AU1550: + return 3; + } + return 0; +} + +/* enable an UART block if it isn't already */ +static inline void alchemy_uart_enable(u32 uart_phys) +{ + void __iomem *addr = (void __iomem *)KSEG1ADDR(uart_phys); + + /* reset, enable clock, deassert reset */ + if ((__raw_readl(addr + 0x100) & 3) != 3) { + __raw_writel(0, addr + 0x100); + wmb(); + __raw_writel(1, addr + 0x100); + wmb(); + } + __raw_writel(3, addr + 0x100); + wmb(); +} + +static inline void alchemy_uart_disable(u32 uart_phys) +{ + void __iomem *addr = (void __iomem *)KSEG1ADDR(uart_phys); + __raw_writel(0, addr + 0x100); /* UART_MOD_CNTRL */ + wmb(); +} + static inline void alchemy_uart_putchar(u32 uart_phys, u8 c) { void __iomem *base = (void __iomem *)KSEG1ADDR(uart_phys); @@ -180,6 +219,20 @@ static inline void alchemy_uart_putchar(u32 uart_phys, u8 c) wmb(); } +/* return number of ethernet MACs on a given cputype */ +static inline int alchemy_get_macs(int type) +{ + switch (type) { + case ALCHEMY_CPU_AU1000: + case ALCHEMY_CPU_AU1500: + case ALCHEMY_CPU_AU1550: + return 2; + case ALCHEMY_CPU_AU1100: + return 1; + } + return 0; +} + /* arch/mips/au1000/common/clocks.c */ extern void set_au1x00_speed(unsigned int new_freq); extern unsigned int get_au1x00_speed(void); @@ -630,38 +683,42 @@ enum soc_au1200_ints { /* * Physical base addresses for integrated peripherals + * 0..au1000 1..au1500 2..au1100 3..au1550 4..au1200 */ +#define AU1000_AC97_PHYS_ADDR 0x10000000 /* 012 */ +#define AU1000_USBD_PHYS_ADDR 0x10200000 /* 0123 */ +#define AU1000_IC0_PHYS_ADDR 0x10400000 /* 01234 */ +#define AU1000_MAC0_PHYS_ADDR 0x10500000 /* 023 */ +#define AU1000_MAC1_PHYS_ADDR 0x10510000 /* 023 */ +#define AU1000_MACEN_PHYS_ADDR 0x10520000 /* 023 */ +#define AU1100_SD0_PHYS_ADDR 0x10600000 /* 24 */ +#define AU1100_SD1_PHYS_ADDR 0x10680000 /* 24 */ +#define AU1000_I2S_PHYS_ADDR 0x11000000 /* 02 */ +#define AU1500_MAC0_PHYS_ADDR 0x11500000 /* 1 */ +#define AU1500_MAC1_PHYS_ADDR 0x11510000 /* 1 */ +#define AU1500_MACEN_PHYS_ADDR 0x11520000 /* 1 */ +#define AU1000_UART0_PHYS_ADDR 0x11100000 /* 01234 */ +#define AU1000_UART1_PHYS_ADDR 0x11200000 /* 0234 */ +#define AU1000_UART2_PHYS_ADDR 0x11300000 /* 0 */ +#define AU1000_UART3_PHYS_ADDR 0x11400000 /* 0123 */ +#define AU1500_GPIO2_PHYS_ADDR 0x11700000 /* 1234 */ +#define AU1000_IC1_PHYS_ADDR 0x11800000 /* 01234 */ +#define AU1000_SYS_PHYS_ADDR 0x11900000 /* 01234 */ +#define AU1000_DMA_PHYS_ADDR 0x14002000 /* 012 */ +#define AU1550_DBDMA_PHYS_ADDR 0x14002000 /* 34 */ +#define AU1550_DBDMA_CONF_PHYS_ADDR 0x14003000 /* 34 */ +#define AU1000_MACDMA0_PHYS_ADDR 0x14004000 /* 0123 */ +#define AU1000_MACDMA1_PHYS_ADDR 0x14004200 /* 0123 */ + + #ifdef CONFIG_SOC_AU1000 #define MEM_PHYS_ADDR 0x14000000 #define STATIC_MEM_PHYS_ADDR 0x14001000 -#define DMA0_PHYS_ADDR 0x14002000 -#define DMA1_PHYS_ADDR 0x14002100 -#define DMA2_PHYS_ADDR 0x14002200 -#define DMA3_PHYS_ADDR 0x14002300 -#define DMA4_PHYS_ADDR 0x14002400 -#define DMA5_PHYS_ADDR 0x14002500 -#define DMA6_PHYS_ADDR 0x14002600 -#define DMA7_PHYS_ADDR 0x14002700 -#define IC0_PHYS_ADDR 0x10400000 -#define IC1_PHYS_ADDR 0x11800000 -#define AC97_PHYS_ADDR 0x10000000 #define USBH_PHYS_ADDR 0x10100000 -#define USBD_PHYS_ADDR 0x10200000 #define IRDA_PHYS_ADDR 0x10300000 -#define MAC0_PHYS_ADDR 0x10500000 -#define MAC1_PHYS_ADDR 0x10510000 -#define MACEN_PHYS_ADDR 0x10520000 -#define MACDMA0_PHYS_ADDR 0x14004000 -#define MACDMA1_PHYS_ADDR 0x14004200 -#define I2S_PHYS_ADDR 0x11000000 -#define UART0_PHYS_ADDR 0x11100000 -#define UART1_PHYS_ADDR 0x11200000 -#define UART2_PHYS_ADDR 0x11300000 -#define UART3_PHYS_ADDR 0x11400000 #define SSI0_PHYS_ADDR 0x11600000 #define SSI1_PHYS_ADDR 0x11680000 -#define SYS_PHYS_ADDR 0x11900000 #define PCMCIA_IO_PHYS_ADDR 0xF00000000ULL #define PCMCIA_ATTR_PHYS_ADDR 0xF40000000ULL #define PCMCIA_MEM_PHYS_ADDR 0xF80000000ULL @@ -672,30 +729,8 @@ enum soc_au1200_ints { #ifdef CONFIG_SOC_AU1500 #define MEM_PHYS_ADDR 0x14000000 #define STATIC_MEM_PHYS_ADDR 0x14001000 -#define DMA0_PHYS_ADDR 0x14002000 -#define DMA1_PHYS_ADDR 0x14002100 -#define DMA2_PHYS_ADDR 0x14002200 -#define DMA3_PHYS_ADDR 0x14002300 -#define DMA4_PHYS_ADDR 0x14002400 -#define DMA5_PHYS_ADDR 0x14002500 -#define DMA6_PHYS_ADDR 0x14002600 -#define DMA7_PHYS_ADDR 0x14002700 -#define IC0_PHYS_ADDR 0x10400000 -#define IC1_PHYS_ADDR 0x11800000 -#define AC97_PHYS_ADDR 0x10000000 #define USBH_PHYS_ADDR 0x10100000 -#define USBD_PHYS_ADDR 0x10200000 #define PCI_PHYS_ADDR 0x14005000 -#define MAC0_PHYS_ADDR 0x11500000 -#define MAC1_PHYS_ADDR 0x11510000 -#define MACEN_PHYS_ADDR 0x11520000 -#define MACDMA0_PHYS_ADDR 0x14004000 -#define MACDMA1_PHYS_ADDR 0x14004200 -#define I2S_PHYS_ADDR 0x11000000 -#define UART0_PHYS_ADDR 0x11100000 -#define UART3_PHYS_ADDR 0x11400000 -#define GPIO2_PHYS_ADDR 0x11700000 -#define SYS_PHYS_ADDR 0x11900000 #define PCI_MEM_PHYS_ADDR 0x400000000ULL #define PCI_IO_PHYS_ADDR 0x500000000ULL #define PCI_CONFIG0_PHYS_ADDR 0x600000000ULL @@ -710,34 +745,10 @@ enum soc_au1200_ints { #ifdef CONFIG_SOC_AU1100 #define MEM_PHYS_ADDR 0x14000000 #define STATIC_MEM_PHYS_ADDR 0x14001000 -#define DMA0_PHYS_ADDR 0x14002000 -#define DMA1_PHYS_ADDR 0x14002100 -#define DMA2_PHYS_ADDR 0x14002200 -#define DMA3_PHYS_ADDR 0x14002300 -#define DMA4_PHYS_ADDR 0x14002400 -#define DMA5_PHYS_ADDR 0x14002500 -#define DMA6_PHYS_ADDR 0x14002600 -#define DMA7_PHYS_ADDR 0x14002700 -#define IC0_PHYS_ADDR 0x10400000 -#define SD0_PHYS_ADDR 0x10600000 -#define SD1_PHYS_ADDR 0x10680000 -#define IC1_PHYS_ADDR 0x11800000 -#define AC97_PHYS_ADDR 0x10000000 #define USBH_PHYS_ADDR 0x10100000 -#define USBD_PHYS_ADDR 0x10200000 #define IRDA_PHYS_ADDR 0x10300000 -#define MAC0_PHYS_ADDR 0x10500000 -#define MACEN_PHYS_ADDR 0x10520000 -#define MACDMA0_PHYS_ADDR 0x14004000 -#define MACDMA1_PHYS_ADDR 0x14004200 -#define I2S_PHYS_ADDR 0x11000000 -#define UART0_PHYS_ADDR 0x11100000 -#define UART1_PHYS_ADDR 0x11200000 -#define UART3_PHYS_ADDR 0x11400000 #define SSI0_PHYS_ADDR 0x11600000 #define SSI1_PHYS_ADDR 0x11680000 -#define GPIO2_PHYS_ADDR 0x11700000 -#define SYS_PHYS_ADDR 0x11900000 #define LCD_PHYS_ADDR 0x15000000 #define PCMCIA_IO_PHYS_ADDR 0xF00000000ULL #define PCMCIA_ATTR_PHYS_ADDR 0xF40000000ULL @@ -749,22 +760,8 @@ enum soc_au1200_ints { #ifdef CONFIG_SOC_AU1550 #define MEM_PHYS_ADDR 0x14000000 #define STATIC_MEM_PHYS_ADDR 0x14001000 -#define IC0_PHYS_ADDR 0x10400000 -#define IC1_PHYS_ADDR 0x11800000 #define USBH_PHYS_ADDR 0x14020000 -#define USBD_PHYS_ADDR 0x10200000 #define PCI_PHYS_ADDR 0x14005000 -#define MAC0_PHYS_ADDR 0x10500000 -#define MAC1_PHYS_ADDR 0x10510000 -#define MACEN_PHYS_ADDR 0x10520000 -#define MACDMA0_PHYS_ADDR 0x14004000 -#define MACDMA1_PHYS_ADDR 0x14004200 -#define UART0_PHYS_ADDR 0x11100000 -#define UART1_PHYS_ADDR 0x11200000 -#define UART3_PHYS_ADDR 0x11400000 -#define GPIO2_PHYS_ADDR 0x11700000 -#define SYS_PHYS_ADDR 0x11900000 -#define DDMA_PHYS_ADDR 0x14002000 #define PE_PHYS_ADDR 0x14008000 #define PSC0_PHYS_ADDR 0x11A00000 #define PSC1_PHYS_ADDR 0x11B00000 @@ -786,19 +783,10 @@ enum soc_au1200_ints { #define STATIC_MEM_PHYS_ADDR 0x14001000 #define AES_PHYS_ADDR 0x10300000 #define CIM_PHYS_ADDR 0x14004000 -#define IC0_PHYS_ADDR 0x10400000 -#define IC1_PHYS_ADDR 0x11800000 #define USBM_PHYS_ADDR 0x14020000 #define USBH_PHYS_ADDR 0x14020100 -#define UART0_PHYS_ADDR 0x11100000 -#define UART1_PHYS_ADDR 0x11200000 -#define GPIO2_PHYS_ADDR 0x11700000 -#define SYS_PHYS_ADDR 0x11900000 -#define DDMA_PHYS_ADDR 0x14002000 #define PSC0_PHYS_ADDR 0x11A00000 #define PSC1_PHYS_ADDR 0x11B00000 -#define SD0_PHYS_ADDR 0x10600000 -#define SD1_PHYS_ADDR 0x10680000 #define LCD_PHYS_ADDR 0x15000000 #define SWCNT_PHYS_ADDR 0x1110010C #define MAEFE_PHYS_ADDR 0x14012000 @@ -835,183 +823,43 @@ enum soc_au1200_ints { #endif -/* Interrupt Controller register offsets */ -#define IC_CFG0RD 0x40 -#define IC_CFG0SET 0x40 -#define IC_CFG0CLR 0x44 -#define IC_CFG1RD 0x48 -#define IC_CFG1SET 0x48 -#define IC_CFG1CLR 0x4C -#define IC_CFG2RD 0x50 -#define IC_CFG2SET 0x50 -#define IC_CFG2CLR 0x54 -#define IC_REQ0INT 0x54 -#define IC_SRCRD 0x58 -#define IC_SRCSET 0x58 -#define IC_SRCCLR 0x5C -#define IC_REQ1INT 0x5C -#define IC_ASSIGNRD 0x60 -#define IC_ASSIGNSET 0x60 -#define IC_ASSIGNCLR 0x64 -#define IC_WAKERD 0x68 -#define IC_WAKESET 0x68 -#define IC_WAKECLR 0x6C -#define IC_MASKRD 0x70 -#define IC_MASKSET 0x70 -#define IC_MASKCLR 0x74 -#define IC_RISINGRD 0x78 -#define IC_RISINGCLR 0x78 -#define IC_FALLINGRD 0x7C -#define IC_FALLINGCLR 0x7C -#define IC_TESTBIT 0x80 - - -/* Interrupt Controller 0 */ -#define IC0_CFG0RD 0xB0400040 -#define IC0_CFG0SET 0xB0400040 -#define IC0_CFG0CLR 0xB0400044 - -#define IC0_CFG1RD 0xB0400048 -#define IC0_CFG1SET 0xB0400048 -#define IC0_CFG1CLR 0xB040004C - -#define IC0_CFG2RD 0xB0400050 -#define IC0_CFG2SET 0xB0400050 -#define IC0_CFG2CLR 0xB0400054 - -#define IC0_REQ0INT 0xB0400054 -#define IC0_SRCRD 0xB0400058 -#define IC0_SRCSET 0xB0400058 -#define IC0_SRCCLR 0xB040005C -#define IC0_REQ1INT 0xB040005C - -#define IC0_ASSIGNRD 0xB0400060 -#define IC0_ASSIGNSET 0xB0400060 -#define IC0_ASSIGNCLR 0xB0400064 - -#define IC0_WAKERD 0xB0400068 -#define IC0_WAKESET 0xB0400068 -#define IC0_WAKECLR 0xB040006C - -#define IC0_MASKRD 0xB0400070 -#define IC0_MASKSET 0xB0400070 -#define IC0_MASKCLR 0xB0400074 - -#define IC0_RISINGRD 0xB0400078 -#define IC0_RISINGCLR 0xB0400078 -#define IC0_FALLINGRD 0xB040007C -#define IC0_FALLINGCLR 0xB040007C - -#define IC0_TESTBIT 0xB0400080 - -/* Interrupt Controller 1 */ -#define IC1_CFG0RD 0xB1800040 -#define IC1_CFG0SET 0xB1800040 -#define IC1_CFG0CLR 0xB1800044 - -#define IC1_CFG1RD 0xB1800048 -#define IC1_CFG1SET 0xB1800048 -#define IC1_CFG1CLR 0xB180004C - -#define IC1_CFG2RD 0xB1800050 -#define IC1_CFG2SET 0xB1800050 -#define IC1_CFG2CLR 0xB1800054 - -#define IC1_REQ0INT 0xB1800054 -#define IC1_SRCRD 0xB1800058 -#define IC1_SRCSET 0xB1800058 -#define IC1_SRCCLR 0xB180005C -#define IC1_REQ1INT 0xB180005C - -#define IC1_ASSIGNRD 0xB1800060 -#define IC1_ASSIGNSET 0xB1800060 -#define IC1_ASSIGNCLR 0xB1800064 - -#define IC1_WAKERD 0xB1800068 -#define IC1_WAKESET 0xB1800068 -#define IC1_WAKECLR 0xB180006C - -#define IC1_MASKRD 0xB1800070 -#define IC1_MASKSET 0xB1800070 -#define IC1_MASKCLR 0xB1800074 - -#define IC1_RISINGRD 0xB1800078 -#define IC1_RISINGCLR 0xB1800078 -#define IC1_FALLINGRD 0xB180007C -#define IC1_FALLINGCLR 0xB180007C - -#define IC1_TESTBIT 0xB1800080 /* Au1000 */ #ifdef CONFIG_SOC_AU1000 -#define UART0_ADDR 0xB1100000 -#define UART3_ADDR 0xB1400000 - #define USB_OHCI_BASE 0x10100000 /* phys addr for ioremap */ #define USB_HOST_CONFIG 0xB017FFFC #define FOR_PLATFORM_C_USB_HOST_INT AU1000_USB_HOST_INT - -#define AU1000_ETH0_BASE 0xB0500000 -#define AU1000_ETH1_BASE 0xB0510000 -#define AU1000_MAC0_ENABLE 0xB0520000 -#define AU1000_MAC1_ENABLE 0xB0520004 -#define NUM_ETH_INTERFACES 2 #endif /* CONFIG_SOC_AU1000 */ /* Au1500 */ #ifdef CONFIG_SOC_AU1500 -#define UART0_ADDR 0xB1100000 -#define UART3_ADDR 0xB1400000 - #define USB_OHCI_BASE 0x10100000 /* phys addr for ioremap */ #define USB_HOST_CONFIG 0xB017fffc #define FOR_PLATFORM_C_USB_HOST_INT AU1500_USB_HOST_INT - -#define AU1500_ETH0_BASE 0xB1500000 -#define AU1500_ETH1_BASE 0xB1510000 -#define AU1500_MAC0_ENABLE 0xB1520000 -#define AU1500_MAC1_ENABLE 0xB1520004 -#define NUM_ETH_INTERFACES 2 #endif /* CONFIG_SOC_AU1500 */ /* Au1100 */ #ifdef CONFIG_SOC_AU1100 -#define UART0_ADDR 0xB1100000 -#define UART3_ADDR 0xB1400000 - #define USB_OHCI_BASE 0x10100000 /* phys addr for ioremap */ #define USB_HOST_CONFIG 0xB017FFFC #define FOR_PLATFORM_C_USB_HOST_INT AU1100_USB_HOST_INT - -#define AU1100_ETH0_BASE 0xB0500000 -#define AU1100_MAC0_ENABLE 0xB0520000 -#define NUM_ETH_INTERFACES 1 #endif /* CONFIG_SOC_AU1100 */ #ifdef CONFIG_SOC_AU1550 -#define UART0_ADDR 0xB1100000 #define USB_OHCI_BASE 0x14020000 /* phys addr for ioremap */ #define USB_OHCI_LEN 0x00060000 #define USB_HOST_CONFIG 0xB4027ffc #define FOR_PLATFORM_C_USB_HOST_INT AU1550_USB_HOST_INT - -#define AU1550_ETH0_BASE 0xB0500000 -#define AU1550_ETH1_BASE 0xB0510000 -#define AU1550_MAC0_ENABLE 0xB0520000 -#define AU1550_MAC1_ENABLE 0xB0520004 -#define NUM_ETH_INTERFACES 2 #endif /* CONFIG_SOC_AU1550 */ #ifdef CONFIG_SOC_AU1200 -#define UART0_ADDR 0xB1100000 - #define USB_UOC_BASE 0x14020020 #define USB_UOC_LEN 0x20 #define USB_OHCI_BASE 0x14020100 @@ -1504,22 +1352,6 @@ enum soc_au1200_ints { #define SYS_PINFUNC_S1B (1 << 2) #endif -#define SYS_TRIOUTRD 0xB1900100 -#define SYS_TRIOUTCLR 0xB1900100 -#define SYS_OUTPUTRD 0xB1900108 -#define SYS_OUTPUTSET 0xB1900108 -#define SYS_OUTPUTCLR 0xB190010C -#define SYS_PINSTATERD 0xB1900110 -#define SYS_PININPUTEN 0xB1900110 - -/* GPIO2, Au1500, Au1550 only */ -#define GPIO2_BASE 0xB1700000 -#define GPIO2_DIR (GPIO2_BASE + 0) -#define GPIO2_OUTPUT (GPIO2_BASE + 8) -#define GPIO2_PINSTATE (GPIO2_BASE + 0xC) -#define GPIO2_INTENABLE (GPIO2_BASE + 0x10) -#define GPIO2_ENABLE (GPIO2_BASE + 0x14) - /* Power Management */ #define SYS_SCRATCH0 0xB1900018 #define SYS_SCRATCH1 0xB190001C @@ -1635,12 +1467,6 @@ enum soc_au1200_ints { # define AC97C_RS (1 << 1) # define AC97C_CE (1 << 0) -/* Secure Digital (SD) Controller */ -#define SD0_XMIT_FIFO 0xB0600000 -#define SD0_RECV_FIFO 0xB0600004 -#define SD1_XMIT_FIFO 0xB0680000 -#define SD1_RECV_FIFO 0xB0680004 - #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) /* Au1500 PCI Controller */ #define Au1500_CFG_BASE 0xB4005000 /* virtual, KSEG1 addr */ diff --git a/arch/mips/include/asm/mach-au1x00/au1000_dma.h b/arch/mips/include/asm/mach-au1x00/au1000_dma.h index c333b4e1cd44..59f5b55b2200 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000_dma.h +++ b/arch/mips/include/asm/mach-au1x00/au1000_dma.h @@ -37,10 +37,6 @@ #define NUM_AU1000_DMA_CHANNELS 8 -/* DMA Channel Base Addresses */ -#define DMA_CHANNEL_BASE 0xB4002000 -#define DMA_CHANNEL_LEN 0x00000100 - /* DMA Channel Register Offsets */ #define DMA_MODE_SET 0x00000000 #define DMA_MODE_READ DMA_MODE_SET diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h index c8a553a36ba4..2fdacfe85e23 100644 --- a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h +++ b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h @@ -37,14 +37,6 @@ #ifndef _LANGUAGE_ASSEMBLY -/* - * The DMA base addresses. - * The channels are every 256 bytes (0x0100) from the channel 0 base. - * Interrupt status/enable is bits 15:0 for channels 15 to zero. - */ -#define DDMA_GLOBAL_BASE 0xb4003000 -#define DDMA_CHANNEL_BASE 0xb4002000 - typedef volatile struct dbdma_global { u32 ddma_config; u32 ddma_intstat; diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h index 62d2f136d941..1f41a522906d 100644 --- a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h +++ b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h @@ -24,6 +24,23 @@ #define MAKE_IRQ(intc, off) (AU1000_INTC##intc##_INT_BASE + (off)) +/* GPIO1 registers within SYS_ area */ +#define SYS_TRIOUTRD 0x100 +#define SYS_TRIOUTCLR 0x100 +#define SYS_OUTPUTRD 0x108 +#define SYS_OUTPUTSET 0x108 +#define SYS_OUTPUTCLR 0x10C +#define SYS_PINSTATERD 0x110 +#define SYS_PININPUTEN 0x110 + +/* register offsets within GPIO2 block */ +#define GPIO2_DIR 0x00 +#define GPIO2_OUTPUT 0x08 +#define GPIO2_PINSTATE 0x0C +#define GPIO2_INTENABLE 0x10 +#define GPIO2_ENABLE 0x14 + +struct gpio; static inline int au1000_gpio1_to_irq(int gpio) { @@ -200,23 +217,26 @@ static inline int au1200_irq_to_gpio(int irq) */ static inline void alchemy_gpio1_set_value(int gpio, int v) { + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR); unsigned long mask = 1 << (gpio - ALCHEMY_GPIO1_BASE); unsigned long r = v ? SYS_OUTPUTSET : SYS_OUTPUTCLR; - au_writel(mask, r); - au_sync(); + __raw_writel(mask, base + r); + wmb(); } static inline int alchemy_gpio1_get_value(int gpio) { + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR); unsigned long mask = 1 << (gpio - ALCHEMY_GPIO1_BASE); - return au_readl(SYS_PINSTATERD) & mask; + return __raw_readl(base + SYS_PINSTATERD) & mask; } static inline int alchemy_gpio1_direction_input(int gpio) { + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR); unsigned long mask = 1 << (gpio - ALCHEMY_GPIO1_BASE); - au_writel(mask, SYS_TRIOUTCLR); - au_sync(); + __raw_writel(mask, base + SYS_TRIOUTCLR); + wmb(); return 0; } @@ -257,27 +277,31 @@ static inline int alchemy_gpio1_to_irq(int gpio) */ static inline void __alchemy_gpio2_mod_dir(int gpio, int to_out) { + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR); unsigned long mask = 1 << (gpio - ALCHEMY_GPIO2_BASE); - unsigned long d = au_readl(GPIO2_DIR); + unsigned long d = __raw_readl(base + GPIO2_DIR); + if (to_out) d |= mask; else d &= ~mask; - au_writel(d, GPIO2_DIR); - au_sync(); + __raw_writel(d, base + GPIO2_DIR); + wmb(); } static inline void alchemy_gpio2_set_value(int gpio, int v) { + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR); unsigned long mask; mask = ((v) ? 0x00010001 : 0x00010000) << (gpio - ALCHEMY_GPIO2_BASE); - au_writel(mask, GPIO2_OUTPUT); - au_sync(); + __raw_writel(mask, base + GPIO2_OUTPUT); + wmb(); } static inline int alchemy_gpio2_get_value(int gpio) { - return au_readl(GPIO2_PINSTATE) & (1 << (gpio - ALCHEMY_GPIO2_BASE)); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR); + return __raw_readl(base + GPIO2_PINSTATE) & (1 << (gpio - ALCHEMY_GPIO2_BASE)); } static inline int alchemy_gpio2_direction_input(int gpio) @@ -329,21 +353,23 @@ static inline int alchemy_gpio2_to_irq(int gpio) */ static inline void alchemy_gpio1_input_enable(void) { - au_writel(0, SYS_PININPUTEN); /* the write op is key */ - au_sync(); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR); + __raw_writel(0, base + SYS_PININPUTEN); /* the write op is key */ + wmb(); } /* GPIO2 shared interrupts and control */ static inline void __alchemy_gpio2_mod_int(int gpio2, int en) { - unsigned long r = au_readl(GPIO2_INTENABLE); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR); + unsigned long r = __raw_readl(base + GPIO2_INTENABLE); if (en) r |= 1 << gpio2; else r &= ~(1 << gpio2); - au_writel(r, GPIO2_INTENABLE); - au_sync(); + __raw_writel(r, base + GPIO2_INTENABLE); + wmb(); } /** @@ -418,10 +444,11 @@ static inline void alchemy_gpio2_disable_int(int gpio2) */ static inline void alchemy_gpio2_enable(void) { - au_writel(3, GPIO2_ENABLE); /* reset, clock enabled */ - au_sync(); - au_writel(1, GPIO2_ENABLE); /* clock enabled */ - au_sync(); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR); + __raw_writel(3, base + GPIO2_ENABLE); /* reset, clock enabled */ + wmb(); + __raw_writel(1, base + GPIO2_ENABLE); /* clock enabled */ + wmb(); } /** @@ -431,8 +458,9 @@ static inline void alchemy_gpio2_enable(void) */ static inline void alchemy_gpio2_disable(void) { - au_writel(2, GPIO2_ENABLE); /* reset, clock disabled */ - au_sync(); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR); + __raw_writel(2, base + GPIO2_ENABLE); /* reset, clock disabled */ + wmb(); } /**********************************************************************/ @@ -556,6 +584,16 @@ static inline void gpio_set_value(int gpio, int v) alchemy_gpio_set_value(gpio, v); } +static inline int gpio_get_value_cansleep(unsigned gpio) +{ + return gpio_get_value(gpio); +} + +static inline void gpio_set_value_cansleep(unsigned gpio, int value) +{ + gpio_set_value(gpio, value); +} + static inline int gpio_is_valid(int gpio) { return alchemy_gpio_is_valid(gpio); @@ -581,10 +619,50 @@ static inline int gpio_request(unsigned gpio, const char *label) return 0; } +static inline int gpio_request_one(unsigned gpio, + unsigned long flags, const char *label) +{ + return 0; +} + +static inline int gpio_request_array(struct gpio *array, size_t num) +{ + return 0; +} + static inline void gpio_free(unsigned gpio) { } +static inline void gpio_free_array(struct gpio *array, size_t num) +{ +} + +static inline int gpio_set_debounce(unsigned gpio, unsigned debounce) +{ + return -ENOSYS; +} + +static inline int gpio_export(unsigned gpio, bool direction_may_change) +{ + return -ENOSYS; +} + +static inline int gpio_export_link(struct device *dev, const char *name, + unsigned gpio) +{ + return -ENOSYS; +} + +static inline int gpio_sysfs_set_active_low(unsigned gpio, int value) +{ + return -ENOSYS; +} + +static inline void gpio_unexport(unsigned gpio) +{ +} + #endif /* !CONFIG_ALCHEMY_GPIO_INDIRECT */ diff --git a/arch/mips/include/asm/mach-bcm47xx/nvram.h b/arch/mips/include/asm/mach-bcm47xx/nvram.h index 9759588ba3cf..184d5ecb5f51 100644 --- a/arch/mips/include/asm/mach-bcm47xx/nvram.h +++ b/arch/mips/include/asm/mach-bcm47xx/nvram.h @@ -39,8 +39,16 @@ extern int nvram_getenv(char *name, char *val, size_t val_len); static inline void nvram_parse_macaddr(char *buf, u8 *macaddr) { - sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1], - &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]); + if (strchr(buf, ':')) + sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], + &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], + &macaddr[5]); + else if (strchr(buf, '-')) + sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0], + &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], + &macaddr[5]); + else + printk(KERN_WARNING "Can not parse mac address: %s\n", buf); } #endif diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h b/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h index 32978d32561a..ed72e6a26b73 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h @@ -88,7 +88,7 @@ struct bcm_tag { char kernel_crc[CRC_LEN]; /* 228-235: Unused at present */ char reserved1[8]; - /* 236-239: CRC32 of header excluding tagVersion */ + /* 236-239: CRC32 of header excluding last 20 bytes */ char header_crc[CRC_LEN]; /* 240-255: Unused at present */ char reserved2[16]; diff --git a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h index 0b2b5eb22e9b..dedef7d2b01f 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h @@ -63,6 +63,11 @@ # CN30XX Disable instruction prefetching or v0, v0, 0x2000 skip: + # First clear off CvmCtl[IPPCI] bit and move the performance + # counters interrupt to IRQ 6 + li v1, ~(7 << 7) + and v0, v0, v1 + ori v0, v0, (6 << 7) # Write the cavium control register dmtc0 v0, CP0_CVMCTL_REG sync diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h new file mode 100644 index 000000000000..ce2f02929d22 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h @@ -0,0 +1,63 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ +#ifndef _LANTIQ_H__ +#define _LANTIQ_H__ + +#include + +/* generic reg access functions */ +#define ltq_r32(reg) __raw_readl(reg) +#define ltq_w32(val, reg) __raw_writel(val, reg) +#define ltq_w32_mask(clear, set, reg) \ + ltq_w32((ltq_r32(reg) & ~(clear)) | (set), reg) +#define ltq_r8(reg) __raw_readb(reg) +#define ltq_w8(val, reg) __raw_writeb(val, reg) + +/* register access macros for EBU and CGU */ +#define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) +#define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) +#define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y)) +#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x)) + +extern __iomem void *ltq_ebu_membase; +extern __iomem void *ltq_cgu_membase; + +extern unsigned int ltq_get_cpu_ver(void); +extern unsigned int ltq_get_soc_type(void); + +/* clock speeds */ +#define CLOCK_60M 60000000 +#define CLOCK_83M 83333333 +#define CLOCK_111M 111111111 +#define CLOCK_133M 133333333 +#define CLOCK_167M 166666667 +#define CLOCK_200M 200000000 +#define CLOCK_266M 266666666 +#define CLOCK_333M 333333333 +#define CLOCK_400M 400000000 + +/* spinlock all ebu i/o */ +extern spinlock_t ebu_lock; + +/* some irq helpers */ +extern void ltq_disable_irq(struct irq_data *data); +extern void ltq_mask_and_ack_irq(struct irq_data *data); +extern void ltq_enable_irq(struct irq_data *data); + +/* find out what caused the last cpu reset */ +extern int ltq_reset_cause(void); +#define LTQ_RST_CAUSE_WDTRST 0x20 + +#define IOPORT_RESOURCE_START 0x10000000 +#define IOPORT_RESOURCE_END 0xffffffff +#define IOMEM_RESOURCE_START 0x10000000 +#define IOMEM_RESOURCE_END 0xffffffff +#define LTQ_FLASH_START 0x10000000 +#define LTQ_FLASH_MAX 0x04000000 + +#endif diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h new file mode 100644 index 000000000000..a305f1d0259e --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h @@ -0,0 +1,53 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef _LANTIQ_PLATFORM_H__ +#define _LANTIQ_PLATFORM_H__ + +#include +#include + +/* struct used to pass info to the pci core */ +enum { + PCI_CLOCK_INT = 0, + PCI_CLOCK_EXT +}; + +#define PCI_EXIN0 0x0001 +#define PCI_EXIN1 0x0002 +#define PCI_EXIN2 0x0004 +#define PCI_EXIN3 0x0008 +#define PCI_EXIN4 0x0010 +#define PCI_EXIN5 0x0020 +#define PCI_EXIN_MAX 6 + +#define PCI_GNT1 0x0040 +#define PCI_GNT2 0x0080 +#define PCI_GNT3 0x0100 +#define PCI_GNT4 0x0200 + +#define PCI_REQ1 0x0400 +#define PCI_REQ2 0x0800 +#define PCI_REQ3 0x1000 +#define PCI_REQ4 0x2000 +#define PCI_REQ_SHIFT 10 +#define PCI_REQ_MASK 0xf + +struct ltq_pci_data { + int clock; + int gpio; + int irq[16]; +}; + +/* struct used to pass info to network drivers */ +struct ltq_eth_data { + struct sockaddr mac; + int mii_mode; +}; + +#endif diff --git a/arch/mips/include/asm/mach-lantiq/war.h b/arch/mips/include/asm/mach-lantiq/war.h new file mode 100644 index 000000000000..01b08ef368d1 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/war.h @@ -0,0 +1,24 @@ +/* + * 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. + * + */ +#ifndef __ASM_MIPS_MACH_LANTIQ_WAR_H +#define __ASM_MIPS_MACH_LANTIQ_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif diff --git a/arch/mips/include/asm/mach-lantiq/xway/irq.h b/arch/mips/include/asm/mach-lantiq/xway/irq.h new file mode 100644 index 000000000000..a1471d2dd0d2 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/xway/irq.h @@ -0,0 +1,18 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef __LANTIQ_IRQ_H +#define __LANTIQ_IRQ_H + +#include + +#define NR_IRQS 256 + +#include_next + +#endif diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h new file mode 100644 index 000000000000..b4465a888e20 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h @@ -0,0 +1,66 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef _LANTIQ_XWAY_IRQ_H__ +#define _LANTIQ_XWAY_IRQ_H__ + +#define INT_NUM_IRQ0 8 +#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0) +#define INT_NUM_IM1_IRL0 (INT_NUM_IRQ0 + 32) +#define INT_NUM_IM2_IRL0 (INT_NUM_IRQ0 + 64) +#define INT_NUM_IM3_IRL0 (INT_NUM_IRQ0 + 96) +#define INT_NUM_IM4_IRL0 (INT_NUM_IRQ0 + 128) +#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0) + +#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8)) +#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1) +#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2) + +#define LTQ_ASC_ASE_TIR INT_NUM_IM2_IRL0 +#define LTQ_ASC_ASE_RIR (INT_NUM_IM2_IRL0 + 2) +#define LTQ_ASC_ASE_EIR (INT_NUM_IM2_IRL0 + 3) + +#define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15) +#define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14) +#define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16) + +#define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21) +#define LTQ_MEI_INT (INT_NUM_IM1_IRL0 + 23) + +#define LTQ_TIMER6_INT (INT_NUM_IM1_IRL0 + 23) +#define LTQ_USB_INT (INT_NUM_IM1_IRL0 + 22) +#define LTQ_USB_OC_INT (INT_NUM_IM4_IRL0 + 23) + +#define MIPS_CPU_TIMER_IRQ 7 + +#define LTQ_DMA_CH0_INT (INT_NUM_IM2_IRL0) +#define LTQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1) +#define LTQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2) +#define LTQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3) +#define LTQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4) +#define LTQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5) +#define LTQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6) +#define LTQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7) +#define LTQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8) +#define LTQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9) +#define LTQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10) +#define LTQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11) +#define LTQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25) +#define LTQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26) +#define LTQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27) +#define LTQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28) +#define LTQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29) +#define LTQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30) +#define LTQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16) +#define LTQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21) + +#define LTQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24) + +#define INT_NUM_IM4_IRL14 (INT_NUM_IM4_IRL0 + 14) + +#endif diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h new file mode 100644 index 000000000000..8a3c6be669d2 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -0,0 +1,141 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef _LTQ_XWAY_H__ +#define _LTQ_XWAY_H__ + +#ifdef CONFIG_SOC_TYPE_XWAY + +#include + +/* Chip IDs */ +#define SOC_ID_DANUBE1 0x129 +#define SOC_ID_DANUBE2 0x12B +#define SOC_ID_TWINPASS 0x12D +#define SOC_ID_AMAZON_SE 0x152 +#define SOC_ID_ARX188 0x16C +#define SOC_ID_ARX168 0x16D +#define SOC_ID_ARX182 0x16F + +/* SoC Types */ +#define SOC_TYPE_DANUBE 0x01 +#define SOC_TYPE_TWINPASS 0x02 +#define SOC_TYPE_AR9 0x03 +#define SOC_TYPE_VR9 0x04 +#define SOC_TYPE_AMAZON_SE 0x05 + +/* ASC0/1 - serial port */ +#define LTQ_ASC0_BASE_ADDR 0x1E100400 +#define LTQ_ASC1_BASE_ADDR 0x1E100C00 +#define LTQ_ASC_SIZE 0x400 + +/* RCU - reset control unit */ +#define LTQ_RCU_BASE_ADDR 0x1F203000 +#define LTQ_RCU_SIZE 0x1000 + +/* GPTU - general purpose timer unit */ +#define LTQ_GPTU_BASE_ADDR 0x18000300 +#define LTQ_GPTU_SIZE 0x100 + +/* EBU - external bus unit */ +#define LTQ_EBU_GPIO_START 0x14000000 +#define LTQ_EBU_GPIO_SIZE 0x1000 + +#define LTQ_EBU_BASE_ADDR 0x1E105300 +#define LTQ_EBU_SIZE 0x100 + +#define LTQ_EBU_BUSCON0 0x0060 +#define LTQ_EBU_PCC_CON 0x0090 +#define LTQ_EBU_PCC_IEN 0x00A4 +#define LTQ_EBU_PCC_ISTAT 0x00A0 +#define LTQ_EBU_BUSCON1 0x0064 +#define LTQ_EBU_ADDRSEL1 0x0024 +#define EBU_WRDIS 0x80000000 + +/* CGU - clock generation unit */ +#define LTQ_CGU_BASE_ADDR 0x1F103000 +#define LTQ_CGU_SIZE 0x1000 + +/* ICU - interrupt control unit */ +#define LTQ_ICU_BASE_ADDR 0x1F880200 +#define LTQ_ICU_SIZE 0x100 + +/* EIU - external interrupt unit */ +#define LTQ_EIU_BASE_ADDR 0x1F101000 +#define LTQ_EIU_SIZE 0x1000 + +/* PMU - power management unit */ +#define LTQ_PMU_BASE_ADDR 0x1F102000 +#define LTQ_PMU_SIZE 0x1000 + +#define PMU_DMA 0x0020 +#define PMU_USB 0x8041 +#define PMU_LED 0x0800 +#define PMU_GPT 0x1000 +#define PMU_PPE 0x2000 +#define PMU_FPI 0x4000 +#define PMU_SWITCH 0x10000000 + +/* ETOP - ethernet */ +#define LTQ_ETOP_BASE_ADDR 0x1E180000 +#define LTQ_ETOP_SIZE 0x40000 + +/* DMA */ +#define LTQ_DMA_BASE_ADDR 0x1E104100 +#define LTQ_DMA_SIZE 0x800 + +/* PCI */ +#define PCI_CR_BASE_ADDR 0x1E105400 +#define PCI_CR_SIZE 0x400 + +/* WDT */ +#define LTQ_WDT_BASE_ADDR 0x1F8803F0 +#define LTQ_WDT_SIZE 0x10 + +/* STP - serial to parallel conversion unit */ +#define LTQ_STP_BASE_ADDR 0x1E100BB0 +#define LTQ_STP_SIZE 0x40 + +/* GPIO */ +#define LTQ_GPIO0_BASE_ADDR 0x1E100B10 +#define LTQ_GPIO1_BASE_ADDR 0x1E100B40 +#define LTQ_GPIO2_BASE_ADDR 0x1E100B70 +#define LTQ_GPIO_SIZE 0x30 + +/* SSC */ +#define LTQ_SSC_BASE_ADDR 0x1e100800 +#define LTQ_SSC_SIZE 0x100 + +/* MEI - dsl core */ +#define LTQ_MEI_BASE_ADDR 0x1E116000 + +/* DEU - data encryption unit */ +#define LTQ_DEU_BASE_ADDR 0x1E103100 + +/* MPS - multi processor unit (voice) */ +#define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) +#define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344)) + +/* request a non-gpio and set the PIO config */ +extern int ltq_gpio_request(unsigned int pin, unsigned int alt0, + unsigned int alt1, unsigned int dir, const char *name); +extern void ltq_pmu_enable(unsigned int module); +extern void ltq_pmu_disable(unsigned int module); + +static inline int ltq_is_ar9(void) +{ + return (ltq_get_soc_type() == SOC_TYPE_AR9); +} + +static inline int ltq_is_vr9(void) +{ + return (ltq_get_soc_type() == SOC_TYPE_VR9); +} + +#endif /* CONFIG_SOC_TYPE_XWAY */ +#endif /* _LTQ_XWAY_H__ */ diff --git a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h new file mode 100644 index 000000000000..872943a4b90e --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h @@ -0,0 +1,60 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2011 John Crispin + */ + +#ifndef LTQ_DMA_H__ +#define LTQ_DMA_H__ + +#define LTQ_DESC_SIZE 0x08 /* each descriptor is 64bit */ +#define LTQ_DESC_NUM 0x40 /* 64 descriptors / channel */ + +#define LTQ_DMA_OWN BIT(31) /* owner bit */ +#define LTQ_DMA_C BIT(30) /* complete bit */ +#define LTQ_DMA_SOP BIT(29) /* start of packet */ +#define LTQ_DMA_EOP BIT(28) /* end of packet */ +#define LTQ_DMA_TX_OFFSET(x) ((x & 0x1f) << 23) /* data bytes offset */ +#define LTQ_DMA_RX_OFFSET(x) ((x & 0x7) << 23) /* data bytes offset */ +#define LTQ_DMA_SIZE_MASK (0xffff) /* the size field is 16 bit */ + +struct ltq_dma_desc { + u32 ctl; + u32 addr; +}; + +struct ltq_dma_channel { + int nr; /* the channel number */ + int irq; /* the mapped irq */ + int desc; /* the current descriptor */ + struct ltq_dma_desc *desc_base; /* the descriptor base */ + int phys; /* physical addr */ +}; + +enum { + DMA_PORT_ETOP = 0, + DMA_PORT_DEU, +}; + +extern void ltq_dma_enable_irq(struct ltq_dma_channel *ch); +extern void ltq_dma_disable_irq(struct ltq_dma_channel *ch); +extern void ltq_dma_ack_irq(struct ltq_dma_channel *ch); +extern void ltq_dma_open(struct ltq_dma_channel *ch); +extern void ltq_dma_close(struct ltq_dma_channel *ch); +extern void ltq_dma_alloc_tx(struct ltq_dma_channel *ch); +extern void ltq_dma_alloc_rx(struct ltq_dma_channel *ch); +extern void ltq_dma_free(struct ltq_dma_channel *ch); +extern void ltq_dma_init_port(int p); + +#endif diff --git a/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h b/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h new file mode 100644 index 000000000000..3b728275b9b0 --- /dev/null +++ b/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h @@ -0,0 +1,47 @@ +/* + * 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 Netlogic Microsystems + * Copyright (C) 2003 Ralf Baechle + */ +#ifndef __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H +#define __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H + +#define cpu_has_4kex 1 +#define cpu_has_4k_cache 1 +#define cpu_has_watch 1 +#define cpu_has_mips16 0 +#define cpu_has_counter 1 +#define cpu_has_divec 1 +#define cpu_has_vce 0 +#define cpu_has_cache_cdex_p 0 +#define cpu_has_cache_cdex_s 0 +#define cpu_has_prefetch 1 +#define cpu_has_mcheck 1 +#define cpu_has_ejtag 1 + +#define cpu_has_llsc 1 +#define cpu_has_vtag_icache 0 +#define cpu_has_dc_aliases 0 +#define cpu_has_ic_fills_f_dc 0 +#define cpu_has_dsp 0 +#define cpu_has_mipsmt 0 +#define cpu_has_userlocal 0 +#define cpu_icache_snoops_remote_store 0 + +#define cpu_has_nofpuex 0 +#define cpu_has_64bits 1 + +#define cpu_has_mips32r1 1 +#define cpu_has_mips32r2 0 +#define cpu_has_mips64r1 1 +#define cpu_has_mips64r2 0 + +#define cpu_has_inclusive_pcaches 0 + +#define cpu_dcache_line_size() 32 +#define cpu_icache_line_size() 32 + +#endif /* __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H */ diff --git a/arch/mips/include/asm/mach-netlogic/irq.h b/arch/mips/include/asm/mach-netlogic/irq.h new file mode 100644 index 000000000000..b5902458e7c1 --- /dev/null +++ b/arch/mips/include/asm/mach-netlogic/irq.h @@ -0,0 +1,14 @@ +/* + * 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 Netlogic Microsystems. + */ +#ifndef __ASM_NETLOGIC_IRQ_H +#define __ASM_NETLOGIC_IRQ_H + +#define NR_IRQS 64 +#define MIPS_CPU_IRQ_BASE 0 + +#endif /* __ASM_NETLOGIC_IRQ_H */ diff --git a/arch/mips/include/asm/mach-netlogic/war.h b/arch/mips/include/asm/mach-netlogic/war.h new file mode 100644 index 000000000000..22da89327352 --- /dev/null +++ b/arch/mips/include/asm/mach-netlogic/war.h @@ -0,0 +1,26 @@ +/* + * 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 Netlogic Microsystems. + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_NLM_WAR_H +#define __ASM_MIPS_MACH_NLM_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_NLM_WAR_H */ diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h index d94085a3eafb..bc01a02cacd8 100644 --- a/arch/mips/include/asm/module.h +++ b/arch/mips/include/asm/module.h @@ -118,6 +118,8 @@ search_module_dbetables(unsigned long addr) #define MODULE_PROC_FAMILY "LOONGSON2 " #elif defined CONFIG_CPU_CAVIUM_OCTEON #define MODULE_PROC_FAMILY "OCTEON " +#elif defined CONFIG_CPU_XLR +#define MODULE_PROC_FAMILY "XLR " #else #error MODULE_PROC_FAMILY undefined for your processor configuration #endif diff --git a/arch/mips/include/asm/netlogic/interrupt.h b/arch/mips/include/asm/netlogic/interrupt.h new file mode 100644 index 000000000000..a85aadb6cfd7 --- /dev/null +++ b/arch/mips/include/asm/netlogic/interrupt.h @@ -0,0 +1,45 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 _ASM_NLM_INTERRUPT_H +#define _ASM_NLM_INTERRUPT_H + +/* Defines for the IRQ numbers */ + +#define IRQ_IPI_SMP_FUNCTION 3 +#define IRQ_IPI_SMP_RESCHEDULE 4 +#define IRQ_MSGRING 6 +#define IRQ_TIMER 7 + +#endif diff --git a/arch/mips/include/asm/netlogic/mips-extns.h b/arch/mips/include/asm/netlogic/mips-extns.h new file mode 100644 index 000000000000..8c53d0ba4bf2 --- /dev/null +++ b/arch/mips/include/asm/netlogic/mips-extns.h @@ -0,0 +1,76 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 _ASM_NLM_MIPS_EXTS_H +#define _ASM_NLM_MIPS_EXTS_H + +/* + * XLR and XLP interrupt request and interrupt mask registers + */ +#define read_c0_eirr() __read_64bit_c0_register($9, 6) +#define read_c0_eimr() __read_64bit_c0_register($9, 7) +#define write_c0_eirr(val) __write_64bit_c0_register($9, 6, val) + +/* + * Writing EIMR in 32 bit is a special case, the lower 8 bit of the + * EIMR is shadowed in the status register, so we cannot save and + * restore status register for split read. + */ +#define write_c0_eimr(val) \ +do { \ + if (sizeof(unsigned long) == 4) { \ + unsigned long __flags; \ + \ + local_irq_save(__flags); \ + __asm__ __volatile__( \ + ".set\tmips64\n\t" \ + "dsll\t%L0, %L0, 32\n\t" \ + "dsrl\t%L0, %L0, 32\n\t" \ + "dsll\t%M0, %M0, 32\n\t" \ + "or\t%L0, %L0, %M0\n\t" \ + "dmtc0\t%L0, $9, 7\n\t" \ + ".set\tmips0" \ + : : "r" (val)); \ + __flags = (__flags & 0xffff00ff) | (((val) & 0xff) << 8);\ + local_irq_restore(__flags); \ + } else \ + __write_64bit_c0_register($9, 7, (val)); \ +} while (0) + +static inline int hard_smp_processor_id(void) +{ + return __read_32bit_c0_register($15, 1) & 0x3ff; +} + +#endif /*_ASM_NLM_MIPS_EXTS_H */ diff --git a/arch/mips/include/asm/netlogic/psb-bootinfo.h b/arch/mips/include/asm/netlogic/psb-bootinfo.h new file mode 100644 index 000000000000..6878307f0ee6 --- /dev/null +++ b/arch/mips/include/asm/netlogic/psb-bootinfo.h @@ -0,0 +1,109 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 _ASM_NETLOGIC_BOOTINFO_H +#define _ASM_NETLOGIC_BOOTINFO_H + +struct psb_info { + uint64_t boot_level; + uint64_t io_base; + uint64_t output_device; + uint64_t uart_print; + uint64_t led_output; + uint64_t init; + uint64_t exit; + uint64_t warm_reset; + uint64_t wakeup; + uint64_t online_cpu_map; + uint64_t master_reentry_sp; + uint64_t master_reentry_gp; + uint64_t master_reentry_fn; + uint64_t slave_reentry_fn; + uint64_t magic_dword; + uint64_t uart_putchar; + uint64_t size; + uint64_t uart_getchar; + uint64_t nmi_handler; + uint64_t psb_version; + uint64_t mac_addr; + uint64_t cpu_frequency; + uint64_t board_version; + uint64_t malloc; + uint64_t free; + uint64_t global_shmem_addr; + uint64_t global_shmem_size; + uint64_t psb_os_cpu_map; + uint64_t userapp_cpu_map; + uint64_t wakeup_os; + uint64_t psb_mem_map; + uint64_t board_major_version; + uint64_t board_minor_version; + uint64_t board_manf_revision; + uint64_t board_serial_number; + uint64_t psb_physaddr_map; + uint64_t xlr_loaderip_config; + uint64_t bldr_envp; + uint64_t avail_mem_map; +}; + +enum { + NETLOGIC_IO_SPACE = 0x10, + PCIX_IO_SPACE, + PCIX_CFG_SPACE, + PCIX_MEMORY_SPACE, + HT_IO_SPACE, + HT_CFG_SPACE, + HT_MEMORY_SPACE, + SRAM_SPACE, + FLASH_CONTROLLER_SPACE +}; + +#define NLM_MAX_ARGS 64 +#define NLM_MAX_ENVS 32 + +/* This is what netlboot passes and linux boot_mem_map is subtly different */ +#define NLM_BOOT_MEM_MAP_MAX 32 +struct nlm_boot_mem_map { + int nr_map; + struct nlm_boot_mem_map_entry { + uint64_t addr; /* start of memory segment */ + uint64_t size; /* size of memory segment */ + uint32_t type; /* type of memory segment */ + } map[NLM_BOOT_MEM_MAP_MAX]; +}; + +/* Pointer to saved boot loader info */ +extern struct psb_info nlm_prom_info; + +#endif diff --git a/arch/mips/include/asm/netlogic/xlr/gpio.h b/arch/mips/include/asm/netlogic/xlr/gpio.h new file mode 100644 index 000000000000..51f6ad4aeb14 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlr/gpio.h @@ -0,0 +1,73 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 _ASM_NLM_GPIO_H +#define _ASM_NLM_GPIO_H + +#define NETLOGIC_GPIO_INT_EN_REG 0 +#define NETLOGIC_GPIO_INPUT_INVERSION_REG 1 +#define NETLOGIC_GPIO_IO_DIR_REG 2 +#define NETLOGIC_GPIO_IO_DATA_WR_REG 3 +#define NETLOGIC_GPIO_IO_DATA_RD_REG 4 + +#define NETLOGIC_GPIO_SWRESET_REG 8 +#define NETLOGIC_GPIO_DRAM1_CNTRL_REG 9 +#define NETLOGIC_GPIO_DRAM1_RATIO_REG 10 +#define NETLOGIC_GPIO_DRAM1_RESET_REG 11 +#define NETLOGIC_GPIO_DRAM1_STATUS_REG 12 +#define NETLOGIC_GPIO_DRAM2_CNTRL_REG 13 +#define NETLOGIC_GPIO_DRAM2_RATIO_REG 14 +#define NETLOGIC_GPIO_DRAM2_RESET_REG 15 +#define NETLOGIC_GPIO_DRAM2_STATUS_REG 16 + +#define NETLOGIC_GPIO_PWRON_RESET_CFG_REG 21 +#define NETLOGIC_GPIO_BIST_ALL_GO_STATUS_REG 24 +#define NETLOGIC_GPIO_BIST_CPU_GO_STATUS_REG 25 +#define NETLOGIC_GPIO_BIST_DEV_GO_STATUS_REG 26 + +#define NETLOGIC_GPIO_FUSE_BANK_REG 35 +#define NETLOGIC_GPIO_CPU_RESET_REG 40 +#define NETLOGIC_GPIO_RNG_REG 43 + +#define NETLOGIC_PWRON_RESET_PCMCIA_BOOT 17 +#define NETLOGIC_GPIO_LED_BITMAP 0x1700000 +#define NETLOGIC_GPIO_LED_0_SHIFT 20 +#define NETLOGIC_GPIO_LED_1_SHIFT 24 + +#define NETLOGIC_GPIO_LED_OUTPUT_CODE_RESET 0x01 +#define NETLOGIC_GPIO_LED_OUTPUT_CODE_HARD_RESET 0x02 +#define NETLOGIC_GPIO_LED_OUTPUT_CODE_SOFT_RESET 0x03 +#define NETLOGIC_GPIO_LED_OUTPUT_CODE_MAIN 0x04 + +#endif diff --git a/arch/mips/include/asm/netlogic/xlr/iomap.h b/arch/mips/include/asm/netlogic/xlr/iomap.h new file mode 100644 index 000000000000..2e3a4dd53045 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlr/iomap.h @@ -0,0 +1,131 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 _ASM_NLM_IOMAP_H +#define _ASM_NLM_IOMAP_H + +#define DEFAULT_NETLOGIC_IO_BASE CKSEG1ADDR(0x1ef00000) +#define NETLOGIC_IO_DDR2_CHN0_OFFSET 0x01000 +#define NETLOGIC_IO_DDR2_CHN1_OFFSET 0x02000 +#define NETLOGIC_IO_DDR2_CHN2_OFFSET 0x03000 +#define NETLOGIC_IO_DDR2_CHN3_OFFSET 0x04000 +#define NETLOGIC_IO_PIC_OFFSET 0x08000 +#define NETLOGIC_IO_UART_0_OFFSET 0x14000 +#define NETLOGIC_IO_UART_1_OFFSET 0x15100 + +#define NETLOGIC_IO_SIZE 0x1000 + +#define NETLOGIC_IO_BRIDGE_OFFSET 0x00000 + +#define NETLOGIC_IO_RLD2_CHN0_OFFSET 0x05000 +#define NETLOGIC_IO_RLD2_CHN1_OFFSET 0x06000 + +#define NETLOGIC_IO_SRAM_OFFSET 0x07000 + +#define NETLOGIC_IO_PCIX_OFFSET 0x09000 +#define NETLOGIC_IO_HT_OFFSET 0x0A000 + +#define NETLOGIC_IO_SECURITY_OFFSET 0x0B000 + +#define NETLOGIC_IO_GMAC_0_OFFSET 0x0C000 +#define NETLOGIC_IO_GMAC_1_OFFSET 0x0D000 +#define NETLOGIC_IO_GMAC_2_OFFSET 0x0E000 +#define NETLOGIC_IO_GMAC_3_OFFSET 0x0F000 + +/* XLS devices */ +#define NETLOGIC_IO_GMAC_4_OFFSET 0x20000 +#define NETLOGIC_IO_GMAC_5_OFFSET 0x21000 +#define NETLOGIC_IO_GMAC_6_OFFSET 0x22000 +#define NETLOGIC_IO_GMAC_7_OFFSET 0x23000 + +#define NETLOGIC_IO_PCIE_0_OFFSET 0x1E000 +#define NETLOGIC_IO_PCIE_1_OFFSET 0x1F000 +#define NETLOGIC_IO_SRIO_0_OFFSET 0x1E000 +#define NETLOGIC_IO_SRIO_1_OFFSET 0x1F000 + +#define NETLOGIC_IO_USB_0_OFFSET 0x24000 +#define NETLOGIC_IO_USB_1_OFFSET 0x25000 + +#define NETLOGIC_IO_COMP_OFFSET 0x1D000 +/* end XLS devices */ + +/* XLR devices */ +#define NETLOGIC_IO_SPI4_0_OFFSET 0x10000 +#define NETLOGIC_IO_XGMAC_0_OFFSET 0x11000 +#define NETLOGIC_IO_SPI4_1_OFFSET 0x12000 +#define NETLOGIC_IO_XGMAC_1_OFFSET 0x13000 +/* end XLR devices */ + +#define NETLOGIC_IO_I2C_0_OFFSET 0x16000 +#define NETLOGIC_IO_I2C_1_OFFSET 0x17000 + +#define NETLOGIC_IO_GPIO_OFFSET 0x18000 +#define NETLOGIC_IO_FLASH_OFFSET 0x19000 +#define NETLOGIC_IO_TB_OFFSET 0x1C000 + +#define NETLOGIC_CPLD_OFFSET KSEG1ADDR(0x1d840000) + +/* + * Base Address (Virtual) of the PCI Config address space + * For now, choose 256M phys in kseg1 = 0xA0000000 + (1<<28) + * Config space spans 256 (num of buses) * 256 (num functions) * 256 bytes + * ie 1<<24 = 16M + */ +#define DEFAULT_PCI_CONFIG_BASE 0x18000000 +#define DEFAULT_HT_TYPE0_CFG_BASE 0x16000000 +#define DEFAULT_HT_TYPE1_CFG_BASE 0x17000000 + +#ifndef __ASSEMBLY__ +#include +#include + +typedef volatile __u32 nlm_reg_t; +extern unsigned long netlogic_io_base; + +/* FIXME read once in write_reg */ +#ifdef CONFIG_CPU_LITTLE_ENDIAN +#define netlogic_read_reg(base, offset) ((base)[(offset)]) +#define netlogic_write_reg(base, offset, value) ((base)[(offset)] = (value)) +#else +#define netlogic_read_reg(base, offset) (be32_to_cpu((base)[(offset)])) +#define netlogic_write_reg(base, offset, value) \ + ((base)[(offset)] = cpu_to_be32((value))) +#endif + +#define netlogic_read_reg_le32(base, offset) (le32_to_cpu((base)[(offset)])) +#define netlogic_write_reg_le32(base, offset, value) \ + ((base)[(offset)] = cpu_to_le32((value))) +#define netlogic_io_mmio(offset) ((nlm_reg_t *)(netlogic_io_base+(offset))) +#endif /* __ASSEMBLY__ */ +#endif diff --git a/arch/mips/include/asm/netlogic/xlr/pic.h b/arch/mips/include/asm/netlogic/xlr/pic.h new file mode 100644 index 000000000000..5cceb746f080 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlr/pic.h @@ -0,0 +1,231 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 _ASM_NLM_XLR_PIC_H +#define _ASM_NLM_XLR_PIC_H + +#define PIC_CLKS_PER_SEC 66666666ULL +/* PIC hardware interrupt numbers */ +#define PIC_IRT_WD_INDEX 0 +#define PIC_IRT_TIMER_0_INDEX 1 +#define PIC_IRT_TIMER_1_INDEX 2 +#define PIC_IRT_TIMER_2_INDEX 3 +#define PIC_IRT_TIMER_3_INDEX 4 +#define PIC_IRT_TIMER_4_INDEX 5 +#define PIC_IRT_TIMER_5_INDEX 6 +#define PIC_IRT_TIMER_6_INDEX 7 +#define PIC_IRT_TIMER_7_INDEX 8 +#define PIC_IRT_CLOCK_INDEX PIC_IRT_TIMER_7_INDEX +#define PIC_IRT_UART_0_INDEX 9 +#define PIC_IRT_UART_1_INDEX 10 +#define PIC_IRT_I2C_0_INDEX 11 +#define PIC_IRT_I2C_1_INDEX 12 +#define PIC_IRT_PCMCIA_INDEX 13 +#define PIC_IRT_GPIO_INDEX 14 +#define PIC_IRT_HYPER_INDEX 15 +#define PIC_IRT_PCIX_INDEX 16 +/* XLS */ +#define PIC_IRT_CDE_INDEX 15 +#define PIC_IRT_BRIDGE_TB_XLS_INDEX 16 +/* XLS */ +#define PIC_IRT_GMAC0_INDEX 17 +#define PIC_IRT_GMAC1_INDEX 18 +#define PIC_IRT_GMAC2_INDEX 19 +#define PIC_IRT_GMAC3_INDEX 20 +#define PIC_IRT_XGS0_INDEX 21 +#define PIC_IRT_XGS1_INDEX 22 +#define PIC_IRT_HYPER_FATAL_INDEX 23 +#define PIC_IRT_PCIX_FATAL_INDEX 24 +#define PIC_IRT_BRIDGE_AERR_INDEX 25 +#define PIC_IRT_BRIDGE_BERR_INDEX 26 +#define PIC_IRT_BRIDGE_TB_XLR_INDEX 27 +#define PIC_IRT_BRIDGE_AERR_NMI_INDEX 28 +/* XLS */ +#define PIC_IRT_GMAC4_INDEX 21 +#define PIC_IRT_GMAC5_INDEX 22 +#define PIC_IRT_GMAC6_INDEX 23 +#define PIC_IRT_GMAC7_INDEX 24 +#define PIC_IRT_BRIDGE_ERR_INDEX 25 +#define PIC_IRT_PCIE_LINK0_INDEX 26 +#define PIC_IRT_PCIE_LINK1_INDEX 27 +#define PIC_IRT_PCIE_LINK2_INDEX 23 +#define PIC_IRT_PCIE_LINK3_INDEX 24 +#define PIC_IRT_PCIE_XLSB0_LINK2_INDEX 28 +#define PIC_IRT_PCIE_XLSB0_LINK3_INDEX 29 +#define PIC_IRT_SRIO_LINK0_INDEX 26 +#define PIC_IRT_SRIO_LINK1_INDEX 27 +#define PIC_IRT_SRIO_LINK2_INDEX 28 +#define PIC_IRT_SRIO_LINK3_INDEX 29 +#define PIC_IRT_PCIE_INT_INDEX 28 +#define PIC_IRT_PCIE_FATAL_INDEX 29 +#define PIC_IRT_GPIO_B_INDEX 30 +#define PIC_IRT_USB_INDEX 31 +/* XLS */ +#define PIC_NUM_IRTS 32 + + +#define PIC_CLOCK_TIMER 7 + +/* PIC Registers */ +#define PIC_CTRL 0x00 +#define PIC_IPI 0x04 +#define PIC_INT_ACK 0x06 + +#define WD_MAX_VAL_0 0x08 +#define WD_MAX_VAL_1 0x09 +#define WD_MASK_0 0x0a +#define WD_MASK_1 0x0b +#define WD_HEARBEAT_0 0x0c +#define WD_HEARBEAT_1 0x0d + +#define PIC_IRT_0_BASE 0x40 +#define PIC_IRT_1_BASE 0x80 +#define PIC_TIMER_MAXVAL_0_BASE 0x100 +#define PIC_TIMER_MAXVAL_1_BASE 0x110 +#define PIC_TIMER_COUNT_0_BASE 0x120 +#define PIC_TIMER_COUNT_1_BASE 0x130 + +#define PIC_IRT_0(picintr) (PIC_IRT_0_BASE + (picintr)) +#define PIC_IRT_1(picintr) (PIC_IRT_1_BASE + (picintr)) + +#define PIC_TIMER_MAXVAL_0(i) (PIC_TIMER_MAXVAL_0_BASE + (i)) +#define PIC_TIMER_MAXVAL_1(i) (PIC_TIMER_MAXVAL_1_BASE + (i)) +#define PIC_TIMER_COUNT_0(i) (PIC_TIMER_COUNT_0_BASE + (i)) +#define PIC_TIMER_COUNT_1(i) (PIC_TIMER_COUNT_0_BASE + (i)) + +/* + * Mapping between hardware interrupt numbers and IRQs on CPU + * we use a simple scheme to map PIC interrupts 0-31 to IRQs + * 8-39. This leaves the IRQ 0-7 for cpu interrupts like + * count/compare and FMN + */ +#define PIC_IRQ_BASE 8 +#define PIC_INTR_TO_IRQ(i) (PIC_IRQ_BASE + (i)) +#define PIC_IRQ_TO_INTR(i) ((i) - PIC_IRQ_BASE) + +#define PIC_IRT_FIRST_IRQ PIC_IRQ_BASE +#define PIC_WD_IRQ PIC_INTR_TO_IRQ(PIC_IRT_WD_INDEX) +#define PIC_TIMER_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_0_INDEX) +#define PIC_TIMER_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_1_INDEX) +#define PIC_TIMER_2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_2_INDEX) +#define PIC_TIMER_3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_3_INDEX) +#define PIC_TIMER_4_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_4_INDEX) +#define PIC_TIMER_5_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_5_INDEX) +#define PIC_TIMER_6_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_6_INDEX) +#define PIC_TIMER_7_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_7_INDEX) +#define PIC_CLOCK_IRQ (PIC_TIMER_7_IRQ) +#define PIC_UART_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_UART_0_INDEX) +#define PIC_UART_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_UART_1_INDEX) +#define PIC_I2C_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_I2C_0_INDEX) +#define PIC_I2C_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_I2C_1_INDEX) +#define PIC_PCMCIA_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCMCIA_INDEX) +#define PIC_GPIO_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GPIO_INDEX) +#define PIC_HYPER_IRQ PIC_INTR_TO_IRQ(PIC_IRT_HYPER_INDEX) +#define PIC_PCIX_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIX_INDEX) +/* XLS */ +#define PIC_CDE_IRQ PIC_INTR_TO_IRQ(PIC_IRT_CDE_INDEX) +#define PIC_BRIDGE_TB_XLS_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_TB_XLS_INDEX) +/* end XLS */ +#define PIC_GMAC_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC0_INDEX) +#define PIC_GMAC_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC1_INDEX) +#define PIC_GMAC_2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC2_INDEX) +#define PIC_GMAC_3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC3_INDEX) +#define PIC_XGS_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_XGS0_INDEX) +#define PIC_XGS_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_XGS1_INDEX) +#define PIC_HYPER_FATAL_IRQ PIC_INTR_TO_IRQ(PIC_IRT_HYPER_FATAL_INDEX) +#define PIC_PCIX_FATAL_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIX_FATAL_INDEX) +#define PIC_BRIDGE_AERR_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_AERR_INDEX) +#define PIC_BRIDGE_BERR_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_BERR_INDEX) +#define PIC_BRIDGE_TB_XLR_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_TB_XLR_INDEX) +#define PIC_BRIDGE_AERR_NMI_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_AERR_NMI_INDEX) +/* XLS defines */ +#define PIC_GMAC_4_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC4_INDEX) +#define PIC_GMAC_5_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC5_INDEX) +#define PIC_GMAC_6_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC6_INDEX) +#define PIC_GMAC_7_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC7_INDEX) +#define PIC_BRIDGE_ERR_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_ERR_INDEX) +#define PIC_PCIE_LINK0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK0_INDEX) +#define PIC_PCIE_LINK1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK1_INDEX) +#define PIC_PCIE_LINK2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK2_INDEX) +#define PIC_PCIE_LINK3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK3_INDEX) +#define PIC_PCIE_XLSB0_LINK2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_XLSB0_LINK2_INDEX) +#define PIC_PCIE_XLSB0_LINK3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_XLSB0_LINK3_INDEX) +#define PIC_SRIO_LINK0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK0_INDEX) +#define PIC_SRIO_LINK1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK1_INDEX) +#define PIC_SRIO_LINK2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK2_INDEX) +#define PIC_SRIO_LINK3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK3_INDEX) +#define PIC_PCIE_INT_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_INT__INDEX) +#define PIC_PCIE_FATAL_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_FATAL_INDEX) +#define PIC_GPIO_B_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GPIO_B_INDEX) +#define PIC_USB_IRQ PIC_INTR_TO_IRQ(PIC_IRT_USB_INDEX) +#define PIC_IRT_LAST_IRQ PIC_USB_IRQ +/* end XLS */ + +#ifndef __ASSEMBLY__ +static inline void pic_send_ipi(u32 ipi) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + + netlogic_write_reg(mmio, PIC_IPI, ipi); +} + +static inline u32 pic_read_control(void) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + + return netlogic_read_reg(mmio, PIC_CTRL); +} + +static inline void pic_write_control(u32 control) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + + netlogic_write_reg(mmio, PIC_CTRL, control); +} + +static inline void pic_update_control(u32 control) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + + netlogic_write_reg(mmio, PIC_CTRL, + (control | netlogic_read_reg(mmio, PIC_CTRL))); +} + +#define PIC_IRQ_IS_EDGE_TRIGGERED(irq) (((irq) >= PIC_TIMER_0_IRQ) && \ + ((irq) <= PIC_TIMER_7_IRQ)) +#define PIC_IRQ_IS_IRT(irq) (((irq) >= PIC_IRT_FIRST_IRQ) && \ + ((irq) <= PIC_IRT_LAST_IRQ)) +#endif + +#endif /* _ASM_NLM_XLR_PIC_H */ diff --git a/arch/mips/include/asm/netlogic/xlr/xlr.h b/arch/mips/include/asm/netlogic/xlr/xlr.h new file mode 100644 index 000000000000..3e6372692a04 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlr/xlr.h @@ -0,0 +1,75 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 _ASM_NLM_XLR_H +#define _ASM_NLM_XLR_H + +/* Platform UART functions */ +struct uart_port; +unsigned int nlm_xlr_uart_in(struct uart_port *, int); +void nlm_xlr_uart_out(struct uart_port *, int, int); + +/* SMP support functions */ +struct irq_desc; +void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc); +void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc); +int nlm_wakeup_secondary_cpus(u32 wakeup_mask); +void nlm_smp_irq_init(void); +void nlm_boot_smp_nmi(void); +void prom_pre_boot_secondary_cpus(void); + +extern struct plat_smp_ops nlm_smp_ops; +extern unsigned long nlm_common_ebase; + +/* XLS B silicon "Rook" */ +static inline unsigned int nlm_chip_is_xls_b(void) +{ + uint32_t prid = read_c0_prid(); + + return ((prid & 0xf000) == 0x4000); +} + +/* + * XLR chip types + */ + /* The XLS product line has chip versions 0x[48c]? */ +static inline unsigned int nlm_chip_is_xls(void) +{ + uint32_t prid = read_c0_prid(); + + return ((prid & 0xf000) == 0x8000 || (prid & 0xf000) == 0x4000 || + (prid & 0xf000) == 0xc000); +} + +#endif /* _ASM_NLM_XLR_H */ diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index 9f1b8dba2c81..de39b1f343ea 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h @@ -141,7 +141,8 @@ extern int ptrace_set_watch_regs(struct task_struct *child, #define instruction_pointer(regs) ((regs)->cp0_epc) #define profile_pc(regs) instruction_pointer(regs) -extern asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit); +extern asmlinkage void syscall_trace_enter(struct pt_regs *regs); +extern asmlinkage void syscall_trace_leave(struct pt_regs *regs); extern NORET_TYPE void die(const char *, struct pt_regs *) ATTRIB_NORET; diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index d71160de4d10..97f8bf6639e7 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -149,6 +149,9 @@ register struct thread_info *__current_thread_info __asm__("$28"); #define _TIF_FPUBOUND (1< 0xffffff) { if (vdma_debug) @@ -228,8 +228,7 @@ int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size) return -EINVAL; /* invalid physical address */ } - npages = pages = - (((paddr & (VDMA_PAGESIZE - 1)) + size) >> 12) + 1; + pages = (((paddr & (VDMA_PAGESIZE - 1)) + size) >> 12) + 1; first = laddr >> 12; if (vdma_debug) printk("vdma_remap: first=%x, pages=%x\n", first, pages); diff --git a/arch/mips/jz4740/dma.c b/arch/mips/jz4740/dma.c index 5ebe75a68350..d7feb898692c 100644 --- a/arch/mips/jz4740/dma.c +++ b/arch/mips/jz4740/dma.c @@ -242,9 +242,7 @@ EXPORT_SYMBOL_GPL(jz4740_dma_get_residue); static void jz4740_dma_chan_irq(struct jz4740_dma_chan *dma) { - uint32_t status; - - status = jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id)); + (void) jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id)); jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0, JZ_DMA_STATUS_CTRL_ENABLE | JZ_DMA_STATUS_CTRL_TRANSFER_DONE); diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c index 6a9e14dab91e..d97cfbf882f5 100644 --- a/arch/mips/jz4740/setup.c +++ b/arch/mips/jz4740/setup.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2009-2010, Lars-Peter Clausen + * Copyright (C) 2011, Maarten ter Huurne * JZ4740 setup code * * This program is free software; you can redistribute it and/or modify it @@ -14,13 +15,44 @@ */ #include +#include #include +#include + +#include + #include "reset.h" + +#define JZ4740_EMC_SDRAM_CTRL 0x80 + + +static void __init jz4740_detect_mem(void) +{ + void __iomem *jz_emc_base; + u32 ctrl, bus, bank, rows, cols; + phys_t size; + + jz_emc_base = ioremap(JZ4740_EMC_BASE_ADDR, 0x100); + ctrl = readl(jz_emc_base + JZ4740_EMC_SDRAM_CTRL); + bus = 2 - ((ctrl >> 31) & 1); + bank = 1 + ((ctrl >> 19) & 1); + cols = 8 + ((ctrl >> 26) & 7); + rows = 11 + ((ctrl >> 20) & 3); + printk(KERN_DEBUG + "SDRAM preconfigured: bus:%u bank:%u rows:%u cols:%u\n", + bus, bank, rows, cols); + iounmap(jz_emc_base); + + size = 1 << (bus + bank + cols + rows); + add_memory_region(0, size, BOOT_MEM_RAM); +} + void __init plat_mem_setup(void) { jz4740_reset_init(); + jz4740_detect_mem(); } const char *get_system_type(void) diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c index fe01678d94fd..f83c2dd07a27 100644 --- a/arch/mips/jz4740/time.c +++ b/arch/mips/jz4740/time.c @@ -89,7 +89,7 @@ static int jz4740_clockevent_set_next(unsigned long evt, static struct clock_event_device jz4740_clockevent = { .name = "jz4740-timer", - .features = CLOCK_EVT_FEAT_PERIODIC, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_next_event = jz4740_clockevent_set_next, .set_mode = jz4740_clockevent_set_mode, .rating = 200, @@ -121,8 +121,7 @@ void __init plat_time_init(void) clockevents_register_device(&jz4740_clockevent); - clocksource_set_clock(&jz4740_clocksource, clk_rate); - ret = clocksource_register(&jz4740_clocksource); + ret = clocksource_register_hz(&jz4740_clocksource, clk_rate); if (ret) printk(KERN_ERR "Failed to register clocksource: %d\n", ret); diff --git a/arch/mips/jz4740/timer.c b/arch/mips/jz4740/timer.c index b2c015129055..654d5c3900b6 100644 --- a/arch/mips/jz4740/timer.c +++ b/arch/mips/jz4740/timer.c @@ -27,11 +27,13 @@ void jz4740_timer_enable_watchdog(void) { writel(BIT(16), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR); } +EXPORT_SYMBOL_GPL(jz4740_timer_enable_watchdog); void jz4740_timer_disable_watchdog(void) { writel(BIT(16), jz4740_timer_base + JZ_REG_TIMER_STOP_SET); } +EXPORT_SYMBOL_GPL(jz4740_timer_disable_watchdog); void __init jz4740_timer_init(void) { diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index cedee2bcbd18..83bba332bbfc 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_VR41XX) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += octeon_switch.o +obj-$(CONFIG_CPU_XLR) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP_UP) += smp-up.o diff --git a/arch/mips/kernel/cevt-txx9.c b/arch/mips/kernel/cevt-txx9.c index 0b7377361e22..f0ab92a1b057 100644 --- a/arch/mips/kernel/cevt-txx9.c +++ b/arch/mips/kernel/cevt-txx9.c @@ -51,8 +51,7 @@ void __init txx9_clocksource_init(unsigned long baseaddr, { struct txx9_tmr_reg __iomem *tmrptr; - clocksource_set_clock(&txx9_clocksource.cs, TIMER_CLK(imbusclk)); - clocksource_register(&txx9_clocksource.cs); + clocksource_register_hz(&txx9_clocksource.cs, TIMER_CLK(imbusclk)); tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg)); __raw_writel(TCR_BASE, &tmrptr->tcr); diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index f65d4c8c65a6..bb133d10b145 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -291,6 +291,12 @@ static inline int cpu_has_confreg(void) #endif } +static inline void set_elf_platform(int cpu, const char *plat) +{ + if (cpu == 0) + __elf_platform = plat; +} + /* * Get the FPU Implementation/Revision. */ @@ -614,6 +620,16 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) case PRID_IMP_LOONGSON2: c->cputype = CPU_LOONGSON2; __cpu_name[cpu] = "ICT Loongson-2"; + + switch (c->processor_id & PRID_REV_MASK) { + case PRID_REV_LOONGSON2E: + set_elf_platform(cpu, "loongson2e"); + break; + case PRID_REV_LOONGSON2F: + set_elf_platform(cpu, "loongson2f"); + break; + } + c->isa_level = MIPS_CPU_ISA_III; c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC | @@ -911,12 +927,14 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) case PRID_IMP_BMIPS32_REV8: c->cputype = CPU_BMIPS32; __cpu_name[cpu] = "Broadcom BMIPS32"; + set_elf_platform(cpu, "bmips32"); break; case PRID_IMP_BMIPS3300: case PRID_IMP_BMIPS3300_ALT: case PRID_IMP_BMIPS3300_BUG: c->cputype = CPU_BMIPS3300; __cpu_name[cpu] = "Broadcom BMIPS3300"; + set_elf_platform(cpu, "bmips3300"); break; case PRID_IMP_BMIPS43XX: { int rev = c->processor_id & 0xff; @@ -925,15 +943,18 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) rev <= PRID_REV_BMIPS4380_HI) { c->cputype = CPU_BMIPS4380; __cpu_name[cpu] = "Broadcom BMIPS4380"; + set_elf_platform(cpu, "bmips4380"); } else { c->cputype = CPU_BMIPS4350; __cpu_name[cpu] = "Broadcom BMIPS4350"; + set_elf_platform(cpu, "bmips4350"); } break; } case PRID_IMP_BMIPS5000: c->cputype = CPU_BMIPS5000; __cpu_name[cpu] = "Broadcom BMIPS5000"; + set_elf_platform(cpu, "bmips5000"); c->options |= MIPS_CPU_ULRI; break; } @@ -956,14 +977,12 @@ static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_CAVIUM_OCTEON_PLUS; __cpu_name[cpu] = "Cavium Octeon+"; platform: - if (cpu == 0) - __elf_platform = "octeon"; + set_elf_platform(cpu, "octeon"); break; case PRID_IMP_CAVIUM_CN63XX: c->cputype = CPU_CAVIUM_OCTEON2; __cpu_name[cpu] = "Cavium Octeon II"; - if (cpu == 0) - __elf_platform = "octeon2"; + set_elf_platform(cpu, "octeon2"); break; default: printk(KERN_INFO "Unknown Octeon chip!\n"); @@ -988,6 +1007,59 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) } } +static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu) +{ + decode_configs(c); + + c->options = (MIPS_CPU_TLB | + MIPS_CPU_4KEX | + MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | + MIPS_CPU_WATCH | + MIPS_CPU_EJTAG | + MIPS_CPU_LLSC); + + switch (c->processor_id & 0xff00) { + case PRID_IMP_NETLOGIC_XLR732: + case PRID_IMP_NETLOGIC_XLR716: + case PRID_IMP_NETLOGIC_XLR532: + case PRID_IMP_NETLOGIC_XLR308: + case PRID_IMP_NETLOGIC_XLR532C: + case PRID_IMP_NETLOGIC_XLR516C: + case PRID_IMP_NETLOGIC_XLR508C: + case PRID_IMP_NETLOGIC_XLR308C: + c->cputype = CPU_XLR; + __cpu_name[cpu] = "Netlogic XLR"; + break; + + case PRID_IMP_NETLOGIC_XLS608: + case PRID_IMP_NETLOGIC_XLS408: + case PRID_IMP_NETLOGIC_XLS404: + case PRID_IMP_NETLOGIC_XLS208: + case PRID_IMP_NETLOGIC_XLS204: + case PRID_IMP_NETLOGIC_XLS108: + case PRID_IMP_NETLOGIC_XLS104: + case PRID_IMP_NETLOGIC_XLS616B: + case PRID_IMP_NETLOGIC_XLS608B: + case PRID_IMP_NETLOGIC_XLS416B: + case PRID_IMP_NETLOGIC_XLS412B: + case PRID_IMP_NETLOGIC_XLS408B: + case PRID_IMP_NETLOGIC_XLS404B: + c->cputype = CPU_XLR; + __cpu_name[cpu] = "Netlogic XLS"; + break; + + default: + printk(KERN_INFO "Unknown Netlogic chip id [%02x]!\n", + c->processor_id); + c->cputype = CPU_XLR; + break; + } + + c->isa_level = MIPS_CPU_ISA_M64R1; + c->tlbsize = ((read_c0_config1() >> 25) & 0x3f) + 1; +} + #ifdef CONFIG_64BIT /* For use by uaccess.h */ u64 __ua_limit; @@ -1035,6 +1107,9 @@ __cpuinit void cpu_probe(void) case PRID_COMP_INGENIC: cpu_probe_ingenic(c, cpu); break; + case PRID_COMP_NETLOGIC: + cpu_probe_netlogic(c, cpu); + break; } BUG_ON(!__cpu_name[cpu]); diff --git a/arch/mips/kernel/csrc-bcm1480.c b/arch/mips/kernel/csrc-bcm1480.c index 51489f8a825e..f96f99c794a3 100644 --- a/arch/mips/kernel/csrc-bcm1480.c +++ b/arch/mips/kernel/csrc-bcm1480.c @@ -49,6 +49,5 @@ void __init sb1480_clocksource_init(void) plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG))); zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000); - clocksource_set_clock(cs, zbbus); - clocksource_register(cs); + clocksource_register_hz(cs, zbbus); } diff --git a/arch/mips/kernel/csrc-ioasic.c b/arch/mips/kernel/csrc-ioasic.c index 23da108506b0..46bd7fa98d6c 100644 --- a/arch/mips/kernel/csrc-ioasic.c +++ b/arch/mips/kernel/csrc-ioasic.c @@ -59,7 +59,5 @@ void __init dec_ioasic_clocksource_init(void) printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq); clocksource_dec.rating = 200 + freq / 10000000; - clocksource_set_clock(&clocksource_dec, freq); - - clocksource_register(&clocksource_dec); + clocksource_register_hz(&clocksource_dec, freq); } diff --git a/arch/mips/kernel/csrc-powertv.c b/arch/mips/kernel/csrc-powertv.c index a27c16c8690e..2e7c5232da8d 100644 --- a/arch/mips/kernel/csrc-powertv.c +++ b/arch/mips/kernel/csrc-powertv.c @@ -78,9 +78,7 @@ static void __init powertv_c0_hpt_clocksource_init(void) clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; - clocksource_set_clock(&clocksource_mips, mips_hpt_frequency); - - clocksource_register(&clocksource_mips); + clocksource_register_hz(&clocksource_mips, mips_hpt_frequency); } /** @@ -130,43 +128,16 @@ static struct clocksource clocksource_tim_c = { /** * powertv_tim_c_clocksource_init - set up a clock source for the TIM_C clock * - * The hard part here is coming up with a constant k and shift s such that - * the 48-bit TIM_C value multiplied by k doesn't overflow and that value, - * when shifted right by s, yields the corresponding number of nanoseconds. * We know that TIM_C counts at 27 MHz/8, so each cycle corresponds to - * 1 / (27,000,000/8) seconds. Multiply that by a billion and you get the - * number of nanoseconds. Since the TIM_C value has 48 bits and the math is - * done in 64 bits, avoiding an overflow means that k must be less than - * 64 - 48 = 16 bits. + * 1 / (27,000,000/8) seconds. */ static void __init powertv_tim_c_clocksource_init(void) { - int prescale; - unsigned long dividend; - unsigned long k; - int s; - const int max_k_bits = (64 - 48) - 1; - const unsigned long billion = 1000000000; const unsigned long counts_per_second = 27000000 / 8; - prescale = BITS_PER_LONG - ilog2(billion) - 1; - dividend = billion << prescale; - k = dividend / counts_per_second; - s = ilog2(k) - max_k_bits; - - if (s < 0) - s = prescale; - - else { - k >>= s; - s += prescale; - } - - clocksource_tim_c.mult = k; - clocksource_tim_c.shift = s; clocksource_tim_c.rating = 200; - clocksource_register(&clocksource_tim_c); + clocksource_register_hz(&clocksource_tim_c, counts_per_second); tim_c = (struct tim_c *) asic_reg_addr(tim_ch); } diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c index e95a3cd48eea..decd1fa38d55 100644 --- a/arch/mips/kernel/csrc-r4k.c +++ b/arch/mips/kernel/csrc-r4k.c @@ -30,9 +30,7 @@ int __init init_r4k_clocksource(void) /* Calculate a somewhat reasonable rating value */ clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; - clocksource_set_clock(&clocksource_mips, mips_hpt_frequency); - - clocksource_register(&clocksource_mips); + clocksource_register_hz(&clocksource_mips, mips_hpt_frequency); return 0; } diff --git a/arch/mips/kernel/csrc-sb1250.c b/arch/mips/kernel/csrc-sb1250.c index d14d3d1907fa..e9606d907685 100644 --- a/arch/mips/kernel/csrc-sb1250.c +++ b/arch/mips/kernel/csrc-sb1250.c @@ -65,6 +65,5 @@ void __init sb1250_clocksource_init(void) IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); - clocksource_set_clock(cs, V_SCD_TIMER_FREQ); - clocksource_register(cs); + clocksource_register_hz(cs, V_SCD_TIMER_FREQ); } diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index ffa331029e08..37acfa036d44 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -167,14 +167,13 @@ work_notifysig: # deal with pending signals and FEXPORT(syscall_exit_work_partial) SAVE_STATIC syscall_exit_work: - li t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT + li t0, _TIF_WORK_SYSCALL_EXIT and t0, a2 # a2 is preloaded with TI_FLAGS beqz t0, work_pending # trace bit set? - local_irq_enable # could let do_syscall_trace() + local_irq_enable # could let syscall_trace_leave() # call schedule() instead move a0, sp - li a1, 1 - jal do_syscall_trace + jal syscall_trace_leave b resume_userspace #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT) diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index 94ca2b018af7..feb8021a305f 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -23,6 +23,7 @@ #define JAL 0x0c000000 /* jump & link: ip --> ra, jump to target */ #define ADDR_MASK 0x03ffffff /* op_code|addr : 31...26|25 ....0 */ +#define JUMP_RANGE_MASK ((1UL << 28) - 1) #define INSN_NOP 0x00000000 /* nop */ #define INSN_JAL(addr) \ @@ -44,12 +45,12 @@ static inline void ftrace_dyn_arch_init_insns(void) /* jal (ftrace_caller + 8), jump over the first two instruction */ buf = (u32 *)&insn_jal_ftrace_caller; - uasm_i_jal(&buf, (FTRACE_ADDR + 8)); + uasm_i_jal(&buf, (FTRACE_ADDR + 8) & JUMP_RANGE_MASK); #ifdef CONFIG_FUNCTION_GRAPH_TRACER /* j ftrace_graph_caller */ buf = (u32 *)&insn_j_ftrace_graph_caller; - uasm_i_j(&buf, (unsigned long)ftrace_graph_caller); + uasm_i_j(&buf, (unsigned long)ftrace_graph_caller & JUMP_RANGE_MASK); #endif } diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/i8253.c index 2392a7a296d4..391221b6a6aa 100644 --- a/arch/mips/kernel/i8253.c +++ b/arch/mips/kernel/i8253.c @@ -125,87 +125,11 @@ void __init setup_pit_timer(void) setup_irq(0, &irq0); } -/* - * Since the PIT overflows every tick, its not very useful - * to just read by itself. So use jiffies to emulate a free - * running counter: - */ -static cycle_t pit_read(struct clocksource *cs) -{ - unsigned long flags; - int count; - u32 jifs; - static int old_count; - static u32 old_jifs; - - raw_spin_lock_irqsave(&i8253_lock, flags); - /* - * Although our caller may have the read side of xtime_lock, - * this is now a seqlock, and we are cheating in this routine - * by having side effects on state that we cannot undo if - * there is a collision on the seqlock and our caller has to - * retry. (Namely, old_jifs and old_count.) So we must treat - * jiffies as volatile despite the lock. We read jiffies - * before latching the timer count to guarantee that although - * the jiffies value might be older than the count (that is, - * the counter may underflow between the last point where - * jiffies was incremented and the point where we latch the - * count), it cannot be newer. - */ - jifs = jiffies; - outb_p(0x00, PIT_MODE); /* latch the count ASAP */ - count = inb_p(PIT_CH0); /* read the latched count */ - count |= inb_p(PIT_CH0) << 8; - - /* VIA686a test code... reset the latch if count > max + 1 */ - if (count > LATCH) { - outb_p(0x34, PIT_MODE); - outb_p(LATCH & 0xff, PIT_CH0); - outb(LATCH >> 8, PIT_CH0); - count = LATCH - 1; - } - - /* - * It's possible for count to appear to go the wrong way for a - * couple of reasons: - * - * 1. The timer counter underflows, but we haven't handled the - * resulting interrupt and incremented jiffies yet. - * 2. Hardware problem with the timer, not giving us continuous time, - * the counter does small "jumps" upwards on some Pentium systems, - * (see c't 95/10 page 335 for Neptun bug.) - * - * Previous attempts to handle these cases intelligently were - * buggy, so we just do the simple thing now. - */ - if (count > old_count && jifs == old_jifs) { - count = old_count; - } - old_count = count; - old_jifs = jifs; - - raw_spin_unlock_irqrestore(&i8253_lock, flags); - - count = (LATCH - 1) - count; - - return (cycle_t)(jifs * LATCH) + count; -} - -static struct clocksource clocksource_pit = { - .name = "pit", - .rating = 110, - .read = pit_read, - .mask = CLOCKSOURCE_MASK(32), - .mult = 0, - .shift = 20, -}; - static int __init init_pit_clocksource(void) { if (num_possible_cpus() > 1) /* PIT does not scale! */ return 0; - clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20); - return clocksource_register(&clocksource_pit); + return clocksource_i8253_init(); } arch_initcall(init_pit_clocksource); diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index d21c388c0116..4e6ea1ffad46 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -533,15 +533,10 @@ static inline int audit_arch(void) * Notification of system call entry/exit * - triggered by current->work.syscall_trace */ -asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) +asmlinkage void syscall_trace_enter(struct pt_regs *regs) { /* do the secure computing check first */ - if (!entryexit) - secure_computing(regs->regs[2]); - - if (unlikely(current->audit_context) && entryexit) - audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]), - regs->regs[2]); + secure_computing(regs->regs[2]); if (!(current->ptrace & PT_PTRACED)) goto out; @@ -565,8 +560,40 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) } out: - if (unlikely(current->audit_context) && !entryexit) + if (unlikely(current->audit_context)) audit_syscall_entry(audit_arch(), regs->regs[2], regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); } + +/* + * Notification of system call entry/exit + * - triggered by current->work.syscall_trace + */ +asmlinkage void syscall_trace_leave(struct pt_regs *regs) +{ + if (unlikely(current->audit_context)) + audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]), + -regs->regs[2]); + + if (!(current->ptrace & PT_PTRACED)) + return; + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + + /* 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; + } +} diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 7f5468b38d4c..7a8e1dd7f6f2 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -88,8 +88,7 @@ syscall_trace_entry: SAVE_STATIC move s0, t2 move a0, sp - li a1, 0 - jal do_syscall_trace + jal syscall_trace_enter move t0, s0 RESTORE_STATIC @@ -565,7 +564,7 @@ einval: li v0, -ENOSYS sys sys_ioprio_get 2 /* 4315 */ sys sys_utimensat 4 sys sys_signalfd 3 - sys sys_ni_syscall 0 + sys sys_ni_syscall 0 /* was timerfd */ sys sys_eventfd 1 sys sys_fallocate 6 /* 4320 */ sys sys_timerfd_create 2 diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index a2e1fcbc41dc..2d31c83224f9 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -91,8 +91,7 @@ syscall_trace_entry: SAVE_STATIC move s0, t2 move a0, sp - li a1, 0 - jal do_syscall_trace + jal syscall_trace_enter move t0, s0 RESTORE_STATIC @@ -404,7 +403,7 @@ sys_call_table: PTR sys_ioprio_get PTR sys_utimensat /* 5275 */ PTR sys_signalfd - PTR sys_ni_syscall + PTR sys_ni_syscall /* was timerfd */ PTR sys_eventfd PTR sys_fallocate PTR sys_timerfd_create /* 5280 */ diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index b2c7624995b8..38a0503b9a4a 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -89,8 +89,7 @@ n32_syscall_trace_entry: SAVE_STATIC move s0, t2 move a0, sp - li a1, 0 - jal do_syscall_trace + jal syscall_trace_enter move t0, s0 RESTORE_STATIC @@ -403,7 +402,7 @@ EXPORT(sysn32_call_table) PTR sys_ioprio_get PTR compat_sys_utimensat PTR compat_sys_signalfd /* 6280 */ - PTR sys_ni_syscall + PTR sys_ni_syscall /* was timerfd */ PTR sys_eventfd PTR sys_fallocate PTR sys_timerfd_create diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 049a9c8c49a0..91ea5e4041dd 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -123,8 +123,7 @@ trace_a_syscall: move s0, t2 # Save syscall pointer move a0, sp - li a1, 0 - jal do_syscall_trace + jal syscall_trace_enter move t0, s0 RESTORE_STATIC @@ -522,7 +521,7 @@ sys_call_table: PTR sys_ioprio_get /* 4315 */ PTR compat_sys_utimensat PTR compat_sys_signalfd - PTR sys_ni_syscall + PTR sys_ni_syscall /* was timerfd */ PTR sys_eventfd PTR sys32_fallocate /* 4320 */ PTR sys_timerfd_create diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 5a88cc4ccd5a..cedac4633741 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -929,7 +929,7 @@ static void post_direct_ipi(int cpu, struct smtc_ipi *pipi) static void ipi_resched_interrupt(void) { - /* Return from interrupt should be enough to cause scheduler check */ + scheduler_ipi(); } static void ipi_call_interrupt(void) diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 58beabf50b3c..d02765708ddb 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -10,12 +10,9 @@ #include #include #include -#include #include #include -#include #include -#include #include #include #include @@ -25,11 +22,9 @@ #include #include #include -#include #include #include #include -#include #include #include @@ -66,121 +61,6 @@ asmlinkage int sysm_pipe(nabi_no_regargs volatile struct pt_regs regs) return res; } -unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ - -EXPORT_SYMBOL(shm_align_mask); - -#define COLOUR_ALIGN(addr,pgoff) \ - ((((addr) + shm_align_mask) & ~shm_align_mask) + \ - (((pgoff) << PAGE_SHIFT) & shm_align_mask)) - -unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) -{ - struct vm_area_struct * vmm; - int do_color_align; - unsigned long task_size; - -#ifdef CONFIG_32BIT - task_size = TASK_SIZE; -#else /* Must be CONFIG_64BIT*/ - task_size = test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE; -#endif - - if (len > task_size) - return -ENOMEM; - - if (flags & MAP_FIXED) { - /* Even MAP_FIXED mappings must reside within task_size. */ - if (task_size - len < addr) - return -EINVAL; - - /* - * We do not accept a shared mapping if it would violate - * cache aliasing constraints. - */ - if ((flags & MAP_SHARED) && - ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) - return -EINVAL; - return addr; - } - - do_color_align = 0; - if (filp || (flags & MAP_SHARED)) - do_color_align = 1; - if (addr) { - if (do_color_align) - addr = COLOUR_ALIGN(addr, pgoff); - else - addr = PAGE_ALIGN(addr); - vmm = find_vma(current->mm, addr); - if (task_size - len >= addr && - (!vmm || addr + len <= vmm->vm_start)) - return addr; - } - addr = current->mm->mmap_base; - if (do_color_align) - addr = COLOUR_ALIGN(addr, pgoff); - else - addr = PAGE_ALIGN(addr); - - for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { - /* At this point: (!vmm || addr < vmm->vm_end). */ - if (task_size - len < addr) - return -ENOMEM; - if (!vmm || addr + len <= vmm->vm_start) - return addr; - addr = vmm->vm_end; - if (do_color_align) - addr = COLOUR_ALIGN(addr, pgoff); - } -} - -void arch_pick_mmap_layout(struct mm_struct *mm) -{ - unsigned long random_factor = 0UL; - - if (current->flags & PF_RANDOMIZE) { - random_factor = get_random_int(); - random_factor = random_factor << PAGE_SHIFT; - if (TASK_IS_32BIT_ADDR) - random_factor &= 0xfffffful; - else - random_factor &= 0xffffffful; - } - - mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; - mm->get_unmapped_area = arch_get_unmapped_area; - mm->unmap_area = arch_unmap_area; -} - -static inline unsigned long brk_rnd(void) -{ - unsigned long rnd = get_random_int(); - - rnd = rnd << PAGE_SHIFT; - /* 8MB for 32bit, 256MB for 64bit */ - if (TASK_IS_32BIT_ADDR) - rnd = rnd & 0x7ffffful; - else - rnd = rnd & 0xffffffful; - - return rnd; -} - -unsigned long arch_randomize_brk(struct mm_struct *mm) -{ - unsigned long base = mm->brk; - unsigned long ret; - - ret = PAGE_ALIGN(base + brk_rnd()); - - if (ret < mm->brk) - return mm->brk; - - return ret; -} - SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len, unsigned long, prot, unsigned long, flags, unsigned long, fd, off_t, offset) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 71350f7f2d88..e9b3af27d844 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -374,7 +374,8 @@ void __noreturn die(const char *str, struct pt_regs *regs) unsigned long dvpret = dvpe(); #endif /* CONFIG_MIPS_MT_SMTC */ - notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV); + if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP) + sig = 0; console_verbose(); spin_lock_irq(&die_lock); @@ -383,9 +384,6 @@ void __noreturn die(const char *str, struct pt_regs *regs) mips_mt_regdump(dvpret); #endif /* CONFIG_MIPS_MT_SMTC */ - if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP) - sig = 0; - printk("%s[#%d]:\n", str, ++die_counter); show_registers(regs); add_taint(TAINT_DIE); diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 832afbb87588..01af3876cf90 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -65,15 +65,18 @@ SECTIONS NOTES :text :note .dummy : { *(.dummy) } :text + _sdata = .; /* Start of data section */ RODATA /* writeable */ + _sdata = .; /* Start of data section */ .data : { /* Data */ . = . + DATAOFFSET; /* for CONFIG_MAPPED_KERNEL */ INIT_TASK_DATA(PAGE_SIZE) NOSAVE_DATA CACHELINE_ALIGNED_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT) + READ_MOSTLY_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT) DATA_DATA CONSTRUCTORS } diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig new file mode 100644 index 000000000000..3fccf2104513 --- /dev/null +++ b/arch/mips/lantiq/Kconfig @@ -0,0 +1,23 @@ +if LANTIQ + +config SOC_TYPE_XWAY + bool + default n + +choice + prompt "SoC Type" + default SOC_XWAY + +config SOC_AMAZON_SE + bool "Amazon SE" + select SOC_TYPE_XWAY + +config SOC_XWAY + bool "XWAY" + select SOC_TYPE_XWAY + select HW_HAS_PCI +endchoice + +source "arch/mips/lantiq/xway/Kconfig" + +endif diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile new file mode 100644 index 000000000000..e5dae0e24b00 --- /dev/null +++ b/arch/mips/lantiq/Makefile @@ -0,0 +1,11 @@ +# Copyright (C) 2010 John Crispin +# +# 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. + +obj-y := irq.o setup.o clk.o prom.o devices.o + +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + +obj-$(CONFIG_SOC_TYPE_XWAY) += xway/ diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform new file mode 100644 index 000000000000..f3dff05722de --- /dev/null +++ b/arch/mips/lantiq/Platform @@ -0,0 +1,8 @@ +# +# Lantiq +# + +platform-$(CONFIG_LANTIQ) += lantiq/ +cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq +load-$(CONFIG_LANTIQ) = 0xffffffff80002000 +cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c new file mode 100644 index 000000000000..94560899d13e --- /dev/null +++ b/arch/mips/lantiq/clk.c @@ -0,0 +1,140 @@ +/* + * 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. + * + * Copyright (C) 2010 Thomas Langer + * Copyright (C) 2010 John Crispin + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "clk.h" + +struct clk { + const char *name; + unsigned long rate; + unsigned long (*get_rate) (void); +}; + +static struct clk *cpu_clk; +static int cpu_clk_cnt; + +/* lantiq socs have 3 static clocks */ +static struct clk cpu_clk_generic[] = { + { + .name = "cpu", + .get_rate = ltq_get_cpu_hz, + }, { + .name = "fpi", + .get_rate = ltq_get_fpi_hz, + }, { + .name = "io", + .get_rate = ltq_get_io_region_clock, + }, +}; + +static struct resource ltq_cgu_resource = { + .name = "cgu", + .start = LTQ_CGU_BASE_ADDR, + .end = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +/* remapped clock register range */ +void __iomem *ltq_cgu_membase; + +void clk_init(void) +{ + cpu_clk = cpu_clk_generic; + cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic); +} + +static inline int clk_good(struct clk *clk) +{ + return clk && !IS_ERR(clk); +} + +unsigned long clk_get_rate(struct clk *clk) +{ + if (unlikely(!clk_good(clk))) + return 0; + + if (clk->rate != 0) + return clk->rate; + + if (clk->get_rate != NULL) + return clk->get_rate(); + + return 0; +} +EXPORT_SYMBOL(clk_get_rate); + +struct clk *clk_get(struct device *dev, const char *id) +{ + int i; + + for (i = 0; i < cpu_clk_cnt; i++) + if (!strcmp(id, cpu_clk[i].name)) + return &cpu_clk[i]; + BUG(); + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ + /* not used */ +} +EXPORT_SYMBOL(clk_put); + +static inline u32 ltq_get_counter_resolution(void) +{ + u32 res; + + __asm__ __volatile__( + ".set push\n" + ".set mips32r2\n" + "rdhwr %0, $3\n" + ".set pop\n" + : "=&r" (res) + : /* no input */ + : "memory"); + + return res; +} + +void __init plat_time_init(void) +{ + struct clk *clk; + + if (insert_resource(&iomem_resource, <q_cgu_resource) < 0) + panic("Failed to insert cgu memory\n"); + + if (request_mem_region(ltq_cgu_resource.start, + resource_size(<q_cgu_resource), "cgu") < 0) + panic("Failed to request cgu memory\n"); + + ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start, + resource_size(<q_cgu_resource)); + if (!ltq_cgu_membase) { + pr_err("Failed to remap cgu memory\n"); + unreachable(); + } + clk = clk_get(0, "cpu"); + mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution(); + write_c0_compare(read_c0_count()); + clk_put(clk); +} diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h new file mode 100644 index 000000000000..3328925f2c3f --- /dev/null +++ b/arch/mips/lantiq/clk.h @@ -0,0 +1,18 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef _LTQ_CLK_H__ +#define _LTQ_CLK_H__ + +extern void clk_init(void); + +extern unsigned long ltq_get_cpu_hz(void); +extern unsigned long ltq_get_fpi_hz(void); +extern unsigned long ltq_get_io_region_clock(void); + +#endif diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c new file mode 100644 index 000000000000..7b82c34cb169 --- /dev/null +++ b/arch/mips/lantiq/devices.c @@ -0,0 +1,122 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "devices.h" + +/* nor flash */ +static struct resource ltq_nor_resource = { + .name = "nor", + .start = LTQ_FLASH_START, + .end = LTQ_FLASH_START + LTQ_FLASH_MAX - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ltq_nor = { + .name = "ltq_nor", + .resource = <q_nor_resource, + .num_resources = 1, +}; + +void __init ltq_register_nor(struct physmap_flash_data *data) +{ + ltq_nor.dev.platform_data = data; + platform_device_register(<q_nor); +} + +/* watchdog */ +static struct resource ltq_wdt_resource = { + .name = "watchdog", + .start = LTQ_WDT_BASE_ADDR, + .end = LTQ_WDT_BASE_ADDR + LTQ_WDT_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +void __init ltq_register_wdt(void) +{ + platform_device_register_simple("ltq_wdt", 0, <q_wdt_resource, 1); +} + +/* asc ports */ +static struct resource ltq_asc0_resources[] = { + { + .name = "asc0", + .start = LTQ_ASC0_BASE_ADDR, + .end = LTQ_ASC0_BASE_ADDR + LTQ_ASC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + IRQ_RES(tx, LTQ_ASC_TIR(0)), + IRQ_RES(rx, LTQ_ASC_RIR(0)), + IRQ_RES(err, LTQ_ASC_EIR(0)), +}; + +static struct resource ltq_asc1_resources[] = { + { + .name = "asc1", + .start = LTQ_ASC1_BASE_ADDR, + .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + IRQ_RES(tx, LTQ_ASC_TIR(1)), + IRQ_RES(rx, LTQ_ASC_RIR(1)), + IRQ_RES(err, LTQ_ASC_EIR(1)), +}; + +void __init ltq_register_asc(int port) +{ + switch (port) { + case 0: + platform_device_register_simple("ltq_asc", 0, + ltq_asc0_resources, ARRAY_SIZE(ltq_asc0_resources)); + break; + case 1: + platform_device_register_simple("ltq_asc", 1, + ltq_asc1_resources, ARRAY_SIZE(ltq_asc1_resources)); + break; + default: + break; + } +} + +#ifdef CONFIG_PCI +/* pci */ +static struct platform_device ltq_pci = { + .name = "ltq_pci", + .num_resources = 0, +}; + +void __init ltq_register_pci(struct ltq_pci_data *data) +{ + ltq_pci.dev.platform_data = data; + platform_device_register(<q_pci); +} +#else +void __init ltq_register_pci(struct ltq_pci_data *data) +{ + pr_err("kernel is compiled without PCI support\n"); +} +#endif diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h new file mode 100644 index 000000000000..2947bb19a528 --- /dev/null +++ b/arch/mips/lantiq/devices.h @@ -0,0 +1,23 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef _LTQ_DEVICES_H__ +#define _LTQ_DEVICES_H__ + +#include +#include + +#define IRQ_RES(resname, irq) \ + {.name = #resname, .start = (irq), .flags = IORESOURCE_IRQ} + +extern void ltq_register_nor(struct physmap_flash_data *data); +extern void ltq_register_wdt(void); +extern void ltq_register_asc(int port); +extern void ltq_register_pci(struct ltq_pci_data *data); + +#endif diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c new file mode 100644 index 000000000000..972e05f87631 --- /dev/null +++ b/arch/mips/lantiq/early_printk.c @@ -0,0 +1,33 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include + +#include +#include + +/* no ioremap possible at this early stage, lets use KSEG1 instead */ +#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE_ADDR) +#define ASC_BUF 1024 +#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048)) +#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020)) +#define TXMASK 0x3F00 +#define TXOFFSET 8 + +void prom_putchar(char c) +{ + unsigned long flags; + + local_irq_save(flags); + do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET); + if (c == '\n') + ltq_w32('\r', LTQ_ASC_TBUF); + ltq_w32(c, LTQ_ASC_TBUF); + local_irq_restore(flags); +} diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c new file mode 100644 index 000000000000..fc89795cafdb --- /dev/null +++ b/arch/mips/lantiq/irq.c @@ -0,0 +1,326 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + * Copyright (C) 2010 Thomas Langer + */ + +#include +#include + +#include +#include + +#include +#include + +/* register definitions */ +#define LTQ_ICU_IM0_ISR 0x0000 +#define LTQ_ICU_IM0_IER 0x0008 +#define LTQ_ICU_IM0_IOSR 0x0010 +#define LTQ_ICU_IM0_IRSR 0x0018 +#define LTQ_ICU_IM0_IMR 0x0020 +#define LTQ_ICU_IM1_ISR 0x0028 +#define LTQ_ICU_OFFSET (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR) + +#define LTQ_EIU_EXIN_C 0x0000 +#define LTQ_EIU_EXIN_INIC 0x0004 +#define LTQ_EIU_EXIN_INEN 0x000C + +/* irq numbers used by the external interrupt unit (EIU) */ +#define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30) +#define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31) +#define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26) +#define LTQ_EIU_IR3 INT_NUM_IM1_IRL0 +#define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1) +#define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2) +#define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30) + +#define MAX_EIU 6 + +/* irqs generated by device attached to the EBU need to be acked in + * a special manner + */ +#define LTQ_ICU_EBU_IRQ 22 + +#define ltq_icu_w32(x, y) ltq_w32((x), ltq_icu_membase + (y)) +#define ltq_icu_r32(x) ltq_r32(ltq_icu_membase + (x)) + +#define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) +#define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) + +static unsigned short ltq_eiu_irq[MAX_EIU] = { + LTQ_EIU_IR0, + LTQ_EIU_IR1, + LTQ_EIU_IR2, + LTQ_EIU_IR3, + LTQ_EIU_IR4, + LTQ_EIU_IR5, +}; + +static struct resource ltq_icu_resource = { + .name = "icu", + .start = LTQ_ICU_BASE_ADDR, + .end = LTQ_ICU_BASE_ADDR + LTQ_ICU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct resource ltq_eiu_resource = { + .name = "eiu", + .start = LTQ_EIU_BASE_ADDR, + .end = LTQ_EIU_BASE_ADDR + LTQ_ICU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static void __iomem *ltq_icu_membase; +static void __iomem *ltq_eiu_membase; + +void ltq_disable_irq(struct irq_data *d) +{ + u32 ier = LTQ_ICU_IM0_IER; + int irq_nr = d->irq - INT_NUM_IRQ0; + + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + irq_nr %= INT_NUM_IM_OFFSET; + ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); +} + +void ltq_mask_and_ack_irq(struct irq_data *d) +{ + u32 ier = LTQ_ICU_IM0_IER; + u32 isr = LTQ_ICU_IM0_ISR; + int irq_nr = d->irq - INT_NUM_IRQ0; + + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + irq_nr %= INT_NUM_IM_OFFSET; + ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); + ltq_icu_w32((1 << irq_nr), isr); +} + +static void ltq_ack_irq(struct irq_data *d) +{ + u32 isr = LTQ_ICU_IM0_ISR; + int irq_nr = d->irq - INT_NUM_IRQ0; + + isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + irq_nr %= INT_NUM_IM_OFFSET; + ltq_icu_w32((1 << irq_nr), isr); +} + +void ltq_enable_irq(struct irq_data *d) +{ + u32 ier = LTQ_ICU_IM0_IER; + int irq_nr = d->irq - INT_NUM_IRQ0; + + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + irq_nr %= INT_NUM_IM_OFFSET; + ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier); +} + +static unsigned int ltq_startup_eiu_irq(struct irq_data *d) +{ + int i; + int irq_nr = d->irq - INT_NUM_IRQ0; + + ltq_enable_irq(d); + for (i = 0; i < MAX_EIU; i++) { + if (irq_nr == ltq_eiu_irq[i]) { + /* low level - we should really handle set_type */ + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) | + (0x6 << (i * 4)), LTQ_EIU_EXIN_C); + /* clear all pending */ + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~(1 << i), + LTQ_EIU_EXIN_INIC); + /* enable */ + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | (1 << i), + LTQ_EIU_EXIN_INEN); + break; + } + } + + return 0; +} + +static void ltq_shutdown_eiu_irq(struct irq_data *d) +{ + int i; + int irq_nr = d->irq - INT_NUM_IRQ0; + + ltq_disable_irq(d); + for (i = 0; i < MAX_EIU; i++) { + if (irq_nr == ltq_eiu_irq[i]) { + /* disable */ + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i), + LTQ_EIU_EXIN_INEN); + break; + } + } +} + +static struct irq_chip ltq_irq_type = { + "icu", + .irq_enable = ltq_enable_irq, + .irq_disable = ltq_disable_irq, + .irq_unmask = ltq_enable_irq, + .irq_ack = ltq_ack_irq, + .irq_mask = ltq_disable_irq, + .irq_mask_ack = ltq_mask_and_ack_irq, +}; + +static struct irq_chip ltq_eiu_type = { + "eiu", + .irq_startup = ltq_startup_eiu_irq, + .irq_shutdown = ltq_shutdown_eiu_irq, + .irq_enable = ltq_enable_irq, + .irq_disable = ltq_disable_irq, + .irq_unmask = ltq_enable_irq, + .irq_ack = ltq_ack_irq, + .irq_mask = ltq_disable_irq, + .irq_mask_ack = ltq_mask_and_ack_irq, +}; + +static void ltq_hw_irqdispatch(int module) +{ + u32 irq; + + irq = ltq_icu_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET)); + if (irq == 0) + return; + + /* silicon bug causes only the msb set to 1 to be valid. all + * other bits might be bogus + */ + irq = __fls(irq); + do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module)); + + /* if this is a EBU irq, we need to ack it or get a deadlock */ + if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0)) + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10, + LTQ_EBU_PCC_ISTAT); +} + +#define DEFINE_HWx_IRQDISPATCH(x) \ + static void ltq_hw ## x ## _irqdispatch(void) \ + { \ + ltq_hw_irqdispatch(x); \ + } +DEFINE_HWx_IRQDISPATCH(0) +DEFINE_HWx_IRQDISPATCH(1) +DEFINE_HWx_IRQDISPATCH(2) +DEFINE_HWx_IRQDISPATCH(3) +DEFINE_HWx_IRQDISPATCH(4) + +static void ltq_hw5_irqdispatch(void) +{ + do_IRQ(MIPS_CPU_TIMER_IRQ); +} + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; + unsigned int i; + + if (pending & CAUSEF_IP7) { + do_IRQ(MIPS_CPU_TIMER_IRQ); + goto out; + } else { + for (i = 0; i < 5; i++) { + if (pending & (CAUSEF_IP2 << i)) { + ltq_hw_irqdispatch(i); + goto out; + } + } + } + pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status()); + +out: + return; +} + +static struct irqaction cascade = { + .handler = no_action, + .flags = IRQF_DISABLED, + .name = "cascade", +}; + +void __init arch_init_irq(void) +{ + int i; + + if (insert_resource(&iomem_resource, <q_icu_resource) < 0) + panic("Failed to insert icu memory\n"); + + if (request_mem_region(ltq_icu_resource.start, + resource_size(<q_icu_resource), "icu") < 0) + panic("Failed to request icu memory\n"); + + ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start, + resource_size(<q_icu_resource)); + if (!ltq_icu_membase) + panic("Failed to remap icu memory\n"); + + if (insert_resource(&iomem_resource, <q_eiu_resource) < 0) + panic("Failed to insert eiu memory\n"); + + if (request_mem_region(ltq_eiu_resource.start, + resource_size(<q_eiu_resource), "eiu") < 0) + panic("Failed to request eiu memory\n"); + + ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start, + resource_size(<q_eiu_resource)); + if (!ltq_eiu_membase) + panic("Failed to remap eiu memory\n"); + + /* make sure all irqs are turned off by default */ + for (i = 0; i < 5; i++) + ltq_icu_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET)); + + /* clear all possibly pending interrupts */ + ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET)); + + mips_cpu_irq_init(); + + for (i = 2; i <= 6; i++) + setup_irq(i, &cascade); + + if (cpu_has_vint) { + pr_info("Setting up vectored interrupts\n"); + set_vi_handler(2, ltq_hw0_irqdispatch); + set_vi_handler(3, ltq_hw1_irqdispatch); + set_vi_handler(4, ltq_hw2_irqdispatch); + set_vi_handler(5, ltq_hw3_irqdispatch); + set_vi_handler(6, ltq_hw4_irqdispatch); + set_vi_handler(7, ltq_hw5_irqdispatch); + } + + for (i = INT_NUM_IRQ0; + i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++) + if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) || + (i == LTQ_EIU_IR2)) + irq_set_chip_and_handler(i, <q_eiu_type, + handle_level_irq); + /* EIU3-5 only exist on ar9 and vr9 */ + else if (((i == LTQ_EIU_IR3) || (i == LTQ_EIU_IR4) || + (i == LTQ_EIU_IR5)) && (ltq_is_ar9() || ltq_is_vr9())) + irq_set_chip_and_handler(i, <q_eiu_type, + handle_level_irq); + else + irq_set_chip_and_handler(i, <q_irq_type, + handle_level_irq); + +#if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC) + set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | + IE_IRQ3 | IE_IRQ4 | IE_IRQ5); +#else + set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 | + IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); +#endif +} + +unsigned int __cpuinit get_c0_compare_int(void) +{ + return CP0_LEGACY_COMPARE_IRQ; +} diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h new file mode 100644 index 000000000000..7e01b8c484eb --- /dev/null +++ b/arch/mips/lantiq/machtypes.h @@ -0,0 +1,20 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef _LANTIQ_MACH_H__ +#define _LANTIQ_MACH_H__ + +#include + +enum lantiq_mach_type { + LTQ_MACH_GENERIC = 0, + LTQ_MACH_EASY50712, /* Danube evaluation board */ + LTQ_MACH_EASY50601, /* Amazon SE evaluation board */ +}; + +#endif diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c new file mode 100644 index 000000000000..56ba007bf1e5 --- /dev/null +++ b/arch/mips/lantiq/prom.c @@ -0,0 +1,71 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include + +#include "prom.h" +#include "clk.h" + +static struct ltq_soc_info soc_info; + +unsigned int ltq_get_cpu_ver(void) +{ + return soc_info.rev; +} +EXPORT_SYMBOL(ltq_get_cpu_ver); + +unsigned int ltq_get_soc_type(void) +{ + return soc_info.type; +} +EXPORT_SYMBOL(ltq_get_soc_type); + +const char *get_system_type(void) +{ + return soc_info.sys_type; +} + +void prom_free_prom_memory(void) +{ +} + +static void __init prom_init_cmdline(void) +{ + int argc = fw_arg0; + char **argv = (char **) KSEG1ADDR(fw_arg1); + int i; + + for (i = 0; i < argc; i++) { + char *p = (char *) KSEG1ADDR(argv[i]); + + if (p && *p) { + strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); + strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); + } + } +} + +void __init prom_init(void) +{ + struct clk *clk; + + ltq_soc_detect(&soc_info); + clk_init(); + clk = clk_get(0, "cpu"); + snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d", + soc_info.name, soc_info.rev); + clk_put(clk); + soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; + pr_info("SoC: %s\n", soc_info.sys_type); + prom_init_cmdline(); +} diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h new file mode 100644 index 000000000000..b4229d94280f --- /dev/null +++ b/arch/mips/lantiq/prom.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef _LTQ_PROM_H__ +#define _LTQ_PROM_H__ + +#define LTQ_SYS_TYPE_LEN 0x100 + +struct ltq_soc_info { + unsigned char *name; + unsigned int rev; + unsigned int partnum; + unsigned int type; + unsigned char sys_type[LTQ_SYS_TYPE_LEN]; +}; + +extern void ltq_soc_detect(struct ltq_soc_info *i); +extern void ltq_soc_setup(void); + +#endif diff --git a/arch/mips/lantiq/setup.c b/arch/mips/lantiq/setup.c new file mode 100644 index 000000000000..9b8af77ed0f9 --- /dev/null +++ b/arch/mips/lantiq/setup.c @@ -0,0 +1,66 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include + +#include + +#include "machtypes.h" +#include "devices.h" +#include "prom.h" + +void __init plat_mem_setup(void) +{ + /* assume 16M as default incase uboot fails to pass proper ramsize */ + unsigned long memsize = 16; + char **envp = (char **) KSEG1ADDR(fw_arg2); + + ioport_resource.start = IOPORT_RESOURCE_START; + ioport_resource.end = IOPORT_RESOURCE_END; + iomem_resource.start = IOMEM_RESOURCE_START; + iomem_resource.end = IOMEM_RESOURCE_END; + + set_io_port_base((unsigned long) KSEG1); + + while (*envp) { + char *e = (char *)KSEG1ADDR(*envp); + if (!strncmp(e, "memsize=", 8)) { + e += 8; + if (strict_strtoul(e, 0, &memsize)) + pr_warn("bad memsize specified\n"); + } + envp++; + } + memsize *= 1024 * 1024; + add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); +} + +static int __init +lantiq_setup(void) +{ + ltq_soc_setup(); + mips_machine_setup(); + return 0; +} + +arch_initcall(lantiq_setup); + +static void __init +lantiq_generic_init(void) +{ + /* Nothing to do */ +} + +MIPS_MACHINE(LTQ_MACH_GENERIC, + "Generic", + "Generic Lantiq based board", + lantiq_generic_init); diff --git a/arch/mips/lantiq/xway/Kconfig b/arch/mips/lantiq/xway/Kconfig new file mode 100644 index 000000000000..2b857de36620 --- /dev/null +++ b/arch/mips/lantiq/xway/Kconfig @@ -0,0 +1,23 @@ +if SOC_XWAY + +menu "MIPS Machine" + +config LANTIQ_MACH_EASY50712 + bool "Easy50712 - Danube" + default y + +endmenu + +endif + +if SOC_AMAZON_SE + +menu "MIPS Machine" + +config LANTIQ_MACH_EASY50601 + bool "Easy50601 - Amazon SE" + default y + +endmenu + +endif diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile new file mode 100644 index 000000000000..c517f2e77563 --- /dev/null +++ b/arch/mips/lantiq/xway/Makefile @@ -0,0 +1,7 @@ +obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o + +obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o +obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o + +obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o +obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o diff --git a/arch/mips/lantiq/xway/clk-ase.c b/arch/mips/lantiq/xway/clk-ase.c new file mode 100644 index 000000000000..22d823acd536 --- /dev/null +++ b/arch/mips/lantiq/xway/clk-ase.c @@ -0,0 +1,48 @@ +/* + * 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. + * + * Copyright (C) 2011 John Crispin + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* cgu registers */ +#define LTQ_CGU_SYS 0x0010 + +unsigned int ltq_get_io_region_clock(void) +{ + return CLOCK_133M; +} +EXPORT_SYMBOL(ltq_get_io_region_clock); + +unsigned int ltq_get_fpi_bus_clock(int fpi) +{ + return CLOCK_133M; +} +EXPORT_SYMBOL(ltq_get_fpi_bus_clock); + +unsigned int ltq_get_cpu_hz(void) +{ + if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) + return CLOCK_266M; + else + return CLOCK_133M; +} +EXPORT_SYMBOL(ltq_get_cpu_hz); + +unsigned int ltq_get_fpi_hz(void) +{ + return CLOCK_133M; +} +EXPORT_SYMBOL(ltq_get_fpi_hz); diff --git a/arch/mips/lantiq/xway/clk-xway.c b/arch/mips/lantiq/xway/clk-xway.c new file mode 100644 index 000000000000..ddd39593c581 --- /dev/null +++ b/arch/mips/lantiq/xway/clk-xway.c @@ -0,0 +1,223 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +static unsigned int ltq_ram_clocks[] = { + CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; +#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3] + +#define BASIC_FREQUENCY_1 35328000 +#define BASIC_FREQUENCY_2 36000000 +#define BASIS_REQUENCY_USB 12000000 + +#define GET_BITS(x, msb, lsb) \ + (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) + +#define LTQ_CGU_PLL0_CFG 0x0004 +#define LTQ_CGU_PLL1_CFG 0x0008 +#define LTQ_CGU_PLL2_CFG 0x000C +#define LTQ_CGU_SYS 0x0010 +#define LTQ_CGU_UPDATE 0x0014 +#define LTQ_CGU_IF_CLK 0x0018 +#define LTQ_CGU_OSC_CON 0x001C +#define LTQ_CGU_SMD 0x0020 +#define LTQ_CGU_CT1SR 0x0028 +#define LTQ_CGU_CT2SR 0x002C +#define LTQ_CGU_PCMCR 0x0030 +#define LTQ_CGU_PCI_CR 0x0034 +#define LTQ_CGU_PD_PC 0x0038 +#define LTQ_CGU_FMR 0x003C + +#define CGU_PLL0_PHASE_DIVIDER_ENABLE \ + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31)) +#define CGU_PLL0_BYPASS \ + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30)) +#define CGU_PLL0_CFG_DSMSEL \ + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28)) +#define CGU_PLL0_CFG_FRAC_EN \ + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27)) +#define CGU_PLL1_SRC \ + (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31)) +#define CGU_PLL2_PHASE_DIVIDER_ENABLE \ + (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20)) +#define CGU_SYS_FPI_SEL (1 << 6) +#define CGU_SYS_DDR_SEL 0x3 +#define CGU_PLL0_SRC (1 << 29) + +#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17) +#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6) +#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2) +#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17) +#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13) + +static unsigned int ltq_get_pll0_fdiv(void); + +static inline unsigned int get_input_clock(int pll) +{ + switch (pll) { + case 0: + if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC) + return BASIS_REQUENCY_USB; + else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) + return BASIC_FREQUENCY_1; + else + return BASIC_FREQUENCY_2; + case 1: + if (CGU_PLL1_SRC) + return BASIS_REQUENCY_USB; + else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) + return BASIC_FREQUENCY_1; + else + return BASIC_FREQUENCY_2; + case 2: + switch (CGU_PLL2_SRC) { + case 0: + return ltq_get_pll0_fdiv(); + case 1: + return CGU_PLL2_PHASE_DIVIDER_ENABLE ? + BASIC_FREQUENCY_1 : + BASIC_FREQUENCY_2; + case 2: + return BASIS_REQUENCY_USB; + } + default: + return 0; + } +} + +static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den) +{ + u64 res, clock = get_input_clock(pll); + + res = num * clock; + do_div(res, den); + return res; +} + +static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N, + unsigned int K) +{ + unsigned int num = ((N + 1) << 10) + K; + unsigned int den = (M + 1) << 10; + + return cal_dsm(pll, num, den); +} + +static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N, + unsigned int K) +{ + unsigned int num = ((N + 1) << 11) + K + 512; + unsigned int den = (M + 1) << 11; + + return cal_dsm(pll, num, den); +} + +static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N, + unsigned int K) +{ + unsigned int num = K >= 512 ? + ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584; + unsigned int den = (M + 1) << 12; + + return cal_dsm(pll, num, den); +} + +static inline unsigned int dsm(int pll, unsigned int M, unsigned int N, + unsigned int K, unsigned int dsmsel, unsigned int phase_div_en) +{ + if (!dsmsel) + return mash_dsm(pll, M, N, K); + else if (!phase_div_en) + return mash_dsm(pll, M, N, K); + else + return ssff_dsm_2(pll, M, N, K); +} + +static inline unsigned int ltq_get_pll0_fosc(void) +{ + if (CGU_PLL0_BYPASS) + return get_input_clock(0); + else + return !CGU_PLL0_CFG_FRAC_EN + ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0, + CGU_PLL0_CFG_DSMSEL, + CGU_PLL0_PHASE_DIVIDER_ENABLE) + : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, + CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL, + CGU_PLL0_PHASE_DIVIDER_ENABLE); +} + +static unsigned int ltq_get_pll0_fdiv(void) +{ + unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1; + + return (ltq_get_pll0_fosc() + (div >> 1)) / div; +} + +unsigned int ltq_get_io_region_clock(void) +{ + unsigned int ret = ltq_get_pll0_fosc(); + + switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) { + default: + case 0: + return (ret + 1) / 2; + case 1: + return (ret * 2 + 2) / 5; + case 2: + return (ret + 1) / 3; + case 3: + return (ret + 2) / 4; + } +} +EXPORT_SYMBOL(ltq_get_io_region_clock); + +unsigned int ltq_get_fpi_bus_clock(int fpi) +{ + unsigned int ret = ltq_get_io_region_clock(); + + if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL)) + ret >>= 1; + return ret; +} +EXPORT_SYMBOL(ltq_get_fpi_bus_clock); + +unsigned int ltq_get_cpu_hz(void) +{ + switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) { + case 0: + return CLOCK_333M; + case 4: + return DDR_HZ; + case 8: + return DDR_HZ << 1; + default: + return DDR_HZ >> 1; + } +} +EXPORT_SYMBOL(ltq_get_cpu_hz); + +unsigned int ltq_get_fpi_hz(void) +{ + unsigned int ddr_clock = DDR_HZ; + + if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) + return ddr_clock >> 1; + return ddr_clock; +} +EXPORT_SYMBOL(ltq_get_fpi_hz); diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c new file mode 100644 index 000000000000..e09e789dfc27 --- /dev/null +++ b/arch/mips/lantiq/xway/devices.c @@ -0,0 +1,121 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "devices.h" + +/* gpio */ +static struct resource ltq_gpio_resource[] = { + { + .name = "gpio0", + .start = LTQ_GPIO0_BASE_ADDR, + .end = LTQ_GPIO0_BASE_ADDR + LTQ_GPIO_SIZE - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "gpio1", + .start = LTQ_GPIO1_BASE_ADDR, + .end = LTQ_GPIO1_BASE_ADDR + LTQ_GPIO_SIZE - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "gpio2", + .start = LTQ_GPIO2_BASE_ADDR, + .end = LTQ_GPIO2_BASE_ADDR + LTQ_GPIO_SIZE - 1, + .flags = IORESOURCE_MEM, + } +}; + +void __init ltq_register_gpio(void) +{ + platform_device_register_simple("ltq_gpio", 0, + <q_gpio_resource[0], 1); + platform_device_register_simple("ltq_gpio", 1, + <q_gpio_resource[1], 1); + + /* AR9 and VR9 have an extra gpio block */ + if (ltq_is_ar9() || ltq_is_vr9()) { + platform_device_register_simple("ltq_gpio", 2, + <q_gpio_resource[2], 1); + } +} + +/* serial to parallel conversion */ +static struct resource ltq_stp_resource = { + .name = "stp", + .start = LTQ_STP_BASE_ADDR, + .end = LTQ_STP_BASE_ADDR + LTQ_STP_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +void __init ltq_register_gpio_stp(void) +{ + platform_device_register_simple("ltq_stp", 0, <q_stp_resource, 1); +} + +/* asc ports - amazon se has its own serial mapping */ +static struct resource ltq_ase_asc_resources[] = { + { + .name = "asc0", + .start = LTQ_ASC1_BASE_ADDR, + .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + IRQ_RES(tx, LTQ_ASC_ASE_TIR), + IRQ_RES(rx, LTQ_ASC_ASE_RIR), + IRQ_RES(err, LTQ_ASC_ASE_EIR), +}; + +void __init ltq_register_ase_asc(void) +{ + platform_device_register_simple("ltq_asc", 0, + ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources)); +} + +/* ethernet */ +static struct resource ltq_etop_resources = { + .name = "etop", + .start = LTQ_ETOP_BASE_ADDR, + .end = LTQ_ETOP_BASE_ADDR + LTQ_ETOP_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ltq_etop = { + .name = "ltq_etop", + .resource = <q_etop_resources, + .num_resources = 1, +}; + +void __init +ltq_register_etop(struct ltq_eth_data *eth) +{ + if (eth) { + ltq_etop.dev.platform_data = eth; + platform_device_register(<q_etop); + } +} diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h new file mode 100644 index 000000000000..e90493471bc1 --- /dev/null +++ b/arch/mips/lantiq/xway/devices.h @@ -0,0 +1,20 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef _LTQ_DEVICES_XWAY_H__ +#define _LTQ_DEVICES_XWAY_H__ + +#include "../devices.h" +#include + +extern void ltq_register_gpio(void); +extern void ltq_register_gpio_stp(void); +extern void ltq_register_ase_asc(void); +extern void ltq_register_etop(struct ltq_eth_data *eth); + +#endif diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c new file mode 100644 index 000000000000..4278a459d6c4 --- /dev/null +++ b/arch/mips/lantiq/xway/dma.c @@ -0,0 +1,253 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2011 John Crispin + */ + +#include +#include +#include +#include + +#include +#include + +#define LTQ_DMA_CTRL 0x10 +#define LTQ_DMA_CPOLL 0x14 +#define LTQ_DMA_CS 0x18 +#define LTQ_DMA_CCTRL 0x1C +#define LTQ_DMA_CDBA 0x20 +#define LTQ_DMA_CDLEN 0x24 +#define LTQ_DMA_CIS 0x28 +#define LTQ_DMA_CIE 0x2C +#define LTQ_DMA_PS 0x40 +#define LTQ_DMA_PCTRL 0x44 +#define LTQ_DMA_IRNEN 0xf4 + +#define DMA_DESCPT BIT(3) /* descriptor complete irq */ +#define DMA_TX BIT(8) /* TX channel direction */ +#define DMA_CHAN_ON BIT(0) /* channel on / off bit */ +#define DMA_PDEN BIT(6) /* enable packet drop */ +#define DMA_CHAN_RST BIT(1) /* channel on / off bit */ +#define DMA_RESET BIT(0) /* channel on / off bit */ +#define DMA_IRQ_ACK 0x7e /* IRQ status register */ +#define DMA_POLL BIT(31) /* turn on channel polling */ +#define DMA_CLK_DIV4 BIT(6) /* polling clock divider */ +#define DMA_2W_BURST BIT(1) /* 2 word burst length */ +#define DMA_MAX_CHANNEL 20 /* the soc has 20 channels */ +#define DMA_ETOP_ENDIANESS (0xf << 8) /* endianess swap etop channels */ +#define DMA_WEIGHT (BIT(17) | BIT(16)) /* default channel wheight */ + +#define ltq_dma_r32(x) ltq_r32(ltq_dma_membase + (x)) +#define ltq_dma_w32(x, y) ltq_w32(x, ltq_dma_membase + (y)) +#define ltq_dma_w32_mask(x, y, z) ltq_w32_mask(x, y, \ + ltq_dma_membase + (z)) + +static struct resource ltq_dma_resource = { + .name = "dma", + .start = LTQ_DMA_BASE_ADDR, + .end = LTQ_DMA_BASE_ADDR + LTQ_DMA_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static void __iomem *ltq_dma_membase; + +void +ltq_dma_enable_irq(struct ltq_dma_channel *ch) +{ + unsigned long flags; + + local_irq_save(flags); + ltq_dma_w32(ch->nr, LTQ_DMA_CS); + ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(ltq_dma_enable_irq); + +void +ltq_dma_disable_irq(struct ltq_dma_channel *ch) +{ + unsigned long flags; + + local_irq_save(flags); + ltq_dma_w32(ch->nr, LTQ_DMA_CS); + ltq_dma_w32_mask(1 << ch->nr, 0, LTQ_DMA_IRNEN); + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(ltq_dma_disable_irq); + +void +ltq_dma_ack_irq(struct ltq_dma_channel *ch) +{ + unsigned long flags; + + local_irq_save(flags); + ltq_dma_w32(ch->nr, LTQ_DMA_CS); + ltq_dma_w32(DMA_IRQ_ACK, LTQ_DMA_CIS); + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(ltq_dma_ack_irq); + +void +ltq_dma_open(struct ltq_dma_channel *ch) +{ + unsigned long flag; + + local_irq_save(flag); + ltq_dma_w32(ch->nr, LTQ_DMA_CS); + ltq_dma_w32_mask(0, DMA_CHAN_ON, LTQ_DMA_CCTRL); + ltq_dma_enable_irq(ch); + local_irq_restore(flag); +} +EXPORT_SYMBOL_GPL(ltq_dma_open); + +void +ltq_dma_close(struct ltq_dma_channel *ch) +{ + unsigned long flag; + + local_irq_save(flag); + ltq_dma_w32(ch->nr, LTQ_DMA_CS); + ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); + ltq_dma_disable_irq(ch); + local_irq_restore(flag); +} +EXPORT_SYMBOL_GPL(ltq_dma_close); + +static void +ltq_dma_alloc(struct ltq_dma_channel *ch) +{ + unsigned long flags; + + ch->desc = 0; + ch->desc_base = dma_alloc_coherent(NULL, + LTQ_DESC_NUM * LTQ_DESC_SIZE, + &ch->phys, GFP_ATOMIC); + memset(ch->desc_base, 0, LTQ_DESC_NUM * LTQ_DESC_SIZE); + + local_irq_save(flags); + ltq_dma_w32(ch->nr, LTQ_DMA_CS); + ltq_dma_w32(ch->phys, LTQ_DMA_CDBA); + ltq_dma_w32(LTQ_DESC_NUM, LTQ_DMA_CDLEN); + ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); + wmb(); + ltq_dma_w32_mask(0, DMA_CHAN_RST, LTQ_DMA_CCTRL); + while (ltq_dma_r32(LTQ_DMA_CCTRL) & DMA_CHAN_RST) + ; + local_irq_restore(flags); +} + +void +ltq_dma_alloc_tx(struct ltq_dma_channel *ch) +{ + unsigned long flags; + + ltq_dma_alloc(ch); + + local_irq_save(flags); + ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE); + ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); + ltq_dma_w32(DMA_WEIGHT | DMA_TX, LTQ_DMA_CCTRL); + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(ltq_dma_alloc_tx); + +void +ltq_dma_alloc_rx(struct ltq_dma_channel *ch) +{ + unsigned long flags; + + ltq_dma_alloc(ch); + + local_irq_save(flags); + ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE); + ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); + ltq_dma_w32(DMA_WEIGHT, LTQ_DMA_CCTRL); + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(ltq_dma_alloc_rx); + +void +ltq_dma_free(struct ltq_dma_channel *ch) +{ + if (!ch->desc_base) + return; + ltq_dma_close(ch); + dma_free_coherent(NULL, LTQ_DESC_NUM * LTQ_DESC_SIZE, + ch->desc_base, ch->phys); +} +EXPORT_SYMBOL_GPL(ltq_dma_free); + +void +ltq_dma_init_port(int p) +{ + ltq_dma_w32(p, LTQ_DMA_PS); + switch (p) { + case DMA_PORT_ETOP: + /* + * Tell the DMA engine to swap the endianess of data frames and + * drop packets if the channel arbitration fails. + */ + ltq_dma_w32_mask(0, DMA_ETOP_ENDIANESS | DMA_PDEN, + LTQ_DMA_PCTRL); + break; + + case DMA_PORT_DEU: + ltq_dma_w32((DMA_2W_BURST << 4) | (DMA_2W_BURST << 2), + LTQ_DMA_PCTRL); + break; + + default: + break; + } +} +EXPORT_SYMBOL_GPL(ltq_dma_init_port); + +int __init +ltq_dma_init(void) +{ + int i; + + /* insert and request the memory region */ + if (insert_resource(&iomem_resource, <q_dma_resource) < 0) + panic("Failed to insert dma memory\n"); + + if (request_mem_region(ltq_dma_resource.start, + resource_size(<q_dma_resource), "dma") < 0) + panic("Failed to request dma memory\n"); + + /* remap dma register range */ + ltq_dma_membase = ioremap_nocache(ltq_dma_resource.start, + resource_size(<q_dma_resource)); + if (!ltq_dma_membase) + panic("Failed to remap dma memory\n"); + + /* power up and reset the dma engine */ + ltq_pmu_enable(PMU_DMA); + ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL); + + /* disable all interrupts */ + ltq_dma_w32(0, LTQ_DMA_IRNEN); + + /* reset/configure each channel */ + for (i = 0; i < DMA_MAX_CHANNEL; i++) { + ltq_dma_w32(i, LTQ_DMA_CS); + ltq_dma_w32(DMA_CHAN_RST, LTQ_DMA_CCTRL); + ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL); + ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); + } + return 0; +} + +postcore_initcall(ltq_dma_init); diff --git a/arch/mips/lantiq/xway/ebu.c b/arch/mips/lantiq/xway/ebu.c new file mode 100644 index 000000000000..66eb52fa50a1 --- /dev/null +++ b/arch/mips/lantiq/xway/ebu.c @@ -0,0 +1,53 @@ +/* + * 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. + * + * EBU - the external bus unit attaches PCI, NOR and NAND + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include + +/* all access to the ebu must be locked */ +DEFINE_SPINLOCK(ebu_lock); +EXPORT_SYMBOL_GPL(ebu_lock); + +static struct resource ltq_ebu_resource = { + .name = "ebu", + .start = LTQ_EBU_BASE_ADDR, + .end = LTQ_EBU_BASE_ADDR + LTQ_EBU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +/* remapped base addr of the clock unit and external bus unit */ +void __iomem *ltq_ebu_membase; + +static int __init lantiq_ebu_init(void) +{ + /* insert and request the memory region */ + if (insert_resource(&iomem_resource, <q_ebu_resource) < 0) + panic("Failed to insert ebu memory\n"); + + if (request_mem_region(ltq_ebu_resource.start, + resource_size(<q_ebu_resource), "ebu") < 0) + panic("Failed to request ebu memory\n"); + + /* remap ebu register range */ + ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start, + resource_size(<q_ebu_resource)); + if (!ltq_ebu_membase) + panic("Failed to remap ebu memory\n"); + + /* make sure to unprotect the memory region where flash is located */ + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); + return 0; +} + +postcore_initcall(lantiq_ebu_init); diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c new file mode 100644 index 000000000000..a321451a5455 --- /dev/null +++ b/arch/mips/lantiq/xway/gpio.c @@ -0,0 +1,195 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define LTQ_GPIO_OUT 0x00 +#define LTQ_GPIO_IN 0x04 +#define LTQ_GPIO_DIR 0x08 +#define LTQ_GPIO_ALTSEL0 0x0C +#define LTQ_GPIO_ALTSEL1 0x10 +#define LTQ_GPIO_OD 0x14 + +#define PINS_PER_PORT 16 +#define MAX_PORTS 3 + +#define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p))) +#define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r) +#define ltq_gpio_clearbit(m, r, p) ltq_w32_mask((1 << p), 0, m + r) + +struct ltq_gpio { + void __iomem *membase; + struct gpio_chip chip; +}; + +static struct ltq_gpio ltq_gpio_port[MAX_PORTS]; + +int gpio_to_irq(unsigned int gpio) +{ + return -EINVAL; +} +EXPORT_SYMBOL(gpio_to_irq); + +int irq_to_gpio(unsigned int gpio) +{ + return -EINVAL; +} +EXPORT_SYMBOL(irq_to_gpio); + +int ltq_gpio_request(unsigned int pin, unsigned int alt0, + unsigned int alt1, unsigned int dir, const char *name) +{ + int id = 0; + + if (pin >= (MAX_PORTS * PINS_PER_PORT)) + return -EINVAL; + if (gpio_request(pin, name)) { + pr_err("failed to setup lantiq gpio: %s\n", name); + return -EBUSY; + } + if (dir) + gpio_direction_output(pin, 1); + else + gpio_direction_input(pin); + while (pin >= PINS_PER_PORT) { + pin -= PINS_PER_PORT; + id++; + } + if (alt0) + ltq_gpio_setbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL0, pin); + else + ltq_gpio_clearbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL0, pin); + if (alt1) + ltq_gpio_setbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL1, pin); + else + ltq_gpio_clearbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL1, pin); + return 0; +} +EXPORT_SYMBOL(ltq_gpio_request); + +static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) +{ + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + + if (value) + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset); + else + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset); +} + +static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + + return ltq_gpio_getbit(ltq_gpio->membase, LTQ_GPIO_IN, offset); +} + +static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); + + return 0; +} + +static int ltq_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); + ltq_gpio_set(chip, offset, value); + + return 0; +} + +static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset) +{ + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset); + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset); + return 0; +} + +static int ltq_gpio_probe(struct platform_device *pdev) +{ + struct resource *res; + + if (pdev->id >= MAX_PORTS) { + dev_err(&pdev->dev, "invalid gpio port %d\n", + pdev->id); + return -EINVAL; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get memory for gpio port %d\n", + pdev->id); + return -ENOENT; + } + res = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, + "failed to request memory for gpio port %d\n", + pdev->id); + return -EBUSY; + } + ltq_gpio_port[pdev->id].membase = devm_ioremap_nocache(&pdev->dev, + res->start, resource_size(res)); + if (!ltq_gpio_port[pdev->id].membase) { + dev_err(&pdev->dev, "failed to remap memory for gpio port %d\n", + pdev->id); + return -ENOMEM; + } + ltq_gpio_port[pdev->id].chip.label = "ltq_gpio"; + ltq_gpio_port[pdev->id].chip.direction_input = ltq_gpio_direction_input; + ltq_gpio_port[pdev->id].chip.direction_output = + ltq_gpio_direction_output; + ltq_gpio_port[pdev->id].chip.get = ltq_gpio_get; + ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set; + ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req; + ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id; + ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT; + platform_set_drvdata(pdev, <q_gpio_port[pdev->id]); + return gpiochip_add(<q_gpio_port[pdev->id].chip); +} + +static struct platform_driver +ltq_gpio_driver = { + .probe = ltq_gpio_probe, + .driver = { + .name = "ltq_gpio", + .owner = THIS_MODULE, + }, +}; + +int __init ltq_gpio_init(void) +{ + int ret = platform_driver_register(<q_gpio_driver); + + if (ret) + pr_info("ltq_gpio : Error registering platfom driver!"); + return ret; +} + +postcore_initcall(ltq_gpio_init); diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c new file mode 100644 index 000000000000..a479355abdb9 --- /dev/null +++ b/arch/mips/lantiq/xway/gpio_ebu.c @@ -0,0 +1,126 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * By attaching hardware latches to the EBU it is possible to create output + * only gpios. This driver configures a special memory address, which when + * written to outputs 16 bit to the latches. + */ + +#define LTQ_EBU_BUSCON 0x1e7ff /* 16 bit access, slowest timing */ +#define LTQ_EBU_WP 0x80000000 /* write protect bit */ + +/* we keep a shadow value of the last value written to the ebu */ +static int ltq_ebu_gpio_shadow = 0x0; +static void __iomem *ltq_ebu_gpio_membase; + +static void ltq_ebu_apply(void) +{ + unsigned long flags; + + spin_lock_irqsave(&ebu_lock, flags); + ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1); + *((__u16 *)ltq_ebu_gpio_membase) = ltq_ebu_gpio_shadow; + ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1); + spin_unlock_irqrestore(&ebu_lock, flags); +} + +static void ltq_ebu_set(struct gpio_chip *chip, unsigned offset, int value) +{ + if (value) + ltq_ebu_gpio_shadow |= (1 << offset); + else + ltq_ebu_gpio_shadow &= ~(1 << offset); + ltq_ebu_apply(); +} + +static int ltq_ebu_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + ltq_ebu_set(chip, offset, value); + + return 0; +} + +static struct gpio_chip ltq_ebu_chip = { + .label = "ltq_ebu", + .direction_output = ltq_ebu_direction_output, + .set = ltq_ebu_set, + .base = 72, + .ngpio = 16, + .can_sleep = 1, + .owner = THIS_MODULE, +}; + +static int ltq_ebu_probe(struct platform_device *pdev) +{ + int ret = 0; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!res) { + dev_err(&pdev->dev, "failed to get memory resource\n"); + return -ENOENT; + } + + res = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, "failed to request memory resource\n"); + return -EBUSY; + } + + ltq_ebu_gpio_membase = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (!ltq_ebu_gpio_membase) { + dev_err(&pdev->dev, "Failed to ioremap mem region\n"); + return -ENOMEM; + } + + /* grab the default shadow value passed form the platform code */ + ltq_ebu_gpio_shadow = (unsigned int) pdev->dev.platform_data; + + /* tell the ebu controller which memory address we will be using */ + ltq_ebu_w32(pdev->resource->start | 0x1, LTQ_EBU_ADDRSEL1); + + /* write protect the region */ + ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1); + + ret = gpiochip_add(<q_ebu_chip); + if (!ret) + ltq_ebu_apply(); + return ret; +} + +static struct platform_driver ltq_ebu_driver = { + .probe = ltq_ebu_probe, + .driver = { + .name = "ltq_ebu", + .owner = THIS_MODULE, + }, +}; + +static int __init ltq_ebu_init(void) +{ + int ret = platform_driver_register(<q_ebu_driver); + + if (ret) + pr_info("ltq_ebu : Error registering platfom driver!"); + return ret; +} + +postcore_initcall(ltq_ebu_init); diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c new file mode 100644 index 000000000000..67d59d690340 --- /dev/null +++ b/arch/mips/lantiq/xway/gpio_stp.c @@ -0,0 +1,157 @@ +/* + * 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. + * + * Copyright (C) 2007 John Crispin + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LTQ_STP_CON0 0x00 +#define LTQ_STP_CON1 0x04 +#define LTQ_STP_CPU0 0x08 +#define LTQ_STP_CPU1 0x0C +#define LTQ_STP_AR 0x10 + +#define LTQ_STP_CON_SWU (1 << 31) +#define LTQ_STP_2HZ 0 +#define LTQ_STP_4HZ (1 << 23) +#define LTQ_STP_8HZ (2 << 23) +#define LTQ_STP_10HZ (3 << 23) +#define LTQ_STP_SPEED_MASK (0xf << 23) +#define LTQ_STP_UPD_FPI (1 << 31) +#define LTQ_STP_UPD_MASK (3 << 30) +#define LTQ_STP_ADSL_SRC (3 << 24) + +#define LTQ_STP_GROUP0 (1 << 0) + +#define LTQ_STP_RISING 0 +#define LTQ_STP_FALLING (1 << 26) +#define LTQ_STP_EDGE_MASK (1 << 26) + +#define ltq_stp_r32(reg) __raw_readl(ltq_stp_membase + reg) +#define ltq_stp_w32(val, reg) __raw_writel(val, ltq_stp_membase + reg) +#define ltq_stp_w32_mask(clear, set, reg) \ + ltq_w32((ltq_r32(ltq_stp_membase + reg) & ~(clear)) | (set), \ + ltq_stp_membase + (reg)) + +static int ltq_stp_shadow = 0xffff; +static void __iomem *ltq_stp_membase; + +static void ltq_stp_set(struct gpio_chip *chip, unsigned offset, int value) +{ + if (value) + ltq_stp_shadow |= (1 << offset); + else + ltq_stp_shadow &= ~(1 << offset); + ltq_stp_w32(ltq_stp_shadow, LTQ_STP_CPU0); +} + +static int ltq_stp_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + ltq_stp_set(chip, offset, value); + + return 0; +} + +static struct gpio_chip ltq_stp_chip = { + .label = "ltq_stp", + .direction_output = ltq_stp_direction_output, + .set = ltq_stp_set, + .base = 48, + .ngpio = 24, + .can_sleep = 1, + .owner = THIS_MODULE, +}; + +static int ltq_stp_hw_init(void) +{ + /* the 3 pins used to control the external stp */ + ltq_gpio_request(4, 1, 0, 1, "stp-st"); + ltq_gpio_request(5, 1, 0, 1, "stp-d"); + ltq_gpio_request(6, 1, 0, 1, "stp-sh"); + + /* sane defaults */ + ltq_stp_w32(0, LTQ_STP_AR); + ltq_stp_w32(0, LTQ_STP_CPU0); + ltq_stp_w32(0, LTQ_STP_CPU1); + ltq_stp_w32(LTQ_STP_CON_SWU, LTQ_STP_CON0); + ltq_stp_w32(0, LTQ_STP_CON1); + + /* rising or falling edge */ + ltq_stp_w32_mask(LTQ_STP_EDGE_MASK, LTQ_STP_FALLING, LTQ_STP_CON0); + + /* per default stp 15-0 are set */ + ltq_stp_w32_mask(0, LTQ_STP_GROUP0, LTQ_STP_CON1); + + /* stp are update periodically by the FPI bus */ + ltq_stp_w32_mask(LTQ_STP_UPD_MASK, LTQ_STP_UPD_FPI, LTQ_STP_CON1); + + /* set stp update speed */ + ltq_stp_w32_mask(LTQ_STP_SPEED_MASK, LTQ_STP_8HZ, LTQ_STP_CON1); + + /* tell the hardware that pin (led) 0 and 1 are controlled + * by the dsl arc + */ + ltq_stp_w32_mask(0, LTQ_STP_ADSL_SRC, LTQ_STP_CON0); + + ltq_pmu_enable(PMU_LED); + return 0; +} + +static int __devinit ltq_stp_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int ret = 0; + + if (!res) + return -ENOENT; + res = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, "failed to request STP memory\n"); + return -EBUSY; + } + ltq_stp_membase = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (!ltq_stp_membase) { + dev_err(&pdev->dev, "failed to remap STP memory\n"); + return -ENOMEM; + } + ret = gpiochip_add(<q_stp_chip); + if (!ret) + ret = ltq_stp_hw_init(); + + return ret; +} + +static struct platform_driver ltq_stp_driver = { + .probe = ltq_stp_probe, + .driver = { + .name = "ltq_stp", + .owner = THIS_MODULE, + }, +}; + +int __init ltq_stp_init(void) +{ + int ret = platform_driver_register(<q_stp_driver); + + if (ret) + pr_info("ltq_stp: error registering platfom driver"); + return ret; +} + +postcore_initcall(ltq_stp_init); diff --git a/arch/mips/lantiq/xway/mach-easy50601.c b/arch/mips/lantiq/xway/mach-easy50601.c new file mode 100644 index 000000000000..d5aaf637ab19 --- /dev/null +++ b/arch/mips/lantiq/xway/mach-easy50601.c @@ -0,0 +1,57 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "../machtypes.h" +#include "devices.h" + +static struct mtd_partition easy50601_partitions[] = { + { + .name = "uboot", + .offset = 0x0, + .size = 0x10000, + }, + { + .name = "uboot_env", + .offset = 0x10000, + .size = 0x10000, + }, + { + .name = "linux", + .offset = 0x20000, + .size = 0xE0000, + }, + { + .name = "rootfs", + .offset = 0x100000, + .size = 0x300000, + }, +}; + +static struct physmap_flash_data easy50601_flash_data = { + .nr_parts = ARRAY_SIZE(easy50601_partitions), + .parts = easy50601_partitions, +}; + +static void __init easy50601_init(void) +{ + ltq_register_nor(&easy50601_flash_data); +} + +MIPS_MACHINE(LTQ_MACH_EASY50601, + "EASY50601", + "EASY50601 Eval Board", + easy50601_init); diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c new file mode 100644 index 000000000000..ea5027b3239d --- /dev/null +++ b/arch/mips/lantiq/xway/mach-easy50712.c @@ -0,0 +1,74 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../machtypes.h" +#include "devices.h" + +static struct mtd_partition easy50712_partitions[] = { + { + .name = "uboot", + .offset = 0x0, + .size = 0x10000, + }, + { + .name = "uboot_env", + .offset = 0x10000, + .size = 0x10000, + }, + { + .name = "linux", + .offset = 0x20000, + .size = 0xe0000, + }, + { + .name = "rootfs", + .offset = 0x100000, + .size = 0x300000, + }, +}; + +static struct physmap_flash_data easy50712_flash_data = { + .nr_parts = ARRAY_SIZE(easy50712_partitions), + .parts = easy50712_partitions, +}; + +static struct ltq_pci_data ltq_pci_data = { + .clock = PCI_CLOCK_INT, + .gpio = PCI_GNT1 | PCI_REQ1, + .irq = { + [14] = INT_NUM_IM0_IRL0 + 22, + }, +}; + +static struct ltq_eth_data ltq_eth_data = { + .mii_mode = PHY_INTERFACE_MODE_MII, +}; + +static void __init easy50712_init(void) +{ + ltq_register_gpio_stp(); + ltq_register_nor(&easy50712_flash_data); + ltq_register_pci(<q_pci_data); + ltq_register_etop(<q_eth_data); +} + +MIPS_MACHINE(LTQ_MACH_EASY50712, + "EASY50712", + "EASY50712 Eval Board", + easy50712_init); diff --git a/arch/mips/lantiq/xway/pmu.c b/arch/mips/lantiq/xway/pmu.c new file mode 100644 index 000000000000..9d69f01e352b --- /dev/null +++ b/arch/mips/lantiq/xway/pmu.c @@ -0,0 +1,70 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include + +/* PMU - the power management unit allows us to turn part of the core + * on and off + */ + +/* the enable / disable registers */ +#define LTQ_PMU_PWDCR 0x1C +#define LTQ_PMU_PWDSR 0x20 + +#define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y)) +#define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x)) + +static struct resource ltq_pmu_resource = { + .name = "pmu", + .start = LTQ_PMU_BASE_ADDR, + .end = LTQ_PMU_BASE_ADDR + LTQ_PMU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static void __iomem *ltq_pmu_membase; + +void ltq_pmu_enable(unsigned int module) +{ + int err = 1000000; + + ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR); + do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module)); + + if (!err) + panic("activating PMU module failed!\n"); +} +EXPORT_SYMBOL(ltq_pmu_enable); + +void ltq_pmu_disable(unsigned int module) +{ + ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR); +} +EXPORT_SYMBOL(ltq_pmu_disable); + +int __init ltq_pmu_init(void) +{ + if (insert_resource(&iomem_resource, <q_pmu_resource) < 0) + panic("Failed to insert pmu memory\n"); + + if (request_mem_region(ltq_pmu_resource.start, + resource_size(<q_pmu_resource), "pmu") < 0) + panic("Failed to request pmu memory\n"); + + ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start, + resource_size(<q_pmu_resource)); + if (!ltq_pmu_membase) + panic("Failed to remap pmu memory\n"); + return 0; +} + +core_initcall(ltq_pmu_init); diff --git a/arch/mips/lantiq/xway/prom-ase.c b/arch/mips/lantiq/xway/prom-ase.c new file mode 100644 index 000000000000..abe49f4db57f --- /dev/null +++ b/arch/mips/lantiq/xway/prom-ase.c @@ -0,0 +1,39 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include + +#include "../prom.h" + +#define SOC_AMAZON_SE "Amazon_SE" + +#define PART_SHIFT 12 +#define PART_MASK 0x0FFFFFFF +#define REV_SHIFT 28 +#define REV_MASK 0xF0000000 + +void __init ltq_soc_detect(struct ltq_soc_info *i) +{ + i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; + i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; + switch (i->partnum) { + case SOC_ID_AMAZON_SE: + i->name = SOC_AMAZON_SE; + i->type = SOC_TYPE_AMAZON_SE; + break; + + default: + unreachable(); + break; + } +} diff --git a/arch/mips/lantiq/xway/prom-xway.c b/arch/mips/lantiq/xway/prom-xway.c new file mode 100644 index 000000000000..1686692ac24d --- /dev/null +++ b/arch/mips/lantiq/xway/prom-xway.c @@ -0,0 +1,54 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include + +#include "../prom.h" + +#define SOC_DANUBE "Danube" +#define SOC_TWINPASS "Twinpass" +#define SOC_AR9 "AR9" + +#define PART_SHIFT 12 +#define PART_MASK 0x0FFFFFFF +#define REV_SHIFT 28 +#define REV_MASK 0xF0000000 + +void __init ltq_soc_detect(struct ltq_soc_info *i) +{ + i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; + i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; + switch (i->partnum) { + case SOC_ID_DANUBE1: + case SOC_ID_DANUBE2: + i->name = SOC_DANUBE; + i->type = SOC_TYPE_DANUBE; + break; + + case SOC_ID_TWINPASS: + i->name = SOC_TWINPASS; + i->type = SOC_TYPE_DANUBE; + break; + + case SOC_ID_ARX188: + case SOC_ID_ARX168: + case SOC_ID_ARX182: + i->name = SOC_AR9; + i->type = SOC_TYPE_AR9; + break; + + default: + unreachable(); + break; + } +} diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c new file mode 100644 index 000000000000..a1be36d0e490 --- /dev/null +++ b/arch/mips/lantiq/xway/reset.c @@ -0,0 +1,91 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define ltq_rcu_w32(x, y) ltq_w32((x), ltq_rcu_membase + (y)) +#define ltq_rcu_r32(x) ltq_r32(ltq_rcu_membase + (x)) + +/* register definitions */ +#define LTQ_RCU_RST 0x0010 +#define LTQ_RCU_RST_ALL 0x40000000 + +#define LTQ_RCU_RST_STAT 0x0014 +#define LTQ_RCU_STAT_SHIFT 26 + +static struct resource ltq_rcu_resource = { + .name = "rcu", + .start = LTQ_RCU_BASE_ADDR, + .end = LTQ_RCU_BASE_ADDR + LTQ_RCU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +/* remapped base addr of the reset control unit */ +static void __iomem *ltq_rcu_membase; + +/* This function is used by the watchdog driver */ +int ltq_reset_cause(void) +{ + u32 val = ltq_rcu_r32(LTQ_RCU_RST_STAT); + return val >> LTQ_RCU_STAT_SHIFT; +} +EXPORT_SYMBOL_GPL(ltq_reset_cause); + +static void ltq_machine_restart(char *command) +{ + pr_notice("System restart\n"); + local_irq_disable(); + ltq_rcu_w32(ltq_rcu_r32(LTQ_RCU_RST) | LTQ_RCU_RST_ALL, LTQ_RCU_RST); + unreachable(); +} + +static void ltq_machine_halt(void) +{ + pr_notice("System halted.\n"); + local_irq_disable(); + unreachable(); +} + +static void ltq_machine_power_off(void) +{ + pr_notice("Please turn off the power now.\n"); + local_irq_disable(); + unreachable(); +} + +static int __init mips_reboot_setup(void) +{ + /* insert and request the memory region */ + if (insert_resource(&iomem_resource, <q_rcu_resource) < 0) + panic("Failed to insert rcu memory\n"); + + if (request_mem_region(ltq_rcu_resource.start, + resource_size(<q_rcu_resource), "rcu") < 0) + panic("Failed to request rcu memory\n"); + + /* remap rcu register range */ + ltq_rcu_membase = ioremap_nocache(ltq_rcu_resource.start, + resource_size(<q_rcu_resource)); + if (!ltq_rcu_membase) + panic("Failed to remap rcu memory\n"); + + _machine_restart = ltq_machine_restart; + _machine_halt = ltq_machine_halt; + pm_power_off = ltq_machine_power_off; + + return 0; +} + +arch_initcall(mips_reboot_setup); diff --git a/arch/mips/lantiq/xway/setup-ase.c b/arch/mips/lantiq/xway/setup-ase.c new file mode 100644 index 000000000000..f6f326798a39 --- /dev/null +++ b/arch/mips/lantiq/xway/setup-ase.c @@ -0,0 +1,19 @@ +/* + * 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. + * + * Copyright (C) 2011 John Crispin + */ + +#include + +#include "../prom.h" +#include "devices.h" + +void __init ltq_soc_setup(void) +{ + ltq_register_ase_asc(); + ltq_register_gpio(); + ltq_register_wdt(); +} diff --git a/arch/mips/lantiq/xway/setup-xway.c b/arch/mips/lantiq/xway/setup-xway.c new file mode 100644 index 000000000000..c292f643a858 --- /dev/null +++ b/arch/mips/lantiq/xway/setup-xway.c @@ -0,0 +1,20 @@ +/* + * 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. + * + * Copyright (C) 2011 John Crispin + */ + +#include + +#include "../prom.h" +#include "devices.h" + +void __init ltq_soc_setup(void) +{ + ltq_register_asc(0); + ltq_register_asc(1); + ltq_register_gpio(); + ltq_register_wdt(); +} diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index 2adead5a8a37..b2cad4fd5fc4 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_CPU_TX39XX) += r3k_dump_tlb.o obj-$(CONFIG_CPU_TX49XX) += dump_tlb.o obj-$(CONFIG_CPU_VR41XX) += dump_tlb.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += dump_tlb.o +obj-$(CONFIG_CPU_XLR) += dump_tlb.o # libgcc-style stuff needed in the kernel obj-y += ashldi3.o ashrdi3.o cmpdi2.o lshrdi3.o ucmpdi2.o diff --git a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c index 8c807c965199..0cb1b9760e34 100644 --- a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c +++ b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c @@ -201,8 +201,6 @@ static struct clocksource clocksource_mfgpt = { .rating = 120, /* Functional for real use, but not desired */ .read = mfgpt_read, .mask = CLOCKSOURCE_MASK(32), - .mult = 0, - .shift = 22, }; int __init init_mfgpt_clocksource(void) @@ -210,8 +208,7 @@ int __init init_mfgpt_clocksource(void) if (num_possible_cpus() > 1) /* MFGPT does not scale! */ return 0; - clocksource_mfgpt.mult = clocksource_hz2mult(MFGPT_TICK_RATE, 22); - return clocksource_register(&clocksource_mfgpt); + return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE); } arch_initcall(init_mfgpt_clocksource); diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c index 11b193f848f8..d93830ad6113 100644 --- a/arch/mips/loongson/common/env.c +++ b/arch/mips/loongson/common/env.c @@ -29,9 +29,10 @@ unsigned long memsize, highmemsize; #define parse_even_earlier(res, option, p) \ do { \ - int ret; \ + unsigned int tmp __maybe_unused; \ + \ if (strncmp(option, (char *)p, strlen(option)) == 0) \ - ret = strict_strtol((char *)p + strlen(option"="), 10, &res); \ + tmp = strict_strtol((char *)p + strlen(option"="), 10, &res); \ } while (0) void __init prom_init_env(void) diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index d679c772d082..4d8c1623eee2 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -3,7 +3,8 @@ # obj-y += cache.o dma-default.o extable.o fault.o \ - init.o tlbex.o tlbex-fault.o uasm.o page.o + init.o mmap.o tlbex.o tlbex-fault.o uasm.o \ + page.o obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o obj-$(CONFIG_64BIT) += pgtable-64.o @@ -29,6 +30,7 @@ obj-$(CONFIG_CPU_TX39XX) += c-tx39.o tlb-r3k.o obj-$(CONFIG_CPU_TX49XX) += c-r4k.o cex-gen.o tlb-r4k.o obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-gen.o tlb-r4k.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += c-octeon.o cex-oct.o tlb-r4k.o +obj-$(CONFIG_CPU_XLR) += c-r4k.o tlb-r4k.o cex-gen.o obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index b4923a75cb4b..d9bc5d3593b6 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1006,6 +1006,7 @@ static void __cpuinit probe_pcache(void) case CPU_25KF: case CPU_SB1: case CPU_SB1A: + case CPU_XLR: c->dcache.flags |= MIPS_CACHE_PINDEX; break; @@ -1075,7 +1076,6 @@ static int __cpuinit probe_scache(void) unsigned long flags, addr, begin, end, pow2; unsigned int config = read_c0_config(); struct cpuinfo_mips *c = ¤t_cpu_data; - int tmp; if (config & CONF_SC) return 0; @@ -1108,7 +1108,6 @@ static int __cpuinit probe_scache(void) /* Now search for the wrap around point. */ pow2 = (128 * 1024); - tmp = 0; for (addr = begin + (128 * 1024); addr < end; addr = begin + pow2) { cache_op(Index_Load_Tag_SD, addr); __asm__ __volatile__("nop; nop; nop; nop;"); /* hazard... */ diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c new file mode 100644 index 000000000000..ae3c20a9556e --- /dev/null +++ b/arch/mips/mm/mmap.c @@ -0,0 +1,122 @@ +/* + * 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 Wind River Systems, + * written by Ralf Baechle + */ +#include +#include +#include +#include +#include +#include + +unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ + +EXPORT_SYMBOL(shm_align_mask); + +#define COLOUR_ALIGN(addr,pgoff) \ + ((((addr) + shm_align_mask) & ~shm_align_mask) + \ + (((pgoff) << PAGE_SHIFT) & shm_align_mask)) + +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct vm_area_struct * vmm; + int do_color_align; + + if (len > TASK_SIZE) + return -ENOMEM; + + if (flags & MAP_FIXED) { + /* Even MAP_FIXED mappings must reside within TASK_SIZE. */ + if (TASK_SIZE - len < addr) + return -EINVAL; + + /* + * We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ + if ((flags & MAP_SHARED) && + ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) + return -EINVAL; + return addr; + } + + do_color_align = 0; + if (filp || (flags & MAP_SHARED)) + do_color_align = 1; + if (addr) { + if (do_color_align) + addr = COLOUR_ALIGN(addr, pgoff); + else + addr = PAGE_ALIGN(addr); + vmm = find_vma(current->mm, addr); + if (TASK_SIZE - len >= addr && + (!vmm || addr + len <= vmm->vm_start)) + return addr; + } + addr = current->mm->mmap_base; + if (do_color_align) + addr = COLOUR_ALIGN(addr, pgoff); + else + addr = PAGE_ALIGN(addr); + + for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { + /* At this point: (!vmm || addr < vmm->vm_end). */ + if (TASK_SIZE - len < addr) + return -ENOMEM; + if (!vmm || addr + len <= vmm->vm_start) + return addr; + addr = vmm->vm_end; + if (do_color_align) + addr = COLOUR_ALIGN(addr, pgoff); + } +} + +void arch_pick_mmap_layout(struct mm_struct *mm) +{ + unsigned long random_factor = 0UL; + + if (current->flags & PF_RANDOMIZE) { + random_factor = get_random_int(); + random_factor = random_factor << PAGE_SHIFT; + if (TASK_IS_32BIT_ADDR) + random_factor &= 0xfffffful; + else + random_factor &= 0xffffffful; + } + + mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; + mm->get_unmapped_area = arch_get_unmapped_area; + mm->unmap_area = arch_unmap_area; +} + +static inline unsigned long brk_rnd(void) +{ + unsigned long rnd = get_random_int(); + + rnd = rnd << PAGE_SHIFT; + /* 8MB for 32bit, 256MB for 64bit */ + if (TASK_IS_32BIT_ADDR) + rnd = rnd & 0x7ffffful; + else + rnd = rnd & 0xffffffful; + + return rnd; +} + +unsigned long arch_randomize_brk(struct mm_struct *mm) +{ + unsigned long base = mm->brk; + unsigned long ret; + + ret = PAGE_ALIGN(base + brk_rnd()); + + if (ret < mm->brk) + return mm->brk; + + return ret; +} diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 5ef294fbb6e7..424ed4b92e6d 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -404,6 +404,7 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l, case CPU_5KC: case CPU_TX49XX: case CPU_PR4450: + case CPU_XLR: uasm_i_nop(p); tlbw(p); break; @@ -1151,8 +1152,8 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) struct uasm_reloc *r = relocs; u32 *f; unsigned int final_len; - struct mips_huge_tlb_info htlb_info; - enum vmalloc64_mode vmalloc_mode; + struct mips_huge_tlb_info htlb_info __maybe_unused; + enum vmalloc64_mode vmalloc_mode __maybe_unused; memset(tlb_handler, 0, sizeof(tlb_handler)); memset(labels, 0, sizeof(labels)); diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index 414f0c99b196..31180c321a1a 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -193,8 +193,6 @@ extern struct plat_smp_ops msmtc_smp_ops; void __init prom_init(void) { - int result; - prom_argc = fw_arg0; _prom_argv = (int *) fw_arg1; _prom_envp = (int *) fw_arg2; @@ -360,20 +358,14 @@ void __init prom_init(void) #ifdef CONFIG_SERIAL_8250_CONSOLE console_config(); #endif - /* Early detection of CMP support */ - result = gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ); - #ifdef CONFIG_MIPS_CMP - if (result) + /* Early detection of CMP support */ + if (gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ)) register_smp_ops(&cmp_smp_ops); + else #endif #ifdef CONFIG_MIPS_MT_SMP -#ifdef CONFIG_MIPS_CMP - if (!result) register_smp_ops(&vsmp_smp_ops); -#else - register_smp_ops(&vsmp_smp_ops); -#endif #endif #ifdef CONFIG_MIPS_MT_SMTC register_smp_ops(&msmtc_smp_ops); diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index 9027061f0ead..1d36c511a7a5 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c @@ -56,7 +56,6 @@ static DEFINE_RAW_SPINLOCK(mips_irq_lock); static inline int mips_pcibios_iack(void) { int irq; - u32 dummy; /* * Determine highest priority pending interrupt by performing @@ -83,7 +82,7 @@ static inline int mips_pcibios_iack(void) BONITO_PCIMAP_CFG = 0x20000; /* Flush Bonito register block */ - dummy = BONITO_PCIMAP_CFG; + (void) BONITO_PCIMAP_CFG; iob(); /* sync */ irq = __raw_readl((u32 *)_pcictrl_bonito_pcicfg); @@ -309,6 +308,8 @@ static void ipi_call_dispatch(void) static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) { + scheduler_ipi(); + return IRQ_HANDLED; } diff --git a/arch/mips/netlogic/Kconfig b/arch/mips/netlogic/Kconfig new file mode 100644 index 000000000000..a5ca743613f2 --- /dev/null +++ b/arch/mips/netlogic/Kconfig @@ -0,0 +1,5 @@ +config NLM_COMMON + bool + +config NLM_XLR + bool diff --git a/arch/mips/netlogic/xlr/Makefile b/arch/mips/netlogic/xlr/Makefile new file mode 100644 index 000000000000..9bd3f731f62e --- /dev/null +++ b/arch/mips/netlogic/xlr/Makefile @@ -0,0 +1,5 @@ +obj-y += setup.o platform.o irq.o setup.o time.o +obj-$(CONFIG_SMP) += smp.o smpboot.o +obj-$(CONFIG_EARLY_PRINTK) += xlr_console.o + +EXTRA_CFLAGS += -Werror diff --git a/arch/mips/netlogic/xlr/irq.c b/arch/mips/netlogic/xlr/irq.c new file mode 100644 index 000000000000..1446d58e364c --- /dev/null +++ b/arch/mips/netlogic/xlr/irq.c @@ -0,0 +1,300 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +static u64 nlm_irq_mask; +static DEFINE_SPINLOCK(nlm_pic_lock); + +static void xlr_pic_enable(struct irq_data *d) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + unsigned long flags; + nlm_reg_t reg; + int irq = d->irq; + + WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); + + spin_lock_irqsave(&nlm_pic_lock, flags); + reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE); + netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE, + reg | (1 << 6) | (1 << 30) | (1 << 31)); + spin_unlock_irqrestore(&nlm_pic_lock, flags); +} + +static void xlr_pic_mask(struct irq_data *d) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + unsigned long flags; + nlm_reg_t reg; + int irq = d->irq; + + WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); + + spin_lock_irqsave(&nlm_pic_lock, flags); + reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE); + netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE, + reg | (1 << 6) | (1 << 30) | (0 << 31)); + spin_unlock_irqrestore(&nlm_pic_lock, flags); +} + +#ifdef CONFIG_PCI +/* Extra ACK needed for XLR on chip PCI controller */ +static void xlr_pci_ack(struct irq_data *d) +{ + nlm_reg_t *pci_mmio = netlogic_io_mmio(NETLOGIC_IO_PCIX_OFFSET); + + netlogic_read_reg(pci_mmio, (0x140 >> 2)); +} + +/* Extra ACK needed for XLS on chip PCIe controller */ +static void xls_pcie_ack(struct irq_data *d) +{ + nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET); + + switch (d->irq) { + case PIC_PCIE_LINK0_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK1_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK2_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK3_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff); + break; + } +} + +/* For XLS B silicon, the 3,4 PCI interrupts are different */ +static void xls_pcie_ack_b(struct irq_data *d) +{ + nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET); + + switch (d->irq) { + case PIC_PCIE_LINK0_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK1_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff); + break; + case PIC_PCIE_XLSB0_LINK2_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff); + break; + case PIC_PCIE_XLSB0_LINK3_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff); + break; + } +} +#endif + +static void xlr_pic_ack(struct irq_data *d) +{ + unsigned long flags; + nlm_reg_t *mmio; + int irq = d->irq; + void *hd = irq_data_get_irq_handler_data(d); + + WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); + + if (hd) { + void (*extra_ack)(void *) = hd; + extra_ack(d); + } + mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + spin_lock_irqsave(&nlm_pic_lock, flags); + netlogic_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE))); + spin_unlock_irqrestore(&nlm_pic_lock, flags); +} + +/* + * This chip definition handles interrupts routed thru the XLR + * hardware PIC, currently IRQs 8-39 are mapped to hardware intr + * 0-31 wired the XLR PIC + */ +static struct irq_chip xlr_pic = { + .name = "XLR-PIC", + .irq_enable = xlr_pic_enable, + .irq_mask = xlr_pic_mask, + .irq_ack = xlr_pic_ack, +}; + +static void rsvd_irq_handler(struct irq_data *d) +{ + WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq); +} + +/* + * Chip definition for CPU originated interrupts(timer, msg) and + * IPIs + */ +struct irq_chip nlm_cpu_intr = { + .name = "XLR-CPU-INTR", + .irq_enable = rsvd_irq_handler, + .irq_mask = rsvd_irq_handler, + .irq_ack = rsvd_irq_handler, +}; + +void __init init_xlr_irqs(void) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + uint32_t thread_mask = 1; + int level, i; + + pr_info("Interrupt thread mask [%x]\n", thread_mask); + for (i = 0; i < PIC_NUM_IRTS; i++) { + level = PIC_IRQ_IS_EDGE_TRIGGERED(i); + + /* Bind all PIC irqs to boot cpu */ + netlogic_write_reg(mmio, PIC_IRT_0_BASE + i, thread_mask); + + /* + * Use local scheduling and high polarity for all IRTs + * Invalidate all IRTs, by default + */ + netlogic_write_reg(mmio, PIC_IRT_1_BASE + i, + (level << 30) | (1 << 6) | (PIC_IRQ_BASE + i)); + } + + /* Make all IRQs as level triggered by default */ + for (i = 0; i < NR_IRQS; i++) { + if (PIC_IRQ_IS_IRT(i)) + irq_set_chip_and_handler(i, &xlr_pic, handle_level_irq); + else + irq_set_chip_and_handler(i, &nlm_cpu_intr, + handle_level_irq); + } +#ifdef CONFIG_SMP + irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr, + nlm_smp_function_ipi_handler); + irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr, + nlm_smp_resched_ipi_handler); + nlm_irq_mask |= + ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE)); +#endif + +#ifdef CONFIG_PCI + /* + * For PCI interrupts, we need to ack the PIC controller too, overload + * irq handler data to do this + */ + if (nlm_chip_is_xls()) { + if (nlm_chip_is_xls_b()) { + irq_set_handler_data(PIC_PCIE_LINK0_IRQ, + xls_pcie_ack_b); + irq_set_handler_data(PIC_PCIE_LINK1_IRQ, + xls_pcie_ack_b); + irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ, + xls_pcie_ack_b); + irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, + xls_pcie_ack_b); + } else { + irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack); + irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack); + irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack); + irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack); + } + } else { + /* XLR PCI controller ACK */ + irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack); + } +#endif + /* unmask all PIC related interrupts. If no handler is installed by the + * drivers, it'll just ack the interrupt and return + */ + for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) + nlm_irq_mask |= (1ULL << i); + + nlm_irq_mask |= (1ULL << IRQ_TIMER); +} + +void __init arch_init_irq(void) +{ + /* Initialize the irq descriptors */ + init_xlr_irqs(); + write_c0_eimr(nlm_irq_mask); +} + +void __cpuinit nlm_smp_irq_init(void) +{ + /* set interrupt mask for non-zero cpus */ + write_c0_eimr(nlm_irq_mask); +} + +asmlinkage void plat_irq_dispatch(void) +{ + uint64_t eirr; + int i; + + eirr = read_c0_eirr() & read_c0_eimr(); + if (!eirr) + return; + + /* no need of EIRR here, writing compare clears interrupt */ + if (eirr & (1 << IRQ_TIMER)) { + do_IRQ(IRQ_TIMER); + return; + } + + /* use dcltz: optimize below code */ + for (i = 63; i != -1; i--) { + if (eirr & (1ULL << i)) + break; + } + if (i == -1) { + pr_err("no interrupt !!\n"); + return; + } + + /* Ack eirr */ + write_c0_eirr(1ULL << i); + + do_IRQ(i); +} diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c new file mode 100644 index 000000000000..609ec2534642 --- /dev/null +++ b/arch/mips/netlogic/xlr/platform.c @@ -0,0 +1,98 @@ +/* + * Copyright 2011, Netlogic Microsystems. + * Copyright 2004, Matt Porter + * + * 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 + +unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) +{ + nlm_reg_t *mmio; + unsigned int value; + + /* XLR uart does not need any mapping of regs */ + mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift)); + value = netlogic_read_reg(mmio, 0); + + /* See XLR/XLS errata */ + if (offset == UART_MSR) + value ^= 0xF0; + else if (offset == UART_MCR) + value ^= 0x3; + + return value; +} + +void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) +{ + nlm_reg_t *mmio; + + /* XLR uart does not need any mapping of regs */ + mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift)); + + /* See XLR/XLS errata */ + if (offset == UART_MSR) + value ^= 0xF0; + else if (offset == UART_MCR) + value ^= 0x3; + + netlogic_write_reg(mmio, 0, value); +} + +#define PORT(_irq) \ + { \ + .irq = _irq, \ + .regshift = 2, \ + .iotype = UPIO_MEM32, \ + .flags = (UPF_SKIP_TEST | \ + UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF),\ + .uartclk = PIC_CLKS_PER_SEC, \ + .type = PORT_16550A, \ + .serial_in = nlm_xlr_uart_in, \ + .serial_out = nlm_xlr_uart_out, \ + } + +static struct plat_serial8250_port xlr_uart_data[] = { + PORT(PIC_UART_0_IRQ), + PORT(PIC_UART_1_IRQ), + {}, +}; + +static struct platform_device uart_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = xlr_uart_data, + }, +}; + +static int __init nlm_uart_init(void) +{ + nlm_reg_t *mmio; + + mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET); + xlr_uart_data[0].membase = (void __iomem *)mmio; + xlr_uart_data[0].mapbase = CPHYSADDR((unsigned long)mmio); + + mmio = netlogic_io_mmio(NETLOGIC_IO_UART_1_OFFSET); + xlr_uart_data[1].membase = (void __iomem *)mmio; + xlr_uart_data[1].mapbase = CPHYSADDR((unsigned long)mmio); + + return platform_device_register(&uart_device); +} + +arch_initcall(nlm_uart_init); diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c new file mode 100644 index 000000000000..482802569e74 --- /dev/null +++ b/arch/mips/netlogic/xlr/setup.c @@ -0,0 +1,188 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +unsigned long netlogic_io_base = (unsigned long)(DEFAULT_NETLOGIC_IO_BASE); +unsigned long nlm_common_ebase = 0x0; +struct psb_info nlm_prom_info; + +static void nlm_early_serial_setup(void) +{ + struct uart_port s; + nlm_reg_t *uart_base; + + uart_base = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET); + memset(&s, 0, sizeof(s)); + s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; + s.iotype = UPIO_MEM32; + s.regshift = 2; + s.irq = PIC_UART_0_IRQ; + s.uartclk = PIC_CLKS_PER_SEC; + s.serial_in = nlm_xlr_uart_in; + s.serial_out = nlm_xlr_uart_out; + s.mapbase = (unsigned long)uart_base; + s.membase = (unsigned char __iomem *)uart_base; + early_serial_setup(&s); +} + +static void nlm_linux_exit(void) +{ + nlm_reg_t *mmio; + + mmio = netlogic_io_mmio(NETLOGIC_IO_GPIO_OFFSET); + /* trigger a chip reset by writing 1 to GPIO_SWRESET_REG */ + netlogic_write_reg(mmio, NETLOGIC_GPIO_SWRESET_REG, 1); + for ( ; ; ) + cpu_wait(); +} + +void __init plat_mem_setup(void) +{ + panic_timeout = 5; + _machine_restart = (void (*)(char *))nlm_linux_exit; + _machine_halt = nlm_linux_exit; + pm_power_off = nlm_linux_exit; +} + +const char *get_system_type(void) +{ + return "Netlogic XLR/XLS Series"; +} + +void __init prom_free_prom_memory(void) +{ + /* Nothing yet */ +} + +static void build_arcs_cmdline(int *argv) +{ + int i, remain, len; + char *arg; + + remain = sizeof(arcs_cmdline) - 1; + arcs_cmdline[0] = '\0'; + for (i = 0; argv[i] != 0; i++) { + arg = (char *)(long)argv[i]; + len = strlen(arg); + if (len + 1 > remain) + break; + strcat(arcs_cmdline, arg); + strcat(arcs_cmdline, " "); + remain -= len + 1; + } + + /* Add the default options here */ + if ((strstr(arcs_cmdline, "console=")) == NULL) { + arg = "console=ttyS0,38400 "; + len = strlen(arg); + if (len > remain) + goto fail; + strcat(arcs_cmdline, arg); + remain -= len; + } +#ifdef CONFIG_BLK_DEV_INITRD + if ((strstr(arcs_cmdline, "rdinit=")) == NULL) { + arg = "rdinit=/sbin/init "; + len = strlen(arg); + if (len > remain) + goto fail; + strcat(arcs_cmdline, arg); + remain -= len; + } +#endif + return; +fail: + panic("Cannot add %s, command line too big!", arg); +} + +static void prom_add_memory(void) +{ + struct nlm_boot_mem_map *bootm; + u64 start, size; + u64 pref_backup = 512; /* avoid pref walking beyond end */ + int i; + + bootm = (void *)(long)nlm_prom_info.psb_mem_map; + for (i = 0; i < bootm->nr_map; i++) { + if (bootm->map[i].type != BOOT_MEM_RAM) + continue; + start = bootm->map[i].addr; + size = bootm->map[i].size; + + /* Work around for using bootloader mem */ + if (i == 0 && start == 0 && size == 0x0c000000) + size = 0x0ff00000; + + add_memory_region(start, size - pref_backup, BOOT_MEM_RAM); + } +} + +void __init prom_init(void) +{ + int *argv, *envp; /* passed as 32 bit ptrs */ + struct psb_info *prom_infop; + + /* truncate to 32 bit and sign extend all args */ + argv = (int *)(long)(int)fw_arg1; + envp = (int *)(long)(int)fw_arg2; + prom_infop = (struct psb_info *)(long)(int)fw_arg3; + + nlm_prom_info = *prom_infop; + + nlm_early_serial_setup(); + build_arcs_cmdline(argv); + nlm_common_ebase = read_c0_ebase() & (~((1 << 12) - 1)); + prom_add_memory(); + +#ifdef CONFIG_SMP + nlm_wakeup_secondary_cpus(nlm_prom_info.online_cpu_map); + register_smp_ops(&nlm_smp_ops); +#endif +} diff --git a/arch/mips/netlogic/xlr/smp.c b/arch/mips/netlogic/xlr/smp.c new file mode 100644 index 000000000000..b495a7f1433b --- /dev/null +++ b/arch/mips/netlogic/xlr/smp.c @@ -0,0 +1,225 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 +#include +#include + +#include + +#include +#include + +#include +#include +#include + +void core_send_ipi(int logical_cpu, unsigned int action) +{ + int cpu = cpu_logical_map(logical_cpu); + u32 tid = cpu & 0x3; + u32 pid = (cpu >> 2) & 0x07; + u32 ipi = (tid << 16) | (pid << 20); + + if (action & SMP_CALL_FUNCTION) + ipi |= IRQ_IPI_SMP_FUNCTION; + else if (action & SMP_RESCHEDULE_YOURSELF) + ipi |= IRQ_IPI_SMP_RESCHEDULE; + else + return; + + pic_send_ipi(ipi); +} + +void nlm_send_ipi_single(int cpu, unsigned int action) +{ + core_send_ipi(cpu, action); +} + +void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) +{ + int cpu; + + for_each_cpu(cpu, mask) { + core_send_ipi(cpu, action); + } +} + +/* IRQ_IPI_SMP_FUNCTION Handler */ +void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) +{ + smp_call_function_interrupt(); +} + +/* IRQ_IPI_SMP_RESCHEDULE handler */ +void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc) +{ + set_need_resched(); +} + +void nlm_common_ipi_handler(int irq, struct pt_regs *regs) +{ + if (irq == IRQ_IPI_SMP_FUNCTION) { + smp_call_function_interrupt(); + } else { + /* Announce that we are for reschduling */ + set_need_resched(); + } +} + +/* + * Called before going into mips code, early cpu init + */ +void nlm_early_init_secondary(void) +{ + write_c0_ebase((uint32_t)nlm_common_ebase); + /* TLB partition here later */ +} + +/* + * Code to run on secondary just after probing the CPU + */ +static void __cpuinit nlm_init_secondary(void) +{ + nlm_smp_irq_init(); +} + +void nlm_smp_finish(void) +{ +#ifdef notyet + nlm_common_msgring_cpu_init(); +#endif +} + +void nlm_cpus_done(void) +{ +} + +/* + * Boot all other cpus in the system, initialize them, and bring them into + * the boot function + */ +int nlm_cpu_unblock[NR_CPUS]; +int nlm_cpu_ready[NR_CPUS]; +unsigned long nlm_next_gp; +unsigned long nlm_next_sp; +cpumask_t phys_cpu_present_map; + +void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) +{ + unsigned long gp = (unsigned long)task_thread_info(idle); + unsigned long sp = (unsigned long)__KSTK_TOS(idle); + int cpu = cpu_logical_map(logical_cpu); + + nlm_next_sp = sp; + nlm_next_gp = gp; + + /* barrier */ + __sync(); + nlm_cpu_unblock[cpu] = 1; +} + +void __init nlm_smp_setup(void) +{ + unsigned int boot_cpu; + int num_cpus, i; + + boot_cpu = hard_smp_processor_id(); + cpus_clear(phys_cpu_present_map); + + cpu_set(boot_cpu, phys_cpu_present_map); + __cpu_number_map[boot_cpu] = 0; + __cpu_logical_map[0] = boot_cpu; + cpu_set(0, cpu_possible_map); + + num_cpus = 1; + for (i = 0; i < NR_CPUS; i++) { + if (nlm_cpu_ready[i]) { + cpu_set(i, phys_cpu_present_map); + __cpu_number_map[i] = num_cpus; + __cpu_logical_map[num_cpus] = i; + cpu_set(num_cpus, cpu_possible_map); + ++num_cpus; + } + } + + pr_info("Phys CPU present map: %lx, possible map %lx\n", + (unsigned long)phys_cpu_present_map.bits[0], + (unsigned long)cpu_possible_map.bits[0]); + + pr_info("Detected %i Slave CPU(s)\n", num_cpus); +} + +void nlm_prepare_cpus(unsigned int max_cpus) +{ +} + +struct plat_smp_ops nlm_smp_ops = { + .send_ipi_single = nlm_send_ipi_single, + .send_ipi_mask = nlm_send_ipi_mask, + .init_secondary = nlm_init_secondary, + .smp_finish = nlm_smp_finish, + .cpus_done = nlm_cpus_done, + .boot_secondary = nlm_boot_secondary, + .smp_setup = nlm_smp_setup, + .prepare_cpus = nlm_prepare_cpus, +}; + +unsigned long secondary_entry_point; + +int nlm_wakeup_secondary_cpus(u32 wakeup_mask) +{ + unsigned int tid, pid, ipi, i, boot_cpu; + void *reset_vec; + + secondary_entry_point = (unsigned long)prom_pre_boot_secondary_cpus; + reset_vec = (void *)CKSEG1ADDR(0x1fc00000); + memcpy(reset_vec, nlm_boot_smp_nmi, 0x80); + boot_cpu = hard_smp_processor_id(); + + for (i = 0; i < NR_CPUS; i++) { + if (i == boot_cpu) + continue; + if (wakeup_mask & (1u << i)) { + tid = i & 0x3; + pid = (i >> 2) & 0x7; + ipi = (tid << 16) | (pid << 20) | (1 << 8); + pic_send_ipi(ipi); + } + } + + return 0; +} diff --git a/arch/mips/netlogic/xlr/smpboot.S b/arch/mips/netlogic/xlr/smpboot.S new file mode 100644 index 000000000000..b8e074402c99 --- /dev/null +++ b/arch/mips/netlogic/xlr/smpboot.S @@ -0,0 +1,94 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 +#include + + +/* Don't jump to linux function from Bootloader stack. Change it + * here. Kernel might allocate bootloader memory before all the CPUs are + * brought up (eg: Inode cache region) and we better don't overwrite this + * memory + */ +NESTED(prom_pre_boot_secondary_cpus, 16, sp) + .set mips64 + mfc0 t0, $15, 1 # read ebase + andi t0, 0x1f # t0 has the processor_id() + sll t0, 2 # offset in cpu array + + PTR_LA t1, nlm_cpu_ready # mark CPU ready + PTR_ADDU t1, t0 + li t2, 1 + sw t2, 0(t1) + + PTR_LA t1, nlm_cpu_unblock + PTR_ADDU t1, t0 +1: lw t2, 0(t1) # wait till unblocked + beqz t2, 1b + nop + + PTR_LA t1, nlm_next_sp + PTR_L sp, 0(t1) + PTR_LA t1, nlm_next_gp + PTR_L gp, 0(t1) + + PTR_LA t0, nlm_early_init_secondary + jalr t0 + nop + + PTR_LA t0, smp_bootstrap + jr t0 + nop +END(prom_pre_boot_secondary_cpus) + +NESTED(nlm_boot_smp_nmi, 0, sp) + .set push + .set noat + .set mips64 + .set noreorder + + /* Clear the NMI and BEV bits */ + MFC0 k0, CP0_STATUS + li k1, 0xffb7ffff + and k0, k0, k1 + MTC0 k0, CP0_STATUS + + PTR_LA k1, secondary_entry_point + PTR_L k0, 0(k1) + jr k0 + nop + .set pop +END(nlm_boot_smp_nmi) diff --git a/arch/mips/netlogic/xlr/time.c b/arch/mips/netlogic/xlr/time.c new file mode 100644 index 000000000000..0d81b262593c --- /dev/null +++ b/arch/mips/netlogic/xlr/time.c @@ -0,0 +1,51 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 +#include + +unsigned int __cpuinit get_c0_compare_int(void) +{ + return IRQ_TIMER; +} + +void __init plat_time_init(void) +{ + mips_hpt_frequency = nlm_prom_info.cpu_frequency; + pr_info("MIPS counter frequency [%ld]\n", + (unsigned long)mips_hpt_frequency); +} diff --git a/arch/mips/netlogic/xlr/xlr_console.c b/arch/mips/netlogic/xlr/xlr_console.c new file mode 100644 index 000000000000..759df0692201 --- /dev/null +++ b/arch/mips/netlogic/xlr/xlr_console.c @@ -0,0 +1,46 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 + +void prom_putchar(char c) +{ + nlm_reg_t *mmio; + + mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET); + while (netlogic_read_reg(mmio, 0x5) == 0) + ; + netlogic_write_reg(mmio, 0x0, c); +} diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index c9209ca6c8e7..4df879937446 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o +obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o @@ -55,6 +56,7 @@ obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o obj-$(CONFIG_MIKROTIK_RB532) += pci-rc32434.o ops-rc32434.o fixup-rc32434.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += pci-octeon.o pcie-octeon.o +obj-$(CONFIG_NLM_XLR) += pci-xlr.o ifdef CONFIG_PCI_MSI obj-$(CONFIG_CPU_CAVIUM_OCTEON) += msi-octeon.o diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c new file mode 100644 index 000000000000..1f2afb55cc71 --- /dev/null +++ b/arch/mips/pci/ops-lantiq.c @@ -0,0 +1,116 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pci-lantiq.h" + +#define LTQ_PCI_CFG_BUSNUM_SHF 16 +#define LTQ_PCI_CFG_DEVNUM_SHF 11 +#define LTQ_PCI_CFG_FUNNUM_SHF 8 + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus, + unsigned int devfn, unsigned int where, u32 *data) +{ + unsigned long cfg_base; + unsigned long flags; + u32 temp; + + /* we support slot from 0 to 15 dev_fn & 0x68 (AD29) is the + SoC itself */ + if ((bus->number != 0) || ((devfn & 0xf8) > 0x78) + || ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68)) + return 1; + + spin_lock_irqsave(&ebu_lock, flags); + + cfg_base = (unsigned long) ltq_pci_mapped_cfg; + cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn << + LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3); + + /* Perform access */ + if (access_type == PCI_ACCESS_WRITE) { + ltq_w32(swab32(*data), ((u32 *)cfg_base)); + } else { + *data = ltq_r32(((u32 *)(cfg_base))); + *data = swab32(*data); + } + wmb(); + + /* clean possible Master abort */ + cfg_base = (unsigned long) ltq_pci_mapped_cfg; + cfg_base |= (0x0 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; + temp = ltq_r32(((u32 *)(cfg_base))); + temp = swab32(temp); + cfg_base = (unsigned long) ltq_pci_mapped_cfg; + cfg_base |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; + ltq_w32(temp, ((u32 *)cfg_base)); + + spin_unlock_irqrestore(&ebu_lock, flags); + + if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ)) + return 1; + + return 0; +} + +int ltq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + u32 data = 0; + + if (ltq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 1) + *val = (data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (data >> ((where & 3) << 3)) & 0xffff; + else + *val = data; + + return PCIBIOS_SUCCESSFUL; +} + +int ltq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + u32 data = 0; + + if (size == 4) { + data = val; + } else { + if (ltq_pci_config_access(PCI_ACCESS_READ, bus, + devfn, where, &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 1) + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + else if (size == 2) + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + } + + if (ltq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; +} diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c new file mode 100644 index 000000000000..603d7493e966 --- /dev/null +++ b/arch/mips/pci/pci-lantiq.c @@ -0,0 +1,297 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "pci-lantiq.h" + +#define LTQ_PCI_CFG_BASE 0x17000000 +#define LTQ_PCI_CFG_SIZE 0x00008000 +#define LTQ_PCI_MEM_BASE 0x18000000 +#define LTQ_PCI_MEM_SIZE 0x02000000 +#define LTQ_PCI_IO_BASE 0x1AE00000 +#define LTQ_PCI_IO_SIZE 0x00200000 + +#define PCI_CR_FCI_ADDR_MAP0 0x00C0 +#define PCI_CR_FCI_ADDR_MAP1 0x00C4 +#define PCI_CR_FCI_ADDR_MAP2 0x00C8 +#define PCI_CR_FCI_ADDR_MAP3 0x00CC +#define PCI_CR_FCI_ADDR_MAP4 0x00D0 +#define PCI_CR_FCI_ADDR_MAP5 0x00D4 +#define PCI_CR_FCI_ADDR_MAP6 0x00D8 +#define PCI_CR_FCI_ADDR_MAP7 0x00DC +#define PCI_CR_CLK_CTRL 0x0000 +#define PCI_CR_PCI_MOD 0x0030 +#define PCI_CR_PC_ARB 0x0080 +#define PCI_CR_FCI_ADDR_MAP11hg 0x00E4 +#define PCI_CR_BAR11MASK 0x0044 +#define PCI_CR_BAR12MASK 0x0048 +#define PCI_CR_BAR13MASK 0x004C +#define PCI_CS_BASE_ADDR1 0x0010 +#define PCI_CR_PCI_ADDR_MAP11 0x0064 +#define PCI_CR_FCI_BURST_LENGTH 0x00E8 +#define PCI_CR_PCI_EOI 0x002C +#define PCI_CS_STS_CMD 0x0004 + +#define PCI_MASTER0_REQ_MASK_2BITS 8 +#define PCI_MASTER1_REQ_MASK_2BITS 10 +#define PCI_MASTER2_REQ_MASK_2BITS 12 +#define INTERNAL_ARB_ENABLE_BIT 0 + +#define LTQ_CGU_IFCCR 0x0018 +#define LTQ_CGU_PCICR 0x0034 + +#define ltq_pci_w32(x, y) ltq_w32((x), ltq_pci_membase + (y)) +#define ltq_pci_r32(x) ltq_r32(ltq_pci_membase + (x)) + +#define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_mapped_cfg + (y)) +#define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_mapped_cfg + (x)) + +struct ltq_pci_gpio_map { + int pin; + int alt0; + int alt1; + int dir; + char *name; +}; + +/* the pci core can make use of the following gpios */ +static struct ltq_pci_gpio_map ltq_pci_gpio_map[] = { + { 0, 1, 0, 0, "pci-exin0" }, + { 1, 1, 0, 0, "pci-exin1" }, + { 2, 1, 0, 0, "pci-exin2" }, + { 39, 1, 0, 0, "pci-exin3" }, + { 10, 1, 0, 0, "pci-exin4" }, + { 9, 1, 0, 0, "pci-exin5" }, + { 30, 1, 0, 1, "pci-gnt1" }, + { 23, 1, 0, 1, "pci-gnt2" }, + { 19, 1, 0, 1, "pci-gnt3" }, + { 38, 1, 0, 1, "pci-gnt4" }, + { 29, 1, 0, 0, "pci-req1" }, + { 31, 1, 0, 0, "pci-req2" }, + { 3, 1, 0, 0, "pci-req3" }, + { 37, 1, 0, 0, "pci-req4" }, +}; + +__iomem void *ltq_pci_mapped_cfg; +static __iomem void *ltq_pci_membase; + +int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL; + +/* Since the PCI REQ pins can be reused for other functionality, make it + possible to exclude those from interpretation by the PCI controller */ +static int ltq_pci_req_mask = 0xf; + +static int *ltq_pci_irq_map; + +struct pci_ops ltq_pci_ops = { + .read = ltq_pci_read_config_dword, + .write = ltq_pci_write_config_dword +}; + +static struct resource pci_io_resource = { + .name = "pci io space", + .start = LTQ_PCI_IO_BASE, + .end = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1, + .flags = IORESOURCE_IO +}; + +static struct resource pci_mem_resource = { + .name = "pci memory space", + .start = LTQ_PCI_MEM_BASE, + .end = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM +}; + +static struct pci_controller ltq_pci_controller = { + .pci_ops = <q_pci_ops, + .mem_resource = &pci_mem_resource, + .mem_offset = 0x00000000UL, + .io_resource = &pci_io_resource, + .io_offset = 0x00000000UL, +}; + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + if (ltqpci_plat_dev_init) + return ltqpci_plat_dev_init(dev); + + return 0; +} + +static u32 ltq_calc_bar11mask(void) +{ + u32 mem, bar11mask; + + /* BAR11MASK value depends on available memory on system. */ + mem = num_physpages * PAGE_SIZE; + bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) - 1)) - 1)) | 8; + + return bar11mask; +} + +static void ltq_pci_setup_gpio(int gpio) +{ + int i; + for (i = 0; i < ARRAY_SIZE(ltq_pci_gpio_map); i++) { + if (gpio & (1 << i)) { + ltq_gpio_request(ltq_pci_gpio_map[i].pin, + ltq_pci_gpio_map[i].alt0, + ltq_pci_gpio_map[i].alt1, + ltq_pci_gpio_map[i].dir, + ltq_pci_gpio_map[i].name); + } + } + ltq_gpio_request(21, 0, 0, 1, "pci-reset"); + ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; +} + +static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) +{ + u32 temp_buffer; + + /* set clock to 33Mhz */ + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR); + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR); + + /* external or internal clock ? */ + if (conf->clock) { + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~(1 << 16), + LTQ_CGU_IFCCR); + ltq_cgu_w32((1 << 30), LTQ_CGU_PCICR); + } else { + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | (1 << 16), + LTQ_CGU_IFCCR); + ltq_cgu_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR); + } + + /* setup pci clock and gpis used by pci */ + ltq_pci_setup_gpio(conf->gpio); + + /* enable auto-switching between PCI and EBU */ + ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); + + /* busy, i.e. configuration is not done, PCI access has to be retried */ + ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) & ~(1 << 24), PCI_CR_PCI_MOD); + wmb(); + /* BUS Master/IO/MEM access */ + ltq_pci_cfg_w32(ltq_pci_cfg_r32(PCI_CS_STS_CMD) | 7, PCI_CS_STS_CMD); + + /* enable external 2 PCI masters */ + temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB); + temp_buffer &= (~(ltq_pci_req_mask << 16)); + /* enable internal arbiter */ + temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT); + /* enable internal PCI master reqest */ + temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS)); + + /* enable EBU request */ + temp_buffer &= (~(3 << PCI_MASTER1_REQ_MASK_2BITS)); + + /* enable all external masters request */ + temp_buffer &= (~(3 << PCI_MASTER2_REQ_MASK_2BITS)); + ltq_pci_w32(temp_buffer, PCI_CR_PC_ARB); + wmb(); + + /* setup BAR memory regions */ + ltq_pci_w32(0x18000000, PCI_CR_FCI_ADDR_MAP0); + ltq_pci_w32(0x18400000, PCI_CR_FCI_ADDR_MAP1); + ltq_pci_w32(0x18800000, PCI_CR_FCI_ADDR_MAP2); + ltq_pci_w32(0x18c00000, PCI_CR_FCI_ADDR_MAP3); + ltq_pci_w32(0x19000000, PCI_CR_FCI_ADDR_MAP4); + ltq_pci_w32(0x19400000, PCI_CR_FCI_ADDR_MAP5); + ltq_pci_w32(0x19800000, PCI_CR_FCI_ADDR_MAP6); + ltq_pci_w32(0x19c00000, PCI_CR_FCI_ADDR_MAP7); + ltq_pci_w32(0x1ae00000, PCI_CR_FCI_ADDR_MAP11hg); + ltq_pci_w32(ltq_calc_bar11mask(), PCI_CR_BAR11MASK); + ltq_pci_w32(0, PCI_CR_PCI_ADDR_MAP11); + ltq_pci_w32(0, PCI_CS_BASE_ADDR1); + /* both TX and RX endian swap are enabled */ + ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_EOI) | 3, PCI_CR_PCI_EOI); + wmb(); + ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR12MASK) | 0x80000000, + PCI_CR_BAR12MASK); + ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR13MASK) | 0x80000000, + PCI_CR_BAR13MASK); + /*use 8 dw burst length */ + ltq_pci_w32(0x303, PCI_CR_FCI_BURST_LENGTH); + ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) | (1 << 24), PCI_CR_PCI_MOD); + wmb(); + + /* setup irq line */ + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_CON) | 0xc, LTQ_EBU_PCC_CON); + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN); + + /* toggle reset pin */ + __gpio_set_value(21, 0); + wmb(); + mdelay(1); + __gpio_set_value(21, 1); + return 0; +} + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + if (ltq_pci_irq_map[slot]) + return ltq_pci_irq_map[slot]; + printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n", + slot); + + return 0; +} + +static int __devinit ltq_pci_probe(struct platform_device *pdev) +{ + struct ltq_pci_data *ltq_pci_data = + (struct ltq_pci_data *) pdev->dev.platform_data; + pci_probe_only = 0; + ltq_pci_irq_map = ltq_pci_data->irq; + ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE); + ltq_pci_mapped_cfg = + ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE); + ltq_pci_controller.io_map_base = + (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1); + ltq_pci_startup(ltq_pci_data); + register_pci_controller(<q_pci_controller); + + return 0; +} + +static struct platform_driver +ltq_pci_driver = { + .probe = ltq_pci_probe, + .driver = { + .name = "ltq_pci", + .owner = THIS_MODULE, + }, +}; + +int __init pcibios_init(void) +{ + int ret = platform_driver_register(<q_pci_driver); + if (ret) + printk(KERN_INFO "ltq_pci: Error registering platfom driver!"); + return ret; +} + +arch_initcall(pcibios_init); diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h new file mode 100644 index 000000000000..66bf6cd6be3c --- /dev/null +++ b/arch/mips/pci/pci-lantiq.h @@ -0,0 +1,18 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef _LTQ_PCI_H__ +#define _LTQ_PCI_H__ + +extern __iomem void *ltq_pci_mapped_cfg; +extern int ltq_pci_read_config_dword(struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 *val); +extern int ltq_pci_write_config_dword(struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 val); + +#endif diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c new file mode 100644 index 000000000000..38fece16c435 --- /dev/null +++ b/arch/mips/pci/pci-xlr.c @@ -0,0 +1,214 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC 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 +#include +#include +#include + +#include + +#include +#include +#include +#include + +static void *pci_config_base; + +#define pci_cfg_addr(bus, devfn, off) (((bus) << 16) | ((devfn) << 8) | (off)) + +/* PCI ops */ +static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn, + int where) +{ + u32 data; + u32 *cfgaddr; + + cfgaddr = (u32 *)(pci_config_base + + pci_cfg_addr(bus->number, devfn, where & ~3)); + data = *cfgaddr; + return cpu_to_le32(data); +} + +static inline void pci_cfg_write_32bit(struct pci_bus *bus, unsigned int devfn, + int where, u32 data) +{ + u32 *cfgaddr; + + cfgaddr = (u32 *)(pci_config_base + + pci_cfg_addr(bus->number, devfn, where & ~3)); + *cfgaddr = cpu_to_le32(data); +} + +static int nlm_pcibios_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + u32 data; + + if ((size == 2) && (where & 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (where & 3)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + data = pci_cfg_read_32bit(bus, devfn, where); + + if (size == 1) + *val = (data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (data >> ((where & 3) << 3)) & 0xffff; + else + *val = data; + + return PCIBIOS_SUCCESSFUL; +} + + +static int nlm_pcibios_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + u32 data; + + if ((size == 2) && (where & 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (where & 3)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + data = pci_cfg_read_32bit(bus, devfn, where); + + if (size == 1) + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + else if (size == 2) + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + else + data = val; + + pci_cfg_write_32bit(bus, devfn, where, data); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops nlm_pci_ops = { + .read = nlm_pcibios_read, + .write = nlm_pcibios_write +}; + +static struct resource nlm_pci_mem_resource = { + .name = "XLR PCI MEM", + .start = 0xd0000000UL, /* 256MB PCI mem @ 0xd000_0000 */ + .end = 0xdfffffffUL, + .flags = IORESOURCE_MEM, +}; + +static struct resource nlm_pci_io_resource = { + .name = "XLR IO MEM", + .start = 0x10000000UL, /* 16MB PCI IO @ 0x1000_0000 */ + .end = 0x100fffffUL, + .flags = IORESOURCE_IO, +}; + +struct pci_controller nlm_pci_controller = { + .index = 0, + .pci_ops = &nlm_pci_ops, + .mem_resource = &nlm_pci_mem_resource, + .mem_offset = 0x00000000UL, + .io_resource = &nlm_pci_io_resource, + .io_offset = 0x00000000UL, +}; + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + if (!nlm_chip_is_xls()) + return PIC_PCIX_IRQ; /* for XLR just one IRQ*/ + + /* + * For XLS PCIe, there is an IRQ per Link, find out which + * link the device is on to assign interrupts + */ + if (dev->bus->self == NULL) + return 0; + + switch (dev->bus->self->devfn) { + case 0x0: + return PIC_PCIE_LINK0_IRQ; + case 0x8: + return PIC_PCIE_LINK1_IRQ; + case 0x10: + if (nlm_chip_is_xls_b()) + return PIC_PCIE_XLSB0_LINK2_IRQ; + else + return PIC_PCIE_LINK2_IRQ; + case 0x18: + if (nlm_chip_is_xls_b()) + return PIC_PCIE_XLSB0_LINK3_IRQ; + else + return PIC_PCIE_LINK3_IRQ; + } + WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn); + return 0; +} + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} + +static int __init pcibios_init(void) +{ + /* PSB assigns PCI resources */ + pci_probe_only = 1; + pci_config_base = ioremap(DEFAULT_PCI_CONFIG_BASE, 16 << 20); + + /* Extend IO port for memory mapped io */ + ioport_resource.start = 0; + ioport_resource.end = ~0; + + set_io_port_base(CKSEG1); + nlm_pci_controller.io_map_base = CKSEG1; + + pr_info("Registering XLR/XLS PCIX/PCIE Controller.\n"); + register_pci_controller(&nlm_pci_controller); + + return 0; +} + +arch_initcall(pcibios_init); + +struct pci_fixup pcibios_fixups[] = { + {0} +}; diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c index f9b9dcdfa9dd..98fd0099d964 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c @@ -97,7 +97,7 @@ static int msp_per_irq_set_affinity(struct irq_data *d, static struct irq_chip msp_per_irq_controller = { .name = "MSP_PER", - .irq_enable = unmask_per_irq. + .irq_enable = unmask_per_irq, .irq_disable = mask_per_irq, .irq_ack = msp_per_irq_ack, #ifdef CONFIG_SMP diff --git a/arch/mips/pmc-sierra/yosemite/smp.c b/arch/mips/pmc-sierra/yosemite/smp.c index efc9e889b349..2608752898c0 100644 --- a/arch/mips/pmc-sierra/yosemite/smp.c +++ b/arch/mips/pmc-sierra/yosemite/smp.c @@ -55,6 +55,8 @@ void titan_mailbox_irq(void) if (status & 0x2) smp_call_function_interrupt(); + if (status & 0x4) + scheduler_ipi(); break; case 1: @@ -63,6 +65,8 @@ void titan_mailbox_irq(void) if (status & 0x2) smp_call_function_interrupt(); + if (status & 0x4) + scheduler_ipi(); break; } } diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S index dbb5c7b4b70f..f8a751c03282 100644 --- a/arch/mips/power/hibernate.S +++ b/arch/mips/power/hibernate.S @@ -35,7 +35,7 @@ LEAF(swsusp_arch_resume) 0: PTR_L t1, PBE_ADDRESS(t0) /* source */ PTR_L t2, PBE_ORIG_ADDRESS(t0) /* destination */ - PTR_ADDIU t3, t1, PAGE_SIZE + PTR_ADDU t3, t1, PAGE_SIZE 1: REG_L t8, (t1) REG_S t8, (t2) diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c index 37de05d595e7..6c47dfeb7be3 100644 --- a/arch/mips/rb532/gpio.c +++ b/arch/mips/rb532/gpio.c @@ -185,7 +185,7 @@ int __init rb532_gpio_init(void) struct resource *r; r = rb532_gpio_reg0_res; - rb532_gpio_chip->regbase = ioremap_nocache(r->start, r->end - r->start); + rb532_gpio_chip->regbase = ioremap_nocache(r->start, resource_size(r)); if (!rb532_gpio_chip->regbase) { printk(KERN_ERR "rb532: cannot remap GPIO register 0\n"); diff --git a/arch/mips/sgi-ip22/ip22-platform.c b/arch/mips/sgi-ip22/ip22-platform.c index deddbf0ebe5c..698904daf901 100644 --- a/arch/mips/sgi-ip22/ip22-platform.c +++ b/arch/mips/sgi-ip22/ip22-platform.c @@ -132,7 +132,7 @@ static struct platform_device eth1_device = { */ static int __init sgiseeq_devinit(void) { - unsigned int tmp; + unsigned int pbdma __maybe_unused; int res, i; eth0_pd.hpc = hpc3c0; @@ -151,7 +151,7 @@ static int __init sgiseeq_devinit(void) /* Second HPC is missing? */ if (ip22_is_fullhouse() || - get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1])) + get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) return 0; sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 | SGIMC_GIOPAR_EXP164 | diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index 603fc91c1030..1a94c9894188 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c @@ -32,7 +32,7 @@ static unsigned long dosample(void) { u32 ct0, ct1; - u8 msb, lsb; + u8 msb; /* Start the counter. */ sgint->tcword = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | @@ -46,7 +46,7 @@ static unsigned long dosample(void) /* Latch and spin until top byte of counter2 is zero */ do { writeb(SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT, &sgint->tcword); - lsb = readb(&sgint->tcnt2); + (void) readb(&sgint->tcnt2); msb = readb(&sgint->tcnt2); ct1 = read_c0_count(); } while (msb); diff --git a/arch/mips/sgi-ip27/ip27-hubio.c b/arch/mips/sgi-ip27/ip27-hubio.c index a1fa4abb3f6a..cd0d5b06cd83 100644 --- a/arch/mips/sgi-ip27/ip27-hubio.c +++ b/arch/mips/sgi-ip27/ip27-hubio.c @@ -29,7 +29,6 @@ unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget, unsigned long xtalk_addr, size_t size) { nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); - volatile hubreg_t junk; unsigned i; /* use small-window mapping if possible */ @@ -64,7 +63,7 @@ unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget, * after we write it. */ IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr); - junk = HUB_L(IIO_ITTE_GET(nasid, i)); + (void) HUB_L(IIO_ITTE_GET(nasid, i)); return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE); } diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index 0a04603d577c..b18b04e48577 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -147,8 +147,10 @@ static void ip27_do_irq_mask0(void) #ifdef CONFIG_SMP if (pend0 & (1UL << CPU_RESCHED_A_IRQ)) { LOCAL_HUB_CLR_INTR(CPU_RESCHED_A_IRQ); + scheduler_ipi(); } else if (pend0 & (1UL << CPU_RESCHED_B_IRQ)) { LOCAL_HUB_CLR_INTR(CPU_RESCHED_B_IRQ); + scheduler_ipi(); } else if (pend0 & (1UL << CPU_CALL_A_IRQ)) { LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ); smp_call_function_interrupt(); diff --git a/arch/mips/sgi-ip27/ip27-klnuma.c b/arch/mips/sgi-ip27/ip27-klnuma.c index c3d30a88daf3..1d1919a44e88 100644 --- a/arch/mips/sgi-ip27/ip27-klnuma.c +++ b/arch/mips/sgi-ip27/ip27-klnuma.c @@ -54,11 +54,8 @@ void __init setup_replication_mask(void) static __init void set_ktext_source(nasid_t client_nasid, nasid_t server_nasid) { - cnodeid_t client_cnode; kern_vars_t *kvp; - client_cnode = NASID_TO_COMPACT_NODEID(client_nasid); - kvp = &hub_data(client_nasid)->kern_vars; KERN_VARS_ADDR(client_nasid) = (unsigned long)kvp; diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index a152538d3c97..ef74f3267f91 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -66,18 +66,7 @@ static int rt_next_event(unsigned long delta, struct clock_event_device *evt) static void rt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - /* The only mode supported */ - break; - - case CLOCK_EVT_MODE_PERIODIC: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - /* Nothing to do */ - break; - } + /* Nothing to do ... */ } int rt_timer_irq; @@ -174,8 +163,7 @@ static void __init hub_rt_clocksource_init(void) { struct clocksource *cs = &hub_rt_clocksource; - clocksource_set_clock(cs, CYCLES_PER_SEC); - clocksource_register(cs); + clocksource_register_hz(cs, CYCLES_PER_SEC); } void __init plat_time_init(void) diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c index 47b347c992ea..d667875be564 100644 --- a/arch/mips/sibyte/bcm1480/smp.c +++ b/arch/mips/sibyte/bcm1480/smp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -189,10 +190,8 @@ void bcm1480_mailbox_interrupt(void) /* Clear the mailbox to clear the interrupt */ __raw_writeq(((u64)action)<<48, mailbox_0_clear_regs[cpu]); - /* - * Nothing to do for SMP_RESCHEDULE_YOURSELF; returning from the - * interrupt will do the reschedule for us - */ + if (action & SMP_RESCHEDULE_YOURSELF) + scheduler_ipi(); if (action & SMP_CALL_FUNCTION) smp_call_function_interrupt(); diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c index c00a5cb1128d..38e7f6bd7922 100644 --- a/arch/mips/sibyte/sb1250/smp.c +++ b/arch/mips/sibyte/sb1250/smp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -177,10 +178,8 @@ void sb1250_mailbox_interrupt(void) /* Clear the mailbox to clear the interrupt */ ____raw_writeq(((u64)action) << 48, mailbox_clear_regs[cpu]); - /* - * Nothing to do for SMP_RESCHEDULE_YOURSELF; returning from the - * interrupt will do the reschedule for us - */ + if (action & SMP_RESCHEDULE_YOURSELF) + scheduler_ipi(); if (action & SMP_CALL_FUNCTION) smp_call_function_interrupt(); diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c index c76151b56568..0904d4d30cb3 100644 --- a/arch/mips/sni/time.c +++ b/arch/mips/sni/time.c @@ -95,7 +95,7 @@ static void __init sni_a20r_timer_setup(void) static __init unsigned long dosample(void) { u32 ct0, ct1; - volatile u8 msb, lsb; + volatile u8 msb; /* Start the counter. */ outb_p(0x34, 0x43); @@ -108,7 +108,7 @@ static __init unsigned long dosample(void) /* Latch and spin until top byte of counter0 is zero */ do { outb(0x00, 0x43); - lsb = inb(0x40); + (void) inb(0x40); msb = inb(0x40); ct1 = read_c0_count(); } while (msb); diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c index 3dc19f482959..e9f95dcde379 100644 --- a/arch/mips/txx9/generic/setup_tx4939.c +++ b/arch/mips/txx9/generic/setup_tx4939.c @@ -318,19 +318,15 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask) } #if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE) -static int tx4939_get_eth_speed(struct net_device *dev) +static u32 tx4939_get_eth_speed(struct net_device *dev) { - struct ethtool_cmd cmd = { ETHTOOL_GSET }; - int speed = 100; /* default 100Mbps */ - int err; - if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings) - return speed; - err = dev->ethtool_ops->get_settings(dev, &cmd); - if (err < 0) - return speed; - speed = cmd.speed == SPEED_100 ? 100 : 10; - return speed; + struct ethtool_cmd cmd; + if (dev_ethtool_get_settings(dev, &cmd)) + return 100; /* default 100Mbps */ + + return ethtool_cmd_speed(&cmd); } + static int tx4939_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) @@ -343,8 +339,7 @@ static int tx4939_netdev_event(struct notifier_block *this, else if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(1)) bit = TX4939_PCFG_SPEED1; if (bit) { - int speed = tx4939_get_eth_speed(dev); - if (speed == 100) + if (tx4939_get_eth_speed(dev) == 100) txx9_set64(&tx4939_ccfgptr->pcfg, bit); else txx9_clear64(&tx4939_ccfgptr->pcfg, bit); diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c index 226c826a2194..83fb27912231 100644 --- a/arch/mn10300/kernel/smp.c +++ b/arch/mn10300/kernel/smp.c @@ -494,14 +494,11 @@ void smp_send_stop(void) * @irq: The interrupt number. * @dev_id: The device ID. * - * We need do nothing here, since the scheduling will be effected on our way - * back through entry.S. - * * Returns IRQ_HANDLED to indicate we handled the interrupt successfully. */ static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id) { - /* do nothing */ + scheduler_ipi(); return IRQ_HANDLED; } diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index d18328b3f938..da601dd34c05 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -3,6 +3,7 @@ #include #include +#include /* The usual comment is "Caches aren't brain-dead on the ". * Unfortunately, that doesn't apply to PA-RISC. */ @@ -112,8 +113,10 @@ void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr); static inline void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr) { - if (PageAnon(page)) + if (PageAnon(page)) { + flush_tlb_page(vma, vmaddr); flush_dcache_page_asm(page_to_phys(page), vmaddr); + } } #ifdef CONFIG_DEBUG_RODATA diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index 5d7b8ce9fdf3..22dadeb58695 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -177,7 +177,10 @@ struct vm_area_struct; #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED) #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) -#define _PAGE_KERNEL (_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED) +#define _PAGE_KERNEL_RO (_PAGE_PRESENT | _PAGE_READ | _PAGE_DIRTY | _PAGE_ACCESSED) +#define _PAGE_KERNEL_EXEC (_PAGE_KERNEL_RO | _PAGE_EXEC) +#define _PAGE_KERNEL_RWX (_PAGE_KERNEL_EXEC | _PAGE_WRITE) +#define _PAGE_KERNEL (_PAGE_KERNEL_RO | _PAGE_WRITE) /* The pgd/pmd contains a ptr (in phys addr space); since all pgds/pmds * are page-aligned, we don't care about the PAGE_OFFSET bits, except @@ -208,7 +211,9 @@ struct vm_area_struct; #define PAGE_COPY PAGE_EXECREAD #define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC |_PAGE_ACCESSED) #define PAGE_KERNEL __pgprot(_PAGE_KERNEL) -#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE) +#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL_EXEC) +#define PAGE_KERNEL_RWX __pgprot(_PAGE_KERNEL_RWX) +#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL_RO) #define PAGE_KERNEL_UNC __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE) #define PAGE_GATEWAY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_GATEWAY| _PAGE_READ) diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h index 3eb82c2a5ec3..9cbc2c3bf630 100644 --- a/arch/parisc/include/asm/unistd.h +++ b/arch/parisc/include/asm/unistd.h @@ -814,8 +814,14 @@ #define __NR_recvmmsg (__NR_Linux + 319) #define __NR_accept4 (__NR_Linux + 320) #define __NR_prlimit64 (__NR_Linux + 321) +#define __NR_fanotify_init (__NR_Linux + 322) +#define __NR_fanotify_mark (__NR_Linux + 323) +#define __NR_clock_adjtime (__NR_Linux + 324) +#define __NR_name_to_handle_at (__NR_Linux + 325) +#define __NR_open_by_handle_at (__NR_Linux + 326) +#define __NR_syncfs (__NR_Linux + 327) -#define __NR_Linux_syscalls (__NR_prlimit64 + 1) +#define __NR_Linux_syscalls (__NR_syncfs + 1) #define __IGNORE_select /* newselect */ diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 3f11331c2775..83335f3da5fc 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -304,10 +304,20 @@ void flush_dcache_page(struct page *page) offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; addr = mpnt->vm_start + offset; + /* The TLB is the engine of coherence on parisc: The + * CPU is entitled to speculate any page with a TLB + * mapping, so here we kill the mapping then flush the + * page along a special flush only alias mapping. + * This guarantees that the page is no-longer in the + * cache for any process and nor may it be + * speculatively read in (until the user or kernel + * specifically accesses it, of course) */ + + flush_tlb_page(mpnt, addr); if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) { __flush_cache_page(mpnt, addr, page_to_phys(page)); if (old_addr) - printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? mpnt->vm_file->f_path.dentry->d_name.name : "(null)"); + printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? (char *)mpnt->vm_file->f_path.dentry->d_name.name : "(null)"); old_addr = addr; } } @@ -499,6 +509,7 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long { BUG_ON(!vma->vm_mm->context); + flush_tlb_page(vma, vmaddr); __flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn))); } diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index ead8d2a1034c..6f0594439143 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -692,6 +692,9 @@ ENTRY(fault_vector_11) END(fault_vector_11) #endif + /* Fault vector is separately protected and *must* be on its own page */ + .align PAGE_SIZE +ENTRY(end_fault_vector) .import handle_interruption,code .import do_cpu_irq_mask,code diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S index 145c5e4caaa0..37aabd772fbb 100644 --- a/arch/parisc/kernel/head.S +++ b/arch/parisc/kernel/head.S @@ -106,8 +106,9 @@ $bss_loop: #endif - /* Now initialize the PTEs themselves */ - ldo 0+_PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */ + /* Now initialize the PTEs themselves. We use RWX for + * everything ... it will get remapped correctly later */ + ldo 0+_PAGE_KERNEL_RWX(%r0),%r3 /* Hardwired 0 phys addr start */ ldi (1<<(KERNEL_INITIAL_ORDER-PAGE_SHIFT)),%r11 /* PFN count */ load32 PA(pg0),%r1 diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index 6e81bb596e5b..cedbbb8b18d9 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -61,8 +61,10 @@ #include #include #include +#include #include +#include #include #if 0 @@ -214,7 +216,13 @@ void *module_alloc(unsigned long size) { if (size == 0) return NULL; - return vmalloc(size); + /* using RWX means less protection for modules, but it's + * easier than trying to map the text, data, init_text and + * init_data correctly */ + return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END, + GFP_KERNEL | __GFP_HIGHMEM, + PAGE_KERNEL_RWX, -1, + __builtin_return_address(0)); } #ifndef CONFIG_64BIT diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index a85823668cba..93ff3d90edd1 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -817,10 +817,7 @@ ENTRY(purge_kernel_dcache_page) .procend ENDPROC(purge_kernel_dcache_page) - - .export flush_user_dcache_range_asm - -flush_user_dcache_range_asm: +ENTRY(flush_user_dcache_range_asm) .proc .callinfo NO_CALLS .entry @@ -839,6 +836,7 @@ flush_user_dcache_range_asm: .exit .procend +ENDPROC(flush_user_dcache_range_asm) ENTRY(flush_kernel_dcache_range_asm) .proc diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 69d63d354ef0..828305f19cff 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -155,10 +155,7 @@ ipi_interrupt(int irq, void *dev_id) case IPI_RESCHEDULE: smp_debug(100, KERN_DEBUG "CPU%d IPI_RESCHEDULE\n", this_cpu); - /* - * Reschedule callback. Everything to be - * done is done by the interrupt return path. - */ + scheduler_ipi(); break; case IPI_CALL_FUNC: diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index 88a0ad14a9c9..dc9a62462323 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -228,3 +228,11 @@ asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo, return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo, ((loff_t)lenhi << 32) | lenlo); } + +asmlinkage long compat_sys_fanotify_mark(int fan_fd, int flags, u32 mask_hi, + u32 mask_lo, int fd, + const char __user *pathname) +{ + return sys_fanotify_mark(fan_fd, flags, ((u64)mask_hi << 32) | mask_lo, + fd, pathname); +} diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 4be85ee10b85..a5b02ce4d41e 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -420,6 +420,12 @@ ENTRY_COMP(recvmmsg) ENTRY_SAME(accept4) /* 320 */ ENTRY_SAME(prlimit64) + ENTRY_SAME(fanotify_init) + ENTRY_COMP(fanotify_mark) + ENTRY_COMP(clock_adjtime) + ENTRY_SAME(name_to_handle_at) /* 325 */ + ENTRY_COMP(open_by_handle_at) + ENTRY_SAME(syncfs) /* Nothing yet */ diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 8f1e4efd143e..e1a55849bfa7 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -69,6 +69,9 @@ SECTIONS /* End of text section */ _etext = .; + /* Start of data section */ + _sdata = .; + RODATA /* writeable */ @@ -134,6 +137,7 @@ SECTIONS . = ALIGN(16384); __init_begin = .; INIT_TEXT_SECTION(16384) + . = ALIGN(PAGE_SIZE); INIT_DATA_SECTION(16) /* we have to discard exit text and such at runtime, not link time */ .exit.text : diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index b7ed8d7a9b33..5fa1e273006e 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -266,8 +266,10 @@ static void __init setup_bootmem(void) } memset(pfnnid_map, 0xff, sizeof(pfnnid_map)); - for (i = 0; i < npmem_ranges; i++) + for (i = 0; i < npmem_ranges; i++) { + node_set_state(i, N_NORMAL_MEMORY); node_set_online(i); + } #endif /* @@ -369,24 +371,158 @@ static void __init setup_bootmem(void) request_resource(&sysram_resources[0], &pdcdata_resource); } +static void __init map_pages(unsigned long start_vaddr, + unsigned long start_paddr, unsigned long size, + pgprot_t pgprot, int force) +{ + pgd_t *pg_dir; + pmd_t *pmd; + pte_t *pg_table; + unsigned long end_paddr; + unsigned long start_pmd; + unsigned long start_pte; + unsigned long tmp1; + unsigned long tmp2; + unsigned long address; + unsigned long vaddr; + unsigned long ro_start; + unsigned long ro_end; + unsigned long fv_addr; + unsigned long gw_addr; + extern const unsigned long fault_vector_20; + extern void * const linux_gateway_page; + + ro_start = __pa((unsigned long)_text); + ro_end = __pa((unsigned long)&data_start); + fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK; + gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK; + + end_paddr = start_paddr + size; + + pg_dir = pgd_offset_k(start_vaddr); + +#if PTRS_PER_PMD == 1 + start_pmd = 0; +#else + start_pmd = ((start_vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1)); +#endif + start_pte = ((start_vaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); + + address = start_paddr; + vaddr = start_vaddr; + while (address < end_paddr) { +#if PTRS_PER_PMD == 1 + pmd = (pmd_t *)__pa(pg_dir); +#else + pmd = (pmd_t *)pgd_address(*pg_dir); + + /* + * pmd is physical at this point + */ + + if (!pmd) { + pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0), PAGE_SIZE << PMD_ORDER); + pmd = (pmd_t *) __pa(pmd); + } + + pgd_populate(NULL, pg_dir, __va(pmd)); +#endif + pg_dir++; + + /* now change pmd to kernel virtual addresses */ + + pmd = (pmd_t *)__va(pmd) + start_pmd; + for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++, pmd++) { + + /* + * pg_table is physical at this point + */ + + pg_table = (pte_t *)pmd_address(*pmd); + if (!pg_table) { + pg_table = (pte_t *) + alloc_bootmem_low_pages_node(NODE_DATA(0), PAGE_SIZE); + pg_table = (pte_t *) __pa(pg_table); + } + + pmd_populate_kernel(NULL, pmd, __va(pg_table)); + + /* now change pg_table to kernel virtual addresses */ + + pg_table = (pte_t *) __va(pg_table) + start_pte; + for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++, pg_table++) { + pte_t pte; + + /* + * Map the fault vector writable so we can + * write the HPMC checksum. + */ + if (force) + pte = __mk_pte(address, pgprot); + else if (core_kernel_text(vaddr) && + address != fv_addr) + pte = __mk_pte(address, PAGE_KERNEL_EXEC); + else +#if defined(CONFIG_PARISC_PAGE_SIZE_4KB) + if (address >= ro_start && address < ro_end + && address != fv_addr + && address != gw_addr) + pte = __mk_pte(address, PAGE_KERNEL_RO); + else +#endif + pte = __mk_pte(address, pgprot); + + if (address >= end_paddr) { + if (force) + break; + else + pte_val(pte) = 0; + } + + set_pte(pg_table, pte); + + address += PAGE_SIZE; + vaddr += PAGE_SIZE; + } + start_pte = 0; + + if (address >= end_paddr) + break; + } + start_pmd = 0; + } +} + void free_initmem(void) { unsigned long addr; unsigned long init_begin = (unsigned long)__init_begin; unsigned long init_end = (unsigned long)__init_end; -#ifdef CONFIG_DEBUG_KERNEL + /* The init text pages are marked R-X. We have to + * flush the icache and mark them RW- + * + * This is tricky, because map_pages is in the init section. + * Do a dummy remap of the data section first (the data + * section is already PAGE_KERNEL) to pull in the TLB entries + * for map_kernel */ + map_pages(init_begin, __pa(init_begin), init_end - init_begin, + PAGE_KERNEL_RWX, 1); + /* now remap at PAGE_KERNEL since the TLB is pre-primed to execute + * map_pages */ + map_pages(init_begin, __pa(init_begin), init_end - init_begin, + PAGE_KERNEL, 1); + + /* force the kernel to see the new TLB entries */ + __flush_tlb_range(0, init_begin, init_end); /* Attempt to catch anyone trying to execute code here * by filling the page with BRK insns. */ memset((void *)init_begin, 0x00, init_end - init_begin); + /* finally dump all the instructions which were cached, since the + * pages are no-longer executable */ flush_icache_range(init_begin, init_end); -#endif - /* align __init_begin and __init_end to page size, - ignoring linker script where we might have tried to save RAM */ - init_begin = PAGE_ALIGN(init_begin); - init_end = PAGE_ALIGN(init_end); for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); init_page_count(virt_to_page(addr)); @@ -616,114 +752,6 @@ void show_mem(unsigned int filter) #endif } - -static void __init map_pages(unsigned long start_vaddr, unsigned long start_paddr, unsigned long size, pgprot_t pgprot) -{ - pgd_t *pg_dir; - pmd_t *pmd; - pte_t *pg_table; - unsigned long end_paddr; - unsigned long start_pmd; - unsigned long start_pte; - unsigned long tmp1; - unsigned long tmp2; - unsigned long address; - unsigned long ro_start; - unsigned long ro_end; - unsigned long fv_addr; - unsigned long gw_addr; - extern const unsigned long fault_vector_20; - extern void * const linux_gateway_page; - - ro_start = __pa((unsigned long)_text); - ro_end = __pa((unsigned long)&data_start); - fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK; - gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK; - - end_paddr = start_paddr + size; - - pg_dir = pgd_offset_k(start_vaddr); - -#if PTRS_PER_PMD == 1 - start_pmd = 0; -#else - start_pmd = ((start_vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1)); -#endif - start_pte = ((start_vaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); - - address = start_paddr; - while (address < end_paddr) { -#if PTRS_PER_PMD == 1 - pmd = (pmd_t *)__pa(pg_dir); -#else - pmd = (pmd_t *)pgd_address(*pg_dir); - - /* - * pmd is physical at this point - */ - - if (!pmd) { - pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE << PMD_ORDER); - pmd = (pmd_t *) __pa(pmd); - } - - pgd_populate(NULL, pg_dir, __va(pmd)); -#endif - pg_dir++; - - /* now change pmd to kernel virtual addresses */ - - pmd = (pmd_t *)__va(pmd) + start_pmd; - for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++,pmd++) { - - /* - * pg_table is physical at this point - */ - - pg_table = (pte_t *)pmd_address(*pmd); - if (!pg_table) { - pg_table = (pte_t *) - alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE); - pg_table = (pte_t *) __pa(pg_table); - } - - pmd_populate_kernel(NULL, pmd, __va(pg_table)); - - /* now change pg_table to kernel virtual addresses */ - - pg_table = (pte_t *) __va(pg_table) + start_pte; - for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) { - pte_t pte; - - /* - * Map the fault vector writable so we can - * write the HPMC checksum. - */ -#if defined(CONFIG_PARISC_PAGE_SIZE_4KB) - if (address >= ro_start && address < ro_end - && address != fv_addr - && address != gw_addr) - pte = __mk_pte(address, PAGE_KERNEL_RO); - else -#endif - pte = __mk_pte(address, pgprot); - - if (address >= end_paddr) - pte_val(pte) = 0; - - set_pte(pg_table, pte); - - address += PAGE_SIZE; - } - start_pte = 0; - - if (address >= end_paddr) - break; - } - start_pmd = 0; - } -} - /* * pagetable_init() sets up the page tables * @@ -748,14 +776,14 @@ static void __init pagetable_init(void) size = pmem_ranges[range].pages << PAGE_SHIFT; map_pages((unsigned long)__va(start_paddr), start_paddr, - size, PAGE_KERNEL); + size, PAGE_KERNEL, 0); } #ifdef CONFIG_BLK_DEV_INITRD if (initrd_end && initrd_end > mem_limit) { printk(KERN_INFO "initrd: mapping %08lx-%08lx\n", initrd_start, initrd_end); map_pages(initrd_start, __pa(initrd_start), - initrd_end - initrd_start, PAGE_KERNEL); + initrd_end - initrd_start, PAGE_KERNEL, 0); } #endif @@ -780,7 +808,7 @@ static void __init gateway_init(void) */ map_pages(linux_gateway_page_addr, __pa(&linux_gateway_page), - PAGE_SIZE, PAGE_GATEWAY); + PAGE_SIZE, PAGE_GATEWAY, 1); } #ifdef CONFIG_HPUX diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index b6ff882f695b..a3128ca0fe11 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -193,6 +193,12 @@ config SYS_SUPPORTS_APM_EMULATION default y if PMAC_APM_EMU bool +config EPAPR_BOOT + bool + help + Used to allow a board to specify it wants an ePAPR compliant wrapper. + default n + config DEFAULT_UIMAGE bool help @@ -209,7 +215,7 @@ config ARCH_HIBERNATION_POSSIBLE config ARCH_SUSPEND_POSSIBLE def_bool y depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ - PPC_85xx || PPC_86xx || PPC_PSERIES || 44x || 40x + (PPC_85xx && !SMP) || PPC_86xx || PPC_PSERIES || 44x || 40x config PPC_DCR_NATIVE bool diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 2d38a50e66ba..a597dd77b903 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -267,6 +267,11 @@ config PPC_EARLY_DEBUG_USBGECKO Select this to enable early debugging for Nintendo GameCube/Wii consoles via an external USB Gecko adapter. +config PPC_EARLY_DEBUG_WSP + bool "Early debugging via WSP's internal UART" + depends on PPC_WSP + select PPC_UDBG_16550 + endchoice config PPC_EARLY_DEBUG_44x_PHYSLOW diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 89178164af5e..c26200b40a47 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -69,7 +69,8 @@ src-wlib := string.S crt0.S crtsavres.S stdio.c main.c \ cpm-serial.c stdlib.c mpc52xx-psc.c planetcore.c uartlite.c \ fsl-soc.c mpc8xx.c pq2.c ugecon.c src-plat := of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c \ - cuboot-ebony.c cuboot-hotfoot.c treeboot-ebony.c prpmc2800.c \ + cuboot-ebony.c cuboot-hotfoot.c epapr.c treeboot-ebony.c \ + prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c \ cuboot-bamboo.c cuboot-mpc7448hpc2.c cuboot-taishan.c \ @@ -127,7 +128,7 @@ quiet_cmd_bootas = BOOTAS $@ cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $< quiet_cmd_bootar = BOOTAR $@ - cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@ + cmd_bootar = $(CROSS32AR) -cr$(KBUILD_ARFLAGS) $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@ $(obj-libfdt): $(obj)/%.o: $(srctree)/scripts/dtc/libfdt/%.c FORCE $(call if_changed_dep,bootcc) @@ -182,6 +183,7 @@ image-$(CONFIG_PPC_HOLLY) += dtbImage.holly image-$(CONFIG_PPC_PRPMC2800) += dtbImage.prpmc2800 image-$(CONFIG_PPC_ISERIES) += zImage.iseries image-$(CONFIG_DEFAULT_UIMAGE) += uImage +image-$(CONFIG_EPAPR_BOOT) += zImage.epapr # # Targets which embed a device tree blob diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S index f1c4dfc635be..0f7428a37efb 100644 --- a/arch/powerpc/boot/crt0.S +++ b/arch/powerpc/boot/crt0.S @@ -6,16 +6,28 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * NOTE: this code runs in 32 bit mode and is packaged as ELF32. + * NOTE: this code runs in 32 bit mode, is position-independent, + * and is packaged as ELF32. */ #include "ppc_asm.h" .text - /* a procedure descriptor used when booting this as a COFF file */ + /* A procedure descriptor used when booting this as a COFF file. + * When making COFF, this comes first in the link and we're + * linked at 0x500000. + */ .globl _zimage_start_opd _zimage_start_opd: - .long _zimage_start, 0, 0, 0 + .long 0x500000, 0, 0, 0 + +p_start: .long _start +p_etext: .long _etext +p_bss_start: .long __bss_start +p_end: .long _end + + .weak _platform_stack_top +p_pstack: .long _platform_stack_top .weak _zimage_start .globl _zimage_start @@ -24,37 +36,65 @@ _zimage_start: _zimage_start_lib: /* Work out the offset between the address we were linked at and the address where we're running. */ - bl 1f -1: mflr r0 - lis r9,1b@ha - addi r9,r9,1b@l - subf. r0,r9,r0 - beq 3f /* if running at same address as linked */ + bl .+4 +p_base: mflr r10 /* r10 now points to runtime addr of p_base */ + /* grab the link address of the dynamic section in r11 */ + addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha + lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11) + cmpwi r11,0 + beq 3f /* if not linked -pie */ + /* get the runtime address of the dynamic section in r12 */ + .weak __dynamic_start + addis r12,r10,(__dynamic_start-p_base)@ha + addi r12,r12,(__dynamic_start-p_base)@l + subf r11,r11,r12 /* runtime - linktime offset */ - /* The .got2 section contains a list of addresses, so add - the address offset onto each entry. */ - lis r9,__got2_start@ha - addi r9,r9,__got2_start@l - lis r8,__got2_end@ha - addi r8,r8,__got2_end@l - subf. r8,r9,r8 + /* The dynamic section contains a series of tagged entries. + * We need the RELA and RELACOUNT entries. */ +RELA = 7 +RELACOUNT = 0x6ffffff9 + li r9,0 + li r0,0 +9: lwz r8,0(r12) /* get tag */ + cmpwi r8,0 + beq 10f /* end of list */ + cmpwi r8,RELA + bne 11f + lwz r9,4(r12) /* get RELA pointer in r9 */ + b 12f +11: addis r8,r8,(-RELACOUNT)@ha + cmpwi r8,RELACOUNT@l + bne 12f + lwz r0,4(r12) /* get RELACOUNT value in r0 */ +12: addi r12,r12,8 + b 9b + + /* The relocation section contains a list of relocations. + * We now do the R_PPC_RELATIVE ones, which point to words + * which need to be initialized with addend + offset. + * The R_PPC_RELATIVE ones come first and there are RELACOUNT + * of them. */ +10: /* skip relocation if we don't have both */ + cmpwi r0,0 beq 3f - srwi. r8,r8,2 - mtctr r8 - add r9,r0,r9 -2: lwz r8,0(r9) - add r8,r8,r0 - stw r8,0(r9) - addi r9,r9,4 + cmpwi r9,0 + beq 3f + + add r9,r9,r11 /* Relocate RELA pointer */ + mtctr r0 +2: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */ + cmpwi r0,22 /* R_PPC_RELATIVE */ + bne 3f + lwz r12,0(r9) /* reloc->r_offset */ + lwz r0,8(r9) /* reloc->r_addend */ + add r0,r0,r11 + stwx r0,r11,r12 + addi r9,r9,12 bdnz 2b /* Do a cache flush for our text, in case the loader didn't */ -3: lis r9,_start@ha - addi r9,r9,_start@l - add r9,r0,r9 - lis r8,_etext@ha - addi r8,r8,_etext@l - add r8,r0,r8 +3: lwz r9,p_start-p_base(r10) /* note: these are relocated now */ + lwz r8,p_etext-p_base(r10) 4: dcbf r0,r9 icbi r0,r9 addi r9,r9,0x20 @@ -64,27 +104,19 @@ _zimage_start_lib: isync /* Clear the BSS */ - lis r9,__bss_start@ha - addi r9,r9,__bss_start@l - add r9,r0,r9 - lis r8,_end@ha - addi r8,r8,_end@l - add r8,r0,r8 - li r10,0 -5: stw r10,0(r9) + lwz r9,p_bss_start-p_base(r10) + lwz r8,p_end-p_base(r10) + li r0,0 +5: stw r0,0(r9) addi r9,r9,4 cmplw cr0,r9,r8 blt 5b /* Possibly set up a custom stack */ -.weak _platform_stack_top - lis r8,_platform_stack_top@ha - addi r8,r8,_platform_stack_top@l + lwz r8,p_pstack-p_base(r10) cmpwi r8,0 beq 6f - add r8,r0,r8 lwz r1,0(r8) - add r1,r0,r1 li r0,0 stwu r0,-16(r1) /* establish a stack frame */ 6: diff --git a/arch/powerpc/boot/dts/p1020rdb.dts b/arch/powerpc/boot/dts/p1020rdb.dts index e0668f877794..d6a8ae458137 100644 --- a/arch/powerpc/boot/dts/p1020rdb.dts +++ b/arch/powerpc/boot/dts/p1020rdb.dts @@ -9,12 +9,11 @@ * option) any later version. */ -/dts-v1/; +/include/ "p1020si.dtsi" + / { - model = "fsl,P1020"; + model = "fsl,P1020RDB"; compatible = "fsl,P1020RDB"; - #address-cells = <2>; - #size-cells = <2>; aliases { serial0 = &serial0; @@ -26,34 +25,11 @@ aliases { pci1 = &pci1; }; - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,P1020@0 { - device_type = "cpu"; - reg = <0x0>; - next-level-cache = <&L2>; - }; - - PowerPC,P1020@1 { - device_type = "cpu"; - reg = <0x1>; - next-level-cache = <&L2>; - }; - }; - memory { device_type = "memory"; }; localbus@ffe05000 { - #address-cells = <2>; - #size-cells = <1>; - compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus"; - reg = <0 0xffe05000 0 0x1000>; - interrupts = <19 2>; - interrupt-parent = <&mpic>; /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ ranges = <0x0 0x0 0x0 0xef000000 0x01000000 @@ -165,88 +141,14 @@ L2switch@2,0 { }; soc@ffe00000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "fsl,p1020-immr", "simple-bus"; - ranges = <0x0 0x0 0xffe00000 0x100000>; - bus-frequency = <0>; // Filled out by uboot. - - ecm-law@0 { - compatible = "fsl,ecm-law"; - reg = <0x0 0x1000>; - fsl,num-laws = <12>; - }; - - ecm@1000 { - compatible = "fsl,p1020-ecm", "fsl,ecm"; - reg = <0x1000 0x1000>; - interrupts = <16 2>; - interrupt-parent = <&mpic>; - }; - - memory-controller@2000 { - compatible = "fsl,p1020-memory-controller"; - reg = <0x2000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <16 2>; - }; - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; rtc@68 { compatible = "dallas,ds1339"; reg = <0x68>; }; }; - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - spi@7000 { - cell-index = <0>; - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,espi"; - reg = <0x7000 0x1000>; - interrupts = <59 0x2>; - interrupt-parent = <&mpic>; - mode = "cpu"; fsl_m25p80@0 { #address-cells = <1>; @@ -294,66 +196,7 @@ partition@900000 { }; }; - gpio: gpio-controller@f000 { - #gpio-cells = <2>; - compatible = "fsl,mpc8572-gpio"; - reg = <0xf000 0x100>; - interrupts = <47 0x2>; - interrupt-parent = <&mpic>; - gpio-controller; - }; - - L2: l2-cache-controller@20000 { - compatible = "fsl,p1020-l2-cache-controller"; - reg = <0x20000 0x1000>; - cache-line-size = <32>; // 32 bytes - cache-size = <0x40000>; // L2,256K - interrupt-parent = <&mpic>; - interrupts = <16 2>; - }; - - dma@21300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,eloplus-dma"; - reg = <0x21300 0x4>; - ranges = <0x0 0x21100 0x200>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x0 0x80>; - cell-index = <0>; - interrupt-parent = <&mpic>; - interrupts = <20 2>; - }; - dma-channel@80 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&mpic>; - interrupts = <21 2>; - }; - dma-channel@100 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&mpic>; - interrupts = <22 2>; - }; - dma-channel@180 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x180 0x80>; - cell-index = <3>; - interrupt-parent = <&mpic>; - interrupts = <23 2>; - }; - }; - mdio@24000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,etsec2-mdio"; - reg = <0x24000 0x1000 0xb0030 0x4>; phy0: ethernet-phy@0 { interrupt-parent = <&mpic>; @@ -369,10 +212,6 @@ phy1: ethernet-phy@1 { }; mdio@25000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,etsec2-tbi"; - reg = <0x25000 0x1000 0xb1030 0x4>; tbi0: tbi-phy@11 { reg = <0x11>; @@ -381,97 +220,25 @@ tbi0: tbi-phy@11 { }; enet0: ethernet@b0000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "fsl,etsec2"; - fsl,num_rx_queues = <0x8>; - fsl,num_tx_queues = <0x8>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupt-parent = <&mpic>; fixed-link = <1 1 1000 0 0>; phy-connection-type = "rgmii-id"; - queue-group@0 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xb0000 0x1000>; - interrupts = <29 2 30 2 34 2>; - }; - - queue-group@1 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xb4000 0x1000>; - interrupts = <17 2 18 2 24 2>; - }; }; enet1: ethernet@b1000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "fsl,etsec2"; - fsl,num_rx_queues = <0x8>; - fsl,num_tx_queues = <0x8>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupt-parent = <&mpic>; phy-handle = <&phy0>; tbi-handle = <&tbi0>; phy-connection-type = "sgmii"; - queue-group@0 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xb1000 0x1000>; - interrupts = <35 2 36 2 40 2>; - }; - - queue-group@1 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xb5000 0x1000>; - interrupts = <51 2 52 2 67 2>; - }; }; enet2: ethernet@b2000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "fsl,etsec2"; - fsl,num_rx_queues = <0x8>; - fsl,num_tx_queues = <0x8>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupt-parent = <&mpic>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; - queue-group@0 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xb2000 0x1000>; - interrupts = <31 2 32 2 33 2>; - }; - - queue-group@1 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xb6000 0x1000>; - interrupts = <25 2 26 2 27 2>; - }; }; usb@22000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl-usb2-dr"; - reg = <0x22000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <28 0x2>; phy_type = "ulpi"; }; @@ -481,82 +248,23 @@ since U-Boot doesn't clear the status property when it enables USB2. OTOH, U-Boot does create a new node when there isn't any. So, just comment it out. usb@23000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl-usb2-dr"; - reg = <0x23000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <46 0x2>; phy_type = "ulpi"; }; */ - sdhci@2e000 { - compatible = "fsl,p1020-esdhc", "fsl,esdhc"; - reg = <0x2e000 0x1000>; - interrupts = <72 0x2>; - interrupt-parent = <&mpic>; - /* Filled in by U-Boot */ - clock-frequency = <0>; - }; - - crypto@30000 { - compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", - "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <45 2 58 2>; - interrupt-parent = <&mpic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0xbfe>; - fsl,descriptor-types-mask = <0x3ab0ebf>; - }; - - mpic: pic@40000 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; - }; - - msi@41600 { - compatible = "fsl,p1020-msi", "fsl,mpic-msi"; - reg = <0x41600 0x80>; - msi-available-ranges = <0 0x100>; - interrupts = < - 0xe0 0 - 0xe1 0 - 0xe2 0 - 0xe3 0 - 0xe4 0 - 0xe5 0 - 0xe6 0 - 0xe7 0>; - interrupt-parent = <&mpic>; - }; - - global-utilities@e0000 { //global utilities block - compatible = "fsl,p1020-guts"; - reg = <0xe0000 0x1000>; - fsl,has-rstcr; - }; }; pci0: pcie@ffe09000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe09000 0 0x1000>; - bus-range = <0 255>; ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <16 2>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x4 0x1 + 0000 0x0 0x0 0x2 &mpic 0x5 0x1 + 0000 0x0 0x0 0x3 &mpic 0x6 0x1 + 0000 0x0 0x0 0x4 &mpic 0x7 0x1 + >; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; @@ -573,18 +281,16 @@ pcie@0 { }; pci1: pcie@ffe0a000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe0a000 0 0x1000>; - bus-range = <0 255>; ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <16 2>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x0 0x1 + 0000 0x0 0x0 0x2 &mpic 0x1 0x1 + 0000 0x0 0x0 0x3 &mpic 0x2 0x1 + 0000 0x0 0x0 0x4 &mpic 0x3 0x1 + >; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts new file mode 100644 index 000000000000..f0bf7f42f097 --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts @@ -0,0 +1,213 @@ +/* + * P1020 RDB Core0 Device Tree Source in CAMP mode. + * + * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache + * can be shared, all the other devices must be assigned to one core only. + * This dts file allows core0 to have memory, l2, i2c, spi, gpio, tdm, dma, usb, + * eth1, eth2, sdhc, crypto, global-util, message, pci0, pci1, msi. + * + * Please note to add "-b 0" for core0's dts compiling. + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/include/ "p1020si.dtsi" + +/ { + model = "fsl,P1020RDB"; + compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP"; + + aliases { + ethernet1 = &enet1; + ethernet2 = &enet2; + serial0 = &serial0; + pci0 = &pci0; + pci1 = &pci1; + }; + + cpus { + PowerPC,P1020@1 { + status = "disabled"; + }; + }; + + memory { + device_type = "memory"; + }; + + localbus@ffe05000 { + status = "disabled"; + }; + + soc@ffe00000 { + i2c@3000 { + rtc@68 { + compatible = "dallas,ds1339"; + reg = <0x68>; + }; + }; + + serial1: serial@4600 { + status = "disabled"; + }; + + spi@7000 { + fsl_m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,espi-flash"; + reg = <0>; + linux,modalias = "fsl_m25p80"; + spi-max-frequency = <40000000>; + + partition@0 { + /* 512KB for u-boot Bootloader Image */ + reg = <0x0 0x00080000>; + label = "SPI (RO) U-Boot Image"; + read-only; + }; + + partition@80000 { + /* 512KB for DTB Image */ + reg = <0x00080000 0x00080000>; + label = "SPI (RO) DTB Image"; + read-only; + }; + + partition@100000 { + /* 4MB for Linux Kernel Image */ + reg = <0x00100000 0x00400000>; + label = "SPI (RO) Linux Kernel Image"; + read-only; + }; + + partition@500000 { + /* 4MB for Compressed RFS Image */ + reg = <0x00500000 0x00400000>; + label = "SPI (RO) Compressed RFS Image"; + read-only; + }; + + partition@900000 { + /* 7MB for JFFS2 based RFS */ + reg = <0x00900000 0x00700000>; + label = "SPI (RW) JFFS2 RFS"; + }; + }; + }; + + mdio@24000 { + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = <3 1>; + reg = <0x0>; + }; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = <2 1>; + reg = <0x1>; + }; + }; + + mdio@25000 { + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@b0000 { + status = "disabled"; + }; + + enet1: ethernet@b1000 { + phy-handle = <&phy0>; + tbi-handle = <&tbi0>; + phy-connection-type = "sgmii"; + }; + + enet2: ethernet@b2000 { + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + }; + + usb@22000 { + phy_type = "ulpi"; + }; + + /* USB2 is shared with localbus, so it must be disabled + by default. We can't put 'status = "disabled";' here + since U-Boot doesn't clear the status property when + it enables USB2. OTOH, U-Boot does create a new node + when there isn't any. So, just comment it out. + usb@23000 { + phy_type = "ulpi"; + }; + */ + + mpic: pic@40000 { + protected-sources = < + 42 29 30 34 /* serial1, enet0-queue-group0 */ + 17 18 24 45 /* enet0-queue-group1, crypto */ + >; + }; + + }; + + pci0: pcie@ffe09000 { + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x4 0x1 + 0000 0x0 0x0 0x2 &mpic 0x5 0x1 + 0000 0x0 0x0 0x3 &mpic 0x6 0x1 + 0000 0x0 0x0 0x4 &mpic 0x7 0x1 + >; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@ffe0a000 { + ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x0 0x1 + 0000 0x0 0x0 0x2 &mpic 0x1 0x1 + 0000 0x0 0x0 0x3 &mpic 0x2 0x1 + 0000 0x0 0x0 0x4 &mpic 0x3 0x1 + >; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts new file mode 100644 index 000000000000..6ec02204a44e --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts @@ -0,0 +1,148 @@ +/* + * P1020 RDB Core1 Device Tree Source in CAMP mode. + * + * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache + * can be shared, all the other devices must be assigned to one core only. + * This dts allows core1 to have l2, eth0, crypto. + * + * Please note to add "-b 1" for core1's dts compiling. + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/include/ "p1020si.dtsi" + +/ { + model = "fsl,P1020RDB"; + compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP"; + + aliases { + ethernet0 = &enet0; + serial0 = &serial1; + }; + + cpus { + PowerPC,P1020@0 { + status = "disabled"; + }; + }; + + memory { + device_type = "memory"; + }; + + localbus@ffe05000 { + status = "disabled"; + }; + + soc@ffe00000 { + ecm-law@0 { + status = "disabled"; + }; + + ecm@1000 { + status = "disabled"; + }; + + memory-controller@2000 { + status = "disabled"; + }; + + i2c@3000 { + status = "disabled"; + }; + + i2c@3100 { + status = "disabled"; + }; + + serial0: serial@4500 { + status = "disabled"; + }; + + spi@7000 { + status = "disabled"; + }; + + gpio: gpio-controller@f000 { + status = "disabled"; + }; + + dma@21300 { + status = "disabled"; + }; + + mdio@24000 { + status = "disabled"; + }; + + mdio@25000 { + status = "disabled"; + }; + + enet0: ethernet@b0000 { + fixed-link = <1 1 1000 0 0>; + phy-connection-type = "rgmii-id"; + + }; + + enet1: ethernet@b1000 { + status = "disabled"; + }; + + enet2: ethernet@b2000 { + status = "disabled"; + }; + + usb@22000 { + status = "disabled"; + }; + + sdhci@2e000 { + status = "disabled"; + }; + + mpic: pic@40000 { + protected-sources = < + 16 /* ecm, mem, L2, pci0, pci1 */ + 43 42 59 /* i2c, serial0, spi */ + 47 63 62 /* gpio, tdm */ + 20 21 22 23 /* dma */ + 03 02 /* mdio */ + 35 36 40 /* enet1-queue-group0 */ + 51 52 67 /* enet1-queue-group1 */ + 31 32 33 /* enet2-queue-group0 */ + 25 26 27 /* enet2-queue-group1 */ + 28 72 58 /* usb, sdhci, crypto */ + 0xb0 0xb1 0xb2 /* message */ + 0xb3 0xb4 0xb5 + 0xb6 0xb7 + 0xe0 0xe1 0xe2 /* msi */ + 0xe3 0xe4 0xe5 + 0xe6 0xe7 /* sdhci, crypto , pci */ + >; + }; + + msi@41600 { + status = "disabled"; + }; + + global-utilities@e0000 { //global utilities block + status = "disabled"; + }; + + }; + + pci0: pcie@ffe09000 { + status = "disabled"; + }; + + pci1: pcie@ffe0a000 { + status = "disabled"; + }; +}; diff --git a/arch/powerpc/boot/dts/p1020si.dtsi b/arch/powerpc/boot/dts/p1020si.dtsi new file mode 100644 index 000000000000..5c5acb66c3fc --- /dev/null +++ b/arch/powerpc/boot/dts/p1020si.dtsi @@ -0,0 +1,377 @@ +/* + * P1020si Device Tree Source + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/dts-v1/; +/ { + compatible = "fsl,P1020"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,P1020@0 { + device_type = "cpu"; + reg = <0x0>; + next-level-cache = <&L2>; + }; + + PowerPC,P1020@1 { + device_type = "cpu"; + reg = <0x1>; + next-level-cache = <&L2>; + }; + }; + + localbus@ffe05000 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus"; + reg = <0 0xffe05000 0 0x1000>; + interrupts = <19 2>; + interrupt-parent = <&mpic>; + }; + + soc@ffe00000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + compatible = "fsl,p1020-immr", "simple-bus"; + ranges = <0x0 0x0 0xffe00000 0x100000>; + bus-frequency = <0>; // Filled out by uboot. + + ecm-law@0 { + compatible = "fsl,ecm-law"; + reg = <0x0 0x1000>; + fsl,num-laws = <12>; + }; + + ecm@1000 { + compatible = "fsl,p1020-ecm", "fsl,ecm"; + reg = <0x1000 0x1000>; + interrupts = <16 2>; + interrupt-parent = <&mpic>; + }; + + memory-controller@2000 { + compatible = "fsl,p1020-memory-controller"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; + + i2c@3000 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + compatible = "fsl-i2c"; + reg = <0x3000 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + i2c@3100 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <1>; + compatible = "fsl-i2c"; + reg = <0x3100 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + serial0: serial@4500 { + cell-index = <0>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4500 0x100>; + clock-frequency = <0>; + interrupts = <42 2>; + interrupt-parent = <&mpic>; + }; + + serial1: serial@4600 { + cell-index = <1>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4600 0x100>; + clock-frequency = <0>; + interrupts = <42 2>; + interrupt-parent = <&mpic>; + }; + + spi@7000 { + cell-index = <0>; + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,espi"; + reg = <0x7000 0x1000>; + interrupts = <59 0x2>; + interrupt-parent = <&mpic>; + mode = "cpu"; + }; + + gpio: gpio-controller@f000 { + #gpio-cells = <2>; + compatible = "fsl,mpc8572-gpio"; + reg = <0xf000 0x100>; + interrupts = <47 0x2>; + interrupt-parent = <&mpic>; + gpio-controller; + }; + + L2: l2-cache-controller@20000 { + compatible = "fsl,p1020-l2-cache-controller"; + reg = <0x20000 0x1000>; + cache-line-size = <32>; // 32 bytes + cache-size = <0x40000>; // L2,256K + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; + + dma@21300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,eloplus-dma"; + reg = <0x21300 0x4>; + ranges = <0x0 0x21100 0x200>; + cell-index = <0>; + dma-channel@0 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + cell-index = <0>; + interrupt-parent = <&mpic>; + interrupts = <20 2>; + }; + dma-channel@80 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupt-parent = <&mpic>; + interrupts = <21 2>; + }; + dma-channel@100 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupt-parent = <&mpic>; + interrupts = <22 2>; + }; + dma-channel@180 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupt-parent = <&mpic>; + interrupts = <23 2>; + }; + }; + + mdio@24000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,etsec2-mdio"; + reg = <0x24000 0x1000 0xb0030 0x4>; + + }; + + mdio@25000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,etsec2-tbi"; + reg = <0x25000 0x1000 0xb1030 0x4>; + + }; + + enet0: ethernet@b0000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = <&mpic>; + + queue-group@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb0000 0x1000>; + interrupts = <29 2 30 2 34 2>; + }; + + queue-group@1 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb4000 0x1000>; + interrupts = <17 2 18 2 24 2>; + }; + }; + + enet1: ethernet@b1000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = <&mpic>; + + queue-group@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb1000 0x1000>; + interrupts = <35 2 36 2 40 2>; + }; + + queue-group@1 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb5000 0x1000>; + interrupts = <51 2 52 2 67 2>; + }; + }; + + enet2: ethernet@b2000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = <&mpic>; + + queue-group@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb2000 0x1000>; + interrupts = <31 2 32 2 33 2>; + }; + + queue-group@1 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb6000 0x1000>; + interrupts = <25 2 26 2 27 2>; + }; + }; + + usb@22000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl-usb2-dr"; + reg = <0x22000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <28 0x2>; + }; + + /* USB2 is shared with localbus, so it must be disabled + by default. We can't put 'status = "disabled";' here + since U-Boot doesn't clear the status property when + it enables USB2. OTOH, U-Boot does create a new node + when there isn't any. So, just comment it out. + usb@23000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl-usb2-dr"; + reg = <0x23000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <46 0x2>; + phy_type = "ulpi"; + }; + */ + + sdhci@2e000 { + compatible = "fsl,p1020-esdhc", "fsl,esdhc"; + reg = <0x2e000 0x1000>; + interrupts = <72 0x2>; + interrupt-parent = <&mpic>; + /* Filled in by U-Boot */ + clock-frequency = <0>; + }; + + crypto@30000 { + compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", + "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; + reg = <0x30000 0x10000>; + interrupts = <45 2 58 2>; + interrupt-parent = <&mpic>; + fsl,num-channels = <4>; + fsl,channel-fifo-len = <24>; + fsl,exec-units-mask = <0xbfe>; + fsl,descriptor-types-mask = <0x3ab0ebf>; + }; + + mpic: pic@40000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x40000 0x40000>; + compatible = "chrp,open-pic"; + device_type = "open-pic"; + }; + + msi@41600 { + compatible = "fsl,p1020-msi", "fsl,mpic-msi"; + reg = <0x41600 0x80>; + msi-available-ranges = <0 0x100>; + interrupts = < + 0xe0 0 + 0xe1 0 + 0xe2 0 + 0xe3 0 + 0xe4 0 + 0xe5 0 + 0xe6 0 + 0xe7 0>; + interrupt-parent = <&mpic>; + }; + + global-utilities@e0000 { //global utilities block + compatible = "fsl,p1020-guts","fsl,p2020-guts"; + reg = <0xe0000 0x1000>; + fsl,has-rstcr; + }; + }; + + pci0: pcie@ffe09000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0 0xffe09000 0 0x1000>; + bus-range = <0 255>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; + + pci1: pcie@ffe0a000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0 0xffe0a000 0 0x1000>; + bus-range = <0 255>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; +}; diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts index 59ef405c1c91..4f685a779f4c 100644 --- a/arch/powerpc/boot/dts/p1022ds.dts +++ b/arch/powerpc/boot/dts/p1022ds.dts @@ -52,7 +52,7 @@ localbus@fffe05000 { #size-cells = <1>; compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus"; reg = <0 0xffe05000 0 0x1000>; - interrupts = <19 2>; + interrupts = <19 2 0 0>; ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 0x1 0x0 0xf 0xe0000000 0x08000000 @@ -157,7 +157,7 @@ board-control@3,0 { * IRQ8 is generated if the "EVENT" switch is pressed * and PX_CTL[EVESEL] is set to 00. */ - interrupts = <8 8>; + interrupts = <8 8 0 0>; }; }; @@ -178,13 +178,13 @@ ecm-law@0 { ecm@1000 { compatible = "fsl,p1022-ecm", "fsl,ecm"; reg = <0x1000 0x1000>; - interrupts = <16 2>; + interrupts = <16 2 0 0>; }; memory-controller@2000 { compatible = "fsl,p1022-memory-controller"; reg = <0x2000 0x1000>; - interrupts = <16 2>; + interrupts = <16 2 0 0>; }; i2c@3000 { @@ -193,7 +193,7 @@ i2c@3000 { cell-index = <0>; compatible = "fsl-i2c"; reg = <0x3000 0x100>; - interrupts = <43 2>; + interrupts = <43 2 0 0>; dfsrr; }; @@ -203,7 +203,7 @@ i2c@3100 { cell-index = <1>; compatible = "fsl-i2c"; reg = <0x3100 0x100>; - interrupts = <43 2>; + interrupts = <43 2 0 0>; dfsrr; wm8776:codec@1a { @@ -220,7 +220,7 @@ serial0: serial@4500 { compatible = "ns16550"; reg = <0x4500 0x100>; clock-frequency = <0>; - interrupts = <42 2>; + interrupts = <42 2 0 0>; }; serial1: serial@4600 { @@ -229,7 +229,7 @@ serial1: serial@4600 { compatible = "ns16550"; reg = <0x4600 0x100>; clock-frequency = <0>; - interrupts = <42 2>; + interrupts = <42 2 0 0>; }; spi@7000 { @@ -238,7 +238,7 @@ spi@7000 { #size-cells = <0>; compatible = "fsl,espi"; reg = <0x7000 0x1000>; - interrupts = <59 0x2>; + interrupts = <59 0x2 0 0>; espi,num-ss-bits = <4>; mode = "cpu"; @@ -275,7 +275,7 @@ ssi@15000 { compatible = "fsl,mpc8610-ssi"; cell-index = <0>; reg = <0x15000 0x100>; - interrupts = <75 2>; + interrupts = <75 2 0 0>; fsl,mode = "i2s-slave"; codec-handle = <&wm8776>; fsl,playback-dma = <&dma00>; @@ -294,25 +294,25 @@ dma00: dma-channel@0 { compatible = "fsl,ssi-dma-channel"; reg = <0x0 0x80>; cell-index = <0>; - interrupts = <76 2>; + interrupts = <76 2 0 0>; }; dma01: dma-channel@80 { compatible = "fsl,ssi-dma-channel"; reg = <0x80 0x80>; cell-index = <1>; - interrupts = <77 2>; + interrupts = <77 2 0 0>; }; dma-channel@100 { compatible = "fsl,eloplus-dma-channel"; reg = <0x100 0x80>; cell-index = <2>; - interrupts = <78 2>; + interrupts = <78 2 0 0>; }; dma-channel@180 { compatible = "fsl,eloplus-dma-channel"; reg = <0x180 0x80>; cell-index = <3>; - interrupts = <79 2>; + interrupts = <79 2 0 0>; }; }; @@ -320,7 +320,7 @@ gpio: gpio-controller@f000 { #gpio-cells = <2>; compatible = "fsl,mpc8572-gpio"; reg = <0xf000 0x100>; - interrupts = <47 0x2>; + interrupts = <47 0x2 0 0>; gpio-controller; }; @@ -329,7 +329,7 @@ L2: l2-cache-controller@20000 { reg = <0x20000 0x1000>; cache-line-size = <32>; // 32 bytes cache-size = <0x40000>; // L2, 256K - interrupts = <16 2>; + interrupts = <16 2 0 0>; }; dma@21300 { @@ -343,25 +343,25 @@ dma-channel@0 { compatible = "fsl,eloplus-dma-channel"; reg = <0x0 0x80>; cell-index = <0>; - interrupts = <20 2>; + interrupts = <20 2 0 0>; }; dma-channel@80 { compatible = "fsl,eloplus-dma-channel"; reg = <0x80 0x80>; cell-index = <1>; - interrupts = <21 2>; + interrupts = <21 2 0 0>; }; dma-channel@100 { compatible = "fsl,eloplus-dma-channel"; reg = <0x100 0x80>; cell-index = <2>; - interrupts = <22 2>; + interrupts = <22 2 0 0>; }; dma-channel@180 { compatible = "fsl,eloplus-dma-channel"; reg = <0x180 0x80>; cell-index = <3>; - interrupts = <23 2>; + interrupts = <23 2 0 0>; }; }; @@ -370,7 +370,7 @@ usb@22000 { #size-cells = <0>; compatible = "fsl-usb2-dr"; reg = <0x22000 0x1000>; - interrupts = <28 0x2>; + interrupts = <28 0x2 0 0>; phy_type = "ulpi"; }; @@ -381,11 +381,11 @@ mdio@24000 { reg = <0x24000 0x1000 0xb0030 0x4>; phy0: ethernet-phy@0 { - interrupts = <3 1>; + interrupts = <3 1 0 0>; reg = <0x1>; }; phy1: ethernet-phy@1 { - interrupts = <9 1>; + interrupts = <9 1 0 0>; reg = <0x2>; }; }; @@ -416,13 +416,13 @@ queue-group@0{ #address-cells = <1>; #size-cells = <1>; reg = <0xB0000 0x1000>; - interrupts = <29 2 30 2 34 2>; + interrupts = <29 2 0 0 30 2 0 0 34 2 0 0>; }; queue-group@1{ #address-cells = <1>; #size-cells = <1>; reg = <0xB4000 0x1000>; - interrupts = <17 2 18 2 24 2>; + interrupts = <17 2 0 0 18 2 0 0 24 2 0 0>; }; }; @@ -443,20 +443,20 @@ queue-group@0{ #address-cells = <1>; #size-cells = <1>; reg = <0xB1000 0x1000>; - interrupts = <35 2 36 2 40 2>; + interrupts = <35 2 0 0 36 2 0 0 40 2 0 0>; }; queue-group@1{ #address-cells = <1>; #size-cells = <1>; reg = <0xB5000 0x1000>; - interrupts = <51 2 52 2 67 2>; + interrupts = <51 2 0 0 52 2 0 0 67 2 0 0>; }; }; sdhci@2e000 { compatible = "fsl,p1022-esdhc", "fsl,esdhc"; reg = <0x2e000 0x1000>; - interrupts = <72 0x2>; + interrupts = <72 0x2 0 0>; fsl,sdhci-auto-cmd12; /* Filled in by U-Boot */ clock-frequency = <0>; @@ -467,7 +467,7 @@ crypto@30000 { "fsl,sec2.4", "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; reg = <0x30000 0x10000>; - interrupts = <45 2 58 2>; + interrupts = <45 2 0 0 58 2 0 0>; fsl,num-channels = <4>; fsl,channel-fifo-len = <24>; fsl,exec-units-mask = <0x97c>; @@ -478,14 +478,14 @@ sata@18000 { compatible = "fsl,p1022-sata", "fsl,pq-sata-v2"; reg = <0x18000 0x1000>; cell-index = <1>; - interrupts = <74 0x2>; + interrupts = <74 0x2 0 0>; }; sata@19000 { compatible = "fsl,p1022-sata", "fsl,pq-sata-v2"; reg = <0x19000 0x1000>; cell-index = <2>; - interrupts = <41 0x2>; + interrupts = <41 0x2 0 0>; }; power@e0070{ @@ -496,21 +496,33 @@ power@e0070{ display@10000 { compatible = "fsl,diu", "fsl,p1022-diu"; reg = <0x10000 1000>; - interrupts = <64 2>; + interrupts = <64 2 0 0>; }; timer@41100 { compatible = "fsl,mpic-global-timer"; - reg = <0x41100 0x204>; - interrupts = <0xf7 0x2>; + reg = <0x41100 0x100 0x41300 4>; + interrupts = <0 0 3 0 + 1 0 3 0 + 2 0 3 0 + 3 0 3 0>; + }; + + timer@42100 { + compatible = "fsl,mpic-global-timer"; + reg = <0x42100 0x100 0x42300 4>; + interrupts = <4 0 3 0 + 5 0 3 0 + 6 0 3 0 + 7 0 3 0>; }; mpic: pic@40000 { interrupt-controller; #address-cells = <0>; - #interrupt-cells = <2>; + #interrupt-cells = <4>; reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; + compatible = "fsl,mpic"; device_type = "open-pic"; }; @@ -519,14 +531,14 @@ msi@41600 { reg = <0x41600 0x80>; msi-available-ranges = <0 0x100>; interrupts = < - 0xe0 0 - 0xe1 0 - 0xe2 0 - 0xe3 0 - 0xe4 0 - 0xe5 0 - 0xe6 0 - 0xe7 0>; + 0xe0 0 0 0 + 0xe1 0 0 0 + 0xe2 0 0 0 + 0xe3 0 0 0 + 0xe4 0 0 0 + 0xe5 0 0 0 + 0xe6 0 0 0 + 0xe7 0 0 0>; }; global-utilities@e0000 { //global utilities block @@ -547,7 +559,7 @@ pci0: pcie@fffe09000 { ranges = <0x2000000 0x0 0xa0000000 0xc 0x20000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; clock-frequency = <33333333>; - interrupts = <16 2>; + interrupts = <16 2 0 0>; interrupt-map-mask = <0xf800 0 0 7>; interrupt-map = < /* IDSEL 0x0 */ @@ -582,7 +594,7 @@ pci1: pcie@fffe0a000 { ranges = <0x2000000 0x0 0xc0000000 0xc 0x40000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>; clock-frequency = <33333333>; - interrupts = <16 2>; + interrupts = <16 2 0 0>; interrupt-map-mask = <0xf800 0 0 7>; interrupt-map = < /* IDSEL 0x0 */ @@ -618,7 +630,7 @@ pci2: pcie@fffe0b000 { ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; clock-frequency = <33333333>; - interrupts = <16 2>; + interrupts = <16 2 0 0>; interrupt-map-mask = <0xf800 0 0 7>; interrupt-map = < /* IDSEL 0x0 */ diff --git a/arch/powerpc/boot/dts/p2020ds.dts b/arch/powerpc/boot/dts/p2020ds.dts index 11019142813c..2bcf3683d223 100644 --- a/arch/powerpc/boot/dts/p2020ds.dts +++ b/arch/powerpc/boot/dts/p2020ds.dts @@ -1,7 +1,7 @@ /* * P2020 DS Device Tree Source * - * Copyright 2009 Freescale Semiconductor Inc. + * Copyright 2009-2011 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 @@ -9,12 +9,11 @@ * option) any later version. */ -/dts-v1/; +/include/ "p2020si.dtsi" + / { - model = "fsl,P2020"; + model = "fsl,P2020DS"; compatible = "fsl,P2020DS"; - #address-cells = <2>; - #size-cells = <2>; aliases { ethernet0 = &enet0; @@ -27,35 +26,13 @@ aliases { pci2 = &pci2; }; - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,P2020@0 { - device_type = "cpu"; - reg = <0x0>; - next-level-cache = <&L2>; - }; - - PowerPC,P2020@1 { - device_type = "cpu"; - reg = <0x1>; - next-level-cache = <&L2>; - }; - }; memory { device_type = "memory"; }; localbus@ffe05000 { - #address-cells = <2>; - #size-cells = <1>; compatible = "fsl,elbc", "simple-bus"; - reg = <0 0xffe05000 0 0x1000>; - interrupts = <19 2>; - interrupt-parent = <&mpic>; - ranges = <0x0 0x0 0x0 0xe8000000 0x08000000 0x1 0x0 0x0 0xe0000000 0x08000000 0x2 0x0 0x0 0xffa00000 0x00040000 @@ -158,352 +135,77 @@ nand@6,0 { }; soc@ffe00000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "fsl,p2020-immr", "simple-bus"; - ranges = <0x0 0 0xffe00000 0x100000>; - bus-frequency = <0>; // Filled out by uboot. - - ecm-law@0 { - compatible = "fsl,ecm-law"; - reg = <0x0 0x1000>; - fsl,num-laws = <12>; - }; - - ecm@1000 { - compatible = "fsl,p2020-ecm", "fsl,ecm"; - reg = <0x1000 0x1000>; - interrupts = <17 2>; - interrupt-parent = <&mpic>; - }; - - memory-controller@2000 { - compatible = "fsl,p2020-memory-controller"; - reg = <0x2000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <18 2>; - }; - - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; - }; - - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - - spi@7000 { - compatible = "fsl,espi"; - reg = <0x7000 0x1000>; - interrupts = <59 0x2>; - interrupt-parent = <&mpic>; - }; - - dma@c300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,eloplus-dma"; - reg = <0xc300 0x4>; - ranges = <0x0 0xc100 0x200>; - cell-index = <1>; - dma-channel@0 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x0 0x80>; - cell-index = <0>; - interrupt-parent = <&mpic>; - interrupts = <76 2>; - }; - dma-channel@80 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&mpic>; - interrupts = <77 2>; - }; - dma-channel@100 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&mpic>; - interrupts = <78 2>; - }; - dma-channel@180 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x180 0x80>; - cell-index = <3>; - interrupt-parent = <&mpic>; - interrupts = <79 2>; - }; - }; - - gpio: gpio-controller@f000 { - #gpio-cells = <2>; - compatible = "fsl,mpc8572-gpio"; - reg = <0xf000 0x100>; - interrupts = <47 0x2>; - interrupt-parent = <&mpic>; - gpio-controller; - }; - - L2: l2-cache-controller@20000 { - compatible = "fsl,p2020-l2-cache-controller"; - reg = <0x20000 0x1000>; - cache-line-size = <32>; // 32 bytes - cache-size = <0x80000>; // L2, 512k - interrupt-parent = <&mpic>; - interrupts = <16 2>; - }; - - dma@21300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,eloplus-dma"; - reg = <0x21300 0x4>; - ranges = <0x0 0x21100 0x200>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x0 0x80>; - cell-index = <0>; - interrupt-parent = <&mpic>; - interrupts = <20 2>; - }; - dma-channel@80 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&mpic>; - interrupts = <21 2>; - }; - dma-channel@100 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&mpic>; - interrupts = <22 2>; - }; - dma-channel@180 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x180 0x80>; - cell-index = <3>; - interrupt-parent = <&mpic>; - interrupts = <23 2>; - }; - }; usb@22000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl-usb2-dr"; - reg = <0x22000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <28 0x2>; phy_type = "ulpi"; }; - enet0: ethernet@24000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <0>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x24000 0x1000>; - ranges = <0x0 0x24000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <29 2 30 2 34 2>; - interrupt-parent = <&mpic>; - tbi-handle = <&tbi0>; - phy-handle = <&phy0>; - phy-connection-type = "rgmii-id"; + mdio@24520 { + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = <3 1>; + reg = <0x0>; + }; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = <3 1>; + reg = <0x1>; + }; + phy2: ethernet-phy@2 { + interrupt-parent = <&mpic>; + interrupts = <3 1>; + reg = <0x2>; + }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-mdio"; - reg = <0x520 0x20>; + }; - phy0: ethernet-phy@0 { - interrupt-parent = <&mpic>; - interrupts = <3 1>; - reg = <0x0>; - }; - phy1: ethernet-phy@1 { - interrupt-parent = <&mpic>; - interrupts = <3 1>; - reg = <0x1>; - }; - phy2: ethernet-phy@2 { - interrupt-parent = <&mpic>; - interrupts = <3 1>; - reg = <0x2>; - }; - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; + mdio@25520 { + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; }; }; + mdio@26520 { + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + + }; + + enet0: ethernet@24000 { + tbi-handle = <&tbi0>; + phy-handle = <&phy0>; + phy-connection-type = "rgmii-id"; + }; + enet1: ethernet@25000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x25000 0x1000>; - ranges = <0x0 0x25000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <35 2 36 2 40 2>; - interrupt-parent = <&mpic>; tbi-handle = <&tbi1>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-tbi"; - reg = <0x520 0x20>; - - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; }; enet2: ethernet@26000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <2>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x26000 0x1000>; - ranges = <0x0 0x26000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <31 2 32 2 33 2>; - interrupt-parent = <&mpic>; tbi-handle = <&tbi2>; phy-handle = <&phy2>; phy-connection-type = "rgmii-id"; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-tbi"; - reg = <0x520 0x20>; - - tbi2: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; }; - sdhci@2e000 { - compatible = "fsl,p2020-esdhc", "fsl,esdhc"; - reg = <0x2e000 0x1000>; - interrupts = <72 0x2>; - interrupt-parent = <&mpic>; - /* Filled in by U-Boot */ - clock-frequency = <0>; - }; - - crypto@30000 { - compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", - "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <45 2 58 2>; - interrupt-parent = <&mpic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0xbfe>; - fsl,descriptor-types-mask = <0x3ab0ebf>; - }; - - mpic: pic@40000 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; - }; msi@41600 { compatible = "fsl,mpic-msi"; - reg = <0x41600 0x80>; - msi-available-ranges = <0 0x100>; - interrupts = < - 0xe0 0 - 0xe1 0 - 0xe2 0 - 0xe3 0 - 0xe4 0 - 0xe5 0 - 0xe6 0 - 0xe7 0>; - interrupt-parent = <&mpic>; - }; - - global-utilities@e0000 { //global utilities block - compatible = "fsl,p2020-guts"; - reg = <0xe0000 0x1000>; - fsl,has-rstcr; }; }; pci0: pcie@ffe08000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe08000 0 0x1000>; - bus-range = <0 255>; ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <24 2>; interrupt-map-mask = <0xf800 0x0 0x0 0x7>; interrupt-map = < /* IDSEL 0x0 */ @@ -528,18 +230,8 @@ pcie@0 { }; pci1: pcie@ffe09000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe09000 0 0x1000>; - bus-range = <0 255>; ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <25 2>; interrupt-map-mask = <0xff00 0x0 0x0 0x7>; interrupt-map = < @@ -667,18 +359,8 @@ gpio@400 { }; pci2: pcie@ffe0a000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe0a000 0 0x1000>; - bus-range = <0 255>; ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <26 2>; interrupt-map-mask = <0xf800 0x0 0x0 0x7>; interrupt-map = < /* IDSEL 0x0 */ diff --git a/arch/powerpc/boot/dts/p2020rdb.dts b/arch/powerpc/boot/dts/p2020rdb.dts index e2d48fd4416e..3782a58f13be 100644 --- a/arch/powerpc/boot/dts/p2020rdb.dts +++ b/arch/powerpc/boot/dts/p2020rdb.dts @@ -9,12 +9,11 @@ * option) any later version. */ -/dts-v1/; +/include/ "p2020si.dtsi" + / { - model = "fsl,P2020"; + model = "fsl,P2020RDB"; compatible = "fsl,P2020RDB"; - #address-cells = <2>; - #size-cells = <2>; aliases { ethernet0 = &enet0; @@ -26,34 +25,11 @@ aliases { pci1 = &pci1; }; - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,P2020@0 { - device_type = "cpu"; - reg = <0x0>; - next-level-cache = <&L2>; - }; - - PowerPC,P2020@1 { - device_type = "cpu"; - reg = <0x1>; - next-level-cache = <&L2>; - }; - }; - memory { device_type = "memory"; }; localbus@ffe05000 { - #address-cells = <2>; - #size-cells = <1>; - compatible = "fsl,p2020-elbc", "fsl,elbc", "simple-bus"; - reg = <0 0xffe05000 0 0x1000>; - interrupts = <19 2>; - interrupt-parent = <&mpic>; /* NOR and NAND Flashes */ ranges = <0x0 0x0 0x0 0xef000000 0x01000000 @@ -165,90 +141,16 @@ L2switch@2,0 { }; soc@ffe00000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "fsl,p2020-immr", "simple-bus"; - ranges = <0x0 0x0 0xffe00000 0x100000>; - bus-frequency = <0>; // Filled out by uboot. - - ecm-law@0 { - compatible = "fsl,ecm-law"; - reg = <0x0 0x1000>; - fsl,num-laws = <12>; - }; - - ecm@1000 { - compatible = "fsl,p2020-ecm", "fsl,ecm"; - reg = <0x1000 0x1000>; - interrupts = <17 2>; - interrupt-parent = <&mpic>; - }; - - memory-controller@2000 { - compatible = "fsl,p2020-memory-controller"; - reg = <0x2000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <18 2>; - }; - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; rtc@68 { compatible = "dallas,ds1339"; reg = <0x68>; }; }; - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; - }; + spi@7000 { - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - - spi@7000 { - cell-index = <0>; - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,espi"; - reg = <0x7000 0x1000>; - interrupts = <59 0x2>; - interrupt-parent = <&mpic>; - mode = "cpu"; - - fsl_m25p80@0 { + fsl_m25p80@0 { #address-cells = <1>; #size-cells = <1>; compatible = "fsl,espi-flash"; @@ -294,254 +196,68 @@ partition@900000 { }; }; - dma@c300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,eloplus-dma"; - reg = <0xc300 0x4>; - ranges = <0x0 0xc100 0x200>; - cell-index = <1>; - dma-channel@0 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x0 0x80>; - cell-index = <0>; - interrupt-parent = <&mpic>; - interrupts = <76 2>; - }; - dma-channel@80 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&mpic>; - interrupts = <77 2>; - }; - dma-channel@100 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&mpic>; - interrupts = <78 2>; - }; - dma-channel@180 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x180 0x80>; - cell-index = <3>; - interrupt-parent = <&mpic>; - interrupts = <79 2>; - }; - }; - - gpio: gpio-controller@f000 { - #gpio-cells = <2>; - compatible = "fsl,mpc8572-gpio"; - reg = <0xf000 0x100>; - interrupts = <47 0x2>; - interrupt-parent = <&mpic>; - gpio-controller; - }; - - L2: l2-cache-controller@20000 { - compatible = "fsl,p2020-l2-cache-controller"; - reg = <0x20000 0x1000>; - cache-line-size = <32>; // 32 bytes - cache-size = <0x80000>; // L2,512K - interrupt-parent = <&mpic>; - interrupts = <16 2>; - }; - - dma@21300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,eloplus-dma"; - reg = <0x21300 0x4>; - ranges = <0x0 0x21100 0x200>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x0 0x80>; - cell-index = <0>; - interrupt-parent = <&mpic>; - interrupts = <20 2>; - }; - dma-channel@80 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&mpic>; - interrupts = <21 2>; - }; - dma-channel@100 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&mpic>; - interrupts = <22 2>; - }; - dma-channel@180 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x180 0x80>; - cell-index = <3>; - interrupt-parent = <&mpic>; - interrupts = <23 2>; - }; - }; - usb@22000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl-usb2-dr"; - reg = <0x22000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <28 0x2>; phy_type = "ulpi"; }; + mdio@24520 { + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = <3 1>; + reg = <0x0>; + }; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = <3 1>; + reg = <0x1>; + }; + }; + + mdio@25520 { + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + status = "disabled"; + }; + enet0: ethernet@24000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <0>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x24000 0x1000>; - ranges = <0x0 0x24000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <29 2 30 2 34 2>; - interrupt-parent = <&mpic>; fixed-link = <1 1 1000 0 0>; phy-connection-type = "rgmii-id"; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-mdio"; - reg = <0x520 0x20>; - - phy0: ethernet-phy@0 { - interrupt-parent = <&mpic>; - interrupts = <3 1>; - reg = <0x0>; - }; - phy1: ethernet-phy@1 { - interrupt-parent = <&mpic>; - interrupts = <3 1>; - reg = <0x1>; - }; - }; }; enet1: ethernet@25000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x25000 0x1000>; - ranges = <0x0 0x25000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <35 2 36 2 40 2>; - interrupt-parent = <&mpic>; tbi-handle = <&tbi0>; phy-handle = <&phy0>; phy-connection-type = "sgmii"; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-tbi"; - reg = <0x520 0x20>; - - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; }; enet2: ethernet@26000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <2>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x26000 0x1000>; - ranges = <0x0 0x26000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <31 2 32 2 33 2>; - interrupt-parent = <&mpic>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; }; - sdhci@2e000 { - compatible = "fsl,p2020-esdhc", "fsl,esdhc"; - reg = <0x2e000 0x1000>; - interrupts = <72 0x2>; - interrupt-parent = <&mpic>; - /* Filled in by U-Boot */ - clock-frequency = <0>; - }; - - crypto@30000 { - compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", - "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <45 2 58 2>; - interrupt-parent = <&mpic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0xbfe>; - fsl,descriptor-types-mask = <0x3ab0ebf>; - }; - - mpic: pic@40000 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; - }; - - msi@41600 { - compatible = "fsl,p2020-msi", "fsl,mpic-msi"; - reg = <0x41600 0x80>; - msi-available-ranges = <0 0x100>; - interrupts = < - 0xe0 0 - 0xe1 0 - 0xe2 0 - 0xe3 0 - 0xe4 0 - 0xe5 0 - 0xe6 0 - 0xe7 0>; - interrupt-parent = <&mpic>; - }; - - global-utilities@e0000 { //global utilities block - compatible = "fsl,p2020-guts"; - reg = <0xe0000 0x1000>; - fsl,has-rstcr; - }; }; - pci0: pcie@ffe09000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe09000 0 0x1000>; - bus-range = <0 255>; + pci0: pcie@ffe08000 { + status = "disabled"; + }; + + pci1: pcie@ffe09000 { ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <25 2>; - pcie@0 { + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x4 0x1 + 0000 0x0 0x0 0x2 &mpic 0x5 0x1 + 0000 0x0 0x0 0x3 &mpic 0x6 0x1 + 0000 0x0 0x0 0x4 &mpic 0x7 0x1 + >; + pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; #address-cells = <3>; @@ -556,19 +272,17 @@ pcie@0 { }; }; - pci1: pcie@ffe0a000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe0a000 0 0x1000>; - bus-range = <0 255>; + pci2: pcie@ffe0a000 { ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <26 2>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x0 0x1 + 0000 0x0 0x0 0x2 &mpic 0x1 0x1 + 0000 0x0 0x0 0x3 &mpic 0x2 0x1 + 0000 0x0 0x0 0x4 &mpic 0x3 0x1 + >; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts index b69c3a5dc858..fc8ddddfccb6 100644 --- a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts +++ b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts @@ -14,12 +14,11 @@ * option) any later version. */ -/dts-v1/; +/include/ "p2020si.dtsi" + / { - model = "fsl,P2020"; + model = "fsl,P2020RDB"; compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP"; - #address-cells = <2>; - #size-cells = <2>; aliases { ethernet1 = &enet1; @@ -29,91 +28,33 @@ aliases { }; cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,P2020@0 { - device_type = "cpu"; - reg = <0x0>; - next-level-cache = <&L2>; + PowerPC,P2020@1 { + status = "disabled"; }; + }; memory { device_type = "memory"; }; + localbus@ffe05000 { + status = "disabled"; + }; + soc@ffe00000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "fsl,p2020-immr", "simple-bus"; - ranges = <0x0 0x0 0xffe00000 0x100000>; - bus-frequency = <0>; // Filled out by uboot. - - ecm-law@0 { - compatible = "fsl,ecm-law"; - reg = <0x0 0x1000>; - fsl,num-laws = <12>; - }; - - ecm@1000 { - compatible = "fsl,p2020-ecm", "fsl,ecm"; - reg = <0x1000 0x1000>; - interrupts = <17 2>; - interrupt-parent = <&mpic>; - }; - - memory-controller@2000 { - compatible = "fsl,p2020-memory-controller"; - reg = <0x2000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <18 2>; - }; - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; rtc@68 { compatible = "dallas,ds1339"; reg = <0x68>; }; }; - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; + serial1: serial@4600 { + status = "disabled"; }; spi@7000 { - cell-index = <0>; - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,espi"; - reg = <0x7000 0x1000>; - interrupts = <59 0x2>; - interrupt-parent = <&mpic>; - mode = "cpu"; fsl_m25p80@0 { #address-cells = <1>; @@ -161,76 +102,15 @@ partition@900000 { }; }; - gpio: gpio-controller@f000 { - #gpio-cells = <2>; - compatible = "fsl,mpc8572-gpio"; - reg = <0xf000 0x100>; - interrupts = <47 0x2>; - interrupt-parent = <&mpic>; - gpio-controller; - }; - - L2: l2-cache-controller@20000 { - compatible = "fsl,p2020-l2-cache-controller"; - reg = <0x20000 0x1000>; - cache-line-size = <32>; // 32 bytes - cache-size = <0x80000>; // L2,512K - interrupt-parent = <&mpic>; - interrupts = <16 2>; - }; - - dma@21300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,eloplus-dma"; - reg = <0x21300 0x4>; - ranges = <0x0 0x21100 0x200>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x0 0x80>; - cell-index = <0>; - interrupt-parent = <&mpic>; - interrupts = <20 2>; - }; - dma-channel@80 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&mpic>; - interrupts = <21 2>; - }; - dma-channel@100 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&mpic>; - interrupts = <22 2>; - }; - dma-channel@180 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x180 0x80>; - cell-index = <3>; - interrupt-parent = <&mpic>; - interrupts = <23 2>; - }; + dma@c300 { + status = "disabled"; }; usb@22000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl-usb2-dr"; - reg = <0x22000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <28 0x2>; phy_type = "ulpi"; }; mdio@24520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-mdio"; - reg = <0x24520 0x20>; phy0: ethernet-phy@0 { interrupt-parent = <&mpic>; @@ -245,29 +125,21 @@ phy1: ethernet-phy@1 { }; mdio@25520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-tbi"; - reg = <0x26520 0x20>; - tbi0: tbi-phy@11 { reg = <0x11>; device_type = "tbi-phy"; }; }; + mdio@26520 { + status = "disabled"; + }; + + enet0: ethernet@24000 { + status = "disabled"; + }; + enet1: ethernet@25000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x25000 0x1000>; - ranges = <0x0 0x25000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <35 2 36 2 40 2>; - interrupt-parent = <&mpic>; tbi-handle = <&tbi0>; phy-handle = <&phy0>; phy-connection-type = "sgmii"; @@ -275,49 +147,12 @@ enet1: ethernet@25000 { }; enet2: ethernet@26000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <2>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x26000 0x1000>; - ranges = <0x0 0x26000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <31 2 32 2 33 2>; - interrupt-parent = <&mpic>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; }; - sdhci@2e000 { - compatible = "fsl,p2020-esdhc", "fsl,esdhc"; - reg = <0x2e000 0x1000>; - interrupts = <72 0x2>; - interrupt-parent = <&mpic>; - /* Filled in by U-Boot */ - clock-frequency = <0>; - }; - - crypto@30000 { - compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", - "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <45 2 58 2>; - interrupt-parent = <&mpic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0xbfe>; - fsl,descriptor-types-mask = <0x3ab0ebf>; - }; mpic: pic@40000 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; protected-sources = < 42 76 77 78 79 /* serial1 , dma2 */ 29 30 34 26 /* enet0, pci1 */ @@ -326,26 +161,28 @@ mpic: pic@40000 { >; }; - global-utilities@e0000 { - compatible = "fsl,p2020-guts"; - reg = <0xe0000 0x1000>; - fsl,has-rstcr; + msi@41600 { + status = "disabled"; }; + + }; - pci0: pcie@ffe09000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe09000 0 0x1000>; - bus-range = <0 255>; + pci0: pcie@ffe08000 { + status = "disabled"; + }; + + pci1: pcie@ffe09000 { ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <25 2>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x4 0x1 + 0000 0x0 0x0 0x2 &mpic 0x5 0x1 + 0000 0x0 0x0 0x3 &mpic 0x6 0x1 + 0000 0x0 0x0 0x4 &mpic 0x7 0x1 + >; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; @@ -360,4 +197,8 @@ pcie@0 { 0x0 0x100000>; }; }; + + pci2: pcie@ffe0a000 { + status = "disabled"; + }; }; diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts index 7a31d46c01b0..261c34ba45ec 100644 --- a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts +++ b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts @@ -15,27 +15,21 @@ * option) any later version. */ -/dts-v1/; +/include/ "p2020si.dtsi" + / { - model = "fsl,P2020"; + model = "fsl,P2020RDB"; compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP"; - #address-cells = <2>; - #size-cells = <2>; aliases { ethernet0 = &enet0; - serial0 = &serial0; + serial0 = &serial1; pci1 = &pci1; }; cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,P2020@1 { - device_type = "cpu"; - reg = <0x1>; - next-level-cache = <&L2>; + PowerPC,P2020@0 { + status = "disabled"; }; }; @@ -43,20 +37,37 @@ memory { device_type = "memory"; }; - soc@ffe00000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "fsl,p2020-immr", "simple-bus"; - ranges = <0x0 0x0 0xffe00000 0x100000>; - bus-frequency = <0>; // Filled out by uboot. + localbus@ffe05000 { + status = "disabled"; + }; - serial0: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; + soc@ffe00000 { + ecm-law@0 { + status = "disabled"; + }; + + ecm@1000 { + status = "disabled"; + }; + + memory-controller@2000 { + status = "disabled"; + }; + + i2c@3000 { + status = "disabled"; + }; + + i2c@3100 { + status = "disabled"; + }; + + serial0: serial@4500 { + status = "disabled"; + }; + + spi@7000 { + status = "disabled"; }; dma@c300 { @@ -96,6 +107,10 @@ dma-channel@180 { }; }; + gpio: gpio-controller@f000 { + status = "disabled"; + }; + L2: l2-cache-controller@20000 { compatible = "fsl,p2020-l2-cache-controller"; reg = <0x20000 0x1000>; @@ -104,31 +119,49 @@ L2: l2-cache-controller@20000 { interrupt-parent = <&mpic>; }; + dma@21300 { + status = "disabled"; + }; + + usb@22000 { + status = "disabled"; + }; + + mdio@24520 { + status = "disabled"; + }; + + mdio@25520 { + status = "disabled"; + }; + + mdio@26520 { + status = "disabled"; + }; enet0: ethernet@24000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <0>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x24000 0x1000>; - ranges = <0x0 0x24000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <29 2 30 2 34 2>; - interrupt-parent = <&mpic>; fixed-link = <1 1 1000 0 0>; phy-connection-type = "rgmii-id"; }; + enet1: ethernet@25000 { + status = "disabled"; + }; + + enet2: ethernet@26000 { + status = "disabled"; + }; + + sdhci@2e000 { + status = "disabled"; + }; + + crypto@30000 { + status = "disabled"; + }; + mpic: pic@40000 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; protected-sources = < 17 18 43 42 59 47 /*ecm, mem, i2c, serial0, spi,gpio */ 16 20 21 22 23 28 /* L2, dma1, USB */ @@ -152,21 +185,32 @@ msi@41600 { 0xe7 0>; interrupt-parent = <&mpic>; }; + + global-utilities@e0000 { //global utilities block + status = "disabled"; + }; + }; - pci1: pcie@ffe0a000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe0a000 0 0x1000>; - bus-range = <0 255>; + pci0: pcie@ffe08000 { + status = "disabled"; + }; + + pci1: pcie@ffe09000 { + status = "disabled"; + }; + + pci2: pcie@ffe0a000 { ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <26 2>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x0 0x1 + 0000 0x0 0x0 0x2 &mpic 0x1 0x1 + 0000 0x0 0x0 0x3 &mpic 0x2 0x1 + 0000 0x0 0x0 0x4 &mpic 0x3 0x1 + >; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; diff --git a/arch/powerpc/boot/dts/p2020si.dtsi b/arch/powerpc/boot/dts/p2020si.dtsi new file mode 100644 index 000000000000..6def17f265d3 --- /dev/null +++ b/arch/powerpc/boot/dts/p2020si.dtsi @@ -0,0 +1,382 @@ +/* + * P2020 Device Tree Source + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/dts-v1/; +/ { + compatible = "fsl,P2020"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,P2020@0 { + device_type = "cpu"; + reg = <0x0>; + next-level-cache = <&L2>; + }; + + PowerPC,P2020@1 { + device_type = "cpu"; + reg = <0x1>; + next-level-cache = <&L2>; + }; + }; + + localbus@ffe05000 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "fsl,p2020-elbc", "fsl,elbc", "simple-bus"; + reg = <0 0xffe05000 0 0x1000>; + interrupts = <19 2>; + interrupt-parent = <&mpic>; + }; + + soc@ffe00000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + compatible = "fsl,p2020-immr", "simple-bus"; + ranges = <0x0 0x0 0xffe00000 0x100000>; + bus-frequency = <0>; // Filled out by uboot. + + ecm-law@0 { + compatible = "fsl,ecm-law"; + reg = <0x0 0x1000>; + fsl,num-laws = <12>; + }; + + ecm@1000 { + compatible = "fsl,p2020-ecm", "fsl,ecm"; + reg = <0x1000 0x1000>; + interrupts = <17 2>; + interrupt-parent = <&mpic>; + }; + + memory-controller@2000 { + compatible = "fsl,p2020-memory-controller"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <18 2>; + }; + + i2c@3000 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + compatible = "fsl-i2c"; + reg = <0x3000 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + i2c@3100 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <1>; + compatible = "fsl-i2c"; + reg = <0x3100 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + serial0: serial@4500 { + cell-index = <0>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4500 0x100>; + clock-frequency = <0>; + interrupts = <42 2>; + interrupt-parent = <&mpic>; + }; + + serial1: serial@4600 { + cell-index = <1>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4600 0x100>; + clock-frequency = <0>; + interrupts = <42 2>; + interrupt-parent = <&mpic>; + }; + + spi@7000 { + cell-index = <0>; + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,espi"; + reg = <0x7000 0x1000>; + interrupts = <59 0x2>; + interrupt-parent = <&mpic>; + mode = "cpu"; + }; + + dma@c300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,eloplus-dma"; + reg = <0xc300 0x4>; + ranges = <0x0 0xc100 0x200>; + cell-index = <1>; + dma-channel@0 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + cell-index = <0>; + interrupt-parent = <&mpic>; + interrupts = <76 2>; + }; + dma-channel@80 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupt-parent = <&mpic>; + interrupts = <77 2>; + }; + dma-channel@100 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupt-parent = <&mpic>; + interrupts = <78 2>; + }; + dma-channel@180 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupt-parent = <&mpic>; + interrupts = <79 2>; + }; + }; + + gpio: gpio-controller@f000 { + #gpio-cells = <2>; + compatible = "fsl,mpc8572-gpio"; + reg = <0xf000 0x100>; + interrupts = <47 0x2>; + interrupt-parent = <&mpic>; + gpio-controller; + }; + + L2: l2-cache-controller@20000 { + compatible = "fsl,p2020-l2-cache-controller"; + reg = <0x20000 0x1000>; + cache-line-size = <32>; // 32 bytes + cache-size = <0x80000>; // L2,512K + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; + + dma@21300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,eloplus-dma"; + reg = <0x21300 0x4>; + ranges = <0x0 0x21100 0x200>; + cell-index = <0>; + dma-channel@0 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + cell-index = <0>; + interrupt-parent = <&mpic>; + interrupts = <20 2>; + }; + dma-channel@80 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupt-parent = <&mpic>; + interrupts = <21 2>; + }; + dma-channel@100 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupt-parent = <&mpic>; + interrupts = <22 2>; + }; + dma-channel@180 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupt-parent = <&mpic>; + interrupts = <23 2>; + }; + }; + + usb@22000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl-usb2-dr"; + reg = <0x22000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <28 0x2>; + }; + + mdio@24520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-mdio"; + reg = <0x24520 0x20>; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x520 0x20>; + }; + + enet0: ethernet@24000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <0x24000 0x1000>; + ranges = <0x0 0x24000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <29 2 30 2 34 2>; + interrupt-parent = <&mpic>; + }; + + enet1: ethernet@25000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <0x25000 0x1000>; + ranges = <0x0 0x25000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <35 2 36 2 40 2>; + interrupt-parent = <&mpic>; + + }; + + enet2: ethernet@26000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <2>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <0x26000 0x1000>; + ranges = <0x0 0x26000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <31 2 32 2 33 2>; + interrupt-parent = <&mpic>; + + }; + + sdhci@2e000 { + compatible = "fsl,p2020-esdhc", "fsl,esdhc"; + reg = <0x2e000 0x1000>; + interrupts = <72 0x2>; + interrupt-parent = <&mpic>; + /* Filled in by U-Boot */ + clock-frequency = <0>; + }; + + crypto@30000 { + compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", + "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; + reg = <0x30000 0x10000>; + interrupts = <45 2 58 2>; + interrupt-parent = <&mpic>; + fsl,num-channels = <4>; + fsl,channel-fifo-len = <24>; + fsl,exec-units-mask = <0xbfe>; + fsl,descriptor-types-mask = <0x3ab0ebf>; + }; + + mpic: pic@40000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x40000 0x40000>; + compatible = "chrp,open-pic"; + device_type = "open-pic"; + }; + + msi@41600 { + compatible = "fsl,p2020-msi", "fsl,mpic-msi"; + reg = <0x41600 0x80>; + msi-available-ranges = <0 0x100>; + interrupts = < + 0xe0 0 + 0xe1 0 + 0xe2 0 + 0xe3 0 + 0xe4 0 + 0xe5 0 + 0xe6 0 + 0xe7 0>; + interrupt-parent = <&mpic>; + }; + + global-utilities@e0000 { //global utilities block + compatible = "fsl,p2020-guts"; + reg = <0xe0000 0x1000>; + fsl,has-rstcr; + }; + }; + + pci0: pcie@ffe08000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0 0xffe08000 0 0x1000>; + bus-range = <0 255>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <24 2>; + }; + + pci1: pcie@ffe09000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0 0xffe09000 0 0x1000>; + bus-range = <0 255>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <25 2>; + }; + + pci2: pcie@ffe0a000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0 0xffe0a000 0 0x1000>; + bus-range = <0 255>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <26 2>; + }; +}; diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts index 5b7fc29dd6cf..927f94d16e9b 100644 --- a/arch/powerpc/boot/dts/p4080ds.dts +++ b/arch/powerpc/boot/dts/p4080ds.dts @@ -1,7 +1,7 @@ /* * P4080DS Device Tree Source * - * Copyright 2009 Freescale Semiconductor Inc. + * Copyright 2009-2011 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 @@ -33,6 +33,17 @@ aliases { dma1 = &dma1; sdhc = &sdhc; + crypto = &crypto; + sec_jr0 = &sec_jr0; + sec_jr1 = &sec_jr1; + sec_jr2 = &sec_jr2; + sec_jr3 = &sec_jr3; + rtic_a = &rtic_a; + rtic_b = &rtic_b; + rtic_c = &rtic_c; + rtic_d = &rtic_d; + sec_mon = &sec_mon; + rio0 = &rapidio0; }; @@ -410,6 +421,79 @@ usb1: usb@211000 { dr_mode = "host"; phy_type = "ulpi"; }; + + crypto: crypto@300000 { + compatible = "fsl,sec-v4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x300000 0x10000>; + ranges = <0 0x300000 0x10000>; + interrupt-parent = <&mpic>; + interrupts = <92 2>; + + sec_jr0: jr@1000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x1000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <88 2>; + }; + + sec_jr1: jr@2000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <89 2>; + }; + + sec_jr2: jr@3000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x3000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <90 2>; + }; + + sec_jr3: jr@4000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x4000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <91 2>; + }; + + rtic@6000 { + compatible = "fsl,sec-v4.0-rtic"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x6000 0x100>; + ranges = <0x0 0x6100 0xe00>; + + rtic_a: rtic-a@0 { + compatible = "fsl,sec-v4.0-rtic-memory"; + reg = <0x00 0x20 0x100 0x80>; + }; + + rtic_b: rtic-b@20 { + compatible = "fsl,sec-v4.0-rtic-memory"; + reg = <0x20 0x20 0x200 0x80>; + }; + + rtic_c: rtic-c@40 { + compatible = "fsl,sec-v4.0-rtic-memory"; + reg = <0x40 0x20 0x300 0x80>; + }; + + rtic_d: rtic-d@60 { + compatible = "fsl,sec-v4.0-rtic-memory"; + reg = <0x60 0x20 0x500 0x80>; + }; + }; + }; + + sec_mon: sec_mon@314000 { + compatible = "fsl,sec-v4.0-mon"; + reg = <0x314000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <93 2>; + }; }; rapidio0: rapidio@ffe0c0000 { diff --git a/arch/powerpc/boot/epapr.c b/arch/powerpc/boot/epapr.c new file mode 100644 index 000000000000..06c1961bd124 --- /dev/null +++ b/arch/powerpc/boot/epapr.c @@ -0,0 +1,66 @@ +/* + * Bootwrapper for ePAPR compliant firmwares + * + * Copyright 2010 David Gibson , IBM Corporation. + * + * Based on earlier bootwrappers by: + * (c) Benjamin Herrenschmidt , IBM Corp,\ + * and + * Scott Wood + * Copyright (c) 2007 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 version 2 as published + * by the Free Software Foundation. + */ + +#include "ops.h" +#include "stdio.h" +#include "io.h" +#include + +BSS_STACK(4096); + +#define EPAPR_SMAGIC 0x65504150 +#define EPAPR_EMAGIC 0x45504150 + +static unsigned epapr_magic; +static unsigned long ima_size; +static unsigned long fdt_addr; + +static void platform_fixups(void) +{ + if ((epapr_magic != EPAPR_EMAGIC) + && (epapr_magic != EPAPR_SMAGIC)) + fatal("r6 contained 0x%08x instead of ePAPR magic number\n", + epapr_magic); + + if (ima_size < (unsigned long)_end) + printf("WARNING: Image loaded outside IMA!" + " (_end=%p, ima_size=0x%lx)\n", _end, ima_size); + if (ima_size < fdt_addr) + printf("WARNING: Device tree address is outside IMA!" + "(fdt_addr=0x%lx, ima_size=0x%lx)\n", fdt_addr, + ima_size); + if (ima_size < fdt_addr + fdt_totalsize((void *)fdt_addr)) + printf("WARNING: Device tree extends outside IMA!" + " (fdt_addr=0x%lx, size=0x%x, ima_size=0x%lx\n", + fdt_addr, fdt_totalsize((void *)fdt_addr), ima_size); +} + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + epapr_magic = r6; + ima_size = r7; + fdt_addr = r3; + + /* FIXME: we should process reserve entries */ + + simple_alloc_init(_end, ima_size - (unsigned long)_end, 32, 64); + + fdt_init((void *)fdt_addr); + + serial_console_init(); + platform_ops.fixups = platform_fixups; +} diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index cb97e7511d7e..c74531af72c0 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -39,6 +39,7 @@ dts= cacheit= binary= gzip=.gz +pie= # cross-compilation prefix CROSS= @@ -157,9 +158,10 @@ pmac|chrp) platformo=$object/of.o ;; coff) - platformo=$object/of.o + platformo="$object/crt0.o $object/of.o" lds=$object/zImage.coff.lds link_address='0x500000' + pie= ;; miboot|uboot) # miboot and U-boot want just the bare bits, not an ELF binary @@ -208,6 +210,7 @@ ps3) ksection=.kernel:vmlinux.bin isection=.kernel:initrd link_address='' + pie= ;; ep88xc|ep405|ep8248e) platformo="$object/fixed-head.o $object/$platform.o" @@ -244,6 +247,10 @@ gamecube|wii) treeboot-iss4xx-mpic) platformo="$object/treeboot-iss4xx.o" ;; +epapr) + link_address='0x20000000' + pie=-pie + ;; esac vmz="$tmpdir/`basename \"$kernel\"`.$ext" @@ -251,7 +258,7 @@ if [ -z "$cacheit" -o ! -f "$vmz$gzip" -o "$vmz$gzip" -ot "$kernel" ]; then ${CROSS}objcopy $objflags "$kernel" "$vmz.$$" if [ -n "$gzip" ]; then - gzip -f -9 "$vmz.$$" + gzip -n -f -9 "$vmz.$$" fi if [ -n "$cacheit" ]; then @@ -310,9 +317,9 @@ fi if [ "$platform" != "miboot" ]; then if [ -n "$link_address" ] ; then - text_start="-Ttext $link_address --defsym _start=$link_address" + text_start="-Ttext $link_address" fi - ${CROSS}ld -m elf32ppc -T $lds $text_start -o "$ofile" \ + ${CROSS}ld -m elf32ppc -T $lds $text_start $pie -o "$ofile" \ $platformo $tmp $object/wrapper.a rm $tmp fi @@ -336,7 +343,7 @@ coff) $objbin/hack-coff "$ofile" ;; cuboot*) - gzip -f -9 "$ofile" + gzip -n -f -9 "$ofile" ${MKIMAGE} -A ppc -O linux -T kernel -C gzip -a "$base" -e "$entry" \ $uboot_version -d "$ofile".gz "$ofile" ;; @@ -383,6 +390,6 @@ ps3) odir="$(dirname "$ofile.bin")" rm -f "$odir/otheros.bld" - gzip --force -9 --stdout "$ofile.bin" > "$odir/otheros.bld" + gzip -n --force -9 --stdout "$ofile.bin" > "$odir/otheros.bld" ;; esac diff --git a/arch/powerpc/boot/zImage.coff.lds.S b/arch/powerpc/boot/zImage.coff.lds.S index 856dc78b14ef..de4c9e3c9344 100644 --- a/arch/powerpc/boot/zImage.coff.lds.S +++ b/arch/powerpc/boot/zImage.coff.lds.S @@ -3,13 +3,13 @@ ENTRY(_zimage_start_opd) EXTERN(_zimage_start_opd) SECTIONS { - _start = .; .text : { + _start = .; *(.text) *(.fixup) + _etext = .; } - _etext = .; . = ALIGN(4096); .data : { @@ -17,9 +17,7 @@ SECTIONS *(.data*) *(__builtin_*) *(.sdata*) - __got2_start = .; *(.got2) - __got2_end = .; _dtb_start = .; *(.kernel:dtb) diff --git a/arch/powerpc/boot/zImage.lds.S b/arch/powerpc/boot/zImage.lds.S index 0962d62bdb50..2bd8731f1365 100644 --- a/arch/powerpc/boot/zImage.lds.S +++ b/arch/powerpc/boot/zImage.lds.S @@ -3,49 +3,64 @@ ENTRY(_zimage_start) EXTERN(_zimage_start) SECTIONS { - _start = .; .text : { + _start = .; *(.text) *(.fixup) + _etext = .; } - _etext = .; . = ALIGN(4096); .data : { *(.rodata*) *(.data*) *(.sdata*) - __got2_start = .; *(.got2) - __got2_end = .; } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .dynamic : + { + __dynamic_start = .; + *(.dynamic) + } + .hash : { *(.hash) } + .interp : { *(.interp) } + .rela.dyn : { *(.rela*) } . = ALIGN(8); - _dtb_start = .; - .kernel:dtb : { *(.kernel:dtb) } - _dtb_end = .; + .kernel:dtb : + { + _dtb_start = .; + *(.kernel:dtb) + _dtb_end = .; + } . = ALIGN(4096); - _vmlinux_start = .; - .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) } - _vmlinux_end = .; + .kernel:vmlinux.strip : + { + _vmlinux_start = .; + *(.kernel:vmlinux.strip) + _vmlinux_end = .; + } . = ALIGN(4096); - _initrd_start = .; - .kernel:initrd : { *(.kernel:initrd) } - _initrd_end = .; + .kernel:initrd : + { + _initrd_start = .; + *(.kernel:initrd) + _initrd_end = .; + } . = ALIGN(4096); - _edata = .; - - . = ALIGN(4096); - __bss_start = .; .bss : { - *(.sbss) - *(.bss) + _edata = .; + __bss_start = .; + *(.sbss) + *(.bss) + *(COMMON) + _end = . ; } - . = ALIGN(4096); - _end = . ; } diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig index c683bce4c26e..126ef1b08a01 100644 --- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig @@ -104,7 +104,6 @@ CONFIG_ROOT_NFS=y CONFIG_PARTITION_ADVANCED=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig index a721cd3d793f..abcf00ad939e 100644 --- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig @@ -101,7 +101,6 @@ CONFIG_ROOT_NFS=y CONFIG_PARTITION_ADVANCED=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig index 55e0725500dc..11662c217ac0 100644 --- a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig +++ b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig @@ -58,7 +58,6 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_MUTEXES=y -# CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig index d724095530a6..ebe9b30b0721 100644 --- a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig +++ b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig @@ -59,7 +59,6 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_MUTEXES=y -# CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig index 4b44beaa21ae..eb25229b387a 100644 --- a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig +++ b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig @@ -63,7 +63,6 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_MUTEXES=y -# CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig index b614508d6fd2..f51c7ebc181e 100644 --- a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig +++ b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig @@ -168,7 +168,6 @@ CONFIG_MAC_PARTITION=y CONFIG_CRC_T10DIF=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y diff --git a/arch/powerpc/configs/c2k_defconfig b/arch/powerpc/configs/c2k_defconfig index f9e6a3ea5a64..2a84fd7f631c 100644 --- a/arch/powerpc/configs/c2k_defconfig +++ b/arch/powerpc/configs/c2k_defconfig @@ -132,8 +132,8 @@ CONFIG_NET_CLS_RSVP=m CONFIG_NET_CLS_RSVP6=m CONFIG_NET_CLS_IND=y CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m diff --git a/arch/powerpc/configs/e55xx_smp_defconfig b/arch/powerpc/configs/e55xx_smp_defconfig index 9fa1613e5e2b..d32283555b53 100644 --- a/arch/powerpc/configs/e55xx_smp_defconfig +++ b/arch/powerpc/configs/e55xx_smp_defconfig @@ -6,10 +6,10 @@ CONFIG_NR_CPUS=2 CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SPARSE_IRQ=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y @@ -25,8 +25,32 @@ CONFIG_P5020_DS=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=m -CONFIG_SPARSE_IRQ=y # CONFIG_PCI is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_ARPD=y +CONFIG_INET_ESP=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_IPV6=y +CONFIG_IP_SCTP=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y @@ -34,6 +58,9 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 CONFIG_MISC_DEVICES=y CONFIG_EEPROM_LEGACY=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_NET_ETHERNET=y CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set @@ -64,22 +91,14 @@ CONFIG_NLS=y CONFIG_NLS_UTF8=m CONFIG_CRC_T10DIF=y CONFIG_CRC_ITU_T=m -CONFIG_LIBCRC32C=m CONFIG_FRAME_WARN=1024 CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_VIRQ_DEBUG=y -CONFIG_CRYPTO=y -CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_SHA1=m -CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRYPTO_DEV_TALITOS=y diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index c06a86c33098..96b89df7752a 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -204,7 +204,6 @@ CONFIG_CRC_T10DIF=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index 942ced90557c..de65841aa04e 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -206,7 +206,6 @@ CONFIG_CRC_T10DIF=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y diff --git a/arch/powerpc/configs/mpc86xx_defconfig b/arch/powerpc/configs/mpc86xx_defconfig index 038a308cbfc4..a1cc8179e9fd 100644 --- a/arch/powerpc/configs/mpc86xx_defconfig +++ b/arch/powerpc/configs/mpc86xx_defconfig @@ -171,7 +171,6 @@ CONFIG_MAC_PARTITION=y CONFIG_CRC_T10DIF=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig index ac4fc41035f6..f8b394a76ac3 100644 --- a/arch/powerpc/configs/pmac32_defconfig +++ b/arch/powerpc/configs/pmac32_defconfig @@ -112,8 +112,8 @@ CONFIG_IRDA_CACHE_LAST_LSAP=y CONFIG_IRDA_FAST_RR=y CONFIG_IRTTY_SIR=m CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 0a10fb009ef7..214208924a9c 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -351,8 +351,8 @@ CONFIG_VLSI_FIR=m CONFIG_VIA_FIR=m CONFIG_MCS_FIR=m CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig index caba919f65d8..6472322bf13b 100644 --- a/arch/powerpc/configs/ps3_defconfig +++ b/arch/powerpc/configs/ps3_defconfig @@ -52,8 +52,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_INET_DIAG is not set CONFIG_IPV6=y CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 249ddd0a27cd..7de13865508c 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -146,12 +146,18 @@ CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_CXGB3_ISCSI=m +CONFIG_SCSI_CXGB4_ISCSI=m +CONFIG_SCSI_BNX2_ISCSI=m +CONFIG_SCSI_BNX2_ISCSI=m +CONFIG_BE2ISCSI=m CONFIG_SCSI_IBMVSCSI=y CONFIG_SCSI_IBMVFC=m CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 CONFIG_SCSI_IPR=y CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m CONFIG_SCSI_LPFC=m CONFIG_ATA=y # CONFIG_ATA_SFF is not set @@ -197,6 +203,8 @@ CONFIG_S2IO=m CONFIG_MYRI10GE=m CONFIG_NETXEN_NIC=m CONFIG_MLX4_EN=m +CONFIG_QLGE=m +CONFIG_BE2NET=m CONFIG_PPP=m CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m diff --git a/arch/powerpc/include/asm/8xx_immap.h b/arch/powerpc/include/asm/8xx_immap.h index 6b6dc20b0beb..bdf0563ba423 100644 --- a/arch/powerpc/include/asm/8xx_immap.h +++ b/arch/powerpc/include/asm/8xx_immap.h @@ -393,8 +393,8 @@ typedef struct fec { uint fec_addr_low; /* lower 32 bits of station address */ ushort fec_addr_high; /* upper 16 bits of station address */ ushort res1; /* reserved */ - uint fec_hash_table_high; /* upper 32-bits of hash table */ - uint fec_hash_table_low; /* lower 32-bits of hash table */ + uint fec_grp_hash_table_high; /* upper 32-bits of hash table */ + uint fec_grp_hash_table_low; /* lower 32-bits of hash table */ uint fec_r_des_start; /* beginning of Rx descriptor ring */ uint fec_x_des_start; /* beginning of Tx descriptor ring */ uint fec_r_buff_size; /* Rx buffer size */ diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index be3cdf9134ce..c0d842cfd012 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -157,6 +157,7 @@ extern const char *powerpc_base_platform; #define CPU_FTR_476_DD2 ASM_CONST(0x0000000000010000) #define CPU_FTR_NEED_COHERENT ASM_CONST(0x0000000000020000) #define CPU_FTR_NO_BTIC ASM_CONST(0x0000000000040000) +#define CPU_FTR_DEBUG_LVL_EXC ASM_CONST(0x0000000000080000) #define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000000000100000) #define CPU_FTR_PPC_LE ASM_CONST(0x0000000000200000) #define CPU_FTR_REAL_LE ASM_CONST(0x0000000000400000) @@ -178,22 +179,18 @@ extern const char *powerpc_base_platform; #define LONG_ASM_CONST(x) 0 #endif -#define CPU_FTR_SLB LONG_ASM_CONST(0x0000000100000000) -#define CPU_FTR_16M_PAGE LONG_ASM_CONST(0x0000000200000000) -#define CPU_FTR_TLBIEL LONG_ASM_CONST(0x0000000400000000) + +#define CPU_FTR_HVMODE_206 LONG_ASM_CONST(0x0000000800000000) +#define CPU_FTR_CFAR LONG_ASM_CONST(0x0000001000000000) #define CPU_FTR_IABR LONG_ASM_CONST(0x0000002000000000) #define CPU_FTR_MMCRA LONG_ASM_CONST(0x0000004000000000) #define CPU_FTR_CTRL LONG_ASM_CONST(0x0000008000000000) #define CPU_FTR_SMT LONG_ASM_CONST(0x0000010000000000) -#define CPU_FTR_LOCKLESS_TLBIE LONG_ASM_CONST(0x0000040000000000) -#define CPU_FTR_CI_LARGE_PAGE LONG_ASM_CONST(0x0000100000000000) #define CPU_FTR_PAUSE_ZERO LONG_ASM_CONST(0x0000200000000000) #define CPU_FTR_PURR LONG_ASM_CONST(0x0000400000000000) #define CPU_FTR_CELL_TB_BUG LONG_ASM_CONST(0x0000800000000000) #define CPU_FTR_SPURR LONG_ASM_CONST(0x0001000000000000) #define CPU_FTR_DSCR LONG_ASM_CONST(0x0002000000000000) -#define CPU_FTR_1T_SEGMENT LONG_ASM_CONST(0x0004000000000000) -#define CPU_FTR_NO_SLBIE_B LONG_ASM_CONST(0x0008000000000000) #define CPU_FTR_VSX LONG_ASM_CONST(0x0010000000000000) #define CPU_FTR_SAO LONG_ASM_CONST(0x0020000000000000) #define CPU_FTR_CP_USE_DCBTZ LONG_ASM_CONST(0x0040000000000000) @@ -202,12 +199,14 @@ extern const char *powerpc_base_platform; #define CPU_FTR_STCX_CHECKS_ADDRESS LONG_ASM_CONST(0x0200000000000000) #define CPU_FTR_POPCNTB LONG_ASM_CONST(0x0400000000000000) #define CPU_FTR_POPCNTD LONG_ASM_CONST(0x0800000000000000) +#define CPU_FTR_ICSWX LONG_ASM_CONST(0x1000000000000000) #ifndef __ASSEMBLY__ -#define CPU_FTR_PPCAS_ARCH_V2 (CPU_FTR_SLB | \ - CPU_FTR_TLBIEL | CPU_FTR_NOEXECUTE | \ - CPU_FTR_NODSISRALIGN | CPU_FTR_16M_PAGE) +#define CPU_FTR_PPCAS_ARCH_V2 (CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN) + +#define MMU_FTR_PPCAS_ARCH_V2 (MMU_FTR_SLB | MMU_FTR_TLBIEL | \ + MMU_FTR_16M_PAGE) /* We only set the altivec features if the kernel was compiled with altivec * support @@ -382,10 +381,13 @@ extern const char *powerpc_base_platform; #define CPU_FTRS_E500_2 (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \ CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | \ CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE) -#define CPU_FTRS_E500MC (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \ - CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN | \ +#define CPU_FTRS_E500MC (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \ CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ CPU_FTR_DBELL) +#define CPU_FTRS_E5500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \ + CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ + CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ + CPU_FTR_DEBUG_LVL_EXC) #define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) /* 64-bit CPUs */ @@ -405,41 +407,46 @@ extern const char *powerpc_base_platform; #define CPU_FTRS_POWER5 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_MMCRA | CPU_FTR_SMT | \ - CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \ - CPU_FTR_PURR | CPU_FTR_STCX_CHECKS_ADDRESS | \ - CPU_FTR_POPCNTB) + CPU_FTR_COHERENT_ICACHE | CPU_FTR_PURR | \ + CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB) #define CPU_FTRS_POWER6 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_MMCRA | CPU_FTR_SMT | \ - CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \ + CPU_FTR_COHERENT_ICACHE | \ CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD | \ - CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB) + CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_CFAR) #define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_HVMODE_206 |\ CPU_FTR_MMCRA | CPU_FTR_SMT | \ - CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \ + CPU_FTR_COHERENT_ICACHE | \ CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT | \ - CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD) + CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ + CPU_FTR_ICSWX | CPU_FTR_CFAR) #define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ - CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | \ - CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ | \ + CPU_FTR_PAUSE_ZERO | CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ | \ CPU_FTR_UNALIGNED_LD_STD) #define CPU_FTRS_PA6T (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_PPCAS_ARCH_V2 | \ - CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \ - CPU_FTR_PURR | CPU_FTR_REAL_LE | CPU_FTR_NO_SLBIE_B) + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | \ + CPU_FTR_PURR | CPU_FTR_REAL_LE) #define CPU_FTRS_COMPATIBLE (CPU_FTR_USE_TB | CPU_FTR_PPCAS_ARCH_V2) +#define CPU_FTRS_A2 (CPU_FTR_USE_TB | CPU_FTR_SMT | CPU_FTR_DBELL | \ + CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN) + #ifdef __powerpc64__ +#ifdef CONFIG_PPC_BOOK3E +#define CPU_FTRS_POSSIBLE (CPU_FTRS_E5500 | CPU_FTRS_A2) +#else #define CPU_FTRS_POSSIBLE \ (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \ CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 | \ CPU_FTRS_POWER7 | CPU_FTRS_CELL | CPU_FTRS_PA6T | \ - CPU_FTR_1T_SEGMENT | CPU_FTR_VSX) + CPU_FTR_VSX) +#endif #else enum { CPU_FTRS_POSSIBLE = @@ -473,16 +480,21 @@ enum { #endif #ifdef CONFIG_E500 CPU_FTRS_E500 | CPU_FTRS_E500_2 | CPU_FTRS_E500MC | + CPU_FTRS_E5500 | #endif 0, }; #endif /* __powerpc64__ */ #ifdef __powerpc64__ +#ifdef CONFIG_PPC_BOOK3E +#define CPU_FTRS_ALWAYS (CPU_FTRS_E5500 & CPU_FTRS_A2) +#else #define CPU_FTRS_ALWAYS \ (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & \ CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_POWER6 & \ CPU_FTRS_POWER7 & CPU_FTRS_CELL & CPU_FTRS_PA6T & CPU_FTRS_POSSIBLE) +#endif #else enum { CPU_FTRS_ALWAYS = @@ -513,6 +525,7 @@ enum { #endif #ifdef CONFIG_E500 CPU_FTRS_E500 & CPU_FTRS_E500_2 & CPU_FTRS_E500MC & + CPU_FTRS_E5500 & #endif CPU_FTRS_POSSIBLE, }; diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h index f71bb4c118b4..ce516e5eb0d3 100644 --- a/arch/powerpc/include/asm/cputhreads.h +++ b/arch/powerpc/include/asm/cputhreads.h @@ -37,16 +37,16 @@ extern cpumask_t threads_core_mask; * This can typically be used for things like IPI for tlb invalidations * since those need to be done only once per core/TLB */ -static inline cpumask_t cpu_thread_mask_to_cores(cpumask_t threads) +static inline cpumask_t cpu_thread_mask_to_cores(const struct cpumask *threads) { cpumask_t tmp, res; int i; - res = CPU_MASK_NONE; + cpumask_clear(&res); for (i = 0; i < NR_CPUS; i += threads_per_core) { - cpus_shift_left(tmp, threads_core_mask, i); - if (cpus_intersects(threads, tmp)) - cpu_set(i, res); + cpumask_shift_left(&tmp, &threads_core_mask, i); + if (cpumask_intersects(threads, &tmp)) + cpumask_set_cpu(i, &res); } return res; } @@ -58,7 +58,7 @@ static inline int cpu_nr_cores(void) static inline cpumask_t cpu_online_cores_map(void) { - return cpu_thread_mask_to_cores(cpu_online_map); + return cpu_thread_mask_to_cores(cpu_online_mask); } #ifdef CONFIG_SMP diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h index 0893ab9343a6..9c70d0ca96d4 100644 --- a/arch/powerpc/include/asm/dbell.h +++ b/arch/powerpc/include/asm/dbell.h @@ -27,9 +27,8 @@ enum ppc_dbell { PPC_G_DBELL_MC = 4, /* guest mcheck doorbell */ }; -extern void doorbell_message_pass(int target, int msg); +extern void doorbell_cause_ipi(int cpu, unsigned long data); extern void doorbell_exception(struct pt_regs *regs); -extern void doorbell_check_self(void); extern void doorbell_setup_this_cpu(void); static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag) diff --git a/arch/powerpc/include/asm/emulated_ops.h b/arch/powerpc/include/asm/emulated_ops.h index f0fb4fc1f6e6..45921672b97a 100644 --- a/arch/powerpc/include/asm/emulated_ops.h +++ b/arch/powerpc/include/asm/emulated_ops.h @@ -52,6 +52,10 @@ extern struct ppc_emulated { #ifdef CONFIG_VSX struct ppc_emulated_entry vsx; #endif +#ifdef CONFIG_PPC64 + struct ppc_emulated_entry mfdscr; + struct ppc_emulated_entry mtdscr; +#endif } ppc_emulated; extern u32 ppc_warn_emulated; diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 7778d6f0c878..f5dfe3411f64 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -46,6 +46,7 @@ #define EX_CCR 60 #define EX_R3 64 #define EX_LR 72 +#define EX_CFAR 80 /* * We're short on space and time in the exception prolog, so we can't @@ -56,30 +57,40 @@ #define LOAD_HANDLER(reg, label) \ addi reg,reg,(label)-_stext; /* virt addr of handler ... */ -#define EXCEPTION_PROLOG_1(area) \ - mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \ +/* Exception register prefixes */ +#define EXC_HV H +#define EXC_STD + +#define EXCEPTION_PROLOG_1(area) \ + GET_PACA(r13); \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ std r10,area+EX_R10(r13); \ std r11,area+EX_R11(r13); \ std r12,area+EX_R12(r13); \ - mfspr r9,SPRN_SPRG_SCRATCH0; \ + BEGIN_FTR_SECTION_NESTED(66); \ + mfspr r10,SPRN_CFAR; \ + std r10,area+EX_CFAR(r13); \ + END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \ + GET_SCRATCH0(r9); \ std r9,area+EX_R13(r13); \ mfcr r9 -#define EXCEPTION_PROLOG_PSERIES_1(label) \ +#define __EXCEPTION_PROLOG_PSERIES_1(label, h) \ ld r12,PACAKBASE(r13); /* get high part of &label */ \ ld r10,PACAKMSR(r13); /* get MSR value for kernel */ \ - mfspr r11,SPRN_SRR0; /* save SRR0 */ \ + mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \ LOAD_HANDLER(r12,label) \ - mtspr SPRN_SRR0,r12; \ - mfspr r12,SPRN_SRR1; /* and SRR1 */ \ - mtspr SPRN_SRR1,r10; \ - rfid; \ + mtspr SPRN_##h##SRR0,r12; \ + mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \ + mtspr SPRN_##h##SRR1,r10; \ + h##rfid; \ b . /* prevent speculative execution */ +#define EXCEPTION_PROLOG_PSERIES_1(label, h) \ + __EXCEPTION_PROLOG_PSERIES_1(label, h) -#define EXCEPTION_PROLOG_PSERIES(area, label) \ +#define EXCEPTION_PROLOG_PSERIES(area, label, h) \ EXCEPTION_PROLOG_1(area); \ - EXCEPTION_PROLOG_PSERIES_1(label); + EXCEPTION_PROLOG_PSERIES_1(label, h); /* * The common exception prolog is used for all except a few exceptions @@ -98,10 +109,11 @@ beq- 1f; \ ld r1,PACAKSAVE(r13); /* kernel stack to use */ \ 1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \ - bge- cr1,2f; /* abort if it is */ \ - b 3f; \ -2: li r1,(n); /* will be reloaded later */ \ + blt+ cr1,3f; /* abort if it is */ \ + li r1,(n); /* will be reloaded later */ \ sth r1,PACA_TRAP_SAVE(r13); \ + std r3,area+EX_R3(r13); \ + addi r3,r13,area; /* r3 -> where regs are saved*/ \ b bad_stack; \ 3: std r9,_CCR(r1); /* save CR in stackframe */ \ std r11,_NIP(r1); /* save SRR0 in stackframe */ \ @@ -123,6 +135,10 @@ std r9,GPR11(r1); \ std r10,GPR12(r1); \ std r11,GPR13(r1); \ + BEGIN_FTR_SECTION_NESTED(66); \ + ld r10,area+EX_CFAR(r13); \ + std r10,ORIG_GPR3(r1); \ + END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \ ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \ mflr r9; /* save LR in stackframe */ \ std r9,_LINK(r1); \ @@ -143,57 +159,62 @@ /* * Exception vectors. */ -#define STD_EXCEPTION_PSERIES(n, label) \ - . = n; \ +#define STD_EXCEPTION_PSERIES(loc, vec, label) \ + . = loc; \ .globl label##_pSeries; \ label##_pSeries: \ HMT_MEDIUM; \ - DO_KVM n; \ - mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) + DO_KVM vec; \ + SET_SCRATCH0(r13); /* save r13 */ \ + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, EXC_STD) -#define HSTD_EXCEPTION_PSERIES(n, label) \ - . = n; \ - .globl label##_pSeries; \ -label##_pSeries: \ +#define STD_EXCEPTION_HV(loc, vec, label) \ + . = loc; \ + .globl label##_hv; \ +label##_hv: \ HMT_MEDIUM; \ - mtspr SPRN_SPRG_SCRATCH0,r20; /* save r20 */ \ - mfspr r20,SPRN_HSRR0; /* copy HSRR0 to SRR0 */ \ - mtspr SPRN_SRR0,r20; \ - mfspr r20,SPRN_HSRR1; /* copy HSRR0 to SRR0 */ \ - mtspr SPRN_SRR1,r20; \ - mfspr r20,SPRN_SPRG_SCRATCH0; /* restore r20 */ \ - mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) + DO_KVM vec; \ + SET_SCRATCH0(r13); /* save r13 */ \ + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, EXC_HV) - -#define MASKABLE_EXCEPTION_PSERIES(n, label) \ - . = n; \ - .globl label##_pSeries; \ -label##_pSeries: \ +#define __MASKABLE_EXCEPTION_PSERIES(vec, label, h) \ HMT_MEDIUM; \ - DO_KVM n; \ - mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \ + DO_KVM vec; \ + SET_SCRATCH0(r13); /* save r13 */ \ + GET_PACA(r13); \ std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ std r10,PACA_EXGEN+EX_R10(r13); \ lbz r10,PACASOFTIRQEN(r13); \ mfcr r9; \ cmpwi r10,0; \ - beq masked_interrupt; \ - mfspr r10,SPRN_SPRG_SCRATCH0; \ + beq masked_##h##interrupt; \ + GET_SCRATCH0(r10); \ std r10,PACA_EXGEN+EX_R13(r13); \ std r11,PACA_EXGEN+EX_R11(r13); \ std r12,PACA_EXGEN+EX_R12(r13); \ ld r12,PACAKBASE(r13); /* get high part of &label */ \ ld r10,PACAKMSR(r13); /* get MSR value for kernel */ \ - mfspr r11,SPRN_SRR0; /* save SRR0 */ \ + mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \ LOAD_HANDLER(r12,label##_common) \ - mtspr SPRN_SRR0,r12; \ - mfspr r12,SPRN_SRR1; /* and SRR1 */ \ - mtspr SPRN_SRR1,r10; \ - rfid; \ + mtspr SPRN_##h##SRR0,r12; \ + mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \ + mtspr SPRN_##h##SRR1,r10; \ + h##rfid; \ b . /* prevent speculative execution */ +#define _MASKABLE_EXCEPTION_PSERIES(vec, label, h) \ + __MASKABLE_EXCEPTION_PSERIES(vec, label, h) + +#define MASKABLE_EXCEPTION_PSERIES(loc, vec, label) \ + . = loc; \ + .globl label##_pSeries; \ +label##_pSeries: \ + _MASKABLE_EXCEPTION_PSERIES(vec, label, EXC_STD) + +#define MASKABLE_EXCEPTION_HV(loc, vec, label) \ + . = loc; \ + .globl label##_hv; \ +label##_hv: \ + _MASKABLE_EXCEPTION_PSERIES(vec, label, EXC_HV) #ifdef CONFIG_PPC_ISERIES #define DISABLE_INTS \ diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h index 921a8470e18a..9a67a38bf7b9 100644 --- a/arch/powerpc/include/asm/feature-fixups.h +++ b/arch/powerpc/include/asm/feature-fixups.h @@ -49,7 +49,7 @@ label##5: \ FTR_ENTRY_OFFSET label##2b-label##5b; \ FTR_ENTRY_OFFSET label##3b-label##5b; \ FTR_ENTRY_OFFSET label##4b-label##5b; \ - .ifgt (label##4b-label##3b)-(label##2b-label##1b); \ + .ifgt (label##4b- label##3b)-(label##2b- label##1b); \ .error "Feature section else case larger than body"; \ .endif; \ .popsection; @@ -146,6 +146,19 @@ label##5: \ #ifndef __ASSEMBLY__ +#define ASM_FTR_IF(section_if, section_else, msk, val) \ + stringify_in_c(BEGIN_FTR_SECTION) \ + section_if "; " \ + stringify_in_c(FTR_SECTION_ELSE) \ + section_else "; " \ + stringify_in_c(ALT_FTR_SECTION_END((msk), (val))) + +#define ASM_FTR_IFSET(section_if, section_else, msk) \ + ASM_FTR_IF(section_if, section_else, (msk), (msk)) + +#define ASM_FTR_IFCLR(section_if, section_else, msk) \ + ASM_FTR_IF(section_if, section_else, (msk), 0) + #define ASM_MMU_FTR_IF(section_if, section_else, msk, val) \ stringify_in_c(BEGIN_MMU_FTR_SECTION) \ section_if "; " \ diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h index 4ef662e4a31d..3a6c586c4e40 100644 --- a/arch/powerpc/include/asm/firmware.h +++ b/arch/powerpc/include/asm/firmware.h @@ -47,6 +47,7 @@ #define FW_FEATURE_BEAT ASM_CONST(0x0000000001000000) #define FW_FEATURE_CMO ASM_CONST(0x0000000002000000) #define FW_FEATURE_VPHN ASM_CONST(0x0000000004000000) +#define FW_FEATURE_XCMO ASM_CONST(0x0000000008000000) #ifndef __ASSEMBLY__ @@ -60,7 +61,7 @@ enum { FW_FEATURE_VIO | FW_FEATURE_RDMA | FW_FEATURE_LLAN | FW_FEATURE_BULK_REMOVE | FW_FEATURE_XDABR | FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR | - FW_FEATURE_CMO | FW_FEATURE_VPHN, + FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO, FW_FEATURE_PSERIES_ALWAYS = 0, FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index 8edec710cc6d..852b8c1c09db 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -102,6 +102,7 @@ #define H_ANDCOND (1UL<<(63-33)) #define H_ICACHE_INVALIDATE (1UL<<(63-40)) /* icbi, etc. (ignored for IO pages) */ #define H_ICACHE_SYNCHRONIZE (1UL<<(63-41)) /* dcbst, icbi, etc (ignored for IO pages */ +#define H_COALESCE_CAND (1UL<<(63-42)) /* page is a good candidate for coalescing */ #define H_ZERO_PAGE (1UL<<(63-48)) /* zero the page before mapping (ignored for IO pages) */ #define H_COPY_PAGE (1UL<<(63-49)) #define H_N (1UL<<(63-61)) @@ -234,6 +235,7 @@ #define H_GET_MPP 0x2D4 #define H_HOME_NODE_ASSOCIATIVITY 0x2EC #define H_BEST_ENERGY 0x2F4 +#define H_GET_MPP_X 0x314 #define MAX_HCALL_OPCODE H_BEST_ENERGY #ifndef __ASSEMBLY__ @@ -312,6 +314,16 @@ struct hvcall_mpp_data { int h_get_mpp(struct hvcall_mpp_data *); +struct hvcall_mpp_x_data { + unsigned long coalesced_bytes; + unsigned long pool_coalesced_bytes; + unsigned long pool_purr_cycles; + unsigned long pool_spurr_cycles; + unsigned long reserved[3]; +}; + +int h_get_mpp_x(struct hvcall_mpp_x_data *mpp_x_data); + #ifdef CONFIG_PPC_PSERIES extern int CMO_PrPSP; extern int CMO_SecPSP; diff --git a/arch/powerpc/platforms/cell/io-workarounds.h b/arch/powerpc/include/asm/io-workarounds.h similarity index 97% rename from arch/powerpc/platforms/cell/io-workarounds.h rename to arch/powerpc/include/asm/io-workarounds.h index 6efc7782ebf2..fbae49286926 100644 --- a/arch/powerpc/platforms/cell/io-workarounds.h +++ b/arch/powerpc/include/asm/io-workarounds.h @@ -31,7 +31,6 @@ struct iowa_bus { void *private; }; -void __devinit io_workaround_init(void); void __devinit iowa_register_bus(struct pci_controller *, struct ppc_pci_io *, int (*)(struct iowa_bus *, void *), void *); struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR); diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 001f2f11c19b..45698d55cd6a 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -2,6 +2,8 @@ #define _ASM_POWERPC_IO_H #ifdef __KERNEL__ +#define ARCH_HAS_IOREMAP_WC + /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -481,10 +483,16 @@ __do_out_asm(_rec_outl, "stwbrx") _memcpy_fromio(dst,PCI_FIX_ADDR(src),n) #endif /* !CONFIG_EEH */ -#ifdef CONFIG_PPC_INDIRECT_IO -#define DEF_PCI_HOOK(x) x +#ifdef CONFIG_PPC_INDIRECT_PIO +#define DEF_PCI_HOOK_pio(x) x #else -#define DEF_PCI_HOOK(x) NULL +#define DEF_PCI_HOOK_pio(x) NULL +#endif + +#ifdef CONFIG_PPC_INDIRECT_MMIO +#define DEF_PCI_HOOK_mem(x) x +#else +#define DEF_PCI_HOOK_mem(x) NULL #endif /* Structure containing all the hooks */ @@ -504,7 +512,7 @@ extern struct ppc_pci_io { #define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \ static inline ret name at \ { \ - if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL) \ + if (DEF_PCI_HOOK_##space(ppc_pci_io.name) != NULL) \ return ppc_pci_io.name al; \ return __do_##name al; \ } @@ -512,7 +520,7 @@ static inline ret name at \ #define DEF_PCI_AC_NORET(name, at, al, space, aa) \ static inline void name at \ { \ - if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL) \ + if (DEF_PCI_HOOK_##space(ppc_pci_io.name) != NULL) \ ppc_pci_io.name al; \ else \ __do_##name al; \ @@ -616,12 +624,13 @@ static inline void iosync(void) * * ioremap is the standard one and provides non-cacheable guarded mappings * and can be hooked by the platform via ppc_md * - * * ioremap_flags allows to specify the page flags as an argument and can - * also be hooked by the platform via ppc_md. ioremap_prot is the exact - * same thing as ioremap_flags. + * * ioremap_prot allows to specify the page flags as an argument and can + * also be hooked by the platform via ppc_md. * * * ioremap_nocache is identical to ioremap * + * * ioremap_wc enables write combining + * * * iounmap undoes such a mapping and can be hooked * * * __ioremap_at (and the pending __iounmap_at) are low level functions to @@ -629,7 +638,7 @@ static inline void iosync(void) * currently be hooked. Must be page aligned. * * * __ioremap is the low level implementation used by ioremap and - * ioremap_flags and cannot be hooked (but can be used by a hook on one + * ioremap_prot and cannot be hooked (but can be used by a hook on one * of the previous ones) * * * __ioremap_caller is the same as above but takes an explicit caller @@ -640,10 +649,10 @@ static inline void iosync(void) * */ extern void __iomem *ioremap(phys_addr_t address, unsigned long size); -extern void __iomem *ioremap_flags(phys_addr_t address, unsigned long size, - unsigned long flags); +extern void __iomem *ioremap_prot(phys_addr_t address, unsigned long size, + unsigned long flags); +extern void __iomem *ioremap_wc(phys_addr_t address, unsigned long size); #define ioremap_nocache(addr, size) ioremap((addr), (size)) -#define ioremap_prot(addr, size, prot) ioremap_flags((addr), (size), (prot)) extern void iounmap(volatile void __iomem *addr); diff --git a/arch/powerpc/include/asm/io_event_irq.h b/arch/powerpc/include/asm/io_event_irq.h new file mode 100644 index 000000000000..b1a9a1be3c21 --- /dev/null +++ b/arch/powerpc/include/asm/io_event_irq.h @@ -0,0 +1,54 @@ +/* + * Copyright 2010, 2011 Mark Nelson and Tseng-Hui (Frank) Lin, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ASM_POWERPC_IO_EVENT_IRQ_H +#define _ASM_POWERPC_IO_EVENT_IRQ_H + +#include +#include + +#define PSERIES_IOEI_RPC_MAX_LEN 216 + +#define PSERIES_IOEI_TYPE_ERR_DETECTED 0x01 +#define PSERIES_IOEI_TYPE_ERR_RECOVERED 0x02 +#define PSERIES_IOEI_TYPE_EVENT 0x03 +#define PSERIES_IOEI_TYPE_RPC_PASS_THRU 0x04 + +#define PSERIES_IOEI_SUBTYPE_NOT_APP 0x00 +#define PSERIES_IOEI_SUBTYPE_REBALANCE_REQ 0x01 +#define PSERIES_IOEI_SUBTYPE_NODE_ONLINE 0x03 +#define PSERIES_IOEI_SUBTYPE_NODE_OFFLINE 0x04 +#define PSERIES_IOEI_SUBTYPE_DUMP_SIZE_CHANGE 0x05 +#define PSERIES_IOEI_SUBTYPE_TORRENT_IRV_UPDATE 0x06 +#define PSERIES_IOEI_SUBTYPE_TORRENT_HFI_CFGED 0x07 + +#define PSERIES_IOEI_SCOPE_NOT_APP 0x00 +#define PSERIES_IOEI_SCOPE_RIO_HUB 0x36 +#define PSERIES_IOEI_SCOPE_RIO_BRIDGE 0x37 +#define PSERIES_IOEI_SCOPE_PHB 0x38 +#define PSERIES_IOEI_SCOPE_EADS_GLOBAL 0x39 +#define PSERIES_IOEI_SCOPE_EADS_SLOT 0x3A +#define PSERIES_IOEI_SCOPE_TORRENT_HUB 0x3B +#define PSERIES_IOEI_SCOPE_SERVICE_PROC 0x51 + +/* Platform Event Log Format, Version 6, data portition of IO event section */ +struct pseries_io_event { + uint8_t event_type; /* 0x00 IO-Event Type */ + uint8_t rpc_data_len; /* 0x01 RPC data length */ + uint8_t scope; /* 0x02 Error/Event Scope */ + uint8_t event_subtype; /* 0x03 I/O-Event Sub-Type */ + uint32_t drc_index; /* 0x04 DRC Index */ + uint8_t rpc_data[PSERIES_IOEI_RPC_MAX_LEN]; + /* 0x08 RPC Data (0-216 bytes, */ + /* padded to 4 bytes alignment) */ +}; + +extern struct atomic_notifier_head pseries_ioei_notifier_list; + +#endif /* _ASM_POWERPC_IO_EVENT_IRQ_H */ diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index 67ab5fb7d153..1bff591f7f72 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -88,9 +88,6 @@ struct irq_host_ops { /* Dispose of such a mapping */ void (*unmap)(struct irq_host *h, unsigned int virq); - /* Update of such a mapping */ - void (*remap)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw); - /* Translate device-tree interrupt specifier from raw format coming * from the firmware to a irq_hw_number_t (interrupt line number) and * type (sense) that can be passed to set_irq_type(). In the absence @@ -128,19 +125,10 @@ struct irq_host { struct device_node *of_node; }; -/* The main irq map itself is an array of NR_IRQ entries containing the - * associate host and irq number. An entry with a host of NULL is free. - * An entry can be allocated if it's free, the allocator always then sets - * hwirq first to the host's invalid irq number and then fills ops. - */ -struct irq_map_entry { - irq_hw_number_t hwirq; - struct irq_host *host; -}; - -extern struct irq_map_entry irq_map[NR_IRQS]; - +struct irq_data; +extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); extern irq_hw_number_t virq_to_hw(unsigned int virq); +extern bool virq_is_host(unsigned int virq, struct irq_host *host); /** * irq_alloc_host - Allocate a new irq_host data structure diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h index f54408d995b5..8a33698c61bd 100644 --- a/arch/powerpc/include/asm/kexec.h +++ b/arch/powerpc/include/asm/kexec.h @@ -76,7 +76,7 @@ extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)); extern cpumask_t cpus_in_sr; static inline int kexec_sr_activated(int cpu) { - return cpu_isset(cpu,cpus_in_sr); + return cpumask_test_cpu(cpu, &cpus_in_sr); } struct kimage; diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h index 5b7504674397..0951b17f4eb5 100644 --- a/arch/powerpc/include/asm/kvm_asm.h +++ b/arch/powerpc/include/asm/kvm_asm.h @@ -59,6 +59,7 @@ #define BOOK3S_INTERRUPT_INST_SEGMENT 0x480 #define BOOK3S_INTERRUPT_EXTERNAL 0x500 #define BOOK3S_INTERRUPT_EXTERNAL_LEVEL 0x501 +#define BOOK3S_INTERRUPT_EXTERNAL_HV 0x502 #define BOOK3S_INTERRUPT_ALIGNMENT 0x600 #define BOOK3S_INTERRUPT_PROGRAM 0x700 #define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800 diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h b/arch/powerpc/include/asm/kvm_book3s_asm.h index 36fdb3aff30b..d5a8a3861635 100644 --- a/arch/powerpc/include/asm/kvm_book3s_asm.h +++ b/arch/powerpc/include/asm/kvm_book3s_asm.h @@ -34,6 +34,7 @@ (\intno == BOOK3S_INTERRUPT_DATA_SEGMENT) || \ (\intno == BOOK3S_INTERRUPT_INST_SEGMENT) || \ (\intno == BOOK3S_INTERRUPT_EXTERNAL) || \ + (\intno == BOOK3S_INTERRUPT_EXTERNAL_HV) || \ (\intno == BOOK3S_INTERRUPT_ALIGNMENT) || \ (\intno == BOOK3S_INTERRUPT_PROGRAM) || \ (\intno == BOOK3S_INTERRUPT_FP_UNAVAIL) || \ diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h index a077adc0b35e..e0298d26ce5d 100644 --- a/arch/powerpc/include/asm/lppaca.h +++ b/arch/powerpc/include/asm/lppaca.h @@ -210,6 +210,8 @@ struct dtl_entry { #define DISPATCH_LOG_BYTES 4096 /* bytes per cpu */ #define N_DISPATCH_LOG (DISPATCH_LOG_BYTES / sizeof(struct dtl_entry)) +extern struct kmem_cache *dtl_cache; + /* * When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls * reading from the dispatch trace log. If other code wants to consume diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index e4f01915fbb0..47cacddb14cf 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -29,21 +29,6 @@ struct file; struct pci_controller; struct kimage; -#ifdef CONFIG_SMP -struct smp_ops_t { - void (*message_pass)(int target, int msg); - int (*probe)(void); - void (*kick_cpu)(int nr); - void (*setup_cpu)(int nr); - void (*bringup_done)(void); - void (*take_timebase)(void); - void (*give_timebase)(void); - int (*cpu_disable)(void); - void (*cpu_die)(unsigned int nr); - int (*cpu_bootable)(unsigned int nr); -}; -#endif - struct machdep_calls { char *name; #ifdef CONFIG_PPC64 @@ -267,6 +252,7 @@ struct machdep_calls { extern void e500_idle(void); extern void power4_idle(void); +extern void power7_idle(void); extern void ppc6xx_idle(void); extern void book3e_idle(void); @@ -311,12 +297,6 @@ extern sys_ctrler_t sys_ctrler; #endif /* CONFIG_PPC_PMAC */ -#ifdef CONFIG_SMP -/* Poor default implementations */ -extern void __devinit smp_generic_give_timebase(void); -extern void __devinit smp_generic_take_timebase(void); -#endif /* CONFIG_SMP */ - /* Functions to produce codes on the leds. * The SRC code should be unique for the message category and should diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h index 17194fcd4040..3ea0f9a259d8 100644 --- a/arch/powerpc/include/asm/mmu-book3e.h +++ b/arch/powerpc/include/asm/mmu-book3e.h @@ -43,6 +43,7 @@ #define MAS0_TLBSEL(x) (((x) << 28) & 0x30000000) #define MAS0_ESEL(x) (((x) << 16) & 0x0FFF0000) #define MAS0_NV(x) ((x) & 0x00000FFF) +#define MAS0_ESEL_MASK 0x0FFF0000 #define MAS0_HES 0x00004000 #define MAS0_WQ_ALLWAYS 0x00000000 #define MAS0_WQ_COND 0x00001000 @@ -137,6 +138,21 @@ #define MMUCSR0_TLB2PS 0x00078000 /* TLB2 Page Size */ #define MMUCSR0_TLB3PS 0x00780000 /* TLB3 Page Size */ +/* MMUCFG bits */ +#define MMUCFG_MAVN_NASK 0x00000003 +#define MMUCFG_MAVN_V1_0 0x00000000 +#define MMUCFG_MAVN_V2_0 0x00000001 +#define MMUCFG_NTLB_MASK 0x0000000c +#define MMUCFG_NTLB_SHIFT 2 +#define MMUCFG_PIDSIZE_MASK 0x000007c0 +#define MMUCFG_PIDSIZE_SHIFT 6 +#define MMUCFG_TWC 0x00008000 +#define MMUCFG_LRAT 0x00010000 +#define MMUCFG_RASIZE_MASK 0x00fe0000 +#define MMUCFG_RASIZE_SHIFT 17 +#define MMUCFG_LPIDSIZE_MASK 0x0f000000 +#define MMUCFG_LPIDSIZE_SHIFT 24 + /* TLBnCFG encoding */ #define TLBnCFG_N_ENTRY 0x00000fff /* number of entries */ #define TLBnCFG_HES 0x00002000 /* HW select supported */ @@ -229,6 +245,10 @@ extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; extern int mmu_linear_psize; extern int mmu_vmemmap_psize; +#ifdef CONFIG_PPC64 +extern unsigned long linear_map_top; +#endif + #endif /* !__ASSEMBLY__ */ #endif /* _ASM_POWERPC_MMU_BOOK3E_H_ */ diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index ae7b3efec8e5..d865bd909c7d 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h @@ -408,6 +408,7 @@ static inline void subpage_prot_init_new_context(struct mm_struct *mm) { } #endif /* CONFIG_PPC_SUBPAGE_PROT */ typedef unsigned long mm_context_id_t; +struct spinlock; typedef struct { mm_context_id_t id; @@ -423,6 +424,11 @@ typedef struct { #ifdef CONFIG_PPC_SUBPAGE_PROT struct subpage_prot_table spt; #endif /* CONFIG_PPC_SUBPAGE_PROT */ +#ifdef CONFIG_PPC_ICSWX + struct spinlock *cop_lockp; /* guard acop and cop_pid */ + unsigned long acop; /* mask of enabled coprocessor types */ + unsigned int cop_pid; /* pid value used with coprocessors */ +#endif /* CONFIG_PPC_ICSWX */ } mm_context_t; diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index bb40a06d3b77..4138b21ae80a 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -56,11 +56,6 @@ */ #define MMU_FTR_NEED_DTLB_SW_LRU ASM_CONST(0x00200000) -/* This indicates that the processor uses the ISA 2.06 server tlbie - * mnemonics - */ -#define MMU_FTR_TLBIE_206 ASM_CONST(0x00400000) - /* Enable use of TLB reservation. Processor should support tlbsrx. * instruction and MAS0[WQ]. */ @@ -70,6 +65,53 @@ */ #define MMU_FTR_USE_PAIRED_MAS ASM_CONST(0x01000000) +/* MMU is SLB-based + */ +#define MMU_FTR_SLB ASM_CONST(0x02000000) + +/* Support 16M large pages + */ +#define MMU_FTR_16M_PAGE ASM_CONST(0x04000000) + +/* Supports TLBIEL variant + */ +#define MMU_FTR_TLBIEL ASM_CONST(0x08000000) + +/* Supports tlbies w/o locking + */ +#define MMU_FTR_LOCKLESS_TLBIE ASM_CONST(0x10000000) + +/* Large pages can be marked CI + */ +#define MMU_FTR_CI_LARGE_PAGE ASM_CONST(0x20000000) + +/* 1T segments available + */ +#define MMU_FTR_1T_SEGMENT ASM_CONST(0x40000000) + +/* Doesn't support the B bit (1T segment) in SLBIE + */ +#define MMU_FTR_NO_SLBIE_B ASM_CONST(0x80000000) + +/* MMU feature bit sets for various CPUs */ +#define MMU_FTRS_DEFAULT_HPTE_ARCH_V2 \ + MMU_FTR_HPTE_TABLE | MMU_FTR_PPCAS_ARCH_V2 +#define MMU_FTRS_POWER4 MMU_FTRS_DEFAULT_HPTE_ARCH_V2 +#define MMU_FTRS_PPC970 MMU_FTRS_POWER4 +#define MMU_FTRS_POWER5 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE +#define MMU_FTRS_POWER6 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE +#define MMU_FTRS_POWER7 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE +#define MMU_FTRS_CELL MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ + MMU_FTR_CI_LARGE_PAGE +#define MMU_FTRS_PA6T MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ + MMU_FTR_CI_LARGE_PAGE | MMU_FTR_NO_SLBIE_B +#define MMU_FTRS_A2 MMU_FTR_TYPE_3E | MMU_FTR_USE_TLBILX | \ + MMU_FTR_USE_TLBIVAX_BCAST | \ + MMU_FTR_LOCK_BCAST_INVAL | \ + MMU_FTR_USE_TLBRSRV | \ + MMU_FTR_USE_PAIRED_MAS | \ + MMU_FTR_TLBIEL | \ + MMU_FTR_16M_PAGE #ifndef __ASSEMBLY__ #include diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index 81fb41289d6c..a73668a5f30d 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h @@ -32,6 +32,10 @@ extern void __destroy_context(unsigned long context_id); extern void mmu_context_init(void); #endif +extern void switch_cop(struct mm_struct *next); +extern int use_cop(unsigned long acop, struct mm_struct *mm); +extern void drop_cop(unsigned long acop, struct mm_struct *mm); + /* * switch_mm is the entry point called from the architecture independent * code in kernel/sched.c @@ -55,6 +59,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, if (prev == next) return; +#ifdef CONFIG_PPC_ICSWX + /* Switch coprocessor context only if prev or next uses a coprocessor */ + if (prev->context.acop || next->context.acop) + switch_cop(next); +#endif /* CONFIG_PPC_ICSWX */ + /* We must stop all altivec streams before changing the HW * context */ @@ -67,7 +77,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, * sub architectures. */ #ifdef CONFIG_PPC_STD_MMU_64 - if (cpu_has_feature(CPU_FTR_SLB)) + if (mmu_has_feature(MMU_FTR_SLB)) switch_slb(tsk, next); else switch_stab(tsk, next); diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 7005ee0b074d..df18989e78d4 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -3,7 +3,6 @@ #ifdef __KERNEL__ #include -#include #include #include @@ -263,6 +262,7 @@ struct mpic #ifdef CONFIG_SMP struct irq_chip hc_ipi; #endif + struct irq_chip hc_tm; const char *name; /* Flags */ unsigned int flags; @@ -281,7 +281,7 @@ struct mpic /* vector numbers used for internal sources (ipi/timers) */ unsigned int ipi_vecs[4]; - unsigned int timer_vecs[4]; + unsigned int timer_vecs[8]; /* Spurious vector to program into unused sources */ unsigned int spurious_vec; @@ -320,8 +320,6 @@ struct mpic /* link */ struct mpic *next; - struct sys_device sysdev; - #ifdef CONFIG_PM struct mpic_irq_save *save_data; #endif @@ -371,6 +369,8 @@ struct mpic * NOTE: This flag trumps MPIC_WANTS_RESET. */ #define MPIC_NO_RESET 0x00004000 +/* Freescale MPIC (compatible includes "fsl,mpic") */ +#define MPIC_FSL 0x00008000 /* MPIC HW modification ID */ #define MPIC_REGSET_MASK 0xf0000000 diff --git a/arch/powerpc/include/asm/pSeries_reconfig.h b/arch/powerpc/include/asm/pSeries_reconfig.h index d4b4bfa26fb3..89d2f99c1bf4 100644 --- a/arch/powerpc/include/asm/pSeries_reconfig.h +++ b/arch/powerpc/include/asm/pSeries_reconfig.h @@ -18,13 +18,18 @@ extern int pSeries_reconfig_notifier_register(struct notifier_block *); extern void pSeries_reconfig_notifier_unregister(struct notifier_block *); extern struct blocking_notifier_head pSeries_reconfig_chain; +/* Not the best place to put this, will be fixed when we move some + * of the rtas suspend-me stuff to pseries */ +extern void pSeries_coalesce_init(void); #else /* !CONFIG_PPC_PSERIES */ static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb) { return 0; } static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { } +static inline void pSeries_coalesce_init(void) { } #endif /* CONFIG_PPC_PSERIES */ + #endif /* __KERNEL__ */ #endif /* _PPC64_PSERIES_RECONFIG_H */ diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index ec57540cd7af..74126765106a 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -92,9 +92,9 @@ struct paca_struct { * Now, starting in cacheline 2, the exception save areas */ /* used for most interrupts/exceptions */ - u64 exgen[10] __attribute__((aligned(0x80))); - u64 exmc[10]; /* used for machine checks */ - u64 exslb[10]; /* used for SLB/segment table misses + u64 exgen[11] __attribute__((aligned(0x80))); + u64 exmc[11]; /* used for machine checks */ + u64 exslb[11]; /* used for SLB/segment table misses * on the linear mapping */ /* SLB related definitions */ u16 vmalloc_sllp; @@ -106,7 +106,8 @@ struct paca_struct { pgd_t *pgd; /* Current PGD */ pgd_t *kernel_pgd; /* Kernel PGD */ u64 exgen[8] __attribute__((aligned(0x80))); - u64 extlb[EX_TLB_SIZE*3] __attribute__((aligned(0x80))); + /* We can have up to 3 levels of reentrancy in the TLB miss handler */ + u64 extlb[3][EX_TLB_SIZE / sizeof(u64)] __attribute__((aligned(0x80))); u64 exmc[8]; /* used for machine checks */ u64 excrit[8]; /* used for crit interrupts */ u64 exdbg[8]; /* used for debug interrupts */ @@ -125,7 +126,7 @@ struct paca_struct { struct task_struct *__current; /* Pointer to current */ u64 kstack; /* Saved Kernel stack addr */ u64 stab_rr; /* stab/slb round-robin counter */ - u64 saved_r1; /* r1 save for RTAS calls */ + u64 saved_r1; /* r1 save for RTAS calls or PM */ u64 saved_msr; /* MSR saved here by enter_rtas */ u16 trap_save; /* Used when bad stack is encountered */ u8 soft_enabled; /* irq soft-enable flag */ diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h index 812b2cd80aed..9356262fd3cc 100644 --- a/arch/powerpc/include/asm/page_64.h +++ b/arch/powerpc/include/asm/page_64.h @@ -59,24 +59,7 @@ static __inline__ void clear_page(void *addr) : "ctr", "memory"); } -extern void copy_4K_page(void *to, void *from); - -#ifdef CONFIG_PPC_64K_PAGES -static inline void copy_page(void *to, void *from) -{ - unsigned int i; - for (i=0; i < (1 << (PAGE_SHIFT - 12)); i++) { - copy_4K_page(to, from); - to += 4096; - from += 4096; - } -} -#else /* CONFIG_PPC_64K_PAGES */ -static inline void copy_page(void *to, void *from) -{ - copy_4K_page(to, from); -} -#endif /* CONFIG_PPC_64K_PAGES */ +extern void copy_page(void *to, void *from); /* Log 2 of page table size */ extern u64 ppc64_pft_size; @@ -130,7 +113,7 @@ extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize); extern void slice_set_range_psize(struct mm_struct *mm, unsigned long start, unsigned long len, unsigned int psize); -#define slice_mm_new_context(mm) ((mm)->context.id == 0) +#define slice_mm_new_context(mm) ((mm)->context.id == MMU_NO_CONTEXT) #endif /* __ASSEMBLY__ */ #else diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h index 2b09cd522d33..81576ee0cfb1 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64.h +++ b/arch/powerpc/include/asm/pgtable-ppc64.h @@ -257,21 +257,20 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm, static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - unsigned long old; - if ((pte_val(*ptep) & _PAGE_RW) == 0) - return; - old = pte_update(mm, addr, ptep, _PAGE_RW, 0); + if ((pte_val(*ptep) & _PAGE_RW) == 0) + return; + + pte_update(mm, addr, ptep, _PAGE_RW, 0); } static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - unsigned long old; - if ((pte_val(*ptep) & _PAGE_RW) == 0) return; - old = pte_update(mm, addr, ptep, _PAGE_RW, 1); + + pte_update(mm, addr, ptep, _PAGE_RW, 1); } /* diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 1255569387b6..e472659d906c 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -41,6 +41,10 @@ #define PPC_INST_RFCI 0x4c000066 #define PPC_INST_RFDI 0x4c00004e #define PPC_INST_RFMCI 0x4c00004c +#define PPC_INST_MFSPR_DSCR 0x7c1102a6 +#define PPC_INST_MFSPR_DSCR_MASK 0xfc1fffff +#define PPC_INST_MTSPR_DSCR 0x7c1103a6 +#define PPC_INST_MTSPR_DSCR_MASK 0xfc1fffff #define PPC_INST_STRING 0x7c00042a #define PPC_INST_STRING_MASK 0xfc0007fe @@ -56,6 +60,17 @@ #define PPC_INST_TLBSRX_DOT 0x7c0006a5 #define PPC_INST_XXLOR 0xf0000510 +#define PPC_INST_NAP 0x4c000364 +#define PPC_INST_SLEEP 0x4c0003a4 + +/* A2 specific instructions */ +#define PPC_INST_ERATWE 0x7c0001a6 +#define PPC_INST_ERATRE 0x7c000166 +#define PPC_INST_ERATILX 0x7c000066 +#define PPC_INST_ERATIVAX 0x7c000666 +#define PPC_INST_ERATSX 0x7c000126 +#define PPC_INST_ERATSX_DOT 0x7c000127 + /* macros to insert fields into opcodes */ #define __PPC_RA(a) (((a) & 0x1f) << 16) #define __PPC_RB(b) (((b) & 0x1f) << 11) @@ -67,6 +82,8 @@ #define __PPC_XT(s) __PPC_XS(s) #define __PPC_T_TLB(t) (((t) & 0x3) << 21) #define __PPC_WC(w) (((w) & 0x3) << 21) +#define __PPC_WS(w) (((w) & 0x1f) << 11) + /* * Only use the larx hint bit on 64bit CPUs. e500v1/v2 based CPUs will treat a * larx with EH set as an illegal instruction. @@ -113,6 +130,21 @@ #define PPC_TLBIVAX(a,b) stringify_in_c(.long PPC_INST_TLBIVAX | \ __PPC_RA(a) | __PPC_RB(b)) +#define PPC_ERATWE(s, a, w) stringify_in_c(.long PPC_INST_ERATWE | \ + __PPC_RS(s) | __PPC_RA(a) | __PPC_WS(w)) +#define PPC_ERATRE(s, a, w) stringify_in_c(.long PPC_INST_ERATRE | \ + __PPC_RS(s) | __PPC_RA(a) | __PPC_WS(w)) +#define PPC_ERATILX(t, a, b) stringify_in_c(.long PPC_INST_ERATILX | \ + __PPC_T_TLB(t) | __PPC_RA(a) | \ + __PPC_RB(b)) +#define PPC_ERATIVAX(s, a, b) stringify_in_c(.long PPC_INST_ERATIVAX | \ + __PPC_RS(s) | __PPC_RA(a) | __PPC_RB(b)) +#define PPC_ERATSX(t, a, w) stringify_in_c(.long PPC_INST_ERATSX | \ + __PPC_RS(t) | __PPC_RA(a) | __PPC_RB(b)) +#define PPC_ERATSX_DOT(t, a, w) stringify_in_c(.long PPC_INST_ERATSX_DOT | \ + __PPC_RS(t) | __PPC_RA(a) | __PPC_RB(b)) + + /* * Define what the VSX XX1 form instructions will look like, then add * the 128 bit load store instructions based on that. @@ -126,4 +158,7 @@ #define XXLOR(t, a, b) stringify_in_c(.long PPC_INST_XXLOR | \ VSX_XX3((t), (a), (b))) +#define PPC_NAP stringify_in_c(.long PPC_INST_NAP) +#define PPC_SLEEP stringify_in_c(.long PPC_INST_SLEEP) + #endif /* _ASM_POWERPC_PPC_OPCODE_H */ diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index 98210067c1cc..1b422381fc16 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -170,6 +170,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) #define HMT_MEDIUM or 2,2,2 #define HMT_MEDIUM_HIGH or 5,5,5 # medium high priority #define HMT_HIGH or 3,3,3 +#define HMT_EXTRA_HIGH or 7,7,7 # power7 only #ifdef __KERNEL__ #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index de1967a1ff57..d50c2b6d9bc3 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -238,6 +238,10 @@ struct thread_struct { #ifdef CONFIG_KVM_BOOK3S_32_HANDLER void* kvm_shadow_vcpu; /* KVM internal data */ #endif /* CONFIG_KVM_BOOK3S_32_HANDLER */ +#ifdef CONFIG_PPC64 + unsigned long dscr; + int dscr_inherit; +#endif }; #define ARCH_MIN_TASKALIGN 16 diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h index 811f04ac3660..8d1569c29042 100644 --- a/arch/powerpc/include/asm/pte-common.h +++ b/arch/powerpc/include/asm/pte-common.h @@ -162,7 +162,7 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void); * on platforms where such control is possible. */ #if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH) ||\ - defined(CONFIG_KPROBES) + defined(CONFIG_KPROBES) || defined(CONFIG_DYNAMIC_FTRACE) #define PAGE_KERNEL_TEXT PAGE_KERNEL_X #else #define PAGE_KERNEL_TEXT PAGE_KERNEL_ROX diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 7e4abebe76c0..c5cae0dd176c 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -99,17 +99,23 @@ #define MSR_LE __MASK(MSR_LE_LG) /* Little Endian */ #if defined(CONFIG_PPC_BOOK3S_64) +#define MSR_64BIT MSR_SF + /* Server variant */ #define MSR_ MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF |MSR_HV -#define MSR_KERNEL MSR_ | MSR_SF +#define MSR_KERNEL MSR_ | MSR_64BIT #define MSR_USER32 MSR_ | MSR_PR | MSR_EE -#define MSR_USER64 MSR_USER32 | MSR_SF +#define MSR_USER64 MSR_USER32 | MSR_64BIT #elif defined(CONFIG_PPC_BOOK3S_32) || defined(CONFIG_8xx) /* Default MSR for kernel mode. */ #define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR) #define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE) #endif +#ifndef MSR_64BIT +#define MSR_64BIT 0 +#endif + /* Floating Point Status and Control Register (FPSCR) Fields */ #define FPSCR_FX 0x80000000 /* FPU exception summary */ #define FPSCR_FEX 0x40000000 /* FPU enabled exception summary */ @@ -182,6 +188,8 @@ #define SPRN_CTR 0x009 /* Count Register */ #define SPRN_DSCR 0x11 +#define SPRN_CFAR 0x1c /* Come From Address Register */ +#define SPRN_ACOP 0x1F /* Available Coprocessor Register */ #define SPRN_CTRLF 0x088 #define SPRN_CTRLT 0x098 #define CTRL_CT 0xc0000000 /* current thread */ @@ -210,8 +218,43 @@ #define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */ #define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */ #define SPRN_SPURR 0x134 /* Scaled PURR */ +#define SPRN_HSPRG0 0x130 /* Hypervisor Scratch 0 */ +#define SPRN_HSPRG1 0x131 /* Hypervisor Scratch 1 */ +#define SPRN_HDSISR 0x132 +#define SPRN_HDAR 0x133 +#define SPRN_HDEC 0x136 /* Hypervisor Decrementer */ #define SPRN_HIOR 0x137 /* 970 Hypervisor interrupt offset */ +#define SPRN_RMOR 0x138 /* Real mode offset register */ +#define SPRN_HRMOR 0x139 /* Real mode offset register */ +#define SPRN_HSRR0 0x13A /* Hypervisor Save/Restore 0 */ +#define SPRN_HSRR1 0x13B /* Hypervisor Save/Restore 1 */ #define SPRN_LPCR 0x13E /* LPAR Control Register */ +#define LPCR_VPM0 (1ul << (63-0)) +#define LPCR_VPM1 (1ul << (63-1)) +#define LPCR_ISL (1ul << (63-2)) +#define LPCR_DPFD_SH (63-11) +#define LPCR_VRMA_L (1ul << (63-12)) +#define LPCR_VRMA_LP0 (1ul << (63-15)) +#define LPCR_VRMA_LP1 (1ul << (63-16)) +#define LPCR_RMLS 0x1C000000 /* impl dependent rmo limit sel */ +#define LPCR_ILE 0x02000000 /* !HV irqs set MSR:LE */ +#define LPCR_PECE 0x00007000 /* powersave exit cause enable */ +#define LPCR_PECE0 0x00004000 /* ext. exceptions can cause exit */ +#define LPCR_PECE1 0x00002000 /* decrementer can cause exit */ +#define LPCR_PECE2 0x00001000 /* machine check etc can cause exit */ +#define LPCR_MER 0x00000800 /* Mediated External Exception */ +#define LPCR_LPES0 0x00000008 /* LPAR Env selector 0 */ +#define LPCR_LPES1 0x00000004 /* LPAR Env selector 1 */ +#define LPCR_RMI 0x00000002 /* real mode is cache inhibit */ +#define LPCR_HDICE 0x00000001 /* Hyp Decr enable (HV,PR,EE) */ +#define SPRN_LPID 0x13F /* Logical Partition Identifier */ +#define SPRN_HMER 0x150 /* Hardware m? error recovery */ +#define SPRN_HMEER 0x151 /* Hardware m? enable error recovery */ +#define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */ +#define SPRN_TLBINDEXR 0x154 /* P7 TLB control register */ +#define SPRN_TLBVPNR 0x155 /* P7 TLB control register */ +#define SPRN_TLBRPNR 0x156 /* P7 TLB control register */ +#define SPRN_TLBLPIDR 0x157 /* P7 TLB control register */ #define SPRN_DBAT0L 0x219 /* Data BAT 0 Lower Register */ #define SPRN_DBAT0U 0x218 /* Data BAT 0 Upper Register */ #define SPRN_DBAT1L 0x21B /* Data BAT 1 Lower Register */ @@ -434,16 +477,23 @@ #define SPRN_SRR0 0x01A /* Save/Restore Register 0 */ #define SPRN_SRR1 0x01B /* Save/Restore Register 1 */ #define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */ -#define SRR1_WAKERESET 0x00380000 /* System reset */ #define SRR1_WAKESYSERR 0x00300000 /* System error */ #define SRR1_WAKEEE 0x00200000 /* External interrupt */ #define SRR1_WAKEMT 0x00280000 /* mtctrl */ +#define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */ #define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ #define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */ +#define SRR1_WAKERESET 0x00100000 /* System reset */ +#define SRR1_WAKESTATE 0x00030000 /* Powersave exit mask [46:47] */ +#define SRR1_WS_DEEPEST 0x00030000 /* Some resources not maintained, + * may not be recoverable */ +#define SRR1_WS_DEEPER 0x00020000 /* Some resources not maintained */ +#define SRR1_WS_DEEP 0x00010000 /* All resources maintained */ #define SRR1_PROGFPE 0x00100000 /* Floating Point Enabled */ #define SRR1_PROGPRIV 0x00040000 /* Privileged instruction */ #define SRR1_PROGTRAP 0x00020000 /* Trap */ #define SRR1_PROGADDR 0x00010000 /* SRR0 contains subsequent addr */ + #define SPRN_HSRR0 0x13A /* Save/Restore Register 0 */ #define SPRN_HSRR1 0x13B /* Save/Restore Register 1 */ @@ -673,12 +723,15 @@ * SPRG usage: * * All 64-bit: - * - SPRG1 stores PACA pointer + * - SPRG1 stores PACA pointer except 64-bit server in + * HV mode in which case it is HSPRG0 * * 64-bit server: * - SPRG0 unused (reserved for HV on Power4) * - SPRG2 scratch for exception vectors * - SPRG3 unused (user visible) + * - HSPRG0 stores PACA in HV mode + * - HSPRG1 scratch for "HV" exceptions * * 64-bit embedded * - SPRG0 generic exception scratch @@ -741,6 +794,41 @@ #ifdef CONFIG_PPC_BOOK3S_64 #define SPRN_SPRG_SCRATCH0 SPRN_SPRG2 +#define SPRN_SPRG_HPACA SPRN_HSPRG0 +#define SPRN_SPRG_HSCRATCH0 SPRN_HSPRG1 + +#define GET_PACA(rX) \ + BEGIN_FTR_SECTION_NESTED(66); \ + mfspr rX,SPRN_SPRG_PACA; \ + FTR_SECTION_ELSE_NESTED(66); \ + mfspr rX,SPRN_SPRG_HPACA; \ + ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) + +#define SET_PACA(rX) \ + BEGIN_FTR_SECTION_NESTED(66); \ + mtspr SPRN_SPRG_PACA,rX; \ + FTR_SECTION_ELSE_NESTED(66); \ + mtspr SPRN_SPRG_HPACA,rX; \ + ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) + +#define GET_SCRATCH0(rX) \ + BEGIN_FTR_SECTION_NESTED(66); \ + mfspr rX,SPRN_SPRG_SCRATCH0; \ + FTR_SECTION_ELSE_NESTED(66); \ + mfspr rX,SPRN_SPRG_HSCRATCH0; \ + ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) + +#define SET_SCRATCH0(rX) \ + BEGIN_FTR_SECTION_NESTED(66); \ + mtspr SPRN_SPRG_SCRATCH0,rX; \ + FTR_SECTION_ELSE_NESTED(66); \ + mtspr SPRN_SPRG_HSCRATCH0,rX; \ + ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) + +#else /* CONFIG_PPC_BOOK3S_64 */ +#define GET_SCRATCH0(rX) mfspr rX,SPRN_SPRG_SCRATCH0 +#define SET_SCRATCH0(rX) mtspr SPRN_SPRG_SCRATCH0,rX + #endif #ifdef CONFIG_PPC_BOOK3E_64 @@ -750,6 +838,10 @@ #define SPRN_SPRG_TLB_EXFRAME SPRN_SPRG2 #define SPRN_SPRG_TLB_SCRATCH SPRN_SPRG6 #define SPRN_SPRG_GEN_SCRATCH SPRN_SPRG0 + +#define SET_PACA(rX) mtspr SPRN_SPRG_PACA,rX +#define GET_PACA(rX) mfspr rX,SPRN_SPRG_PACA + #endif #ifdef CONFIG_PPC_BOOK3S_32 @@ -800,6 +892,8 @@ #define SPRN_SPRG_SCRATCH1 SPRN_SPRG1 #endif + + /* * An mtfsf instruction with the L bit set. On CPUs that support this a * full 64bits of FPSCR is restored and on other CPUs the L bit is ignored. @@ -894,6 +988,8 @@ #define PV_POWER5p 0x003B #define PV_POWER7 0x003F #define PV_970FX 0x003C +#define PV_POWER6 0x003E +#define PV_POWER7 0x003F #define PV_630 0x0040 #define PV_630p 0x0041 #define PV_970MP 0x0044 diff --git a/arch/powerpc/include/asm/reg_a2.h b/arch/powerpc/include/asm/reg_a2.h new file mode 100644 index 000000000000..3d52a1132f3d --- /dev/null +++ b/arch/powerpc/include/asm/reg_a2.h @@ -0,0 +1,165 @@ +/* + * Register definitions specific to the A2 core + * + * Copyright (C) 2008 Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp. + * + * 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 __ASM_POWERPC_REG_A2_H__ +#define __ASM_POWERPC_REG_A2_H__ + +#define SPRN_TENSR 0x1b5 +#define SPRN_TENS 0x1b6 /* Thread ENable Set */ +#define SPRN_TENC 0x1b7 /* Thread ENable Clear */ + +#define SPRN_A2_CCR0 0x3f0 /* Core Configuration Register 0 */ +#define SPRN_A2_CCR1 0x3f1 /* Core Configuration Register 1 */ +#define SPRN_A2_CCR2 0x3f2 /* Core Configuration Register 2 */ +#define SPRN_MMUCR0 0x3fc /* MMU Control Register 0 */ +#define SPRN_MMUCR1 0x3fd /* MMU Control Register 1 */ +#define SPRN_MMUCR2 0x3fe /* MMU Control Register 2 */ +#define SPRN_MMUCR3 0x3ff /* MMU Control Register 3 */ + +#define SPRN_IAR 0x372 + +#define SPRN_IUCR0 0x3f3 +#define IUCR0_ICBI_ACK 0x1000 + +#define SPRN_XUCR0 0x3f6 /* Execution Unit Config Register 0 */ + +#define A2_IERAT_SIZE 16 +#define A2_DERAT_SIZE 32 + +/* A2 MMUCR0 bits */ +#define MMUCR0_ECL 0x80000000 /* Extended Class for TLB fills */ +#define MMUCR0_TID_NZ 0x40000000 /* TID is non-zero */ +#define MMUCR0_TS 0x10000000 /* Translation space for TLB fills */ +#define MMUCR0_TGS 0x20000000 /* Guest space for TLB fills */ +#define MMUCR0_TLBSEL 0x0c000000 /* TLB or ERAT target for TLB fills */ +#define MMUCR0_TLBSEL_U 0x00000000 /* TLBSEL = UTLB */ +#define MMUCR0_TLBSEL_I 0x08000000 /* TLBSEL = I-ERAT */ +#define MMUCR0_TLBSEL_D 0x0c000000 /* TLBSEL = D-ERAT */ +#define MMUCR0_LOCKSRSH 0x02000000 /* Use TLB lock on tlbsx. */ +#define MMUCR0_TID_MASK 0x000000ff /* TID field */ + +/* A2 MMUCR1 bits */ +#define MMUCR1_IRRE 0x80000000 /* I-ERAT round robin enable */ +#define MMUCR1_DRRE 0x40000000 /* D-ERAT round robin enable */ +#define MMUCR1_REE 0x20000000 /* Reference Exception Enable*/ +#define MMUCR1_CEE 0x10000000 /* Change exception enable */ +#define MMUCR1_CSINV_ALL 0x00000000 /* Inval ERAT on all CS evts */ +#define MMUCR1_CSINV_NISYNC 0x04000000 /* Inval ERAT on all ex isync*/ +#define MMUCR1_CSINV_NEVER 0x0c000000 /* Don't inval ERAT on CS */ +#define MMUCR1_ICTID 0x00080000 /* IERAT class field as TID */ +#define MMUCR1_ITTID 0x00040000 /* IERAT thdid field as TID */ +#define MMUCR1_DCTID 0x00020000 /* DERAT class field as TID */ +#define MMUCR1_DTTID 0x00010000 /* DERAT thdid field as TID */ +#define MMUCR1_DCCD 0x00008000 /* DERAT class ignore */ +#define MMUCR1_TLBWE_BINV 0x00004000 /* back invalidate on tlbwe */ + +/* A2 MMUCR2 bits */ +#define MMUCR2_PSSEL_SHIFT 4 + +/* A2 MMUCR3 bits */ +#define MMUCR3_THID 0x0000000f /* Thread ID */ + +/* *** ERAT TLB bits definitions */ +#define TLB0_EPN_MASK ASM_CONST(0xfffffffffffff000) +#define TLB0_CLASS_MASK ASM_CONST(0x0000000000000c00) +#define TLB0_CLASS_00 ASM_CONST(0x0000000000000000) +#define TLB0_CLASS_01 ASM_CONST(0x0000000000000400) +#define TLB0_CLASS_10 ASM_CONST(0x0000000000000800) +#define TLB0_CLASS_11 ASM_CONST(0x0000000000000c00) +#define TLB0_V ASM_CONST(0x0000000000000200) +#define TLB0_X ASM_CONST(0x0000000000000100) +#define TLB0_SIZE_MASK ASM_CONST(0x00000000000000f0) +#define TLB0_SIZE_4K ASM_CONST(0x0000000000000010) +#define TLB0_SIZE_64K ASM_CONST(0x0000000000000030) +#define TLB0_SIZE_1M ASM_CONST(0x0000000000000050) +#define TLB0_SIZE_16M ASM_CONST(0x0000000000000070) +#define TLB0_SIZE_1G ASM_CONST(0x00000000000000a0) +#define TLB0_THDID_MASK ASM_CONST(0x000000000000000f) +#define TLB0_THDID_0 ASM_CONST(0x0000000000000001) +#define TLB0_THDID_1 ASM_CONST(0x0000000000000002) +#define TLB0_THDID_2 ASM_CONST(0x0000000000000004) +#define TLB0_THDID_3 ASM_CONST(0x0000000000000008) +#define TLB0_THDID_ALL ASM_CONST(0x000000000000000f) + +#define TLB1_RESVATTR ASM_CONST(0x00f0000000000000) +#define TLB1_U0 ASM_CONST(0x0008000000000000) +#define TLB1_U1 ASM_CONST(0x0004000000000000) +#define TLB1_U2 ASM_CONST(0x0002000000000000) +#define TLB1_U3 ASM_CONST(0x0001000000000000) +#define TLB1_R ASM_CONST(0x0000800000000000) +#define TLB1_C ASM_CONST(0x0000400000000000) +#define TLB1_RPN_MASK ASM_CONST(0x000003fffffff000) +#define TLB1_W ASM_CONST(0x0000000000000800) +#define TLB1_I ASM_CONST(0x0000000000000400) +#define TLB1_M ASM_CONST(0x0000000000000200) +#define TLB1_G ASM_CONST(0x0000000000000100) +#define TLB1_E ASM_CONST(0x0000000000000080) +#define TLB1_VF ASM_CONST(0x0000000000000040) +#define TLB1_UX ASM_CONST(0x0000000000000020) +#define TLB1_SX ASM_CONST(0x0000000000000010) +#define TLB1_UW ASM_CONST(0x0000000000000008) +#define TLB1_SW ASM_CONST(0x0000000000000004) +#define TLB1_UR ASM_CONST(0x0000000000000002) +#define TLB1_SR ASM_CONST(0x0000000000000001) + +#ifdef CONFIG_PPC_EARLY_DEBUG_WSP +#define WSP_UART_PHYS 0xffc000c000 +/* This needs to be careful chosen to hit a !0 congruence class + * in the TLB since we bolt it in way 3, which is already occupied + * by our linear mapping primary bolted entry in CC 0. + */ +#define WSP_UART_VIRT 0xf000000000001000 +#endif + +/* A2 erativax attributes definitions */ +#define ERATIVAX_RS_IS_ALL 0x000 +#define ERATIVAX_RS_IS_TID 0x040 +#define ERATIVAX_RS_IS_CLASS 0x080 +#define ERATIVAX_RS_IS_FULLMATCH 0x0c0 +#define ERATIVAX_CLASS_00 0x000 +#define ERATIVAX_CLASS_01 0x010 +#define ERATIVAX_CLASS_10 0x020 +#define ERATIVAX_CLASS_11 0x030 +#define ERATIVAX_PSIZE_4K (TLB_PSIZE_4K >> 1) +#define ERATIVAX_PSIZE_64K (TLB_PSIZE_64K >> 1) +#define ERATIVAX_PSIZE_1M (TLB_PSIZE_1M >> 1) +#define ERATIVAX_PSIZE_16M (TLB_PSIZE_16M >> 1) +#define ERATIVAX_PSIZE_1G (TLB_PSIZE_1G >> 1) + +/* A2 eratilx attributes definitions */ +#define ERATILX_T_ALL 0 +#define ERATILX_T_TID 1 +#define ERATILX_T_TGS 2 +#define ERATILX_T_FULLMATCH 3 +#define ERATILX_T_CLASS0 4 +#define ERATILX_T_CLASS1 5 +#define ERATILX_T_CLASS2 6 +#define ERATILX_T_CLASS3 7 + +/* XUCR0 bits */ +#define XUCR0_TRACE_UM_T0 0x40000000 /* Thread 0 */ +#define XUCR0_TRACE_UM_T1 0x20000000 /* Thread 1 */ +#define XUCR0_TRACE_UM_T2 0x10000000 /* Thread 2 */ +#define XUCR0_TRACE_UM_T3 0x08000000 /* Thread 3 */ + +/* A2 CCR0 register */ +#define A2_CCR0_PME_DISABLED 0x00000000 +#define A2_CCR0_PME_SLEEP 0x40000000 +#define A2_CCR0_PME_RVW 0x80000000 +#define A2_CCR0_PME_DISABLED2 0xc0000000 + +/* A2 CCR2 register */ +#define A2_CCR2_ERAT_ONLY_MODE 0x00000001 +#define A2_CCR2_ENABLE_ICSWX 0x00000002 +#define A2_CCR2_ENABLE_PC 0x20000000 +#define A2_CCR2_ENABLE_TRACE 0x40000000 + +#endif /* __ASM_POWERPC_REG_A2_H__ */ diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index b316794aa2b5..0f0ad9fa01c1 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -27,10 +27,12 @@ #define MSR_CM (1<<31) /* Computation Mode (0=32-bit, 1=64-bit) */ #if defined(CONFIG_PPC_BOOK3E_64) +#define MSR_64BIT MSR_CM + #define MSR_ MSR_ME | MSR_CE -#define MSR_KERNEL MSR_ | MSR_CM +#define MSR_KERNEL MSR_ | MSR_64BIT #define MSR_USER32 MSR_ | MSR_PR | MSR_EE | MSR_DE -#define MSR_USER64 MSR_USER32 | MSR_CM | MSR_DE +#define MSR_USER64 MSR_USER32 | MSR_64BIT #elif defined (CONFIG_40x) #define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE) #define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE) @@ -81,6 +83,10 @@ #define SPRN_IVOR13 0x19D /* Interrupt Vector Offset Register 13 */ #define SPRN_IVOR14 0x19E /* Interrupt Vector Offset Register 14 */ #define SPRN_IVOR15 0x19F /* Interrupt Vector Offset Register 15 */ +#define SPRN_IVOR38 0x1B0 /* Interrupt Vector Offset Register 38 */ +#define SPRN_IVOR39 0x1B1 /* Interrupt Vector Offset Register 39 */ +#define SPRN_IVOR40 0x1B2 /* Interrupt Vector Offset Register 40 */ +#define SPRN_IVOR41 0x1B3 /* Interrupt Vector Offset Register 41 */ #define SPRN_SPEFSCR 0x200 /* SPE & Embedded FP Status & Control */ #define SPRN_BBEAR 0x201 /* Branch Buffer Entry Address Register */ #define SPRN_BBTAR 0x202 /* Branch Buffer Target Address Register */ diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 9a1193e30f26..58625d1e7802 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -158,7 +158,50 @@ struct rtas_error_log { unsigned long target:4; /* Target of failed operation */ unsigned long type:8; /* General event or error*/ unsigned long extended_log_length:32; /* length in bytes */ - unsigned char buffer[1]; + unsigned char buffer[1]; /* Start of extended log */ + /* Variable length. */ +}; + +#define RTAS_V6EXT_LOG_FORMAT_EVENT_LOG 14 + +#define RTAS_V6EXT_COMPANY_ID_IBM (('I' << 24) | ('B' << 16) | ('M' << 8)) + +/* RTAS general extended event log, Version 6. The extended log starts + * from "buffer" field of struct rtas_error_log defined above. + */ +struct rtas_ext_event_log_v6 { + /* Byte 0 */ + uint32_t log_valid:1; /* 1:Log valid */ + uint32_t unrecoverable_error:1; /* 1:Unrecoverable error */ + uint32_t recoverable_error:1; /* 1:recoverable (correctable */ + /* or successfully retried) */ + uint32_t degraded_operation:1; /* 1:Unrecoverable err, bypassed*/ + /* - degraded operation (e.g. */ + /* CPU or mem taken off-line) */ + uint32_t predictive_error:1; + uint32_t new_log:1; /* 1:"New" log (Always 1 for */ + /* data returned from RTAS */ + uint32_t big_endian:1; /* 1: Big endian */ + uint32_t :1; /* reserved */ + /* Byte 1 */ + uint32_t :8; /* reserved */ + /* Byte 2 */ + uint32_t powerpc_format:1; /* Set to 1 (indicating log is */ + /* in PowerPC format */ + uint32_t :3; /* reserved */ + uint32_t log_format:4; /* Log format indicator. Define */ + /* format used for byte 12-2047 */ + /* Byte 3 */ + uint32_t :8; /* reserved */ + /* Byte 4-11 */ + uint8_t reserved[8]; /* reserved */ + /* Byte 12-15 */ + uint32_t company_id; /* Company ID of the company */ + /* that defines the format for */ + /* the vendor specific log type */ + /* Byte 16-end of log */ + uint8_t vendor_log[1]; /* Start of vendor specific log */ + /* Variable length. */ }; /* diff --git a/arch/powerpc/include/asm/scom.h b/arch/powerpc/include/asm/scom.h new file mode 100644 index 000000000000..0cabfd7bc2d1 --- /dev/null +++ b/arch/powerpc/include/asm/scom.h @@ -0,0 +1,156 @@ +/* + * Copyright 2010 Benjamin Herrenschmidt, IBM Corp + * + * and David Gibson, IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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_POWERPC_SCOM_H +#define _ASM_POWERPC_SCOM_H + +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ +#ifdef CONFIG_PPC_SCOM + +/* + * The SCOM bus is a sideband bus used for accessing various internal + * registers of the processor or the chipset. The implementation details + * differ between processors and platforms, and the access method as + * well. + * + * This API allows to "map" ranges of SCOM register numbers associated + * with a given SCOM controller. The later must be represented by a + * device node, though some implementations might support NULL if there + * is no possible ambiguity + * + * Then, scom_read/scom_write can be used to accesses registers inside + * that range. The argument passed is a register number relative to + * the beginning of the range mapped. + */ + +typedef void *scom_map_t; + +/* Value for an invalid SCOM map */ +#define SCOM_MAP_INVALID (NULL) + +/* The scom_controller data structure is what the platform passes + * to the core code in scom_init, it provides the actual implementation + * of all the SCOM functions + */ +struct scom_controller { + scom_map_t (*map)(struct device_node *ctrl_dev, u64 reg, u64 count); + void (*unmap)(scom_map_t map); + + u64 (*read)(scom_map_t map, u32 reg); + void (*write)(scom_map_t map, u32 reg, u64 value); +}; + +extern const struct scom_controller *scom_controller; + +/** + * scom_init - Initialize the SCOM backend, called by the platform + * @controller: The platform SCOM controller + */ +static inline void scom_init(const struct scom_controller *controller) +{ + scom_controller = controller; +} + +/** + * scom_map_ok - Test is a SCOM mapping is successful + * @map: The result of scom_map to test + */ +static inline int scom_map_ok(scom_map_t map) +{ + return map != SCOM_MAP_INVALID; +} + +/** + * scom_map - Map a block of SCOM registers + * @ctrl_dev: Device node of the SCOM controller + * some implementations allow NULL here + * @reg: first SCOM register to map + * @count: Number of SCOM registers to map + */ + +static inline scom_map_t scom_map(struct device_node *ctrl_dev, + u64 reg, u64 count) +{ + return scom_controller->map(ctrl_dev, reg, count); +} + +/** + * scom_find_parent - Find the SCOM controller for a device + * @dev: OF node of the device + * + * This is not meant for general usage, but in combination with + * scom_map() allows to map registers not represented by the + * device own scom-reg property. Useful for applying HW workarounds + * on things not properly represented in the device-tree for example. + */ +struct device_node *scom_find_parent(struct device_node *dev); + + +/** + * scom_map_device - Map a device's block of SCOM registers + * @dev: OF node of the device + * @index: Register bank index (index in "scom-reg" property) + * + * This function will use the device-tree binding for SCOM which + * is to follow "scom-parent" properties until it finds a node with + * a "scom-controller" property to find the controller. It will then + * use the "scom-reg" property which is made of reg/count pairs, + * each of them having a size defined by the controller's #scom-cells + * property + */ +extern scom_map_t scom_map_device(struct device_node *dev, int index); + + +/** + * scom_unmap - Unmap a block of SCOM registers + * @map: Result of scom_map is to be unmapped + */ +static inline void scom_unmap(scom_map_t map) +{ + if (scom_map_ok(map)) + scom_controller->unmap(map); +} + +/** + * scom_read - Read a SCOM register + * @map: Result of scom_map + * @reg: Register index within that map + */ +static inline u64 scom_read(scom_map_t map, u32 reg) +{ + return scom_controller->read(map, reg); +} + +/** + * scom_write - Write to a SCOM register + * @map: Result of scom_map + * @reg: Register index within that map + * @value: Value to write + */ +static inline void scom_write(scom_map_t map, u32 reg, u64 value) +{ + scom_controller->write(map, reg, value); +} + +#endif /* CONFIG_PPC_SCOM */ +#endif /* __ASSEMBLY__ */ +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_SCOM_H */ diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index a902a0d3ae0d..880b8c1e6e53 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -20,6 +20,7 @@ #include #include #include +#include #ifndef __ASSEMBLY__ @@ -29,14 +30,32 @@ #include extern int boot_cpuid; +extern int boot_cpu_count; extern void cpu_die(void); #ifdef CONFIG_SMP -extern void smp_send_debugger_break(int cpu); -extern void smp_message_recv(int); +struct smp_ops_t { + void (*message_pass)(int cpu, int msg); +#ifdef CONFIG_PPC_SMP_MUXED_IPI + void (*cause_ipi)(int cpu, unsigned long data); +#endif + int (*probe)(void); + int (*kick_cpu)(int nr); + void (*setup_cpu)(int nr); + void (*bringup_done)(void); + void (*take_timebase)(void); + void (*give_timebase)(void); + int (*cpu_disable)(void); + void (*cpu_die)(unsigned int nr); + int (*cpu_bootable)(unsigned int nr); +}; + +extern void smp_send_debugger_break(void); extern void start_secondary_resume(void); +extern void __devinit smp_generic_give_timebase(void); +extern void __devinit smp_generic_take_timebase(void); DECLARE_PER_CPU(unsigned int, cpu_pvr); @@ -93,13 +112,16 @@ extern int cpu_to_core_id(int cpu); #define PPC_MSG_CALL_FUNC_SINGLE 2 #define PPC_MSG_DEBUGGER_BREAK 3 -/* - * irq controllers that have dedicated ipis per message and don't - * need additional code in the action handler may use this - */ +/* for irq controllers that have dedicated ipis per message (4) */ extern int smp_request_message_ipi(int virq, int message); extern const char *smp_ipi_name[]; +/* for irq controllers with only a single ipi */ +extern void smp_muxed_ipi_set_data(int cpu, unsigned long data); +extern void smp_muxed_ipi_message_pass(int cpu, int msg); +extern void smp_muxed_ipi_resend(void); +extern irqreturn_t smp_ipi_demux(void); + void smp_init_iSeries(void); void smp_init_pSeries(void); void smp_init_cell(void); @@ -149,7 +171,7 @@ extern int smt_enabled_at_boot; extern int smp_mpic_probe(void); extern void smp_mpic_setup_cpu(int cpu); -extern void smp_generic_kick_cpu(int nr); +extern int smp_generic_kick_cpu(int nr); extern void smp_generic_give_timebase(void); extern void smp_generic_take_timebase(void); @@ -169,6 +191,8 @@ extern unsigned long __secondary_hold_spinloop; extern unsigned long __secondary_hold_acknowledge; extern char __secondary_hold; +extern irqreturn_t debug_ipi_action(int irq, void *data); + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index 60f64b132bd4..8489d372077f 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -352,3 +352,4 @@ SYSCALL_SPU(name_to_handle_at) COMPAT_SYS_SPU(open_by_handle_at) COMPAT_SYS_SPU(clock_adjtime) SYSCALL_SPU(syncfs) +COMPAT_SYS_SPU(sendmmsg) diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h index 5e474ddd2273..2dc595dda03b 100644 --- a/arch/powerpc/include/asm/system.h +++ b/arch/powerpc/include/asm/system.h @@ -219,8 +219,6 @@ extern int mem_init_done; /* set on boot once kmalloc can be called */ extern int init_bootmem_done; /* set once bootmem is available */ extern phys_addr_t memory_limit; extern unsigned long klimit; - -extern void *alloc_maybe_bootmem(size_t size, gfp_t mask); extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask); extern int powersave_nap; /* set if nap mode can be used in idle loop */ diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h index d50a380b2b6f..81143fcbd113 100644 --- a/arch/powerpc/include/asm/tlbflush.h +++ b/arch/powerpc/include/asm/tlbflush.h @@ -79,6 +79,8 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm) #elif defined(CONFIG_PPC_STD_MMU_64) +#define MMU_NO_CONTEXT 0 + /* * TLB flushing for 64-bit hash-MMU CPUs */ diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h index 11ae699135ba..58580e94a2bb 100644 --- a/arch/powerpc/include/asm/udbg.h +++ b/arch/powerpc/include/asm/udbg.h @@ -52,6 +52,7 @@ extern void __init udbg_init_44x_as1(void); extern void __init udbg_init_40x_realmode(void); extern void __init udbg_init_cpm(void); extern void __init udbg_init_usbgecko(void); +extern void __init udbg_init_wsp(void); #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_UDBG_H */ diff --git a/arch/powerpc/include/asm/uninorth.h b/arch/powerpc/include/asm/uninorth.h index ae9c899c8a6d..d12b11d7641e 100644 --- a/arch/powerpc/include/asm/uninorth.h +++ b/arch/powerpc/include/asm/uninorth.h @@ -60,7 +60,7 @@ * * Obviously, the GART is not cache coherent and so any change to it * must be flushed to memory (or maybe just make the GART space non - * cachable). AGP memory itself does't seem to be cache coherent neither. + * cachable). AGP memory itself doesn't seem to be cache coherent neither. * * In order to invalidate the GART (which is probably necessary to inval * the bridge internal TLBs), the following sequence has to be written, diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index 3c215648ce6d..6d23c8193caa 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -371,10 +371,11 @@ #define __NR_open_by_handle_at 346 #define __NR_clock_adjtime 347 #define __NR_syncfs 348 +#define __NR_sendmmsg 349 #ifdef __KERNEL__ -#define __NR_syscalls 349 +#define __NR_syscalls 350 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls diff --git a/arch/powerpc/include/asm/wsp.h b/arch/powerpc/include/asm/wsp.h new file mode 100644 index 000000000000..c7dc83088a33 --- /dev/null +++ b/arch/powerpc/include/asm/wsp.h @@ -0,0 +1,14 @@ +/* + * Copyright 2011 Michael Ellerman, IBM Corp. + * + * 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 __ASM_POWERPC_WSP_H +#define __ASM_POWERPC_WSP_H + +extern int wsp_get_chip_id(struct device_node *dn); + +#endif /* __ASM_POWERPC_WSP_H */ diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h new file mode 100644 index 000000000000..b183a4062011 --- /dev/null +++ b/arch/powerpc/include/asm/xics.h @@ -0,0 +1,142 @@ +/* + * Common definitions accross all variants of ICP and ICS interrupt + * controllers. + */ + +#ifndef _XICS_H +#define _XICS_H + +#include + +#define XICS_IPI 2 +#define XICS_IRQ_SPURIOUS 0 + +/* Want a priority other than 0. Various HW issues require this. */ +#define DEFAULT_PRIORITY 5 + +/* + * Mark IPIs as higher priority so we can take them inside interrupts that + * arent marked IRQF_DISABLED + */ +#define IPI_PRIORITY 4 + +/* The least favored priority */ +#define LOWEST_PRIORITY 0xFF + +/* The number of priorities defined above */ +#define MAX_NUM_PRIORITIES 3 + +/* Native ICP */ +extern int icp_native_init(void); + +/* PAPR ICP */ +extern int icp_hv_init(void); + +/* ICP ops */ +struct icp_ops { + unsigned int (*get_irq)(void); + void (*eoi)(struct irq_data *d); + void (*set_priority)(unsigned char prio); + void (*teardown_cpu)(void); + void (*flush_ipi)(void); +#ifdef CONFIG_SMP + void (*cause_ipi)(int cpu, unsigned long data); + irq_handler_t ipi_action; +#endif +}; + +extern const struct icp_ops *icp_ops; + +/* Native ICS */ +extern int ics_native_init(void); + +/* RTAS ICS */ +extern int ics_rtas_init(void); + +/* ICS instance, hooked up to chip_data of an irq */ +struct ics { + struct list_head link; + int (*map)(struct ics *ics, unsigned int virq); + void (*mask_unknown)(struct ics *ics, unsigned long vec); + long (*get_server)(struct ics *ics, unsigned long vec); + int (*host_match)(struct ics *ics, struct device_node *node); + char data[]; +}; + +/* Commons */ +extern unsigned int xics_default_server; +extern unsigned int xics_default_distrib_server; +extern unsigned int xics_interrupt_server_size; +extern struct irq_host *xics_host; + +struct xics_cppr { + unsigned char stack[MAX_NUM_PRIORITIES]; + int index; +}; + +DECLARE_PER_CPU(struct xics_cppr, xics_cppr); + +static inline void xics_push_cppr(unsigned int vec) +{ + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + + if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1)) + return; + + if (vec == XICS_IPI) + os_cppr->stack[++os_cppr->index] = IPI_PRIORITY; + else + os_cppr->stack[++os_cppr->index] = DEFAULT_PRIORITY; +} + +static inline unsigned char xics_pop_cppr(void) +{ + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + + if (WARN_ON(os_cppr->index < 1)) + return LOWEST_PRIORITY; + + return os_cppr->stack[--os_cppr->index]; +} + +static inline void xics_set_base_cppr(unsigned char cppr) +{ + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + + /* we only really want to set the priority when there's + * just one cppr value on the stack + */ + WARN_ON(os_cppr->index != 0); + + os_cppr->stack[0] = cppr; +} + +static inline unsigned char xics_cppr_top(void) +{ + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + + return os_cppr->stack[os_cppr->index]; +} + +DECLARE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message); + +extern void xics_init(void); +extern void xics_setup_cpu(void); +extern void xics_update_irq_servers(void); +extern void xics_set_cpu_giq(unsigned int gserver, unsigned int join); +extern void xics_mask_unknown_vec(unsigned int vec); +extern irqreturn_t xics_ipi_dispatch(int cpu); +extern int xics_smp_probe(void); +extern void xics_register_ics(struct ics *ics); +extern void xics_teardown_cpu(void); +extern void xics_kexec_teardown_cpu(int secondary); +extern void xics_migrate_irqs_away(void); +#ifdef CONFIG_SMP +extern int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask, + unsigned int strict_check); +#else +#define xics_get_irq_server(virq, cpumask, strict_check) (xics_default_server) +#endif + + +#endif /* _XICS_H */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 3bb2a3e6a337..9aab36312572 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -38,11 +38,14 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ paca.o nvram_64.o firmware.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o +obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power7.o obj64-$(CONFIG_RELOCATABLE) += reloc_64.o obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o +obj-$(CONFIG_PPC_A2) += cpu_setup_a2.o obj-$(CONFIG_PPC64) += vdso64/ obj-$(CONFIG_ALTIVEC) += vecemu.o obj-$(CONFIG_PPC_970_NAP) += idle_power4.o +obj-$(CONFIG_PPC_P7_NAP) += idle_power7.o obj-$(CONFIG_PPC_OF) += of_platform.o prom_parse.o obj-$(CONFIG_PPC_CLOCK) += clock.o procfs-y := proc_powerpc.o @@ -75,7 +78,6 @@ obj-$(CONFIG_PPC_FSL_BOOK3E) += cpu_setup_fsl_booke.o dbell.o obj-$(CONFIG_PPC_BOOK3E_64) += dbell.o extra-y := head_$(CONFIG_WORD_SIZE).o -extra-$(CONFIG_PPC_BOOK3E_32) := head_new_booke.o extra-$(CONFIG_40x) := head_40x.o extra-$(CONFIG_44x) := head_44x.o extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o @@ -103,6 +105,8 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o \ obj-$(CONFIG_AUDIT) += audit.o obj64-$(CONFIG_AUDIT) += compat_audit.o +obj-$(CONFIG_PPC_IO_WORKAROUNDS) += io-workarounds.o + obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 23e6a93145ab..6887661ac072 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -74,6 +74,7 @@ int main(void) DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); DEFINE(SIGSEGV, SIGSEGV); DEFINE(NMI_MASK, NMI_MASK); + DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr)); #else DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); #endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/kernel/cpu_setup_a2.S b/arch/powerpc/kernel/cpu_setup_a2.S new file mode 100644 index 000000000000..7f818feaa7a5 --- /dev/null +++ b/arch/powerpc/kernel/cpu_setup_a2.S @@ -0,0 +1,114 @@ +/* + * A2 specific assembly support code + * + * Copyright 2009 Ben Herrenschmidt, IBM Corp. + * + * 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 + +/* + * Disable thdid and class fields in ERATs to bump PID to full 14 bits capacity. + * This also prevents external LPID accesses but that isn't a problem when not a + * guest. Under PV, this setting will be ignored and MMUCR will return the right + * number of PID bits we can use. + */ +#define MMUCR1_EXTEND_PID \ + (MMUCR1_ICTID | MMUCR1_ITTID | MMUCR1_DCTID | \ + MMUCR1_DTTID | MMUCR1_DCCD) + +/* + * Use extended PIDs if enabled. + * Don't clear the ERATs on context sync events and enable I & D LRU. + * Enable ERAT back invalidate when tlbwe overwrites an entry. + */ +#define INITIAL_MMUCR1 \ + (MMUCR1_EXTEND_PID | MMUCR1_CSINV_NEVER | MMUCR1_IRRE | \ + MMUCR1_DRRE | MMUCR1_TLBWE_BINV) + +_GLOBAL(__setup_cpu_a2) + /* Some of these are actually thread local and some are + * core local but doing it always won't hurt + */ + +#ifdef CONFIG_PPC_WSP_COPRO + /* Make sure ACOP starts out as zero */ + li r3,0 + mtspr SPRN_ACOP,r3 + + /* Enable icswx instruction */ + mfspr r3,SPRN_A2_CCR2 + ori r3,r3,A2_CCR2_ENABLE_ICSWX + mtspr SPRN_A2_CCR2,r3 + + /* Unmask all CTs in HACOP */ + li r3,-1 + mtspr SPRN_HACOP,r3 +#endif /* CONFIG_PPC_WSP_COPRO */ + + /* Enable doorbell */ + mfspr r3,SPRN_A2_CCR2 + oris r3,r3,A2_CCR2_ENABLE_PC@h + mtspr SPRN_A2_CCR2,r3 + isync + + /* Setup CCR0 to disable power saving for now as it's busted + * in the current implementations. Setup CCR1 to wake on + * interrupts normally (we write the default value but who + * knows what FW may have clobbered...) + */ + li r3,0 + mtspr SPRN_A2_CCR0, r3 + LOAD_REG_IMMEDIATE(r3,0x0f0f0f0f) + mtspr SPRN_A2_CCR1, r3 + + /* Initialise MMUCR1 */ + lis r3,INITIAL_MMUCR1@h + ori r3,r3,INITIAL_MMUCR1@l + mtspr SPRN_MMUCR1,r3 + + /* Set MMUCR2 to enable 4K, 64K, 1M, 16M and 1G pages */ + LOAD_REG_IMMEDIATE(r3, 0x000a7531) + mtspr SPRN_MMUCR2,r3 + + /* Set MMUCR3 to write all thids bit to the TLB */ + LOAD_REG_IMMEDIATE(r3, 0x0000000f) + mtspr SPRN_MMUCR3,r3 + + /* Don't do ERAT stuff if running guest mode */ + mfmsr r3 + andis. r0,r3,MSR_GS@h + bne 1f + + /* Now set the I-ERAT watermark to 15 */ + lis r4,(MMUCR0_TLBSEL_I|MMUCR0_ECL)@h + mtspr SPRN_MMUCR0, r4 + li r4,A2_IERAT_SIZE-1 + PPC_ERATWE(r4,r4,3) + + /* Now set the D-ERAT watermark to 31 */ + lis r4,(MMUCR0_TLBSEL_D|MMUCR0_ECL)@h + mtspr SPRN_MMUCR0, r4 + li r4,A2_DERAT_SIZE-1 + PPC_ERATWE(r4,r4,3) + + /* And invalidate the beast just in case. That won't get rid of + * a bolted entry though it will be in LRU and so will go away eventually + * but let's not bother for now + */ + PPC_ERATILX(0,0,0) +1: + blr + +_GLOBAL(__restore_cpu_a2) + b __setup_cpu_a2 diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S index 913611105c1f..8053db02b85e 100644 --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S @@ -88,6 +88,9 @@ _GLOBAL(__setup_cpu_e5500) bl __e500_dcache_setup #ifdef CONFIG_PPC_BOOK3E_64 bl .__setup_base_ivors + bl .setup_perfmon_ivor + bl .setup_doorbell_ivors + bl .setup_ehv_ivors #else bl __setup_e500mc_ivors #endif diff --git a/arch/powerpc/kernel/cpu_setup_power7.S b/arch/powerpc/kernel/cpu_setup_power7.S new file mode 100644 index 000000000000..4f9a93fcfe07 --- /dev/null +++ b/arch/powerpc/kernel/cpu_setup_power7.S @@ -0,0 +1,91 @@ +/* + * This file contains low level CPU setup functions. + * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * 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 + +/* Entry: r3 = crap, r4 = ptr to cputable entry + * + * Note that we can be called twice for pseudo-PVRs + */ +_GLOBAL(__setup_cpu_power7) + mflr r11 + bl __init_hvmode_206 + mtlr r11 + beqlr + li r0,0 + mtspr SPRN_LPID,r0 + bl __init_LPCR + bl __init_TLB + mtlr r11 + blr + +_GLOBAL(__restore_cpu_power7) + mflr r11 + mfmsr r3 + rldicl. r0,r3,4,63 + beqlr + li r0,0 + mtspr SPRN_LPID,r0 + bl __init_LPCR + bl __init_TLB + mtlr r11 + blr + +__init_hvmode_206: + /* Disable CPU_FTR_HVMODE_206 and exit if MSR:HV is not set */ + mfmsr r3 + rldicl. r0,r3,4,63 + bnelr + ld r5,CPU_SPEC_FEATURES(r4) + LOAD_REG_IMMEDIATE(r6,CPU_FTR_HVMODE_206) + xor r5,r5,r6 + std r5,CPU_SPEC_FEATURES(r4) + blr + +__init_LPCR: + /* Setup a sane LPCR: + * + * LPES = 0b01 (HSRR0/1 used for 0x500) + * PECE = 0b111 + * DPFD = 4 + * + * Other bits untouched for now + */ + mfspr r3,SPRN_LPCR + ori r3,r3,(LPCR_LPES0|LPCR_LPES1) + xori r3,r3, LPCR_LPES0 + ori r3,r3,(LPCR_PECE0|LPCR_PECE1|LPCR_PECE2) + li r5,7 + sldi r5,r5,LPCR_DPFD_SH + andc r3,r3,r5 + li r5,4 + sldi r5,r5,LPCR_DPFD_SH + or r3,r3,r5 + mtspr SPRN_LPCR,r3 + isync + blr + +__init_TLB: + /* Clear the TLB */ + li r6,128 + mtctr r6 + li r7,0xc00 /* IS field = 0b11 */ + ptesync +2: tlbiel r7 + addi r7,r7,0x1000 + bdnz 2b + ptesync +1: blr diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index c9b68d07ac4f..34d2722b9451 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -62,10 +62,12 @@ extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_ppc970MP(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_pa6t(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_a2(unsigned long offset, struct cpu_spec* spec); extern void __restore_cpu_pa6t(void); extern void __restore_cpu_ppc970(void); extern void __setup_cpu_power7(unsigned long offset, struct cpu_spec* spec); extern void __restore_cpu_power7(void); +extern void __restore_cpu_a2(void); #endif /* CONFIG_PPC64 */ #if defined(CONFIG_E500) extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec); @@ -199,7 +201,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER4 (gp)", .cpu_features = CPU_FTRS_POWER4, .cpu_user_features = COMMON_USER_POWER4, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER4, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -214,7 +216,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER4+ (gq)", .cpu_features = CPU_FTRS_POWER4, .cpu_user_features = COMMON_USER_POWER4, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER4, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -230,7 +232,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_PPC970, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -248,7 +250,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_PPC970, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -284,7 +286,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_PPC970, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -302,7 +304,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_PPC970, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -318,7 +320,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER5 (gr)", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER5, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -338,7 +340,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER5+ (gs)", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5_PLUS, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER5, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -354,7 +356,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER5+ (gs)", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5_PLUS, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER5, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -371,7 +373,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER5+", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5_PLUS, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER5, .icache_bsize = 128, .dcache_bsize = 128, .oprofile_cpu_type = "ppc64/ibm-compat-v1", @@ -385,7 +387,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_POWER6, .cpu_user_features = COMMON_USER_POWER6 | PPC_FEATURE_POWER6_EXT, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER6, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -404,7 +406,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER6 (architected)", .cpu_features = CPU_FTRS_POWER6, .cpu_user_features = COMMON_USER_POWER6, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER6, .icache_bsize = 128, .dcache_bsize = 128, .oprofile_cpu_type = "ppc64/ibm-compat-v1", @@ -417,12 +419,13 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER7 (architected)", .cpu_features = CPU_FTRS_POWER7, .cpu_user_features = COMMON_USER_POWER7, - .mmu_features = MMU_FTR_HPTE_TABLE | - MMU_FTR_TLBIE_206, + .mmu_features = MMU_FTRS_POWER7, .icache_bsize = 128, .dcache_bsize = 128, .oprofile_type = PPC_OPROFILE_POWER4, .oprofile_cpu_type = "ppc64/ibm-compat-v1", + .cpu_setup = __setup_cpu_power7, + .cpu_restore = __restore_cpu_power7, .platform = "power7", }, { /* Power7 */ @@ -431,14 +434,15 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER7 (raw)", .cpu_features = CPU_FTRS_POWER7, .cpu_user_features = COMMON_USER_POWER7, - .mmu_features = MMU_FTR_HPTE_TABLE | - MMU_FTR_TLBIE_206, + .mmu_features = MMU_FTRS_POWER7, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power7", .oprofile_type = PPC_OPROFILE_POWER4, + .cpu_setup = __setup_cpu_power7, + .cpu_restore = __restore_cpu_power7, .platform = "power7", }, { /* Power7+ */ @@ -447,14 +451,15 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER7+ (raw)", .cpu_features = CPU_FTRS_POWER7, .cpu_user_features = COMMON_USER_POWER7, - .mmu_features = MMU_FTR_HPTE_TABLE | - MMU_FTR_TLBIE_206, + .mmu_features = MMU_FTRS_POWER7, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power7", .oprofile_type = PPC_OPROFILE_POWER4, + .cpu_setup = __setup_cpu_power7, + .cpu_restore = __restore_cpu_power7, .platform = "power7+", }, { /* Cell Broadband Engine */ @@ -465,7 +470,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_user_features = COMMON_USER_PPC64 | PPC_FEATURE_CELL | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_SMT, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_CELL, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 4, @@ -480,7 +485,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "PA6T", .cpu_features = CPU_FTRS_PA6T, .cpu_user_features = COMMON_USER_PA6T, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_PA6T, .icache_bsize = 64, .dcache_bsize = 64, .num_pmcs = 6, @@ -497,7 +502,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER4 (compatible)", .cpu_features = CPU_FTRS_COMPATIBLE, .cpu_user_features = COMMON_USER_PPC64, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_DEFAULT_HPTE_ARCH_V2, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -1973,7 +1978,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x80240000, .cpu_name = "e5500", - .cpu_features = CPU_FTRS_E500MC, + .cpu_features = CPU_FTRS_E5500, .cpu_user_features = COMMON_USER_BOOKE, .mmu_features = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS | MMU_FTR_USE_TLBILX, @@ -2005,7 +2010,22 @@ static struct cpu_spec __initdata cpu_specs[] = { #endif /* CONFIG_PPC32 */ #endif /* CONFIG_E500 */ -#ifdef CONFIG_PPC_BOOK3E_64 +#ifdef CONFIG_PPC_A2 + { /* Standard A2 (>= DD2) + FPU core */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00480000, + .cpu_name = "A2 (>= DD2)", + .cpu_features = CPU_FTRS_A2, + .cpu_user_features = COMMON_USER_PPC64, + .mmu_features = MMU_FTRS_A2, + .icache_bsize = 64, + .dcache_bsize = 64, + .num_pmcs = 0, + .cpu_setup = __setup_cpu_a2, + .cpu_restore = __restore_cpu_a2, + .machine_check = machine_check_generic, + .platform = "ppca2", + }, { /* This is a default entry to get going, to be replaced by * a real one at some stage */ @@ -2026,7 +2046,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .machine_check = machine_check_generic, .platform = "power6", }, -#endif +#endif /* CONFIG_PPC_A2 */ }; static struct cpu_spec the_cpu_spec; diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 3d3d416339dd..4e6ee944495a 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -64,9 +64,9 @@ void crash_ipi_callback(struct pt_regs *regs) return; hard_irq_disable(); - if (!cpu_isset(cpu, cpus_in_crash)) + if (!cpumask_test_cpu(cpu, &cpus_in_crash)) crash_save_cpu(regs, cpu); - cpu_set(cpu, cpus_in_crash); + cpumask_set_cpu(cpu, &cpus_in_crash); /* * Entered via soft-reset - could be the kdump @@ -77,8 +77,8 @@ void crash_ipi_callback(struct pt_regs *regs) * Tell the kexec CPU that entered via soft-reset and ready * to go down. */ - if (cpu_isset(cpu, cpus_in_sr)) { - cpu_clear(cpu, cpus_in_sr); + if (cpumask_test_cpu(cpu, &cpus_in_sr)) { + cpumask_clear_cpu(cpu, &cpus_in_sr); atomic_inc(&enter_on_soft_reset); } @@ -87,7 +87,7 @@ void crash_ipi_callback(struct pt_regs *regs) * This barrier is needed to make sure that all CPUs are stopped. * If not, soft-reset will be invoked to bring other CPUs. */ - while (!cpu_isset(crashing_cpu, cpus_in_crash)) + while (!cpumask_test_cpu(crashing_cpu, &cpus_in_crash)) cpu_relax(); if (ppc_md.kexec_cpu_down) @@ -109,7 +109,7 @@ static void crash_soft_reset_check(int cpu) { unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */ - cpu_clear(cpu, cpus_in_sr); + cpumask_clear_cpu(cpu, &cpus_in_sr); while (atomic_read(&enter_on_soft_reset) != ncpus) cpu_relax(); } @@ -132,7 +132,7 @@ static void crash_kexec_prepare_cpus(int cpu) */ printk(KERN_EMERG "Sending IPI to other cpus...\n"); msecs = 10000; - while ((cpus_weight(cpus_in_crash) < ncpus) && (--msecs > 0)) { + while ((cpumask_weight(&cpus_in_crash) < ncpus) && (--msecs > 0)) { cpu_relax(); mdelay(1); } @@ -144,54 +144,24 @@ static void crash_kexec_prepare_cpus(int cpu) * user to do soft reset such that we get all. * Soft-reset will be used until better mechanism is implemented. */ - if (cpus_weight(cpus_in_crash) < ncpus) { + if (cpumask_weight(&cpus_in_crash) < ncpus) { printk(KERN_EMERG "done waiting: %d cpu(s) not responding\n", - ncpus - cpus_weight(cpus_in_crash)); + ncpus - cpumask_weight(&cpus_in_crash)); printk(KERN_EMERG "Activate soft-reset to stop other cpu(s)\n"); - cpus_in_sr = CPU_MASK_NONE; + cpumask_clear(&cpus_in_sr); atomic_set(&enter_on_soft_reset, 0); - while (cpus_weight(cpus_in_crash) < ncpus) + while (cpumask_weight(&cpus_in_crash) < ncpus) cpu_relax(); } /* * Make sure all CPUs are entered via soft-reset if the kdump is * invoked using soft-reset. */ - if (cpu_isset(cpu, cpus_in_sr)) + if (cpumask_test_cpu(cpu, &cpus_in_sr)) crash_soft_reset_check(cpu); /* Leave the IPI callback set */ } -/* wait for all the CPUs to hit real mode but timeout if they don't come in */ -#if defined(CONFIG_PPC_STD_MMU_64) && defined(CONFIG_SMP) -static void crash_kexec_wait_realmode(int cpu) -{ - unsigned int msecs; - int i; - - msecs = 10000; - for (i=0; i < NR_CPUS && msecs > 0; i++) { - if (i == cpu) - continue; - - while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) { - barrier(); - if (!cpu_possible(i)) { - break; - } - if (!cpu_online(i)) { - break; - } - msecs--; - mdelay(1); - } - } - mb(); -} -#else -static inline void crash_kexec_wait_realmode(int cpu) {} -#endif - /* * This function will be called by secondary cpus or by kexec cpu * if soft-reset is activated to stop some CPUs. @@ -212,7 +182,7 @@ void crash_kexec_secondary(struct pt_regs *regs) * exited using 'x'(exit and recover) or * kexec_should_crash() failed for all running tasks. */ - cpu_clear(cpu, cpus_in_sr); + cpumask_clear_cpu(cpu, &cpus_in_sr); local_irq_restore(flags); return; } @@ -226,7 +196,7 @@ void crash_kexec_secondary(struct pt_regs *regs) * then start kexec boot. */ crash_soft_reset_check(cpu); - cpu_set(crashing_cpu, cpus_in_crash); + cpumask_set_cpu(crashing_cpu, &cpus_in_crash); if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(1, 0); machine_kexec(kexec_crash_image); @@ -235,7 +205,8 @@ void crash_kexec_secondary(struct pt_regs *regs) crash_ipi_callback(regs); } -#else +#else /* ! CONFIG_SMP */ + static void crash_kexec_prepare_cpus(int cpu) { /* @@ -253,9 +224,39 @@ static void crash_kexec_prepare_cpus(int cpu) void crash_kexec_secondary(struct pt_regs *regs) { - cpus_in_sr = CPU_MASK_NONE; + cpumask_clear(&cpus_in_sr); } -#endif +#endif /* CONFIG_SMP */ + +/* wait for all the CPUs to hit real mode but timeout if they don't come in */ +#if defined(CONFIG_SMP) && defined(CONFIG_PPC_STD_MMU_64) +static void crash_kexec_wait_realmode(int cpu) +{ + unsigned int msecs; + int i; + + msecs = 10000; + for (i=0; i < nr_cpu_ids && msecs > 0; i++) { + if (i == cpu) + continue; + + while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) { + barrier(); + if (!cpu_possible(i)) { + break; + } + if (!cpu_online(i)) { + break; + } + msecs--; + mdelay(1); + } + } + mb(); +} +#else +static inline void crash_kexec_wait_realmode(int cpu) {} +#endif /* CONFIG_SMP && CONFIG_PPC_STD_MMU_64 */ /* * Register a function to be called on shutdown. Only use this if you @@ -345,7 +346,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) crashing_cpu = smp_processor_id(); crash_save_cpu(regs, crashing_cpu); crash_kexec_prepare_cpus(crashing_cpu); - cpu_set(crashing_cpu, cpus_in_crash); + cpumask_set_cpu(crashing_cpu, &cpus_in_crash); crash_kexec_wait_realmode(crashing_cpu); machine_kexec_mask_interrupts(); diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index 3307a52d797f..2cc451aaaca7 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -13,84 +13,35 @@ #include #include #include -#include +#include #include #include #ifdef CONFIG_SMP -struct doorbell_cpu_info { - unsigned long messages; /* current messages bits */ - unsigned int tag; /* tag value */ -}; - -static DEFINE_PER_CPU(struct doorbell_cpu_info, doorbell_cpu_info); - void doorbell_setup_this_cpu(void) { - struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); + unsigned long tag = mfspr(SPRN_PIR) & 0x3fff; - info->messages = 0; - info->tag = mfspr(SPRN_PIR) & 0x3fff; + smp_muxed_ipi_set_data(smp_processor_id(), tag); } -void doorbell_message_pass(int target, int msg) +void doorbell_cause_ipi(int cpu, unsigned long data) { - struct doorbell_cpu_info *info; - int i; - - if (target < NR_CPUS) { - info = &per_cpu(doorbell_cpu_info, target); - set_bit(msg, &info->messages); - ppc_msgsnd(PPC_DBELL, 0, info->tag); - } - else if (target == MSG_ALL_BUT_SELF) { - for_each_online_cpu(i) { - if (i == smp_processor_id()) - continue; - info = &per_cpu(doorbell_cpu_info, i); - set_bit(msg, &info->messages); - ppc_msgsnd(PPC_DBELL, 0, info->tag); - } - } - else { /* target == MSG_ALL */ - for_each_online_cpu(i) { - info = &per_cpu(doorbell_cpu_info, i); - set_bit(msg, &info->messages); - } - ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0); - } + ppc_msgsnd(PPC_DBELL, 0, data); } void doorbell_exception(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); - struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); - int msg; - /* Warning: regs can be NULL when called from irq enable */ + irq_enter(); - if (!info->messages || (num_online_cpus() < 2)) - goto out; + smp_ipi_demux(); - for (msg = 0; msg < 4; msg++) - if (test_and_clear_bit(msg, &info->messages)) - smp_message_recv(msg); - -out: + irq_exit(); set_irq_regs(old_regs); } - -void doorbell_check_self(void) -{ - struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); - - if (!info->messages) - return; - - ppc_msgsnd(PPC_DBELL, 0, info->tag); -} - #else /* CONFIG_SMP */ void doorbell_exception(struct pt_regs *regs) { diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index d82878c4daa6..d834425186ae 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -421,6 +421,12 @@ BEGIN_FTR_SECTION std r24,THREAD_VRSAVE(r3) END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_PPC64 +BEGIN_FTR_SECTION + mfspr r25,SPRN_DSCR + std r25,THREAD_DSCR(r3) +END_FTR_SECTION_IFSET(CPU_FTR_DSCR) +#endif and. r0,r0,r22 beq+ 1f andc r22,r22,r0 @@ -462,10 +468,10 @@ BEGIN_FTR_SECTION FTR_SECTION_ELSE_NESTED(95) clrrdi r6,r8,40 /* get its 1T ESID */ clrrdi r9,r1,40 /* get current sp 1T ESID */ - ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_1T_SEGMENT, 95) + ALT_MMU_FTR_SECTION_END_NESTED_IFCLR(MMU_FTR_1T_SEGMENT, 95) FTR_SECTION_ELSE b 2f -ALT_FTR_SECTION_END_IFSET(CPU_FTR_SLB) +ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_SLB) clrldi. r0,r6,2 /* is new ESID c00000000? */ cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */ cror eq,4*cr1+eq,eq @@ -479,7 +485,7 @@ BEGIN_FTR_SECTION li r9,MMU_SEGSIZE_1T /* insert B field */ oris r6,r6,(MMU_SEGSIZE_1T << SLBIE_SSIZE_SHIFT)@h rldimi r7,r9,SLB_VSID_SSIZE_SHIFT,0 -END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) /* Update the last bolted SLB. No write barriers are needed * here, provided we only update the current CPU's SLB shadow @@ -491,7 +497,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) std r7,SLBSHADOW_STACKVSID(r9) /* Save VSID */ std r0,SLBSHADOW_STACKESID(r9) /* Save ESID */ - /* No need to check for CPU_FTR_NO_SLBIE_B here, since when + /* No need to check for MMU_FTR_NO_SLBIE_B here, since when * we have 1TB segments, the only CPUs known to have the errata * only support less than 1TB of system memory and we'll never * actually hit this code path. @@ -522,6 +528,15 @@ BEGIN_FTR_SECTION mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_PPC64 +BEGIN_FTR_SECTION + ld r0,THREAD_DSCR(r4) + cmpd r0,r25 + beq 1f + mtspr SPRN_DSCR,r0 +1: +END_FTR_SECTION_IFSET(CPU_FTR_DSCR) +#endif /* r3-r13 are destroyed -- Cort */ REST_8GPRS(14, r1) @@ -838,7 +853,7 @@ _GLOBAL(enter_rtas) _STATIC(rtas_return_loc) /* relocation is off at this point */ - mfspr r4,SPRN_SPRG_PACA /* Get PACA */ + GET_PACA(r4) clrldi r4,r4,2 /* convert to realmode address */ bcl 20,31,$+4 @@ -869,7 +884,7 @@ _STATIC(rtas_restore_regs) REST_8GPRS(14, r1) /* Restore the non-volatiles */ REST_10GPRS(22, r1) /* ditto */ - mfspr r13,SPRN_SPRG_PACA + GET_PACA(r13) ld r4,_CCR(r1) mtcr r4 diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 9651acc3504a..d24d4400cc79 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -252,9 +253,6 @@ exception_marker: .balign 0x1000 .globl interrupt_base_book3e interrupt_base_book3e: /* fake trap */ - /* Note: If real debug exceptions are supported by the HW, the vector - * below will have to be patched up to point to an appropriate handler - */ EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */ EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */ EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */ @@ -271,8 +269,13 @@ interrupt_base_book3e: /* fake trap */ EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */ EXCEPTION_STUB(0x1c0, data_tlb_miss) EXCEPTION_STUB(0x1e0, instruction_tlb_miss) + EXCEPTION_STUB(0x260, perfmon) EXCEPTION_STUB(0x280, doorbell) EXCEPTION_STUB(0x2a0, doorbell_crit) + EXCEPTION_STUB(0x2c0, guest_doorbell) + EXCEPTION_STUB(0x2e0, guest_doorbell_crit) + EXCEPTION_STUB(0x300, hypercall) + EXCEPTION_STUB(0x320, ehpriv) .globl interrupt_end_book3e interrupt_end_book3e: @@ -454,6 +457,70 @@ interrupt_end_book3e: kernel_dbg_exc: b . /* NYI */ +/* Debug exception as a debug interrupt*/ + START_EXCEPTION(debug_debug); + DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS) + + /* + * If there is a single step or branch-taken exception in an + * exception entry sequence, it was probably meant to apply to + * the code where the exception occurred (since exception entry + * doesn't turn off DE automatically). We simulate the effect + * of turning off DE on entry to an exception handler by turning + * off DE in the DSRR1 value and clearing the debug status. + */ + + mfspr r14,SPRN_DBSR /* check single-step/branch taken */ + andis. r15,r14,DBSR_IC@h + beq+ 1f + + LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e) + LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e) + cmpld cr0,r10,r14 + cmpld cr1,r10,r15 + blt+ cr0,1f + bge+ cr1,1f + + /* here it looks like we got an inappropriate debug exception. */ + lis r14,DBSR_IC@h /* clear the IC event */ + rlwinm r11,r11,0,~MSR_DE /* clear DE in the DSRR1 value */ + mtspr SPRN_DBSR,r14 + mtspr SPRN_DSRR1,r11 + lwz r10,PACA_EXDBG+EX_CR(r13) /* restore registers */ + ld r1,PACA_EXDBG+EX_R1(r13) + ld r14,PACA_EXDBG+EX_R14(r13) + ld r15,PACA_EXDBG+EX_R15(r13) + mtcr r10 + ld r10,PACA_EXDBG+EX_R10(r13) /* restore registers */ + ld r11,PACA_EXDBG+EX_R11(r13) + mfspr r13,SPRN_SPRG_DBG_SCRATCH + rfdi + + /* Normal debug exception */ + /* XXX We only handle coming from userspace for now since we can't + * quite save properly an interrupted kernel state yet + */ +1: andi. r14,r11,MSR_PR; /* check for userspace again */ + beq kernel_dbg_exc; /* if from kernel mode */ + + /* Now we mash up things to make it look like we are coming on a + * normal exception + */ + mfspr r15,SPRN_SPRG_DBG_SCRATCH + mtspr SPRN_SPRG_GEN_SCRATCH,r15 + mfspr r14,SPRN_DBSR + EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL) + std r14,_DSISR(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + mr r4,r14 + ld r14,PACA_EXDBG+EX_R14(r13) + ld r15,PACA_EXDBG+EX_R15(r13) + bl .save_nvgprs + bl .DebugException + b .ret_from_except + + MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE) + /* Doorbell interrupt */ MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE) @@ -468,6 +535,11 @@ kernel_dbg_exc: // b ret_from_crit_except b . + MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE) + MASKABLE_EXCEPTION(0x2e0, guest_doorbell_crit, .unknown_exception, ACK_NONE) + MASKABLE_EXCEPTION(0x310, hypercall, .unknown_exception, ACK_NONE) + MASKABLE_EXCEPTION(0x320, ehpriv, .unknown_exception, ACK_NONE) + /* * An interrupt came in while soft-disabled; clear EE in SRR1, @@ -587,7 +659,12 @@ fast_exception_return: BAD_STACK_TRAMPOLINE(0x000) BAD_STACK_TRAMPOLINE(0x100) BAD_STACK_TRAMPOLINE(0x200) +BAD_STACK_TRAMPOLINE(0x260) +BAD_STACK_TRAMPOLINE(0x2c0) +BAD_STACK_TRAMPOLINE(0x2e0) BAD_STACK_TRAMPOLINE(0x300) +BAD_STACK_TRAMPOLINE(0x310) +BAD_STACK_TRAMPOLINE(0x320) BAD_STACK_TRAMPOLINE(0x400) BAD_STACK_TRAMPOLINE(0x500) BAD_STACK_TRAMPOLINE(0x600) @@ -864,8 +941,23 @@ have_hes: * that will have to be made dependent on whether we are running under * a hypervisor I suppose. */ - ori r3,r3,MAS0_HES | MAS0_WQ_ALLWAYS - mtspr SPRN_MAS0,r3 + + /* BEWARE, MAGIC + * This code is called as an ordinary function on the boot CPU. But to + * avoid duplication, this code is also used in SCOM bringup of + * secondary CPUs. We read the code between the initial_tlb_code_start + * and initial_tlb_code_end labels one instruction at a time and RAM it + * into the new core via SCOM. That doesn't process branches, so there + * must be none between those two labels. It also means if this code + * ever takes any parameters, the SCOM code must also be updated to + * provide them. + */ + .globl a2_tlbinit_code_start +a2_tlbinit_code_start: + + ori r11,r3,MAS0_WQ_ALLWAYS + oris r11,r11,MAS0_ESEL(3)@h /* Use way 3: workaround A2 erratum 376 */ + mtspr SPRN_MAS0,r11 lis r3,(MAS1_VALID | MAS1_IPROT)@h ori r3,r3,BOOK3E_PAGESZ_1GB << MAS1_TSIZE_SHIFT mtspr SPRN_MAS1,r3 @@ -879,18 +971,86 @@ have_hes: /* Write the TLB entry */ tlbwe + .globl a2_tlbinit_after_linear_map +a2_tlbinit_after_linear_map: + /* Now we branch the new virtual address mapped by this entry */ LOAD_REG_IMMEDIATE(r3,1f) mtctr r3 bctr 1: /* We are now running at PAGE_OFFSET, clean the TLB of everything - * else (XXX we should scan for bolted crap from the firmware too) + * else (including IPROTed things left by firmware) + * r4 = TLBnCFG + * r3 = current address (more or less) */ + + li r5,0 + mtspr SPRN_MAS6,r5 + tlbsx 0,r3 + + rlwinm r9,r4,0,TLBnCFG_N_ENTRY + rlwinm r10,r4,8,0xff + addi r10,r10,-1 /* Get inner loop mask */ + + li r3,1 + + mfspr r5,SPRN_MAS1 + rlwinm r5,r5,0,(~(MAS1_VALID|MAS1_IPROT)) + + mfspr r6,SPRN_MAS2 + rldicr r6,r6,0,51 /* Extract EPN */ + + mfspr r7,SPRN_MAS0 + rlwinm r7,r7,0,0xffff0fff /* Clear HES and WQ */ + + rlwinm r8,r7,16,0xfff /* Extract ESEL */ + +2: add r4,r3,r8 + and r4,r4,r10 + + rlwimi r7,r4,16,MAS0_ESEL_MASK + + mtspr SPRN_MAS0,r7 + mtspr SPRN_MAS1,r5 + mtspr SPRN_MAS2,r6 + tlbwe + + addi r3,r3,1 + and. r4,r3,r10 + + bne 3f + addis r6,r6,(1<<30)@h +3: + cmpw r3,r9 + blt 2b + + .globl a2_tlbinit_after_iprot_flush +a2_tlbinit_after_iprot_flush: + +#ifdef CONFIG_PPC_EARLY_DEBUG_WSP + /* Now establish early debug mappings if applicable */ + /* Restore the MAS0 we used for linear mapping load */ + mtspr SPRN_MAS0,r11 + + lis r3,(MAS1_VALID | MAS1_IPROT)@h + ori r3,r3,(BOOK3E_PAGESZ_4K << MAS1_TSIZE_SHIFT) + mtspr SPRN_MAS1,r3 + LOAD_REG_IMMEDIATE(r3, WSP_UART_VIRT | MAS2_I | MAS2_G) + mtspr SPRN_MAS2,r3 + LOAD_REG_IMMEDIATE(r3, WSP_UART_PHYS | MAS3_SR | MAS3_SW) + mtspr SPRN_MAS7_MAS3,r3 + /* re-use the MAS8 value from the linear mapping */ + tlbwe +#endif /* CONFIG_PPC_EARLY_DEBUG_WSP */ + PPC_TLBILX(0,0,0) sync isync + .globl a2_tlbinit_code_end +a2_tlbinit_code_end: + /* We translate LR and return */ mflr r3 tovirt(r3,r3) @@ -1040,3 +1200,33 @@ _GLOBAL(__setup_base_ivors) sync blr + +_GLOBAL(setup_perfmon_ivor) + SET_IVOR(35, 0x260) /* Performance Monitor */ + blr + +_GLOBAL(setup_doorbell_ivors) + SET_IVOR(36, 0x280) /* Processor Doorbell */ + SET_IVOR(37, 0x2a0) /* Processor Doorbell Crit */ + + /* Check MMUCFG[LPIDSIZE] to determine if we have category E.HV */ + mfspr r10,SPRN_MMUCFG + rlwinm. r10,r10,0,MMUCFG_LPIDSIZE + beqlr + + SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */ + SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */ + blr + +_GLOBAL(setup_ehv_ivors) + /* + * We may be running as a guest and lack E.HV even on a chip + * that normally has it. + */ + mfspr r10,SPRN_MMUCFG + rlwinm. r10,r10,0,MMUCFG_LPIDSIZE + beqlr + + SET_IVOR(40, 0x300) /* Embedded Hypervisor System Call */ + SET_IVOR(41, 0x320) /* Embedded Hypervisor Privilege */ + blr diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index aeb739e18769..a85f4874cba7 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -37,23 +37,51 @@ .globl __start_interrupts __start_interrupts: - STD_EXCEPTION_PSERIES(0x100, system_reset) + .globl system_reset_pSeries; +system_reset_pSeries: + HMT_MEDIUM; + DO_KVM 0x100; + SET_SCRATCH0(r13) +#ifdef CONFIG_PPC_P7_NAP +BEGIN_FTR_SECTION + /* Running native on arch 2.06 or later, check if we are + * waking up from nap. We only handle no state loss and + * supervisor state loss. We do -not- handle hypervisor + * state loss at this time. + */ + mfspr r13,SPRN_SRR1 + rlwinm r13,r13,47-31,30,31 + cmpwi cr0,r13,1 + bne 1f + b .power7_wakeup_noloss +1: cmpwi cr0,r13,2 + bne 1f + b .power7_wakeup_loss + /* Total loss of HV state is fatal, we could try to use the + * PIR to locate a PACA, then use an emergency stack etc... + * but for now, let's just stay stuck here + */ +1: cmpwi cr0,r13,3 + beq . +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE_206) +#endif /* CONFIG_PPC_P7_NAP */ + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD) . = 0x200 _machine_check_pSeries: HMT_MEDIUM DO_KVM 0x200 - mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ - EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) + SET_SCRATCH0(r13) + EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common, EXC_STD) . = 0x300 .globl data_access_pSeries data_access_pSeries: HMT_MEDIUM DO_KVM 0x300 - mtspr SPRN_SPRG_SCRATCH0,r13 + SET_SCRATCH0(r13) BEGIN_FTR_SECTION - mfspr r13,SPRN_SPRG_PACA + GET_PACA(r13) std r9,PACA_EXSLB+EX_R9(r13) std r10,PACA_EXSLB+EX_R10(r13) mfspr r10,SPRN_DAR @@ -67,22 +95,22 @@ BEGIN_FTR_SECTION std r11,PACA_EXGEN+EX_R11(r13) ld r11,PACA_EXSLB+EX_R9(r13) std r12,PACA_EXGEN+EX_R12(r13) - mfspr r12,SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r12) std r10,PACA_EXGEN+EX_R10(r13) std r11,PACA_EXGEN+EX_R9(r13) std r12,PACA_EXGEN+EX_R13(r13) - EXCEPTION_PROLOG_PSERIES_1(data_access_common) + EXCEPTION_PROLOG_PSERIES_1(data_access_common, EXC_STD) FTR_SECTION_ELSE - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common) -ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD) +ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB) . = 0x380 .globl data_access_slb_pSeries data_access_slb_pSeries: HMT_MEDIUM DO_KVM 0x380 - mtspr SPRN_SPRG_SCRATCH0,r13 - mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ + SET_SCRATCH0(r13) + GET_PACA(r13) std r3,PACA_EXSLB+EX_R3(r13) mfspr r3,SPRN_DAR std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ @@ -95,7 +123,7 @@ data_access_slb_pSeries: std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) - mfspr r10,SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r10) std r10,PACA_EXSLB+EX_R13(r13) mfspr r12,SPRN_SRR1 /* and SRR1 */ #ifndef CONFIG_RELOCATABLE @@ -113,15 +141,15 @@ data_access_slb_pSeries: bctr #endif - STD_EXCEPTION_PSERIES(0x400, instruction_access) + STD_EXCEPTION_PSERIES(0x400, 0x400, instruction_access) . = 0x480 .globl instruction_access_slb_pSeries instruction_access_slb_pSeries: HMT_MEDIUM DO_KVM 0x480 - mtspr SPRN_SPRG_SCRATCH0,r13 - mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ + SET_SCRATCH0(r13) + GET_PACA(r13) std r3,PACA_EXSLB+EX_R3(r13) mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ @@ -134,7 +162,7 @@ instruction_access_slb_pSeries: std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) - mfspr r10,SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r10) std r10,PACA_EXSLB+EX_R13(r13) mfspr r12,SPRN_SRR1 /* and SRR1 */ #ifndef CONFIG_RELOCATABLE @@ -147,13 +175,29 @@ instruction_access_slb_pSeries: bctr #endif - MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt) - STD_EXCEPTION_PSERIES(0x600, alignment) - STD_EXCEPTION_PSERIES(0x700, program_check) - STD_EXCEPTION_PSERIES(0x800, fp_unavailable) - MASKABLE_EXCEPTION_PSERIES(0x900, decrementer) - STD_EXCEPTION_PSERIES(0xa00, trap_0a) - STD_EXCEPTION_PSERIES(0xb00, trap_0b) + /* We open code these as we can't have a ". = x" (even with + * x = "." within a feature section + */ + . = 0x500; + .globl hardware_interrupt_pSeries; + .globl hardware_interrupt_hv; +hardware_interrupt_pSeries: +hardware_interrupt_hv: + BEGIN_FTR_SECTION + _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt, EXC_STD) + FTR_SECTION_ELSE + _MASKABLE_EXCEPTION_PSERIES(0x502, hardware_interrupt, EXC_HV) + ALT_FTR_SECTION_END_IFCLR(CPU_FTR_HVMODE_206) + + STD_EXCEPTION_PSERIES(0x600, 0x600, alignment) + STD_EXCEPTION_PSERIES(0x700, 0x700, program_check) + STD_EXCEPTION_PSERIES(0x800, 0x800, fp_unavailable) + + MASKABLE_EXCEPTION_PSERIES(0x900, 0x900, decrementer) + MASKABLE_EXCEPTION_HV(0x980, 0x980, decrementer) + + STD_EXCEPTION_PSERIES(0xa00, 0xa00, trap_0a) + STD_EXCEPTION_PSERIES(0xb00, 0xb00, trap_0b) . = 0xc00 .globl system_call_pSeries @@ -165,13 +209,13 @@ BEGIN_FTR_SECTION beq- 1f END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) mr r9,r13 - mfspr r13,SPRN_SPRG_PACA + GET_PACA(r13) mfspr r11,SPRN_SRR0 - ld r12,PACAKBASE(r13) - ld r10,PACAKMSR(r13) - LOAD_HANDLER(r12, system_call_entry) - mtspr SPRN_SRR0,r12 mfspr r12,SPRN_SRR1 + ld r10,PACAKBASE(r13) + LOAD_HANDLER(r10, system_call_entry) + mtspr SPRN_SRR0,r10 + ld r10,PACAKMSR(r13) mtspr SPRN_SRR1,r10 rfid b . /* prevent speculative execution */ @@ -183,8 +227,21 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) rfid /* return to userspace */ b . - STD_EXCEPTION_PSERIES(0xd00, single_step) - STD_EXCEPTION_PSERIES(0xe00, trap_0e) + STD_EXCEPTION_PSERIES(0xd00, 0xd00, single_step) + + /* At 0xe??? we have a bunch of hypervisor exceptions, we branch + * out of line to handle them + */ + . = 0xe00 + b h_data_storage_hv + . = 0xe20 + b h_instr_storage_hv + . = 0xe40 + b emulation_assist_hv + . = 0xe50 + b hmi_exception_hv + . = 0xe60 + b hmi_exception_hv /* We need to deal with the Altivec unavailable exception * here which is at 0xf20, thus in the middle of the @@ -193,39 +250,42 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) */ performance_monitor_pSeries_1: . = 0xf00 - DO_KVM 0xf00 b performance_monitor_pSeries altivec_unavailable_pSeries_1: . = 0xf20 - DO_KVM 0xf20 b altivec_unavailable_pSeries vsx_unavailable_pSeries_1: . = 0xf40 - DO_KVM 0xf40 b vsx_unavailable_pSeries #ifdef CONFIG_CBE_RAS - HSTD_EXCEPTION_PSERIES(0x1200, cbe_system_error) + STD_EXCEPTION_HV(0x1200, 0x1202, cbe_system_error) #endif /* CONFIG_CBE_RAS */ - STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint) + STD_EXCEPTION_PSERIES(0x1300, 0x1300, instruction_breakpoint) #ifdef CONFIG_CBE_RAS - HSTD_EXCEPTION_PSERIES(0x1600, cbe_maintenance) + STD_EXCEPTION_HV(0x1600, 0x1602, cbe_maintenance) #endif /* CONFIG_CBE_RAS */ - STD_EXCEPTION_PSERIES(0x1700, altivec_assist) + STD_EXCEPTION_PSERIES(0x1700, 0x1700, altivec_assist) #ifdef CONFIG_CBE_RAS - HSTD_EXCEPTION_PSERIES(0x1800, cbe_thermal) + STD_EXCEPTION_HV(0x1800, 0x1802, cbe_thermal) #endif /* CONFIG_CBE_RAS */ . = 0x3000 -/*** pSeries interrupt support ***/ +/*** Out of line interrupts support ***/ + + /* moved from 0xe00 */ + STD_EXCEPTION_HV(., 0xe00, h_data_storage) + STD_EXCEPTION_HV(., 0xe20, h_instr_storage) + STD_EXCEPTION_HV(., 0xe40, emulation_assist) + STD_EXCEPTION_HV(., 0xe60, hmi_exception) /* need to flush cache ? */ /* moved from 0xf00 */ - STD_EXCEPTION_PSERIES(., performance_monitor) - STD_EXCEPTION_PSERIES(., altivec_unavailable) - STD_EXCEPTION_PSERIES(., vsx_unavailable) + STD_EXCEPTION_PSERIES(., 0xf00, performance_monitor) + STD_EXCEPTION_PSERIES(., 0xf20, altivec_unavailable) + STD_EXCEPTION_PSERIES(., 0xf40, vsx_unavailable) /* * An interrupt came in while soft-disabled; clear EE in SRR1, @@ -240,17 +300,30 @@ masked_interrupt: rotldi r10,r10,16 mtspr SPRN_SRR1,r10 ld r10,PACA_EXGEN+EX_R10(r13) - mfspr r13,SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r13) rfid b . +masked_Hinterrupt: + stb r10,PACAHARDIRQEN(r13) + mtcrf 0x80,r9 + ld r9,PACA_EXGEN+EX_R9(r13) + mfspr r10,SPRN_HSRR1 + rldicl r10,r10,48,1 /* clear MSR_EE */ + rotldi r10,r10,16 + mtspr SPRN_HSRR1,r10 + ld r10,PACA_EXGEN+EX_R10(r13) + GET_SCRATCH0(r13) + hrfid + b . + .align 7 do_stab_bolted_pSeries: std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) - mfspr r10,SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r10) std r10,PACA_EXSLB+EX_R13(r13) - EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted) + EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD) #ifdef CONFIG_PPC_PSERIES /* @@ -260,15 +333,15 @@ do_stab_bolted_pSeries: .align 7 system_reset_fwnmi: HMT_MEDIUM - mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) + SET_SCRATCH0(r13) /* save r13 */ + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD) .globl machine_check_fwnmi .align 7 machine_check_fwnmi: HMT_MEDIUM - mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ - EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) + SET_SCRATCH0(r13) /* save r13 */ + EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common, EXC_STD) #endif /* CONFIG_PPC_PSERIES */ @@ -282,7 +355,7 @@ slb_miss_user_pseries: std r10,PACA_EXGEN+EX_R10(r13) std r11,PACA_EXGEN+EX_R11(r13) std r12,PACA_EXGEN+EX_R12(r13) - mfspr r10,SPRG_SCRATCH0 + GET_SCRATCH0(r10) ld r11,PACA_EXSLB+EX_R9(r13) ld r12,PACA_EXSLB+EX_R3(r13) std r10,PACA_EXGEN+EX_R13(r13) @@ -342,6 +415,8 @@ machine_check_common: STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception) + STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception) + STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception) STD_EXCEPTION_COMMON_IDLE(0xf00, performance_monitor, .performance_monitor_exception) STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) #ifdef CONFIG_ALTIVEC @@ -386,9 +461,24 @@ bad_stack: std r12,_XER(r1) SAVE_GPR(0,r1) SAVE_GPR(2,r1) - SAVE_4GPRS(3,r1) - SAVE_2GPRS(7,r1) - SAVE_10GPRS(12,r1) + ld r10,EX_R3(r3) + std r10,GPR3(r1) + SAVE_GPR(4,r1) + SAVE_4GPRS(5,r1) + ld r9,EX_R9(r3) + ld r10,EX_R10(r3) + SAVE_2GPRS(9,r1) + ld r9,EX_R11(r3) + ld r10,EX_R12(r3) + ld r11,EX_R13(r3) + std r9,GPR11(r1) + std r10,GPR12(r1) + std r11,GPR13(r1) +BEGIN_FTR_SECTION + ld r10,EX_CFAR(r3) + std r10,ORIG_GPR3(r1) +END_FTR_SECTION_IFSET(CPU_FTR_CFAR) + SAVE_8GPRS(14,r1) SAVE_10GPRS(22,r1) lhz r12,PACA_TRAP_SAVE(r13) std r12,_TRAP(r1) @@ -397,6 +487,9 @@ bad_stack: li r12,0 std r12,0(r11) ld r2,PACATOC(r13) + ld r11,exception_marker@toc(r2) + std r12,RESULT(r1) + std r11,STACK_FRAME_OVERHEAD-16(r1) 1: addi r3,r1,STACK_FRAME_OVERHEAD bl .kernel_bad_stack b 1b @@ -419,6 +512,19 @@ data_access_common: li r5,0x300 b .do_hash_page /* Try to handle as hpte fault */ + .align 7 + .globl h_data_storage_common +h_data_storage_common: + mfspr r10,SPRN_HDAR + std r10,PACA_EXGEN+EX_DAR(r13) + mfspr r10,SPRN_HDSISR + stw r10,PACA_EXGEN+EX_DSISR(r13) + EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN) + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + bl .unknown_exception + b .ret_from_except + .align 7 .globl instruction_access_common instruction_access_common: @@ -428,6 +534,8 @@ instruction_access_common: li r5,0x400 b .do_hash_page /* Try to handle as hpte fault */ + STD_EXCEPTION_COMMON(0xe20, h_instr_storage, .unknown_exception) + /* * Here is the common SLB miss user that is used when going to virtual * mode for SLB misses, that is currently not used @@ -750,7 +858,7 @@ _STATIC(do_hash_page) BEGIN_FTR_SECTION andis. r0,r4,0x0020 /* Is it a segment table fault? */ bne- do_ste_alloc /* If so handle it */ -END_FTR_SECTION_IFCLR(CPU_FTR_SLB) +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB) clrrdi r11,r1,THREAD_SHIFT lwz r0,TI_PREEMPT(r11) /* If we're in an "NMI" */ diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index c5c24beb8387..ba250d505e07 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -805,19 +805,6 @@ _ENTRY(copy_and_flush) blr #ifdef CONFIG_SMP -#ifdef CONFIG_GEMINI - .globl __secondary_start_gemini -__secondary_start_gemini: - mfspr r4,SPRN_HID0 - ori r4,r4,HID0_ICFI - li r3,0 - ori r3,r3,HID0_ICE - andc r4,r4,r3 - mtspr SPRN_HID0,r4 - sync - b __secondary_start -#endif /* CONFIG_GEMINI */ - .globl __secondary_start_mpc86xx __secondary_start_mpc86xx: mfspr r3, SPRN_PIR @@ -890,15 +877,6 @@ __secondary_start: mtspr SPRN_SRR1,r4 SYNC RFI - -_GLOBAL(start_secondary_resume) - /* Reset stack */ - rlwinm r1,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ - addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD - li r3,0 - std r3,0(r1) /* Zero the stack frame pointer */ - bl start_secondary - b . #endif /* CONFIG_SMP */ #ifdef CONFIG_KVM_BOOK3S_HANDLER diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 3a319f9c9d3e..ba504099844a 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -147,6 +147,8 @@ __secondary_hold: mtctr r4 mr r3,r24 li r4,0 + /* Make sure that patched code is visible */ + isync bctr #else BUG_OPCODE @@ -216,19 +218,25 @@ generic_secondary_common_init: */ LOAD_REG_ADDR(r13, paca) /* Load paca pointer */ ld r13,0(r13) /* Get base vaddr of paca array */ +#ifndef CONFIG_SMP + addi r13,r13,PACA_SIZE /* know r13 if used accidentally */ + b .kexec_wait /* wait for next kernel if !SMP */ +#else + LOAD_REG_ADDR(r7, nr_cpu_ids) /* Load nr_cpu_ids address */ + lwz r7,0(r7) /* also the max paca allocated */ li r5,0 /* logical cpu id */ 1: lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */ cmpw r6,r24 /* Compare to our id */ beq 2f addi r13,r13,PACA_SIZE /* Loop to next PACA on miss */ addi r5,r5,1 - cmpwi r5,NR_CPUS + cmpw r5,r7 /* Check if more pacas exist */ blt 1b mr r3,r24 /* not found, copy phys to r3 */ b .kexec_wait /* next kernel might do better */ -2: mtspr SPRN_SPRG_PACA,r13 /* Save vaddr of paca in an SPRG */ +2: SET_PACA(r13) #ifdef CONFIG_PPC_BOOK3E addi r12,r13,PACA_EXTLB /* and TLB exc frame in another */ mtspr SPRN_SPRG_TLB_EXFRAME,r12 @@ -236,34 +244,39 @@ generic_secondary_common_init: /* From now on, r24 is expected to be logical cpuid */ mr r24,r5 -3: HMT_LOW - lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ - /* start. */ - -#ifndef CONFIG_SMP - b 3b /* Never go on non-SMP */ -#else - cmpwi 0,r23,0 - beq 3b /* Loop until told to go */ - - sync /* order paca.run and cur_cpu_spec */ /* See if we need to call a cpu state restore handler */ LOAD_REG_ADDR(r23, cur_cpu_spec) ld r23,0(r23) ld r23,CPU_SPEC_RESTORE(r23) cmpdi 0,r23,0 - beq 4f + beq 3f ld r23,0(r23) mtctr r23 bctrl -4: /* Create a temp kernel stack for use before relocation is on. */ +3: LOAD_REG_ADDR(r3, boot_cpu_count) /* Decrement boot_cpu_count */ + lwarx r4,0,r3 + subi r4,r4,1 + stwcx. r4,0,r3 + bne 3b + isync + +4: HMT_LOW + lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ + /* start. */ + cmpwi 0,r23,0 + beq 4b /* Loop until told to go */ + + sync /* order paca.run and cur_cpu_spec */ + isync /* In case code patching happened */ + + /* Create a temp kernel stack for use before relocation is on. */ ld r1,PACAEMERGSP(r13) subi r1,r1,STACK_FRAME_OVERHEAD b __secondary_start -#endif +#endif /* SMP */ /* * Turn the MMU off. @@ -534,7 +547,7 @@ _GLOBAL(pmac_secondary_start) ld r4,0(r4) /* Get base vaddr of paca array */ mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */ add r13,r13,r4 /* for this processor. */ - mtspr SPRN_SPRG_PACA,r13 /* Save vaddr of paca in an SPRG*/ + SET_PACA(r13) /* Save vaddr of paca in an SPRG*/ /* Mark interrupts soft and hard disabled (they might be enabled * in the PACA when doing hotplug) @@ -645,7 +658,7 @@ _GLOBAL(enable_64b_mode) oris r11,r11,0x8000 /* CM bit set, we'll set ICM later */ mtmsr r11 #else /* CONFIG_PPC_BOOK3E */ - li r12,(MSR_SF | MSR_ISF)@highest + li r12,(MSR_64BIT | MSR_ISF)@highest sldi r12,r12,48 or r11,r11,r12 mtmsrd r11 diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S new file mode 100644 index 000000000000..f8f0bc7f1d4f --- /dev/null +++ b/arch/powerpc/kernel/idle_power7.S @@ -0,0 +1,97 @@ +/* + * This file contains the power_save function for 970-family CPUs. + * + * 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 + +#undef DEBUG + + .text + +_GLOBAL(power7_idle) + /* Now check if user or arch enabled NAP mode */ + LOAD_REG_ADDRBASE(r3,powersave_nap) + lwz r4,ADDROFF(powersave_nap)(r3) + cmpwi 0,r4,0 + beqlr + + /* NAP is a state loss, we create a regs frame on the + * stack, fill it up with the state we care about and + * stick a pointer to it in PACAR1. We really only + * need to save PC, some CR bits and the NV GPRs, + * but for now an interrupt frame will do. + */ + mflr r0 + std r0,16(r1) + stdu r1,-INT_FRAME_SIZE(r1) + std r0,_LINK(r1) + std r0,_NIP(r1) + +#ifndef CONFIG_SMP + /* Make sure FPU, VSX etc... are flushed as we may lose + * state when going to nap mode + */ + bl .discard_lazy_cpu_state +#endif /* CONFIG_SMP */ + + /* Hard disable interrupts */ + mfmsr r9 + rldicl r9,r9,48,1 + rotldi r9,r9,16 + mtmsrd r9,1 /* hard-disable interrupts */ + li r0,0 + stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ + stb r0,PACAHARDIRQEN(r13) + + /* Continue saving state */ + SAVE_GPR(2, r1) + SAVE_NVGPRS(r1) + mfcr r3 + std r3,_CCR(r1) + std r9,_MSR(r1) + std r1,PACAR1(r13) + + /* Magic NAP mode enter sequence */ + std r0,0(r1) + ptesync + ld r0,0(r1) +1: cmp cr0,r0,r0 + bne 1b + PPC_NAP + b . + +_GLOBAL(power7_wakeup_loss) + GET_PACA(r13) + ld r1,PACAR1(r13) + REST_NVGPRS(r1) + REST_GPR(2, r1) + ld r3,_CCR(r1) + ld r4,_MSR(r1) + ld r5,_NIP(r1) + addi r1,r1,INT_FRAME_SIZE + mtcr r3 + mtspr SPRN_SRR1,r4 + mtspr SPRN_SRR0,r5 + rfid + +_GLOBAL(power7_wakeup_noloss) + GET_PACA(r13) + ld r1,PACAR1(r13) + ld r4,_MSR(r1) + ld r5,_NIP(r1) + addi r1,r1,INT_FRAME_SIZE + mtspr SPRN_SRR1,r4 + mtspr SPRN_SRR0,r5 + rfid diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/kernel/io-workarounds.c similarity index 95% rename from arch/powerpc/platforms/cell/io-workarounds.c rename to arch/powerpc/kernel/io-workarounds.c index 5c1118e31940..ffafaea3d261 100644 --- a/arch/powerpc/platforms/cell/io-workarounds.c +++ b/arch/powerpc/kernel/io-workarounds.c @@ -17,8 +17,7 @@ #include #include #include - -#include "io-workarounds.h" +#include #define IOWA_MAX_BUS 8 @@ -145,7 +144,19 @@ static void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size, return res; } -/* Regist new bus to support workaround */ +/* Enable IO workaround */ +static void __devinit io_workaround_init(void) +{ + static int io_workaround_inited; + + if (io_workaround_inited) + return; + ppc_pci_io = iowa_pci_io; + ppc_md.ioremap = iowa_ioremap; + io_workaround_inited = 1; +} + +/* Register new bus to support workaround */ void __devinit iowa_register_bus(struct pci_controller *phb, struct ppc_pci_io *ops, int (*initfunc)(struct iowa_bus *, void *), void *data) @@ -153,6 +164,8 @@ void __devinit iowa_register_bus(struct pci_controller *phb, struct iowa_bus *bus; struct device_node *np = phb->dn; + io_workaround_init(); + if (iowa_bus_count >= IOWA_MAX_BUS) { pr_err("IOWA:Too many pci bridges, " "workarounds disabled for %s\n", np->full_name); @@ -162,6 +175,7 @@ void __devinit iowa_register_bus(struct pci_controller *phb, bus = &iowa_busses[iowa_bus_count]; bus->phb = phb; bus->ops = ops; + bus->private = data; if (initfunc) if ((*initfunc)(bus, data)) @@ -172,14 +186,3 @@ void __devinit iowa_register_bus(struct pci_controller *phb, pr_debug("IOWA:[%d]Add bus, %s.\n", iowa_bus_count-1, np->full_name); } -/* enable IO workaround */ -void __devinit io_workaround_init(void) -{ - static int io_workaround_inited; - - if (io_workaround_inited) - return; - ppc_pci_io = iowa_pci_io; - ppc_md.ioremap = iowa_ioremap; - io_workaround_inited = 1; -} diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index f621b7d2d869..a24d37d4cf51 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -66,7 +66,6 @@ #include #include #include -#include #include #ifdef CONFIG_PPC64 @@ -160,7 +159,8 @@ notrace void arch_local_irq_restore(unsigned long en) #if defined(CONFIG_BOOKE) && defined(CONFIG_SMP) /* Check for pending doorbell interrupts and resend to ourself */ - doorbell_check_self(); + if (cpu_has_feature(CPU_FTR_DBELL)) + smp_muxed_ipi_resend(); #endif /* @@ -397,24 +397,28 @@ struct thread_info *mcheckirq_ctx[NR_CPUS] __read_mostly; void exc_lvl_ctx_init(void) { struct thread_info *tp; - int i, hw_cpu; + int i, cpu_nr; for_each_possible_cpu(i) { - hw_cpu = get_hard_smp_processor_id(i); - memset((void *)critirq_ctx[hw_cpu], 0, THREAD_SIZE); - tp = critirq_ctx[hw_cpu]; - tp->cpu = i; +#ifdef CONFIG_PPC64 + cpu_nr = i; +#else + cpu_nr = get_hard_smp_processor_id(i); +#endif + memset((void *)critirq_ctx[cpu_nr], 0, THREAD_SIZE); + tp = critirq_ctx[cpu_nr]; + tp->cpu = cpu_nr; tp->preempt_count = 0; #ifdef CONFIG_BOOKE - memset((void *)dbgirq_ctx[hw_cpu], 0, THREAD_SIZE); - tp = dbgirq_ctx[hw_cpu]; - tp->cpu = i; + memset((void *)dbgirq_ctx[cpu_nr], 0, THREAD_SIZE); + tp = dbgirq_ctx[cpu_nr]; + tp->cpu = cpu_nr; tp->preempt_count = 0; - memset((void *)mcheckirq_ctx[hw_cpu], 0, THREAD_SIZE); - tp = mcheckirq_ctx[hw_cpu]; - tp->cpu = i; + memset((void *)mcheckirq_ctx[cpu_nr], 0, THREAD_SIZE); + tp = mcheckirq_ctx[cpu_nr]; + tp->cpu = cpu_nr; tp->preempt_count = HARDIRQ_OFFSET; #endif } @@ -477,20 +481,41 @@ void do_softirq(void) * IRQ controller and virtual interrupts */ +/* The main irq map itself is an array of NR_IRQ entries containing the + * associate host and irq number. An entry with a host of NULL is free. + * An entry can be allocated if it's free, the allocator always then sets + * hwirq first to the host's invalid irq number and then fills ops. + */ +struct irq_map_entry { + irq_hw_number_t hwirq; + struct irq_host *host; +}; + static LIST_HEAD(irq_hosts); static DEFINE_RAW_SPINLOCK(irq_big_lock); -static unsigned int revmap_trees_allocated; static DEFINE_MUTEX(revmap_trees_mutex); -struct irq_map_entry irq_map[NR_IRQS]; +static struct irq_map_entry irq_map[NR_IRQS]; static unsigned int irq_virq_count = NR_IRQS; static struct irq_host *irq_default_host; +irq_hw_number_t irqd_to_hwirq(struct irq_data *d) +{ + return irq_map[d->irq].hwirq; +} +EXPORT_SYMBOL_GPL(irqd_to_hwirq); + irq_hw_number_t virq_to_hw(unsigned int virq) { return irq_map[virq].hwirq; } EXPORT_SYMBOL_GPL(virq_to_hw); +bool virq_is_host(unsigned int virq, struct irq_host *host) +{ + return irq_map[virq].host == host; +} +EXPORT_SYMBOL_GPL(virq_is_host); + static int default_irq_host_match(struct irq_host *h, struct device_node *np) { return h->of_node != NULL && h->of_node == np; @@ -511,7 +536,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, /* Allocate structure and revmap table if using linear mapping */ if (revmap_type == IRQ_HOST_MAP_LINEAR) size += revmap_arg * sizeof(unsigned int); - host = zalloc_maybe_bootmem(size, GFP_KERNEL); + host = kzalloc(size, GFP_KERNEL); if (host == NULL) return NULL; @@ -561,14 +586,14 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, irq_map[i].host = host; smp_wmb(); - /* Clear norequest flags */ - irq_clear_status_flags(i, IRQ_NOREQUEST); - /* Legacy flags are left to default at this point, * one can then use irq_create_mapping() to * explicitly change them */ ops->map(host, i, i); + + /* Clear norequest flags */ + irq_clear_status_flags(i, IRQ_NOREQUEST); } break; case IRQ_HOST_MAP_LINEAR: @@ -579,6 +604,9 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, smp_wmb(); host->revmap_data.linear.revmap = rmap; break; + case IRQ_HOST_MAP_TREE: + INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); + break; default: break; } @@ -636,8 +664,6 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq, goto error; } - irq_clear_status_flags(virq, IRQ_NOREQUEST); - /* map it */ smp_wmb(); irq_map[virq].hwirq = hwirq; @@ -648,6 +674,8 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq, goto errdesc; } + irq_clear_status_flags(virq, IRQ_NOREQUEST); + return 0; errdesc: @@ -704,8 +732,6 @@ unsigned int irq_create_mapping(struct irq_host *host, */ virq = irq_find_mapping(host, hwirq); if (virq != NO_IRQ) { - if (host->ops->remap) - host->ops->remap(host, virq, hwirq); pr_debug("irq: -> existing mapping on virq %d\n", virq); return virq; } @@ -786,14 +812,15 @@ void irq_dispose_mapping(unsigned int virq) return; host = irq_map[virq].host; - WARN_ON (host == NULL); - if (host == NULL) + if (WARN_ON(host == NULL)) return; /* Never unmap legacy interrupts */ if (host->revmap_type == IRQ_HOST_MAP_LEGACY) return; + irq_set_status_flags(virq, IRQ_NOREQUEST); + /* remove chip and handler */ irq_set_chip_and_handler(virq, NULL, NULL); @@ -813,13 +840,6 @@ void irq_dispose_mapping(unsigned int virq) host->revmap_data.linear.revmap[hwirq] = NO_IRQ; break; case IRQ_HOST_MAP_TREE: - /* - * Check if radix tree allocated yet, if not then nothing to - * remove. - */ - smp_rmb(); - if (revmap_trees_allocated < 1) - break; mutex_lock(&revmap_trees_mutex); radix_tree_delete(&host->revmap_data.tree, hwirq); mutex_unlock(&revmap_trees_mutex); @@ -830,8 +850,6 @@ void irq_dispose_mapping(unsigned int virq) smp_mb(); irq_map[virq].hwirq = host->inval_irq; - irq_set_status_flags(virq, IRQ_NOREQUEST); - irq_free_descs(virq, 1); /* Free it */ irq_free_virt(virq, 1); @@ -877,16 +895,9 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host, struct irq_map_entry *ptr; unsigned int virq; - WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE); - - /* - * Check if the radix tree exists and has bee initialized. - * If not, we fallback to slow mode - */ - if (revmap_trees_allocated < 2) + if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE)) return irq_find_mapping(host, hwirq); - /* Now try to resolve */ /* * No rcu_read_lock(ing) needed, the ptr returned can't go under us * as it's referencing an entry in the static irq_map table. @@ -909,16 +920,7 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host, void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, irq_hw_number_t hwirq) { - - WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE); - - /* - * Check if the radix tree exists yet. - * If not, then the irq will be inserted into the tree when it gets - * initialized. - */ - smp_rmb(); - if (revmap_trees_allocated < 1) + if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE)) return; if (virq != NO_IRQ) { @@ -934,7 +936,8 @@ unsigned int irq_linear_revmap(struct irq_host *host, { unsigned int *revmap; - WARN_ON(host->revmap_type != IRQ_HOST_MAP_LINEAR); + if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR)) + return irq_find_mapping(host, hwirq); /* Check revmap bounds */ if (unlikely(hwirq >= host->revmap_data.linear.size)) @@ -1028,53 +1031,6 @@ int arch_early_irq_init(void) return 0; } -/* We need to create the radix trees late */ -static int irq_late_init(void) -{ - struct irq_host *h; - unsigned int i; - - /* - * No mutual exclusion with respect to accessors of the tree is needed - * here as the synchronization is done via the state variable - * revmap_trees_allocated. - */ - list_for_each_entry(h, &irq_hosts, link) { - if (h->revmap_type == IRQ_HOST_MAP_TREE) - INIT_RADIX_TREE(&h->revmap_data.tree, GFP_KERNEL); - } - - /* - * Make sure the radix trees inits are visible before setting - * the flag - */ - smp_wmb(); - revmap_trees_allocated = 1; - - /* - * Insert the reverse mapping for those interrupts already present - * in irq_map[]. - */ - mutex_lock(&revmap_trees_mutex); - for (i = 0; i < irq_virq_count; i++) { - if (irq_map[i].host && - (irq_map[i].host->revmap_type == IRQ_HOST_MAP_TREE)) - radix_tree_insert(&irq_map[i].host->revmap_data.tree, - irq_map[i].hwirq, &irq_map[i]); - } - mutex_unlock(&revmap_trees_mutex); - - /* - * Make sure the radix trees insertions are visible before setting - * the flag - */ - smp_wmb(); - revmap_trees_allocated = 2; - - return 0; -} -arch_initcall(irq_late_init); - #ifdef CONFIG_VIRQ_DEBUG static int virq_debug_show(struct seq_file *m, void *private) { @@ -1082,10 +1038,11 @@ static int virq_debug_show(struct seq_file *m, void *private) struct irq_desc *desc; const char *p; static const char none[] = "none"; + void *data; int i; - seq_printf(m, "%-5s %-7s %-15s %s\n", "virq", "hwirq", - "chip name", "host name"); + seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq", + "chip name", "chip data", "host name"); for (i = 1; i < nr_irqs; i++) { desc = irq_to_desc(i); @@ -1098,7 +1055,7 @@ static int virq_debug_show(struct seq_file *m, void *private) struct irq_chip *chip; seq_printf(m, "%5d ", i); - seq_printf(m, "0x%05lx ", virq_to_hw(i)); + seq_printf(m, "0x%05lx ", irq_map[i].hwirq); chip = irq_desc_get_chip(desc); if (chip && chip->name) @@ -1107,6 +1064,9 @@ static int virq_debug_show(struct seq_file *m, void *private) p = none; seq_printf(m, "%-15s ", p); + data = irq_desc_get_chip_data(desc); + seq_printf(m, "0x%16p ", data); + if (irq_map[i].host && irq_map[i].host->of_node) p = irq_map[i].host->of_node->full_name; else diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 42850ee00ada..bd9d35f59cf4 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -109,7 +109,7 @@ static int kgdb_call_nmi_hook(struct pt_regs *regs) #ifdef CONFIG_SMP void kgdb_roundup_cpus(unsigned long flags) { - smp_send_debugger_break(MSG_ALL_BUT_SELF); + smp_send_debugger_break(); } #endif diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index c834757bebc0..2b97b80d6d7d 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -330,9 +330,11 @@ void __init find_legacy_serial_ports(void) if (!parent) continue; if (of_match_node(legacy_serial_parents, parent) != NULL) { - index = add_legacy_soc_port(np, np); - if (index >= 0 && np == stdout) - legacy_serial_console = index; + if (of_device_is_available(np)) { + index = add_legacy_soc_port(np, np); + if (index >= 0 && np == stdout) + legacy_serial_console = index; + } } of_node_put(parent); } diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 301db65f05a1..84daabe2fcba 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c @@ -132,34 +132,6 @@ static int iseries_lparcfg_data(struct seq_file *m, void *v) /* * Methods used to fetch LPAR data when running on a pSeries platform. */ -/** - * h_get_mpp - * H_GET_MPP hcall returns info in 7 parms - */ -int h_get_mpp(struct hvcall_mpp_data *mpp_data) -{ - int rc; - unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; - - rc = plpar_hcall9(H_GET_MPP, retbuf); - - mpp_data->entitled_mem = retbuf[0]; - mpp_data->mapped_mem = retbuf[1]; - - mpp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff; - mpp_data->pool_num = retbuf[2] & 0xffff; - - mpp_data->mem_weight = (retbuf[3] >> 7 * 8) & 0xff; - mpp_data->unallocated_mem_weight = (retbuf[3] >> 6 * 8) & 0xff; - mpp_data->unallocated_entitlement = retbuf[3] & 0xffffffffffff; - - mpp_data->pool_size = retbuf[4]; - mpp_data->loan_request = retbuf[5]; - mpp_data->backing_mem = retbuf[6]; - - return rc; -} -EXPORT_SYMBOL(h_get_mpp); struct hvcall_ppp_data { u64 entitlement; @@ -345,6 +317,30 @@ static void parse_mpp_data(struct seq_file *m) seq_printf(m, "backing_memory=%ld bytes\n", mpp_data.backing_mem); } +/** + * parse_mpp_x_data + * Parse out data returned from h_get_mpp_x + */ +static void parse_mpp_x_data(struct seq_file *m) +{ + struct hvcall_mpp_x_data mpp_x_data; + + if (!firmware_has_feature(FW_FEATURE_XCMO)) + return; + if (h_get_mpp_x(&mpp_x_data)) + return; + + seq_printf(m, "coalesced_bytes=%ld\n", mpp_x_data.coalesced_bytes); + + if (mpp_x_data.pool_coalesced_bytes) + seq_printf(m, "pool_coalesced_bytes=%ld\n", + mpp_x_data.pool_coalesced_bytes); + if (mpp_x_data.pool_purr_cycles) + seq_printf(m, "coalesce_pool_purr=%ld\n", mpp_x_data.pool_purr_cycles); + if (mpp_x_data.pool_spurr_cycles) + seq_printf(m, "coalesce_pool_spurr=%ld\n", mpp_x_data.pool_spurr_cycles); +} + #define SPLPAR_CHARACTERISTICS_TOKEN 20 #define SPLPAR_MAXLENGTH 1026*(sizeof(char)) @@ -520,6 +516,7 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v) parse_system_parameter_string(m); parse_ppp_data(m); parse_mpp_data(m); + parse_mpp_x_data(m); pseries_cmo_data(m); splpar_dispatch_data(m); diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 094bd9821ad4..998a10028608 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -694,6 +694,17 @@ _GLOBAL(kernel_thread) addi r1,r1,16 blr +#ifdef CONFIG_SMP +_GLOBAL(start_secondary_resume) + /* Reset stack */ + rlwinm r1,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ + addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD + li r3,0 + stw r3,0(r1) /* Zero the stack frame pointer */ + bl start_secondary + b . +#endif /* CONFIG_SMP */ + /* * This routine is just here to keep GCC happy - sigh... */ diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 206a321a71d3..e89df59cdc5a 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -462,7 +462,8 @@ _GLOBAL(disable_kernel_fp) * wait for the flag to change, indicating this kernel is going away but * the slave code for the next one is at addresses 0 to 100. * - * This is used by all slaves. + * This is used by all slaves, even those that did not find a matching + * paca in the secondary startup code. * * Physical (hardware) cpu id should be in r3. */ @@ -471,10 +472,6 @@ _GLOBAL(kexec_wait) 1: mflr r5 addi r5,r5,kexec_flag-1b - li r4,KEXEC_STATE_REAL_MODE - stb r4,PACAKEXECSTATE(r13) - SYNC - 99: HMT_LOW #ifdef CONFIG_KEXEC /* use no memory without kexec */ lwz r4,0(r5) @@ -499,11 +496,17 @@ kexec_flag: * * get phys id from paca * switch to real mode + * mark the paca as no longer used * join other cpus in kexec_wait(phys_id) */ _GLOBAL(kexec_smp_wait) lhz r3,PACAHWCPUID(r13) bl real_mode + + li r4,KEXEC_STATE_REAL_MODE + stb r4,PACAKEXECSTATE(r13) + SYNC + b .kexec_wait /* diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 10f0aadee95b..efeb88184182 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -7,7 +7,7 @@ * 2 of the License, or (at your option) any later version. */ -#include +#include #include #include @@ -156,18 +156,29 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu) /* Put the paca pointer into r13 and SPRG_PACA */ void setup_paca(struct paca_struct *new_paca) { + /* Setup r13 */ local_paca = new_paca; - mtspr(SPRN_SPRG_PACA, local_paca); + #ifdef CONFIG_PPC_BOOK3E + /* On Book3E, initialize the TLB miss exception frames */ mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb); +#else + /* In HV mode, we setup both HPACA and PACA to avoid problems + * if we do a GET_PACA() before the feature fixups have been + * applied + */ + if (cpu_has_feature(CPU_FTR_HVMODE_206)) + mtspr(SPRN_SPRG_HPACA, local_paca); #endif + mtspr(SPRN_SPRG_PACA, local_paca); + } static int __initdata paca_size; void __init allocate_pacas(void) { - int nr_cpus, cpu, limit; + int cpu, limit; /* * We can't take SLB misses on the paca, and we want to access them @@ -179,23 +190,18 @@ void __init allocate_pacas(void) if (firmware_has_feature(FW_FEATURE_ISERIES)) limit = min(limit, HvPagesToMap * HVPAGESIZE); - nr_cpus = NR_CPUS; - /* On iSeries we know we can never have more than 64 cpus */ - if (firmware_has_feature(FW_FEATURE_ISERIES)) - nr_cpus = min(64, nr_cpus); - - paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpus); + paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids); paca = __va(memblock_alloc_base(paca_size, PAGE_SIZE, limit)); memset(paca, 0, paca_size); printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n", - paca_size, nr_cpus, paca); + paca_size, nr_cpu_ids, paca); - allocate_lppacas(nr_cpus, limit); + allocate_lppacas(nr_cpu_ids, limit); /* Can't use for_each_*_cpu, as they aren't functional yet */ - for (cpu = 0; cpu < nr_cpus; cpu++) + for (cpu = 0; cpu < nr_cpu_ids; cpu++) initialise_paca(&paca[cpu], cpu); } diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c index d225d99fe39d..6baabc13306a 100644 --- a/arch/powerpc/kernel/pci_dn.c +++ b/arch/powerpc/kernel/pci_dn.c @@ -43,10 +43,9 @@ void * __devinit update_dn_pci_info(struct device_node *dn, void *data) const u32 *regs; struct pci_dn *pdn; - pdn = alloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL); + pdn = zalloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL); if (pdn == NULL) return NULL; - memset(pdn, 0, sizeof(*pdn)); dn->data = pdn; pdn->node = dn; pdn->phb = phb; diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c index c4063b7f49a0..822f63008ae1 100644 --- a/arch/powerpc/kernel/perf_event.c +++ b/arch/powerpc/kernel/perf_event.c @@ -398,6 +398,25 @@ static int check_excludes(struct perf_event **ctrs, unsigned int cflags[], return 0; } +static u64 check_and_compute_delta(u64 prev, u64 val) +{ + u64 delta = (val - prev) & 0xfffffffful; + + /* + * POWER7 can roll back counter values, if the new value is smaller + * than the previous value it will cause the delta and the counter to + * have bogus values unless we rolled a counter over. If a coutner is + * rolled back, it will be smaller, but within 256, which is the maximum + * number of events to rollback at once. If we dectect a rollback + * return 0. This can lead to a small lack of precision in the + * counters. + */ + if (prev > val && (prev - val) < 256) + delta = 0; + + return delta; +} + static void power_pmu_read(struct perf_event *event) { s64 val, delta, prev; @@ -416,10 +435,11 @@ static void power_pmu_read(struct perf_event *event) prev = local64_read(&event->hw.prev_count); barrier(); val = read_pmc(event->hw.idx); + delta = check_and_compute_delta(prev, val); + if (!delta) + return; } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev); - /* The counters are only 32 bits wide */ - delta = (val - prev) & 0xfffffffful; local64_add(delta, &event->count); local64_sub(delta, &event->hw.period_left); } @@ -449,8 +469,9 @@ static void freeze_limited_counters(struct cpu_hw_events *cpuhw, val = (event->hw.idx == 5) ? pmc5 : pmc6; prev = local64_read(&event->hw.prev_count); event->hw.idx = 0; - delta = (val - prev) & 0xfffffffful; - local64_add(delta, &event->count); + delta = check_and_compute_delta(prev, val); + if (delta) + local64_add(delta, &event->count); } } @@ -458,14 +479,16 @@ static void thaw_limited_counters(struct cpu_hw_events *cpuhw, unsigned long pmc5, unsigned long pmc6) { struct perf_event *event; - u64 val; + u64 val, prev; int i; for (i = 0; i < cpuhw->n_limited; ++i) { event = cpuhw->limited_counter[i]; event->hw.idx = cpuhw->limited_hwidx[i]; val = (event->hw.idx == 5) ? pmc5 : pmc6; - local64_set(&event->hw.prev_count, val); + prev = local64_read(&event->hw.prev_count); + if (check_and_compute_delta(prev, val)) + local64_set(&event->hw.prev_count, val); perf_event_update_userpage(event); } } @@ -1197,7 +1220,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, /* we don't have to worry about interrupts here */ prev = local64_read(&event->hw.prev_count); - delta = (val - prev) & 0xfffffffful; + delta = check_and_compute_delta(prev, val); local64_add(delta, &event->count); /* diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index ef3ef566235e..7d28f540200c 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -54,7 +54,6 @@ extern void single_step_exception(struct pt_regs *regs); extern int sys_sigreturn(struct pt_regs *regs); EXPORT_SYMBOL(clear_pages); -EXPORT_SYMBOL(copy_page); EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); @@ -88,9 +87,7 @@ EXPORT_SYMBOL(__copy_tofrom_user); EXPORT_SYMBOL(__clear_user); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__strnlen_user); -#ifdef CONFIG_PPC64 -EXPORT_SYMBOL(copy_4K_page); -#endif +EXPORT_SYMBOL(copy_page); #if defined(CONFIG_PCI) && defined(CONFIG_PPC32) EXPORT_SYMBOL(isa_io_base); diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index f74f355a9617..095043d79946 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -702,6 +702,8 @@ void prepare_to_copy(struct task_struct *tsk) /* * Copy a thread.. */ +extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */ + int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) @@ -755,11 +757,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, _ALIGN_UP(sizeof(struct thread_info), 16); #ifdef CONFIG_PPC_STD_MMU_64 - if (cpu_has_feature(CPU_FTR_SLB)) { + if (mmu_has_feature(MMU_FTR_SLB)) { unsigned long sp_vsid; unsigned long llp = mmu_psize_defs[mmu_linear_psize].sllp; - if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) + if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) sp_vsid = get_kernel_vsid(sp, MMU_SEGSIZE_1T) << SLB_VSID_SHIFT_1T; else @@ -769,6 +771,20 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, p->thread.ksp_vsid = sp_vsid; } #endif /* CONFIG_PPC_STD_MMU_64 */ +#ifdef CONFIG_PPC64 + if (cpu_has_feature(CPU_FTR_DSCR)) { + if (current->thread.dscr_inherit) { + p->thread.dscr_inherit = 1; + p->thread.dscr = current->thread.dscr; + } else if (0 != dscr_default) { + p->thread.dscr_inherit = 1; + p->thread.dscr = dscr_default; + } else { + p->thread.dscr_inherit = 0; + p->thread.dscr = 0; + } + } +#endif /* * The PPC64 ABI makes use of a TOC to contain function diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index e74fa12afc82..48aeb55faae9 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -68,6 +68,7 @@ int __initdata iommu_force_on; unsigned long tce_alloc_start, tce_alloc_end; u64 ppc64_rma_size; #endif +static phys_addr_t first_memblock_size; static int __init early_parse_mem(char *p) { @@ -123,18 +124,19 @@ static void __init move_device_tree(void) */ static struct ibm_pa_feature { unsigned long cpu_features; /* CPU_FTR_xxx bit */ + unsigned long mmu_features; /* MMU_FTR_xxx bit */ unsigned int cpu_user_ftrs; /* PPC_FEATURE_xxx bit */ unsigned char pabyte; /* byte number in ibm,pa-features */ unsigned char pabit; /* bit number (big-endian) */ unsigned char invert; /* if 1, pa bit set => clear feature */ } ibm_pa_features[] __initdata = { - {0, PPC_FEATURE_HAS_MMU, 0, 0, 0}, - {0, PPC_FEATURE_HAS_FPU, 0, 1, 0}, - {CPU_FTR_SLB, 0, 0, 2, 0}, - {CPU_FTR_CTRL, 0, 0, 3, 0}, - {CPU_FTR_NOEXECUTE, 0, 0, 6, 0}, - {CPU_FTR_NODSISRALIGN, 0, 1, 1, 1}, - {CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, + {0, 0, PPC_FEATURE_HAS_MMU, 0, 0, 0}, + {0, 0, PPC_FEATURE_HAS_FPU, 0, 1, 0}, + {0, MMU_FTR_SLB, 0, 0, 2, 0}, + {CPU_FTR_CTRL, 0, 0, 0, 3, 0}, + {CPU_FTR_NOEXECUTE, 0, 0, 0, 6, 0}, + {CPU_FTR_NODSISRALIGN, 0, 0, 1, 1, 1}, + {0, MMU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0}, }; @@ -166,9 +168,11 @@ static void __init scan_features(unsigned long node, unsigned char *ftrs, if (bit ^ fp->invert) { cur_cpu_spec->cpu_features |= fp->cpu_features; cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs; + cur_cpu_spec->mmu_features |= fp->mmu_features; } else { cur_cpu_spec->cpu_features &= ~fp->cpu_features; cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs; + cur_cpu_spec->mmu_features &= ~fp->mmu_features; } } } @@ -268,13 +272,13 @@ static int __init early_init_dt_scan_cpus(unsigned long node, const char *uname, int depth, void *data) { - static int logical_cpuid = 0; char *type = of_get_flat_dt_prop(node, "device_type", NULL); const u32 *prop; const u32 *intserv; int i, nthreads; unsigned long len; - int found = 0; + int found = -1; + int found_thread = 0; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) @@ -298,11 +302,10 @@ static int __init early_init_dt_scan_cpus(unsigned long node, * version 2 of the kexec param format adds the phys cpuid of * booted proc. */ - if (initial_boot_params && initial_boot_params->version >= 2) { - if (intserv[i] == - initial_boot_params->boot_cpuid_phys) { - found = 1; - break; + if (initial_boot_params->version >= 2) { + if (intserv[i] == initial_boot_params->boot_cpuid_phys) { + found = boot_cpu_count; + found_thread = i; } } else { /* @@ -311,23 +314,20 @@ static int __init early_init_dt_scan_cpus(unsigned long node, * off secondary threads. */ if (of_get_flat_dt_prop(node, - "linux,boot-cpu", NULL) != NULL) { - found = 1; - break; - } + "linux,boot-cpu", NULL) != NULL) + found = boot_cpu_count; } - #ifdef CONFIG_SMP /* logical cpu id is always 0 on UP kernels */ - logical_cpuid++; + boot_cpu_count++; #endif } - if (found) { - DBG("boot cpu: logical %d physical %d\n", logical_cpuid, - intserv[i]); - boot_cpuid = logical_cpuid; - set_hard_smp_processor_id(boot_cpuid, intserv[i]); + if (found >= 0) { + DBG("boot cpu: logical %d physical %d\n", found, + intserv[found_thread]); + boot_cpuid = found; + set_hard_smp_processor_id(found, intserv[found_thread]); /* * PAPR defines "logical" PVR values for cpus that @@ -509,11 +509,14 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) size = 0x80000000ul - base; } #endif - - /* First MEMBLOCK added, do some special initializations */ - if (memstart_addr == ~(phys_addr_t)0) - setup_initial_memory_limit(base, size); - memstart_addr = min((u64)memstart_addr, base); + /* Keep track of the beginning of memory -and- the size of + * the very first block in the device-tree as it represents + * the RMA on ppc64 server + */ + if (base < memstart_addr) { + memstart_addr = base; + first_memblock_size = size; + } /* Add the chunk to the MEMBLOCK list */ memblock_add(base, size); @@ -698,6 +701,7 @@ void __init early_init_devtree(void *params) of_scan_flat_dt(early_init_dt_scan_root, NULL); of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL); + setup_initial_memory_limit(memstart_addr, first_memblock_size); /* Save command line for /proc/cmdline and then parse parameters */ strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 941ff4dbc567..c016033ba78d 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -335,6 +335,7 @@ static void __init prom_printf(const char *format, ...) const char *p, *q, *s; va_list args; unsigned long v; + long vs; struct prom_t *_prom = &RELOC(prom); va_start(args, format); @@ -368,12 +369,35 @@ static void __init prom_printf(const char *format, ...) v = va_arg(args, unsigned long); prom_print_hex(v); break; + case 'd': + ++q; + vs = va_arg(args, int); + if (vs < 0) { + prom_print(RELOC("-")); + vs = -vs; + } + prom_print_dec(vs); + break; case 'l': ++q; - if (*q == 'u') { /* '%lu' */ + if (*q == 0) + break; + else if (*q == 'x') { + ++q; + v = va_arg(args, unsigned long); + prom_print_hex(v); + } else if (*q == 'u') { /* '%lu' */ ++q; v = va_arg(args, unsigned long); prom_print_dec(v); + } else if (*q == 'd') { /* %ld */ + ++q; + vs = va_arg(args, long); + if (vs < 0) { + prom_print(RELOC("-")); + vs = -vs; + } + prom_print_dec(vs); } break; } @@ -676,8 +700,10 @@ static void __init early_cmdline_parse(void) #endif /* CONFIG_PCI_MSI */ #ifdef CONFIG_PPC_SMLPAR #define OV5_CMO 0x80 /* Cooperative Memory Overcommitment */ +#define OV5_XCMO 0x40 /* Page Coalescing */ #else #define OV5_CMO 0x00 +#define OV5_XCMO 0x00 #endif #define OV5_TYPE1_AFFINITY 0x80 /* Type 1 NUMA affinity */ @@ -732,7 +758,7 @@ static unsigned char ibm_architecture_vec[] = { OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | OV5_DONATE_DEDICATE_CPU | OV5_MSI, 0, - OV5_CMO, + OV5_CMO | OV5_XCMO, OV5_TYPE1_AFFINITY, 0, 0, diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 55613e33e263..a6ae1cfad86c 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -933,12 +933,16 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, if (data && !(data & DABR_TRANSLATION)) return -EIO; #ifdef CONFIG_HAVE_HW_BREAKPOINT + if (ptrace_get_breakpoints(task) < 0) + return -ESRCH; + bp = thread->ptrace_bps[0]; if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) { if (bp) { unregister_hw_breakpoint(bp); thread->ptrace_bps[0] = NULL; } + ptrace_put_breakpoints(task); return 0; } if (bp) { @@ -948,9 +952,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, (DABR_DATA_WRITE | DABR_DATA_READ), &attr.bp_type); ret = modify_user_hw_breakpoint(bp, &attr); - if (ret) + if (ret) { + ptrace_put_breakpoints(task); return ret; + } thread->ptrace_bps[0] = bp; + ptrace_put_breakpoints(task); thread->dabr = data; return 0; } @@ -965,9 +972,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, ptrace_triggered, task); if (IS_ERR(bp)) { thread->ptrace_bps[0] = NULL; + ptrace_put_breakpoints(task); return PTR_ERR(bp); } + ptrace_put_breakpoints(task); + #endif /* CONFIG_HAVE_HW_BREAKPOINT */ /* Move contents to the DABR register */ diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 2097f2b3cba8..271ff6318eda 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -42,6 +42,7 @@ #include #include #include +#include struct rtas_t rtas = { .lock = __ARCH_SPIN_LOCK_UNLOCKED @@ -494,7 +495,7 @@ unsigned int rtas_busy_delay(int status) might_sleep(); ms = rtas_busy_delay_time(status); - if (ms) + if (ms && need_resched()) msleep(ms); return ms; @@ -731,6 +732,7 @@ static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_w atomic_set(&data->error, rc); start_topology_update(); + pSeries_coalesce_init(); if (wake_when_done) { atomic_set(&data->done, 1); diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 21f30cb68077..79fca2651b65 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -381,7 +381,7 @@ static void __init cpu_init_thread_core_maps(int tpc) int i; threads_per_core = tpc; - threads_core_mask = CPU_MASK_NONE; + cpumask_clear(&threads_core_mask); /* This implementation only supports power of 2 number of threads * for simplicity and performance @@ -390,7 +390,7 @@ static void __init cpu_init_thread_core_maps(int tpc) BUG_ON(tpc != (1 << threads_shift)); for (i = 0; i < tpc; i++) - cpu_set(i, threads_core_mask); + cpumask_set_cpu(i, &threads_core_mask); printk(KERN_INFO "CPU maps initialized for %d thread%s per core\n", tpc, tpc > 1 ? "s" : ""); @@ -404,7 +404,7 @@ static void __init cpu_init_thread_core_maps(int tpc) * cpu_present_mask * * Having the possible map set up early allows us to restrict allocations - * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. + * of things like irqstacks to nr_cpu_ids rather than NR_CPUS. * * We do not initialize the online map here; cpus set their own bits in * cpu_online_mask as they come up. @@ -424,7 +424,7 @@ void __init smp_setup_cpu_maps(void) DBG("smp_setup_cpu_maps()\n"); - while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { + while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < nr_cpu_ids) { const int *intserv; int j, len; @@ -443,7 +443,7 @@ void __init smp_setup_cpu_maps(void) intserv = &cpu; /* assume logical == phys */ } - for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { + for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) { DBG(" thread %d -> cpu %d (hard id %d)\n", j, cpu, intserv[j]); set_cpu_present(cpu, true); @@ -483,12 +483,12 @@ void __init smp_setup_cpu_maps(void) if (cpu_has_feature(CPU_FTR_SMT)) maxcpus *= nthreads; - if (maxcpus > NR_CPUS) { + if (maxcpus > nr_cpu_ids) { printk(KERN_WARNING "Partition configured for %d cpus, " "operating system maximum is %d.\n", - maxcpus, NR_CPUS); - maxcpus = NR_CPUS; + maxcpus, nr_cpu_ids); + maxcpus = nr_cpu_ids; } else printk(KERN_INFO "Partition configured for %d cpus.\n", maxcpus); @@ -510,7 +510,7 @@ void __init smp_setup_cpu_maps(void) cpu_init_thread_core_maps(nthreads); /* Now that possible cpus are set, set nr_cpu_ids for later use */ - nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1; + setup_nr_cpu_ids(); free_unused_pacas(); } @@ -602,6 +602,10 @@ int check_legacy_ioport(unsigned long base_port) * name instead */ if (!np) np = of_find_node_by_name(NULL, "8042"); + if (np) { + of_i8042_kbd_irq = 1; + of_i8042_aux_irq = 12; + } break; case FDC_BASE: /* FDC1 */ np = of_find_node_by_type(NULL, "fdc"); diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 1d2fbc905303..620d792b52e4 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -48,6 +48,7 @@ extern void bootx_init(unsigned long r4, unsigned long phys); int boot_cpuid = -1; EXPORT_SYMBOL_GPL(boot_cpuid); +int __initdata boot_cpu_count; int boot_cpuid_phys; int smp_hw_index[NR_CPUS]; diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 5a0401fcaebd..a88bf2713d41 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -62,6 +62,7 @@ #include #include #include +#include #include "setup.h" @@ -72,6 +73,7 @@ #endif int boot_cpuid = 0; +int __initdata boot_cpu_count; u64 ppc64_pft_size; /* Pick defaults since we might want to patch instructions @@ -233,6 +235,7 @@ void early_setup_secondary(void) void smp_release_cpus(void) { unsigned long *ptr; + int i; DBG(" -> smp_release_cpus()\n"); @@ -245,7 +248,16 @@ void smp_release_cpus(void) ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop - PHYSICAL_START); *ptr = __pa(generic_secondary_smp_init); - mb(); + + /* And wait a bit for them to catch up */ + for (i = 0; i < 100000; i++) { + mb(); + HMT_low(); + if (boot_cpu_count == 0) + break; + udelay(1); + } + DBG("boot_cpu_count = %d\n", boot_cpu_count); DBG(" <- smp_release_cpus()\n"); } @@ -423,17 +435,30 @@ void __init setup_system(void) DBG(" <- setup_system()\n"); } -static u64 slb0_limit(void) +/* This returns the limit below which memory accesses to the linear + * mapping are guarnateed not to cause a TLB or SLB miss. This is + * used to allocate interrupt or emergency stacks for which our + * exception entry path doesn't deal with being interrupted. + */ +static u64 safe_stack_limit(void) { - if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) { +#ifdef CONFIG_PPC_BOOK3E + /* Freescale BookE bolts the entire linear mapping */ + if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) + return linear_map_top; + /* Other BookE, we assume the first GB is bolted */ + return 1ul << 30; +#else + /* BookS, the first segment is bolted */ + if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) return 1UL << SID_SHIFT_1T; - } return 1UL << SID_SHIFT; +#endif } static void __init irqstack_early_init(void) { - u64 limit = slb0_limit(); + u64 limit = safe_stack_limit(); unsigned int i; /* @@ -453,6 +478,9 @@ static void __init irqstack_early_init(void) #ifdef CONFIG_PPC_BOOK3E static void __init exc_lvl_early_init(void) { + extern unsigned int interrupt_base_book3e; + extern unsigned int exc_debug_debug_book3e; + unsigned int i; for_each_possible_cpu(i) { @@ -463,6 +491,10 @@ static void __init exc_lvl_early_init(void) mcheckirq_ctx[i] = (struct thread_info *) __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); } + + if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC)) + patch_branch(&interrupt_base_book3e + (0x040 / 4) + 1, + (unsigned long)&exc_debug_debug_book3e, 0); } #else #define exc_lvl_early_init() @@ -486,7 +518,7 @@ static void __init emergency_stack_init(void) * bringup, we need to get at them in real mode. This means they * must also be within the RMO region. */ - limit = min(slb0_limit(), ppc64_rma_size); + limit = min(safe_stack_limit(), ppc64_rma_size); for_each_possible_cpu(i) { unsigned long sp; diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 27c4a4584f80..da989fff19cc 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -381,7 +381,7 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, regs, uc, &uc->uc_mcontext); #endif if (show_unhandled_signals && printk_ratelimit()) - printk(regs->msr & MSR_SF ? fmt64 : fmt32, + printk(regs->msr & MSR_64BIT ? fmt64 : fmt32, current->comm, current->pid, "rt_sigreturn", (long)uc, regs->nip, regs->link); @@ -469,7 +469,7 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info, regs, frame, newsp); #endif if (show_unhandled_signals && printk_ratelimit()) - printk(regs->msr & MSR_SF ? fmt64 : fmt32, + printk(regs->msr & MSR_64BIT ? fmt64 : fmt32, current->comm, current->pid, "setup_rt_frame", (long)frame, regs->nip, regs->link); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index cbdbb14be4b0..4a6f2ec7e761 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -95,7 +95,7 @@ int smt_enabled_at_boot = 1; static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL; #ifdef CONFIG_PPC64 -void __devinit smp_generic_kick_cpu(int nr) +int __devinit smp_generic_kick_cpu(int nr) { BUG_ON(nr < 0 || nr >= NR_CPUS); @@ -106,38 +106,11 @@ void __devinit smp_generic_kick_cpu(int nr) */ paca[nr].cpu_start = 1; smp_mb(); + + return 0; } #endif -void smp_message_recv(int msg) -{ - switch(msg) { - case PPC_MSG_CALL_FUNCTION: - generic_smp_call_function_interrupt(); - break; - case PPC_MSG_RESCHEDULE: - /* we notice need_resched on exit */ - break; - case PPC_MSG_CALL_FUNC_SINGLE: - generic_smp_call_function_single_interrupt(); - break; - case PPC_MSG_DEBUGGER_BREAK: - if (crash_ipi_function_ptr) { - crash_ipi_function_ptr(get_irq_regs()); - break; - } -#ifdef CONFIG_DEBUGGER - debugger_ipi(get_irq_regs()); - break; -#endif /* CONFIG_DEBUGGER */ - /* FALLTHROUGH */ - default: - printk("SMP %d: smp_message_recv(): unknown msg %d\n", - smp_processor_id(), msg); - break; - } -} - static irqreturn_t call_function_action(int irq, void *data) { generic_smp_call_function_interrupt(); @@ -146,7 +119,7 @@ static irqreturn_t call_function_action(int irq, void *data) static irqreturn_t reschedule_action(int irq, void *data) { - /* we just need the return path side effect of checking need_resched */ + scheduler_ipi(); return IRQ_HANDLED; } @@ -156,9 +129,17 @@ static irqreturn_t call_function_single_action(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t debug_ipi_action(int irq, void *data) +irqreturn_t debug_ipi_action(int irq, void *data) { - smp_message_recv(PPC_MSG_DEBUGGER_BREAK); + if (crash_ipi_function_ptr) { + crash_ipi_function_ptr(get_irq_regs()); + return IRQ_HANDLED; + } + +#ifdef CONFIG_DEBUGGER + debugger_ipi(get_irq_regs()); +#endif /* CONFIG_DEBUGGER */ + return IRQ_HANDLED; } @@ -197,6 +178,66 @@ int smp_request_message_ipi(int virq, int msg) return err; } +#ifdef CONFIG_PPC_SMP_MUXED_IPI +struct cpu_messages { + int messages; /* current messages */ + unsigned long data; /* data for cause ipi */ +}; +static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message); + +void smp_muxed_ipi_set_data(int cpu, unsigned long data) +{ + struct cpu_messages *info = &per_cpu(ipi_message, cpu); + + info->data = data; +} + +void smp_muxed_ipi_message_pass(int cpu, int msg) +{ + struct cpu_messages *info = &per_cpu(ipi_message, cpu); + char *message = (char *)&info->messages; + + message[msg] = 1; + mb(); + smp_ops->cause_ipi(cpu, info->data); +} + +void smp_muxed_ipi_resend(void) +{ + struct cpu_messages *info = &__get_cpu_var(ipi_message); + + if (info->messages) + smp_ops->cause_ipi(smp_processor_id(), info->data); +} + +irqreturn_t smp_ipi_demux(void) +{ + struct cpu_messages *info = &__get_cpu_var(ipi_message); + unsigned int all; + + mb(); /* order any irq clear */ + + do { + all = xchg_local(&info->messages, 0); + +#ifdef __BIG_ENDIAN + if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNCTION))) + generic_smp_call_function_interrupt(); + if (all & (1 << (24 - 8 * PPC_MSG_RESCHEDULE))) + scheduler_ipi(); + if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNC_SINGLE))) + generic_smp_call_function_single_interrupt(); + if (all & (1 << (24 - 8 * PPC_MSG_DEBUGGER_BREAK))) + debug_ipi_action(0, NULL); +#else +#error Unsupported ENDIAN +#endif + } while (info->messages); + + return IRQ_HANDLED; +} +#endif /* CONFIG_PPC_SMP_MUXED_IPI */ + void smp_send_reschedule(int cpu) { if (likely(smp_ops)) @@ -216,11 +257,18 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask) smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION); } -#ifdef CONFIG_DEBUGGER -void smp_send_debugger_break(int cpu) +#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) +void smp_send_debugger_break(void) { - if (likely(smp_ops)) - smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK); + int cpu; + int me = raw_smp_processor_id(); + + if (unlikely(!smp_ops)) + return; + + for_each_online_cpu(cpu) + if (cpu != me) + smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK); } #endif @@ -228,9 +276,9 @@ void smp_send_debugger_break(int cpu) void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)) { crash_ipi_function_ptr = crash_ipi_callback; - if (crash_ipi_callback && smp_ops) { + if (crash_ipi_callback) { mb(); - smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK); + smp_send_debugger_break(); } } #endif @@ -410,8 +458,6 @@ int __cpuinit __cpu_up(unsigned int cpu) { int rc, c; - secondary_ti = current_set[cpu]; - if (smp_ops == NULL || (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu))) return -EINVAL; @@ -421,6 +467,8 @@ int __cpuinit __cpu_up(unsigned int cpu) if (rc) return rc; + secondary_ti = current_set[cpu]; + /* Make sure callin-map entry is 0 (can be leftover a CPU * hotplug */ @@ -434,7 +482,11 @@ int __cpuinit __cpu_up(unsigned int cpu) /* wake up cpus */ DBG("smp: kicking cpu %d\n", cpu); - smp_ops->kick_cpu(cpu); + rc = smp_ops->kick_cpu(cpu); + if (rc) { + pr_err("smp: failed starting cpu %d (rc %d)\n", cpu, rc); + return rc; + } /* * wait to see if the cpu made a callin (is actually up). @@ -507,7 +559,7 @@ int cpu_first_thread_of_core(int core) } EXPORT_SYMBOL_GPL(cpu_first_thread_of_core); -/* Must be called when no change can occur to cpu_present_map, +/* Must be called when no change can occur to cpu_present_mask, * i.e. during cpu online or offline. */ static struct device_node *cpu_to_l2cache(int cpu) @@ -608,7 +660,7 @@ void __init smp_cpus_done(unsigned int max_cpus) * se we pin us down to CPU 0 for a short while */ alloc_cpumask_var(&old_mask, GFP_NOWAIT); - cpumask_copy(old_mask, ¤t->cpus_allowed); + cpumask_copy(old_mask, tsk_cpus_allowed(current)); set_cpus_allowed_ptr(current, cpumask_of(boot_cpuid)); if (smp_ops && smp_ops->setup_cpu) diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index c0d8c2006bf4..f0f2199e64e1 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -182,6 +182,41 @@ static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra); static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL); static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr); static SYSDEV_ATTR(purr, 0600, show_purr, store_purr); + +unsigned long dscr_default = 0; +EXPORT_SYMBOL(dscr_default); + +static ssize_t show_dscr_default(struct sysdev_class *class, + struct sysdev_class_attribute *attr, char *buf) +{ + return sprintf(buf, "%lx\n", dscr_default); +} + +static ssize_t __used store_dscr_default(struct sysdev_class *class, + struct sysdev_class_attribute *attr, const char *buf, + size_t count) +{ + unsigned long val; + int ret = 0; + + ret = sscanf(buf, "%lx", &val); + if (ret != 1) + return -EINVAL; + dscr_default = val; + + return count; +} + +static SYSDEV_CLASS_ATTR(dscr_default, 0600, + show_dscr_default, store_dscr_default); + +static void sysfs_create_dscr_default(void) +{ + int err = 0; + if (cpu_has_feature(CPU_FTR_DSCR)) + err = sysfs_create_file(&cpu_sysdev_class.kset.kobj, + &attr_dscr_default.attr); +} #endif /* CONFIG_PPC64 */ #ifdef HAS_PPC_PMC_PA6T @@ -617,6 +652,9 @@ static int __init topology_init(void) if (cpu_online(cpu)) register_cpu_online(cpu); } +#ifdef CONFIG_PPC64 + sysfs_create_dscr_default(); +#endif /* CONFIG_PPC64 */ return 0; } diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 375480c56eb9..f33acfd872ad 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -229,6 +229,9 @@ static u64 scan_dispatch_log(u64 stop_tb) u64 stolen = 0; u64 dtb; + if (!dtl) + return 0; + if (i == vpa->dtl_idx) return 0; while (i < vpa->dtl_idx) { diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 5ddb801bc154..b13306b0d925 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -143,7 +143,6 @@ int die(const char *str, struct pt_regs *regs, long err) #endif printk("%s\n", ppc_md.name ? ppc_md.name : ""); - sysfs_printk_last_file(); if (notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV) == NOTIFY_STOP) return 1; @@ -199,7 +198,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) } else if (show_unhandled_signals && unhandled_signal(current, signr) && printk_ratelimit()) { - printk(regs->msr & MSR_SF ? fmt64 : fmt32, + printk(regs->msr & MSR_64BIT ? fmt64 : fmt32, current->comm, current->pid, signr, addr, regs->nip, regs->link, code); } @@ -221,7 +220,7 @@ void system_reset_exception(struct pt_regs *regs) } #ifdef CONFIG_KEXEC - cpu_set(smp_processor_id(), cpus_in_sr); + cpumask_set_cpu(smp_processor_id(), &cpus_in_sr); #endif die("System Reset", regs, SIGABRT); @@ -909,6 +908,26 @@ static int emulate_instruction(struct pt_regs *regs) return emulate_isel(regs, instword); } +#ifdef CONFIG_PPC64 + /* Emulate the mfspr rD, DSCR. */ + if (((instword & PPC_INST_MFSPR_DSCR_MASK) == PPC_INST_MFSPR_DSCR) && + cpu_has_feature(CPU_FTR_DSCR)) { + PPC_WARN_EMULATED(mfdscr, regs); + rd = (instword >> 21) & 0x1f; + regs->gpr[rd] = mfspr(SPRN_DSCR); + return 0; + } + /* Emulate the mtspr DSCR, rD. */ + if (((instword & PPC_INST_MTSPR_DSCR_MASK) == PPC_INST_MTSPR_DSCR) && + cpu_has_feature(CPU_FTR_DSCR)) { + PPC_WARN_EMULATED(mtdscr, regs); + rd = (instword >> 21) & 0x1f; + mtspr(SPRN_DSCR, regs->gpr[rd]); + current->thread.dscr_inherit = 1; + return 0; + } +#endif + return -EINVAL; } @@ -1506,6 +1525,10 @@ struct ppc_emulated ppc_emulated = { #ifdef CONFIG_VSX WARN_EMULATED_SETUP(vsx), #endif +#ifdef CONFIG_PPC64 + WARN_EMULATED_SETUP(mfdscr), + WARN_EMULATED_SETUP(mtdscr), +#endif }; u32 ppc_warn_emulated; diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index e39cad83c884..23d65abbedce 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -62,6 +62,8 @@ void __init udbg_early_init(void) udbg_init_cpm(); #elif defined(CONFIG_PPC_EARLY_DEBUG_USBGECKO) udbg_init_usbgecko(); +#elif defined(CONFIG_PPC_EARLY_DEBUG_WSP) + udbg_init_wsp(); #endif #ifdef CONFIG_PPC_EARLY_DEBUG diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index baa33a7517bc..6837f839ab78 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c @@ -11,6 +11,7 @@ #include #include #include +#include extern u8 real_readb(volatile u8 __iomem *addr); extern void real_writeb(u8 data, volatile u8 __iomem *addr); @@ -298,3 +299,53 @@ void __init udbg_init_40x_realmode(void) udbg_getc_poll = NULL; } #endif /* CONFIG_PPC_EARLY_DEBUG_40x */ + +#ifdef CONFIG_PPC_EARLY_DEBUG_WSP +static void udbg_wsp_flush(void) +{ + if (udbg_comport) { + while ((readb(&udbg_comport->lsr) & LSR_THRE) == 0) + /* wait for idle */; + } +} + +static void udbg_wsp_putc(char c) +{ + if (udbg_comport) { + if (c == '\n') + udbg_wsp_putc('\r'); + udbg_wsp_flush(); + writeb(c, &udbg_comport->thr); eieio(); + } +} + +static int udbg_wsp_getc(void) +{ + if (udbg_comport) { + while ((readb(&udbg_comport->lsr) & LSR_DR) == 0) + ; /* wait for char */ + return readb(&udbg_comport->rbr); + } + return -1; +} + +static int udbg_wsp_getc_poll(void) +{ + if (udbg_comport) + if (readb(&udbg_comport->lsr) & LSR_DR) + return readb(&udbg_comport->rbr); + return -1; +} + +void __init udbg_init_wsp(void) +{ + udbg_comport = (struct NS16550 __iomem *)WSP_UART_VIRT; + + udbg_init_uart(udbg_comport, 57600, 50000000); + + udbg_putc = udbg_wsp_putc; + udbg_flush = udbg_wsp_flush; + udbg_getc = udbg_wsp_getc; + udbg_getc_poll = udbg_wsp_getc_poll; +} +#endif /* CONFIG_PPC_EARLY_DEBUG_WSP */ diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 9de6f396cf85..4d5a3edff49e 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S @@ -102,7 +102,7 @@ _GLOBAL(giveup_altivec) MTMSRD(r5) /* enable use of VMX now */ isync PPC_LCMPI 0,r3,0 - beqlr- /* if no previous owner, done */ + beqlr /* if no previous owner, done */ addi r3,r3,THREAD /* want THREAD of task */ PPC_LL r5,PT_REGS(r3) PPC_LCMPI 0,r5,0 diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index c961de40c676..0f95b5cce033 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -236,7 +236,7 @@ void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu) int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu) { - return test_bit(BOOK3S_INTERRUPT_DECREMENTER >> 7, &vcpu->arch.pending_exceptions); + return test_bit(BOOK3S_IRQPRIO_DECREMENTER, &vcpu->arch.pending_exceptions); } void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu) diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S index 2b9c9088d00e..1a1b34487e71 100644 --- a/arch/powerpc/kvm/book3s_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_rmhandlers.S @@ -35,9 +35,7 @@ #if defined(CONFIG_PPC_BOOK3S_64) -#define LOAD_SHADOW_VCPU(reg) \ - mfspr reg, SPRN_SPRG_PACA - +#define LOAD_SHADOW_VCPU(reg) GET_PACA(reg) #define SHADOW_VCPU_OFF PACA_KVM_SVCPU #define MSR_NOIRQ MSR_KERNEL & ~(MSR_IR | MSR_DR) #define FUNC(name) GLUE(.,name) @@ -72,7 +70,7 @@ .global kvmppc_trampoline_\intno kvmppc_trampoline_\intno: - mtspr SPRN_SPRG_SCRATCH0, r13 /* Save r13 */ + SET_SCRATCH0(r13) /* Save r13 */ /* * First thing to do is to find out if we're coming @@ -91,7 +89,7 @@ kvmppc_trampoline_\intno: lwz r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) mtcr r12 PPC_LL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) - mfspr r13, SPRN_SPRG_SCRATCH0 /* r13 = original r13 */ + GET_SCRATCH0(r13) /* r13 = original r13 */ b kvmppc_resume_\intno /* Get back original handler */ /* Now we know we're handling a KVM guest */ @@ -114,6 +112,9 @@ INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL +#ifdef CONFIG_PPC_BOOK3S_64 +INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL_HV +#endif INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL @@ -158,7 +159,7 @@ kvmppc_handler_skip_ins: lwz r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) mtcr r12 PPC_LL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) - mfspr r13, SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r13) /* And get back into the code */ RFI diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S index 7c52ed0b7051..451264274b8c 100644 --- a/arch/powerpc/kvm/book3s_segment.S +++ b/arch/powerpc/kvm/book3s_segment.S @@ -155,14 +155,20 @@ kvmppc_handler_trampoline_exit: PPC_LL r2, (SHADOW_VCPU_OFF + SVCPU_HOST_R2)(r13) /* Save guest PC and MSR */ - mfsrr0 r3 + andi. r0,r12,0x2 + beq 1f + mfspr r3,SPRN_HSRR0 + mfspr r4,SPRN_HSRR1 + andi. r12,r12,0x3ffd + b 2f +1: mfsrr0 r3 mfsrr1 r4 - +2: PPC_STL r3, (SHADOW_VCPU_OFF + SVCPU_PC)(r13) PPC_STL r4, (SHADOW_VCPU_OFF + SVCPU_SHADOW_SRR1)(r13) /* Get scratch'ed off registers */ - mfspr r9, SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r9) PPC_LL r8, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) lwz r7, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) diff --git a/arch/powerpc/lib/alloc.c b/arch/powerpc/lib/alloc.c index f53e09c7dac7..13b676c20d12 100644 --- a/arch/powerpc/lib/alloc.c +++ b/arch/powerpc/lib/alloc.c @@ -6,14 +6,6 @@ #include -void * __init_refok alloc_maybe_bootmem(size_t size, gfp_t mask) -{ - if (mem_init_done) - return kmalloc(size, mask); - else - return alloc_bootmem(size); -} - void * __init_refok zalloc_maybe_bootmem(size_t size, gfp_t mask) { void *p; diff --git a/arch/powerpc/lib/copypage_64.S b/arch/powerpc/lib/copypage_64.S index 4d4eeb900486..53dcb6b1b708 100644 --- a/arch/powerpc/lib/copypage_64.S +++ b/arch/powerpc/lib/copypage_64.S @@ -6,6 +6,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#include #include #include #include @@ -15,9 +16,9 @@ PPC64_CACHES: .tc ppc64_caches[TC],ppc64_caches .section ".text" - -_GLOBAL(copy_4K_page) - li r5,4096 /* 4K page size */ +_GLOBAL(copy_page) + lis r5,PAGE_SIZE@h + ori r5,r5,PAGE_SIZE@l BEGIN_FTR_SECTION ld r10,PPC64_CACHES@toc(r2) lwz r11,DCACHEL1LOGLINESIZE(r10) /* log2 of cache line size */ diff --git a/arch/powerpc/lib/devres.c b/arch/powerpc/lib/devres.c index deac4d30daf4..e91615abae66 100644 --- a/arch/powerpc/lib/devres.c +++ b/arch/powerpc/lib/devres.c @@ -9,11 +9,11 @@ #include /* devres_*(), devm_ioremap_release() */ #include -#include /* ioremap_flags() */ +#include /* ioremap_prot() */ #include /* EXPORT_SYMBOL() */ /** - * devm_ioremap_prot - Managed ioremap_flags() + * devm_ioremap_prot - Managed ioremap_prot() * @dev: Generic device to remap IO address for * @offset: BUS offset to map * @size: Size of map @@ -31,7 +31,7 @@ void __iomem *devm_ioremap_prot(struct device *dev, resource_size_t offset, if (!ptr) return NULL; - addr = ioremap_flags(offset, size, flags); + addr = ioremap_prot(offset, size, flags); if (addr) { *ptr = addr; devres_add(dev, ptr); diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index ae5189ab0049..9a52349874ee 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,18 @@ extern int do_lxvd2x(int rn, unsigned long ea); extern int do_stxvd2x(int rn, unsigned long ea); #endif +/* + * Emulate the truncation of 64 bit values in 32-bit mode. + */ +static unsigned long truncate_if_32bit(unsigned long msr, unsigned long val) +{ +#ifdef __powerpc64__ + if ((msr & MSR_64BIT) == 0) + val &= 0xffffffffUL; +#endif + return val; +} + /* * Determine whether a conditional branch instruction would branch. */ @@ -90,11 +103,8 @@ static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs if (instr & 0x04000000) /* update forms */ regs->gpr[ra] = ea; } -#ifdef __powerpc64__ - if (!(regs->msr & MSR_SF)) - ea &= 0xffffffffUL; -#endif - return ea; + + return truncate_if_32bit(regs->msr, ea); } #ifdef __powerpc64__ @@ -113,9 +123,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg if ((instr & 3) == 1) /* update forms */ regs->gpr[ra] = ea; } - if (!(regs->msr & MSR_SF)) - ea &= 0xffffffffUL; - return ea; + + return truncate_if_32bit(regs->msr, ea); } #endif /* __powerpc64 */ @@ -136,11 +145,8 @@ static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs if (do_update) /* update forms */ regs->gpr[ra] = ea; } -#ifdef __powerpc64__ - if (!(regs->msr & MSR_SF)) - ea &= 0xffffffffUL; -#endif - return ea; + + return truncate_if_32bit(regs->msr, ea); } /* @@ -466,7 +472,7 @@ static void __kprobes set_cr0(struct pt_regs *regs, int rd) regs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000); #ifdef __powerpc64__ - if (!(regs->msr & MSR_SF)) + if (!(regs->msr & MSR_64BIT)) val = (int) val; #endif if (val < 0) @@ -487,7 +493,7 @@ static void __kprobes add_with_carry(struct pt_regs *regs, int rd, ++val; regs->gpr[rd] = val; #ifdef __powerpc64__ - if (!(regs->msr & MSR_SF)) { + if (!(regs->msr & MSR_64BIT)) { val = (unsigned int) val; val1 = (unsigned int) val1; } @@ -570,8 +576,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) if ((instr & 2) == 0) imm += regs->nip; regs->nip += 4; - if ((regs->msr & MSR_SF) == 0) - regs->nip &= 0xffffffffUL; + regs->nip = truncate_if_32bit(regs->msr, regs->nip); if (instr & 1) regs->link = regs->nip; if (branch_taken(instr, regs)) @@ -604,13 +609,9 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) imm -= 0x04000000; if ((instr & 2) == 0) imm += regs->nip; - if (instr & 1) { - regs->link = regs->nip + 4; - if ((regs->msr & MSR_SF) == 0) - regs->link &= 0xffffffffUL; - } - if ((regs->msr & MSR_SF) == 0) - imm &= 0xffffffffUL; + if (instr & 1) + regs->link = truncate_if_32bit(regs->msr, regs->nip + 4); + imm = truncate_if_32bit(regs->msr, imm); regs->nip = imm; return 1; case 19: @@ -618,11 +619,8 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) case 16: /* bclr */ case 528: /* bcctr */ imm = (instr & 0x400)? regs->ctr: regs->link; - regs->nip += 4; - if ((regs->msr & MSR_SF) == 0) { - regs->nip &= 0xffffffffUL; - imm &= 0xffffffffUL; - } + regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4); + imm = truncate_if_32bit(regs->msr, imm); if (instr & 1) regs->link = regs->nip; if (branch_taken(instr, regs)) @@ -1616,11 +1614,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) return 0; /* invoke DSI if -EFAULT? */ } instr_done: - regs->nip += 4; -#ifdef __powerpc64__ - if ((regs->msr & MSR_SF) == 0) - regs->nip &= 0xffffffffUL; -#endif + regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4); return 1; logical_done: diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index 5b7dd4ea02b5..a242b5d7cbe4 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S @@ -118,7 +118,7 @@ _GLOBAL(__hash_page_4K) BEGIN_FTR_SECTION cmpdi r9,0 /* check segment size */ bne 3f -END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) /* Calc va and put it in r29 */ rldicr r29,r5,28,63-28 rldicl r3,r3,0,36 @@ -401,7 +401,7 @@ _GLOBAL(__hash_page_4K) BEGIN_FTR_SECTION cmpdi r9,0 /* check segment size */ bne 3f -END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) /* Calc va and put it in r29 */ rldicr r29,r5,28,63-28 /* r29 = (vsid << 28) */ rldicl r3,r3,0,36 /* r3 = (ea & 0x0fffffff) */ @@ -715,7 +715,7 @@ BEGIN_FTR_SECTION andi. r0,r31,_PAGE_NO_CACHE /* If so, bail out and refault as a 4k page */ bne- ht64_bail_ok -END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE) +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_CI_LARGE_PAGE) /* Prepare new PTE value (turn access RW into DIRTY, then * add BUSY and ACCESSED) */ @@ -736,7 +736,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE) BEGIN_FTR_SECTION cmpdi r9,0 /* check segment size */ bne 3f -END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) /* Calc va and put it in r29 */ rldicr r29,r5,28,63-28 rldicl r3,r3,0,36 diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 784a400e0781..dfd764896db0 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c @@ -50,9 +50,8 @@ static inline void __tlbie(unsigned long va, int psize, int ssize) case MMU_PAGE_4K: va &= ~0xffful; va |= ssize << 8; - asm volatile(ASM_MMU_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), - %2) - : : "r" (va), "r"(0), "i" (MMU_FTR_TLBIE_206) + asm volatile(ASM_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), %2) + : : "r" (va), "r"(0), "i" (CPU_FTR_HVMODE_206) : "memory"); break; default: @@ -61,9 +60,8 @@ static inline void __tlbie(unsigned long va, int psize, int ssize) va |= penc << 12; va |= ssize << 8; va |= 1; /* L */ - asm volatile(ASM_MMU_FTR_IFCLR("tlbie %0,1", PPC_TLBIE(%1,%0), - %2) - : : "r" (va), "r"(0), "i" (MMU_FTR_TLBIE_206) + asm volatile(ASM_FTR_IFCLR("tlbie %0,1", PPC_TLBIE(%1,%0), %2) + : : "r" (va), "r"(0), "i" (CPU_FTR_HVMODE_206) : "memory"); break; } @@ -98,8 +96,8 @@ static inline void __tlbiel(unsigned long va, int psize, int ssize) static inline void tlbie(unsigned long va, int psize, int ssize, int local) { - unsigned int use_local = local && cpu_has_feature(CPU_FTR_TLBIEL); - int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); + unsigned int use_local = local && mmu_has_feature(MMU_FTR_TLBIEL); + int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); if (use_local) use_local = mmu_psize_defs[psize].tlbiel; @@ -503,7 +501,7 @@ static void native_flush_hash_range(unsigned long number, int local) } pte_iterate_hashed_end(); } - if (cpu_has_feature(CPU_FTR_TLBIEL) && + if (mmu_has_feature(MMU_FTR_TLBIEL) && mmu_psize_defs[psize].tlbiel && local) { asm volatile("ptesync":::"memory"); for (i = 0; i < number; i++) { @@ -517,7 +515,7 @@ static void native_flush_hash_range(unsigned long number, int local) } asm volatile("ptesync":::"memory"); } else { - int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); + int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); if (lock_tlbie) raw_spin_lock(&native_tlbie_lock); diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 58a022d0f463..26b2872b3d00 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -53,6 +53,7 @@ #include #include #include +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -258,11 +259,11 @@ static int __init htab_dt_scan_seg_sizes(unsigned long node, for (; size >= 4; size -= 4, ++prop) { if (prop[0] == 40) { DBG("1T segment support detected\n"); - cur_cpu_spec->cpu_features |= CPU_FTR_1T_SEGMENT; + cur_cpu_spec->mmu_features |= MMU_FTR_1T_SEGMENT; return 1; } } - cur_cpu_spec->cpu_features &= ~CPU_FTR_NO_SLBIE_B; + cur_cpu_spec->mmu_features &= ~MMU_FTR_NO_SLBIE_B; return 0; } @@ -288,7 +289,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node, if (prop != NULL) { DBG("Page sizes from device-tree:\n"); size /= 4; - cur_cpu_spec->cpu_features &= ~(CPU_FTR_16M_PAGE); + cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE); while(size > 0) { unsigned int shift = prop[0]; unsigned int slbenc = prop[1]; @@ -316,7 +317,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node, break; case 0x18: idx = MMU_PAGE_16M; - cur_cpu_spec->cpu_features |= CPU_FTR_16M_PAGE; + cur_cpu_spec->mmu_features |= MMU_FTR_16M_PAGE; break; case 0x22: idx = MMU_PAGE_16G; @@ -411,7 +412,7 @@ static void __init htab_init_page_sizes(void) * Not in the device-tree, let's fallback on known size * list for 16M capable GP & GR */ - if (cpu_has_feature(CPU_FTR_16M_PAGE)) + if (mmu_has_feature(MMU_FTR_16M_PAGE)) memcpy(mmu_psize_defs, mmu_psize_defaults_gp, sizeof(mmu_psize_defaults_gp)); found: @@ -441,7 +442,7 @@ static void __init htab_init_page_sizes(void) mmu_vmalloc_psize = MMU_PAGE_64K; if (mmu_linear_psize == MMU_PAGE_4K) mmu_linear_psize = MMU_PAGE_64K; - if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE)) { + if (mmu_has_feature(MMU_FTR_CI_LARGE_PAGE)) { /* * Don't use 64k pages for ioremap on pSeries, since * that would stop us accessing the HEA ethernet. @@ -547,15 +548,7 @@ int remove_section_mapping(unsigned long start, unsigned long end) } #endif /* CONFIG_MEMORY_HOTPLUG */ -static inline void make_bl(unsigned int *insn_addr, void *func) -{ - unsigned long funcp = *((unsigned long *)func); - int offset = funcp - (unsigned long)insn_addr; - - *insn_addr = (unsigned int)(0x48000001 | (offset & 0x03fffffc)); - flush_icache_range((unsigned long)insn_addr, 4+ - (unsigned long)insn_addr); -} +#define FUNCTION_TEXT(A) ((*(unsigned long *)(A))) static void __init htab_finish_init(void) { @@ -570,16 +563,33 @@ static void __init htab_finish_init(void) extern unsigned int *ht64_call_hpte_remove; extern unsigned int *ht64_call_hpte_updatepp; - make_bl(ht64_call_hpte_insert1, ppc_md.hpte_insert); - make_bl(ht64_call_hpte_insert2, ppc_md.hpte_insert); - make_bl(ht64_call_hpte_remove, ppc_md.hpte_remove); - make_bl(ht64_call_hpte_updatepp, ppc_md.hpte_updatepp); + patch_branch(ht64_call_hpte_insert1, + FUNCTION_TEXT(ppc_md.hpte_insert), + BRANCH_SET_LINK); + patch_branch(ht64_call_hpte_insert2, + FUNCTION_TEXT(ppc_md.hpte_insert), + BRANCH_SET_LINK); + patch_branch(ht64_call_hpte_remove, + FUNCTION_TEXT(ppc_md.hpte_remove), + BRANCH_SET_LINK); + patch_branch(ht64_call_hpte_updatepp, + FUNCTION_TEXT(ppc_md.hpte_updatepp), + BRANCH_SET_LINK); + #endif /* CONFIG_PPC_HAS_HASH_64K */ - make_bl(htab_call_hpte_insert1, ppc_md.hpte_insert); - make_bl(htab_call_hpte_insert2, ppc_md.hpte_insert); - make_bl(htab_call_hpte_remove, ppc_md.hpte_remove); - make_bl(htab_call_hpte_updatepp, ppc_md.hpte_updatepp); + patch_branch(htab_call_hpte_insert1, + FUNCTION_TEXT(ppc_md.hpte_insert), + BRANCH_SET_LINK); + patch_branch(htab_call_hpte_insert2, + FUNCTION_TEXT(ppc_md.hpte_insert), + BRANCH_SET_LINK); + patch_branch(htab_call_hpte_remove, + FUNCTION_TEXT(ppc_md.hpte_remove), + BRANCH_SET_LINK); + patch_branch(htab_call_hpte_updatepp, + FUNCTION_TEXT(ppc_md.hpte_updatepp), + BRANCH_SET_LINK); } static void __init htab_initialize(void) @@ -598,7 +608,7 @@ static void __init htab_initialize(void) /* Initialize page sizes */ htab_init_page_sizes(); - if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) { + if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) { mmu_kernel_ssize = MMU_SEGSIZE_1T; mmu_highuser_ssize = MMU_SEGSIZE_1T; printk(KERN_INFO "Using 1TB segments\n"); @@ -739,7 +749,7 @@ void __init early_init_mmu(void) /* Initialize stab / SLB management except on iSeries */ - if (cpu_has_feature(CPU_FTR_SLB)) + if (mmu_has_feature(MMU_FTR_SLB)) slb_initialize(); else if (!firmware_has_feature(FW_FEATURE_ISERIES)) stab_initialize(get_paca()->stab_real); @@ -756,7 +766,7 @@ void __cpuinit early_init_mmu_secondary(void) * in real mode on pSeries and we want a virtual address on * iSeries anyway */ - if (cpu_has_feature(CPU_FTR_SLB)) + if (mmu_has_feature(MMU_FTR_SLB)) slb_initialize(); else stab_initialize(get_paca()->stab_addr); diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 9bb249c3046e..0b9a5c1901b9 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -529,7 +529,7 @@ static int __init hugetlbpage_init(void) { int psize; - if (!cpu_has_feature(CPU_FTR_16M_PAGE)) + if (!mmu_has_feature(MMU_FTR_16M_PAGE)) return -ENODEV; for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c index 2535828aa84b..3bafc3deca6d 100644 --- a/arch/powerpc/mm/mmu_context_hash64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c @@ -20,9 +20,205 @@ #include #include #include +#include #include +#ifdef CONFIG_PPC_ICSWX +/* + * The processor and its L2 cache cause the icswx instruction to + * generate a COP_REQ transaction on PowerBus. The transaction has + * no address, and the processor does not perform an MMU access + * to authenticate the transaction. The command portion of the + * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and + * the coprocessor Process ID (PID), which the coprocessor compares + * to the authorized LPID and PID held in the coprocessor, to determine + * if the process is authorized to generate the transaction. + * The data of the COP_REQ transaction is 128-byte or less and is + * placed in cacheable memory on a 128-byte cache line boundary. + * + * The task to use a coprocessor should use use_cop() to allocate + * a coprocessor PID before executing icswx instruction. use_cop() + * also enables the coprocessor context switching. Drop_cop() is + * used to free the coprocessor PID. + * + * Example: + * Host Fabric Interface (HFI) is a PowerPC network coprocessor. + * Each HFI have multiple windows. Each HFI window serves as a + * network device sending to and receiving from HFI network. + * HFI immediate send function uses icswx instruction. The immediate + * send function allows small (single cache-line) packets be sent + * without using the regular HFI send FIFO and doorbell, which are + * much slower than immediate send. + * + * For each task intending to use HFI immediate send, the HFI driver + * calls use_cop() to obtain a coprocessor PID for the task. + * The HFI driver then allocate a free HFI window and save the + * coprocessor PID to the HFI window to allow the task to use the + * HFI window. + * + * The HFI driver repeatedly creates immediate send packets and + * issues icswx instruction to send data through the HFI window. + * The HFI compares the coprocessor PID in the CPU PID register + * to the PID held in the HFI window to determine if the transaction + * is allowed. + * + * When the task to release the HFI window, the HFI driver calls + * drop_cop() to release the coprocessor PID. + */ + +#define COP_PID_NONE 0 +#define COP_PID_MIN (COP_PID_NONE + 1) +#define COP_PID_MAX (0xFFFF) + +static DEFINE_SPINLOCK(mmu_context_acop_lock); +static DEFINE_IDA(cop_ida); + +void switch_cop(struct mm_struct *next) +{ + mtspr(SPRN_PID, next->context.cop_pid); + mtspr(SPRN_ACOP, next->context.acop); +} + +static int new_cop_pid(struct ida *ida, int min_id, int max_id, + spinlock_t *lock) +{ + int index; + int err; + +again: + if (!ida_pre_get(ida, GFP_KERNEL)) + return -ENOMEM; + + spin_lock(lock); + err = ida_get_new_above(ida, min_id, &index); + spin_unlock(lock); + + if (err == -EAGAIN) + goto again; + else if (err) + return err; + + if (index > max_id) { + spin_lock(lock); + ida_remove(ida, index); + spin_unlock(lock); + return -ENOMEM; + } + + return index; +} + +static void sync_cop(void *arg) +{ + struct mm_struct *mm = arg; + + if (mm == current->active_mm) + switch_cop(current->active_mm); +} + +/** + * Start using a coprocessor. + * @acop: mask of coprocessor to be used. + * @mm: The mm the coprocessor to associate with. Most likely current mm. + * + * Return a positive PID if successful. Negative errno otherwise. + * The returned PID will be fed to the coprocessor to determine if an + * icswx transaction is authenticated. + */ +int use_cop(unsigned long acop, struct mm_struct *mm) +{ + int ret; + + if (!cpu_has_feature(CPU_FTR_ICSWX)) + return -ENODEV; + + if (!mm || !acop) + return -EINVAL; + + /* We need to make sure mm_users doesn't change */ + down_read(&mm->mmap_sem); + spin_lock(mm->context.cop_lockp); + + if (mm->context.cop_pid == COP_PID_NONE) { + ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX, + &mmu_context_acop_lock); + if (ret < 0) + goto out; + + mm->context.cop_pid = ret; + } + mm->context.acop |= acop; + + sync_cop(mm); + + /* + * If this is a threaded process then there might be other threads + * running. We need to send an IPI to force them to pick up any + * change in PID and ACOP. + */ + if (atomic_read(&mm->mm_users) > 1) + smp_call_function(sync_cop, mm, 1); + + ret = mm->context.cop_pid; + +out: + spin_unlock(mm->context.cop_lockp); + up_read(&mm->mmap_sem); + + return ret; +} +EXPORT_SYMBOL_GPL(use_cop); + +/** + * Stop using a coprocessor. + * @acop: mask of coprocessor to be stopped. + * @mm: The mm the coprocessor associated with. + */ +void drop_cop(unsigned long acop, struct mm_struct *mm) +{ + int free_pid = COP_PID_NONE; + + if (!cpu_has_feature(CPU_FTR_ICSWX)) + return; + + if (WARN_ON_ONCE(!mm)) + return; + + /* We need to make sure mm_users doesn't change */ + down_read(&mm->mmap_sem); + spin_lock(mm->context.cop_lockp); + + mm->context.acop &= ~acop; + + if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) { + free_pid = mm->context.cop_pid; + mm->context.cop_pid = COP_PID_NONE; + } + + sync_cop(mm); + + /* + * If this is a threaded process then there might be other threads + * running. We need to send an IPI to force them to pick up any + * change in PID and ACOP. + */ + if (atomic_read(&mm->mm_users) > 1) + smp_call_function(sync_cop, mm, 1); + + if (free_pid != COP_PID_NONE) { + spin_lock(&mmu_context_acop_lock); + ida_remove(&cop_ida, free_pid); + spin_unlock(&mmu_context_acop_lock); + } + + spin_unlock(mm->context.cop_lockp); + up_read(&mm->mmap_sem); +} +EXPORT_SYMBOL_GPL(drop_cop); + +#endif /* CONFIG_PPC_ICSWX */ + static DEFINE_SPINLOCK(mmu_context_lock); static DEFINE_IDA(mmu_context_ida); @@ -31,7 +227,6 @@ static DEFINE_IDA(mmu_context_ida); * Each segment contains 2^28 bytes. Each context maps 2^44 bytes, * so we can support 2^19-1 contexts (19 == 35 + 28 - 44). */ -#define NO_CONTEXT 0 #define MAX_CONTEXT ((1UL << 19) - 1) int __init_new_context(void) @@ -79,6 +274,16 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) slice_set_user_psize(mm, mmu_virtual_psize); subpage_prot_init_new_context(mm); mm->context.id = index; +#ifdef CONFIG_PPC_ICSWX + mm->context.cop_lockp = kmalloc(sizeof(spinlock_t), GFP_KERNEL); + if (!mm->context.cop_lockp) { + __destroy_context(index); + subpage_prot_free(mm); + mm->context.id = MMU_NO_CONTEXT; + return -ENOMEM; + } + spin_lock_init(mm->context.cop_lockp); +#endif /* CONFIG_PPC_ICSWX */ return 0; } @@ -93,7 +298,12 @@ EXPORT_SYMBOL_GPL(__destroy_context); void destroy_context(struct mm_struct *mm) { +#ifdef CONFIG_PPC_ICSWX + drop_cop(mm->context.acop, mm); + kfree(mm->context.cop_lockp); + mm->context.cop_lockp = NULL; +#endif /* CONFIG_PPC_ICSWX */ __destroy_context(mm->context.id); subpage_prot_free(mm); - mm->context.id = NO_CONTEXT; + mm->context.id = MMU_NO_CONTEXT; } diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c index c0aab52da3a5..336807de550e 100644 --- a/arch/powerpc/mm/mmu_context_nohash.c +++ b/arch/powerpc/mm/mmu_context_nohash.c @@ -338,12 +338,14 @@ static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self, return NOTIFY_OK; switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: + case CPU_UP_PREPARE: + case CPU_UP_PREPARE_FROZEN: pr_devel("MMU: Allocating stale context map for CPU %d\n", cpu); stale_map[cpu] = kzalloc(CTX_MAP_SIZE, GFP_KERNEL); break; #ifdef CONFIG_HOTPLUG_CPU + case CPU_UP_CANCELED: + case CPU_UP_CANCELED_FROZEN: case CPU_DEAD: case CPU_DEAD_FROZEN: pr_devel("MMU: Freeing stale context map for CPU %d\n", cpu); @@ -407,7 +409,17 @@ void __init mmu_context_init(void) } else if (mmu_has_feature(MMU_FTR_TYPE_47x)) { first_context = 1; last_context = 65535; - } else { + } else +#ifdef CONFIG_PPC_BOOK3E_MMU + if (mmu_has_feature(MMU_FTR_TYPE_3E)) { + u32 mmucfg = mfspr(SPRN_MMUCFG); + u32 pid_bits = (mmucfg & MMUCFG_PIDSIZE_MASK) + >> MMUCFG_PIDSIZE_SHIFT; + first_context = 1; + last_context = (1UL << (pid_bits + 1)) - 1; + } else +#endif + { first_context = 1; last_context = 255; } diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 5ec1dad2a19d..2164006fe170 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -311,14 +311,13 @@ EXPORT_SYMBOL_GPL(of_node_to_nid); static int __init find_min_common_depth(void) { int depth; - struct device_node *rtas_root; struct device_node *chosen; + struct device_node *root; const char *vec5; - rtas_root = of_find_node_by_path("/rtas"); - - if (!rtas_root) - return -1; + root = of_find_node_by_path("/rtas"); + if (!root) + root = of_find_node_by_path("/"); /* * This property is a set of 32-bit integers, each representing @@ -332,7 +331,7 @@ static int __init find_min_common_depth(void) * NUMA boundary and the following are progressively less significant * boundaries. There can be more than one level of NUMA. */ - distance_ref_points = of_get_property(rtas_root, + distance_ref_points = of_get_property(root, "ibm,associativity-reference-points", &distance_ref_points_depth); @@ -376,11 +375,11 @@ static int __init find_min_common_depth(void) distance_ref_points_depth = MAX_DISTANCE_REF_POINTS; } - of_node_put(rtas_root); + of_node_put(root); return depth; err: - of_node_put(rtas_root); + of_node_put(root); return -1; } @@ -1453,7 +1452,7 @@ int arch_update_cpu_topology(void) unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0}; struct sys_device *sysdev; - for_each_cpu_mask(cpu, cpu_associativity_changes_mask) { + for_each_cpu(cpu,&cpu_associativity_changes_mask) { vphn_get_associativity(cpu, associativity); nid = associativity_to_nid(associativity); diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 8dc41c0157fe..51f87956f8f8 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -133,7 +133,15 @@ ioremap(phys_addr_t addr, unsigned long size) EXPORT_SYMBOL(ioremap); void __iomem * -ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags) +ioremap_wc(phys_addr_t addr, unsigned long size) +{ + return __ioremap_caller(addr, size, _PAGE_NO_CACHE, + __builtin_return_address(0)); +} +EXPORT_SYMBOL(ioremap_wc); + +void __iomem * +ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags) { /* writeable implies dirty for kernel addresses */ if (flags & _PAGE_RW) @@ -152,7 +160,7 @@ ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags) return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); } -EXPORT_SYMBOL(ioremap_flags); +EXPORT_SYMBOL(ioremap_prot); void __iomem * __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags) diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 88927a05cdc2..6e595f6496d4 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -255,7 +255,17 @@ void __iomem * ioremap(phys_addr_t addr, unsigned long size) return __ioremap_caller(addr, size, flags, caller); } -void __iomem * ioremap_flags(phys_addr_t addr, unsigned long size, +void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size) +{ + unsigned long flags = _PAGE_NO_CACHE; + void *caller = __builtin_return_address(0); + + if (ppc_md.ioremap) + return ppc_md.ioremap(addr, size, flags, caller); + return __ioremap_caller(addr, size, flags, caller); +} + +void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags) { void *caller = __builtin_return_address(0); @@ -311,7 +321,8 @@ void iounmap(volatile void __iomem *token) } EXPORT_SYMBOL(ioremap); -EXPORT_SYMBOL(ioremap_flags); +EXPORT_SYMBOL(ioremap_wc); +EXPORT_SYMBOL(ioremap_prot); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(__ioremap_at); EXPORT_SYMBOL(iounmap); diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 1d98ecc8eecd..e22276cb67a4 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -24,6 +24,7 @@ #include #include #include +#include extern void slb_allocate_realmode(unsigned long ea); @@ -166,7 +167,7 @@ static inline int esids_match(unsigned long addr1, unsigned long addr2) int esid_1t_count; /* System is not 1T segment size capable. */ - if (!cpu_has_feature(CPU_FTR_1T_SEGMENT)) + if (!mmu_has_feature(MMU_FTR_1T_SEGMENT)) return (GET_ESID(addr1) == GET_ESID(addr2)); esid_1t_count = (((addr1 >> SID_SHIFT_1T) != 0) + @@ -201,7 +202,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) */ hard_irq_disable(); offset = get_paca()->slb_cache_ptr; - if (!cpu_has_feature(CPU_FTR_NO_SLBIE_B) && + if (!mmu_has_feature(MMU_FTR_NO_SLBIE_B) && offset <= SLB_CACHE_ENTRIES) { int i; asm volatile("isync" : : : "memory"); @@ -249,9 +250,8 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) static inline void patch_slb_encoding(unsigned int *insn_addr, unsigned int immed) { - *insn_addr = (*insn_addr & 0xffff0000) | immed; - flush_icache_range((unsigned long)insn_addr, 4+ - (unsigned long)insn_addr); + int insn = (*insn_addr & 0xffff0000) | immed; + patch_instruction(insn_addr, insn); } void slb_set_size(u16 size) diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index 95ce35581696..ef653dc95b65 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -58,7 +58,7 @@ _GLOBAL(slb_miss_kernel_load_linear) li r11,0 BEGIN_FTR_SECTION b slb_finish_load -END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) b slb_finish_load_1T 1: @@ -87,7 +87,7 @@ _GLOBAL(slb_miss_kernel_load_vmemmap) 6: BEGIN_FTR_SECTION b slb_finish_load -END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) b slb_finish_load_1T 0: /* user address: proto-VSID = context << 15 | ESID. First check @@ -138,11 +138,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) ld r9,PACACONTEXTID(r13) BEGIN_FTR_SECTION cmpldi r10,0x1000 -END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) rldimi r10,r9,USER_ESID_BITS,0 BEGIN_FTR_SECTION bge slb_finish_load_1T -END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) b slb_finish_load 8: /* invalid EA */ diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index 446a01842a73..41e31642a86a 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c @@ -243,7 +243,7 @@ void __init stabs_alloc(void) { int cpu; - if (cpu_has_feature(CPU_FTR_SLB)) + if (mmu_has_feature(MMU_FTR_SLB)) return; for_each_possible_cpu(cpu) { diff --git a/arch/powerpc/platforms/44x/iss4xx.c b/arch/powerpc/platforms/44x/iss4xx.c index aa46e9d1e771..19395f18b1db 100644 --- a/arch/powerpc/platforms/44x/iss4xx.c +++ b/arch/powerpc/platforms/44x/iss4xx.c @@ -87,7 +87,7 @@ static void __cpuinit smp_iss4xx_setup_cpu(int cpu) mpic_setup_this_cpu(); } -static void __cpuinit smp_iss4xx_kick_cpu(int cpu) +static int __cpuinit smp_iss4xx_kick_cpu(int cpu) { struct device_node *cpunode = of_get_cpu_node(cpu, NULL); const u64 *spin_table_addr_prop; @@ -104,7 +104,7 @@ static void __cpuinit smp_iss4xx_kick_cpu(int cpu) NULL); if (spin_table_addr_prop == NULL) { pr_err("CPU%d: Can't start, missing cpu-release-addr !\n", cpu); - return; + return -ENOENT; } /* Assume it's mapped as part of the linear mapping. This is a bit @@ -117,6 +117,8 @@ static void __cpuinit smp_iss4xx_kick_cpu(int cpu) smp_wmb(); spin_table[1] = __pa(start_secondary_47x); mb(); + + return 0; } static struct smp_ops_t iss_smp_ops = { diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index cfc4b2009982..9f09319352c0 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -61,7 +61,7 @@ irq_to_pic_bit(unsigned int irq) static void cpld_mask_irq(struct irq_data *d) { - unsigned int cpld_irq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d); void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); out_8(pic_mask, @@ -71,7 +71,7 @@ cpld_mask_irq(struct irq_data *d) static void cpld_unmask_irq(struct irq_data *d) { - unsigned int cpld_irq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d); void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); out_8(pic_mask, @@ -97,7 +97,7 @@ cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp, status |= (ignore | mask); if (status == 0xff) - return NO_IRQ_IGNORE; + return NO_IRQ; cpld_irq = ffz(status) + offset; @@ -109,14 +109,14 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc) { irq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status, &cpld_regs->pci_mask); - if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { + if (irq != NO_IRQ) { generic_handle_irq(irq); return; } irq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status, &cpld_regs->misc_mask); - if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { + if (irq != NO_IRQ) { generic_handle_irq(irq); return; } diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c index 57a6a349e932..96f85e5e0cd3 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c @@ -56,7 +56,7 @@ static void media5200_irq_unmask(struct irq_data *d) spin_lock_irqsave(&media5200_irq.lock, flags); val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE); - val |= 1 << (MEDIA5200_IRQ_SHIFT + irq_map[d->irq].hwirq); + val |= 1 << (MEDIA5200_IRQ_SHIFT + irqd_to_hwirq(d)); out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val); spin_unlock_irqrestore(&media5200_irq.lock, flags); } @@ -68,7 +68,7 @@ static void media5200_irq_mask(struct irq_data *d) spin_lock_irqsave(&media5200_irq.lock, flags); val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE); - val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irq_map[d->irq].hwirq)); + val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irqd_to_hwirq(d))); out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val); spin_unlock_irqrestore(&media5200_irq.lock, flags); } diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 1dd15400f6f0..1a9a49570579 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -157,48 +157,30 @@ static inline void io_be_clrbit(u32 __iomem *addr, int bitno) */ static void mpc52xx_extirq_mask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_clrbit(&intr->ctrl, 11 - l2irq); } static void mpc52xx_extirq_unmask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_setbit(&intr->ctrl, 11 - l2irq); } static void mpc52xx_extirq_ack(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_setbit(&intr->ctrl, 27-l2irq); } static int mpc52xx_extirq_set_type(struct irq_data *d, unsigned int flow_type) { u32 ctrl_reg, type; - int irq; - int l2irq; + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; void *handler = handle_level_irq; - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - - pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type); + pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, + (int) irqd_to_hwirq(d), l2irq, flow_type); switch (flow_type) { case IRQF_TRIGGER_HIGH: type = 0; break; @@ -237,23 +219,13 @@ static int mpc52xx_null_set_type(struct irq_data *d, unsigned int flow_type) static void mpc52xx_main_mask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_setbit(&intr->main_mask, 16 - l2irq); } static void mpc52xx_main_unmask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_clrbit(&intr->main_mask, 16 - l2irq); } @@ -270,23 +242,13 @@ static struct irq_chip mpc52xx_main_irqchip = { */ static void mpc52xx_periph_mask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_setbit(&intr->per_mask, 31 - l2irq); } static void mpc52xx_periph_unmask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_clrbit(&intr->per_mask, 31 - l2irq); } @@ -303,34 +265,19 @@ static struct irq_chip mpc52xx_periph_irqchip = { */ static void mpc52xx_sdma_mask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_setbit(&sdma->IntMask, l2irq); } static void mpc52xx_sdma_unmask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_clrbit(&sdma->IntMask, l2irq); } static void mpc52xx_sdma_ack(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; out_be32(&sdma->IntPend, 1 << l2irq); } @@ -539,7 +486,7 @@ void __init mpc52xx_init_irq(void) unsigned int mpc52xx_get_irq(void) { u32 status; - int irq = NO_IRQ_IGNORE; + int irq; status = in_be32(&intr->enc_status); if (status & 0x00000400) { /* critical */ @@ -562,6 +509,8 @@ unsigned int mpc52xx_get_irq(void) } else { irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET); } + } else { + return NO_IRQ; } return irq_linear_revmap(mpc52xx_irqhost, irq); diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 4a4eb6ffa12f..8ccf9ed62fe2 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -42,7 +42,7 @@ struct pq2ads_pci_pic { static void pq2ads_pci_mask_irq(struct irq_data *d) { struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d); - int irq = NUM_IRQS - virq_to_hw(d->irq) - 1; + int irq = NUM_IRQS - irqd_to_hwirq(d) - 1; if (irq != -1) { unsigned long flags; @@ -58,7 +58,7 @@ static void pq2ads_pci_mask_irq(struct irq_data *d) static void pq2ads_pci_unmask_irq(struct irq_data *d) { struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d); - int irq = NUM_IRQS - virq_to_hw(d->irq) - 1; + int irq = NUM_IRQS - irqd_to_hwirq(d) - 1; if (irq != -1) { unsigned long flags; @@ -112,16 +112,8 @@ static int pci_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static void pci_host_unmap(struct irq_host *h, unsigned int virq) -{ - /* remove chip and handler */ - irq_set_chip_data(virq, NULL); - irq_set_chip(virq, NULL); -} - static struct irq_host_ops pci_pic_host_ops = { .map = pci_pic_host_map, - .unmap = pci_host_unmap, }; int __init pq2ads_pci_init_irq(void) diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index 188272934cfb..104faa8aa23c 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c @@ -318,17 +318,20 @@ static const struct platform_suspend_ops mpc83xx_suspend_ops = { .end = mpc83xx_suspend_end, }; +static struct of_device_id pmc_match[]; static int pmc_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct resource res; struct pmc_type *type; int ret = 0; - if (!ofdev->dev.of_match) + match = of_match_device(pmc_match, &ofdev->dev); + if (!match) return -EINVAL; - type = ofdev->dev.of_match->data; + type = match->data; if (!of_device_is_available(np)) return -ENODEV; diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 0d00ff9d05a0..d6a93a10c0f5 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -41,7 +41,7 @@ extern void __early_start(void); #define NUM_BOOT_ENTRY 8 #define SIZE_BOOT_ENTRY (NUM_BOOT_ENTRY * sizeof(u32)) -static void __init +static int __init smp_85xx_kick_cpu(int nr) { unsigned long flags; @@ -60,7 +60,7 @@ smp_85xx_kick_cpu(int nr) if (cpu_rel_addr == NULL) { printk(KERN_ERR "No cpu-release-addr for cpu %d\n", nr); - return; + return -ENOENT; } /* @@ -107,6 +107,8 @@ smp_85xx_kick_cpu(int nr) iounmap(bptr_vaddr); pr_debug("waited %d msecs for CPU #%d.\n", n, nr); + + return 0; } static void __init @@ -233,8 +235,10 @@ void __init mpc85xx_smp_init(void) smp_85xx_ops.message_pass = smp_mpic_message_pass; } - if (cpu_has_feature(CPU_FTR_DBELL)) - smp_85xx_ops.message_pass = doorbell_message_pass; + if (cpu_has_feature(CPU_FTR_DBELL)) { + smp_85xx_ops.message_pass = smp_muxed_ipi_message_pass; + smp_85xx_ops.cause_ipi = doorbell_cause_ipi; + } BUG_ON(!smp_85xx_ops.message_pass); diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c index db864623b4ae..12cb9bb2cc68 100644 --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c @@ -48,8 +48,6 @@ static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = { [8] = {0, IRQ_TYPE_LEVEL_HIGH}, }; -#define socrates_fpga_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) - static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock); static void __iomem *socrates_fpga_pic_iobase; @@ -110,11 +108,9 @@ void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc) static void socrates_fpga_pic_ack(struct irq_data *d) { unsigned long flags; - unsigned int hwirq, irq_line; + unsigned int irq_line, hwirq = irqd_to_hwirq(d); uint32_t mask; - hwirq = socrates_fpga_irq_to_hw(d->irq); - irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) @@ -127,12 +123,10 @@ static void socrates_fpga_pic_ack(struct irq_data *d) static void socrates_fpga_pic_mask(struct irq_data *d) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); int irq_line; u32 mask; - hwirq = socrates_fpga_irq_to_hw(d->irq); - irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) @@ -145,12 +139,10 @@ static void socrates_fpga_pic_mask(struct irq_data *d) static void socrates_fpga_pic_mask_ack(struct irq_data *d) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); int irq_line; u32 mask; - hwirq = socrates_fpga_irq_to_hw(d->irq); - irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) @@ -164,12 +156,10 @@ static void socrates_fpga_pic_mask_ack(struct irq_data *d) static void socrates_fpga_pic_unmask(struct irq_data *d) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); int irq_line; u32 mask; - hwirq = socrates_fpga_irq_to_hw(d->irq); - irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) @@ -182,12 +172,10 @@ static void socrates_fpga_pic_unmask(struct irq_data *d) static void socrates_fpga_pic_eoi(struct irq_data *d) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); int irq_line; u32 mask; - hwirq = socrates_fpga_irq_to_hw(d->irq); - irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) @@ -201,12 +189,10 @@ static int socrates_fpga_pic_set_type(struct irq_data *d, unsigned int flow_type) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); int polarity; u32 mask; - hwirq = socrates_fpga_irq_to_hw(d->irq); - if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE) return -EINVAL; diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c index 0beec7d5566b..94594e58594c 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ b/arch/powerpc/platforms/86xx/gef_pic.c @@ -46,8 +46,6 @@ #define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0) #define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1) -#define gef_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) - static DEFINE_RAW_SPINLOCK(gef_pic_lock); @@ -113,11 +111,9 @@ void gef_pic_cascade(unsigned int irq, struct irq_desc *desc) static void gef_pic_mask(struct irq_data *d) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); u32 mask; - hwirq = gef_irq_to_hw(d->irq); - raw_spin_lock_irqsave(&gef_pic_lock, flags); mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); mask &= ~(1 << hwirq); @@ -136,11 +132,9 @@ static void gef_pic_mask_ack(struct irq_data *d) static void gef_pic_unmask(struct irq_data *d) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); u32 mask; - hwirq = gef_irq_to_hw(d->irq); - raw_spin_lock_irqsave(&gef_pic_lock, flags); mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); mask |= (1 << hwirq); diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index 018cc67be426..a896511690c2 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -66,7 +66,7 @@ static void __init mpc8610_suspend_init(void) return; } - ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9/wakeup", NULL); + ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9:wakeup", NULL); if (ret) { pr_err("%s: can't request pixis event IRQ: %d\n", __func__, ret); @@ -105,45 +105,77 @@ machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices); #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) -static u32 get_busfreq(void) -{ - struct device_node *node; +/* + * DIU Area Descriptor + * + * The MPC8610 reference manual shows the bits of the AD register in + * little-endian order, which causes the BLUE_C field to be split into two + * parts. To simplify the definition of the MAKE_AD() macro, we define the + * fields in big-endian order and byte-swap the result. + * + * So even though the registers don't look like they're in the + * same bit positions as they are on the P1022, the same value is written to + * the AD register on the MPC8610 and on the P1022. + */ +#define AD_BYTE_F 0x10000000 +#define AD_ALPHA_C_MASK 0x0E000000 +#define AD_ALPHA_C_SHIFT 25 +#define AD_BLUE_C_MASK 0x01800000 +#define AD_BLUE_C_SHIFT 23 +#define AD_GREEN_C_MASK 0x00600000 +#define AD_GREEN_C_SHIFT 21 +#define AD_RED_C_MASK 0x00180000 +#define AD_RED_C_SHIFT 19 +#define AD_PALETTE 0x00040000 +#define AD_PIXEL_S_MASK 0x00030000 +#define AD_PIXEL_S_SHIFT 16 +#define AD_COMP_3_MASK 0x0000F000 +#define AD_COMP_3_SHIFT 12 +#define AD_COMP_2_MASK 0x00000F00 +#define AD_COMP_2_SHIFT 8 +#define AD_COMP_1_MASK 0x000000F0 +#define AD_COMP_1_SHIFT 4 +#define AD_COMP_0_MASK 0x0000000F +#define AD_COMP_0_SHIFT 0 - u32 fs_busfreq = 0; - node = of_find_node_by_type(NULL, "cpu"); - if (node) { - unsigned int size; - const unsigned int *prop = - of_get_property(node, "bus-frequency", &size); - if (prop) - fs_busfreq = *prop; - of_node_put(node); - }; - return fs_busfreq; -} +#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \ + cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \ + (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \ + (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \ + (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \ + (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT)) unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel, int monitor_port) { static const unsigned long pixelformat[][3] = { - {0x88882317, 0x88083218, 0x65052119}, - {0x88883316, 0x88082219, 0x65053118}, + { + MAKE_AD(3, 0, 2, 1, 3, 8, 8, 8, 8), + MAKE_AD(4, 2, 0, 1, 2, 8, 8, 8, 0), + MAKE_AD(4, 0, 2, 1, 1, 5, 6, 5, 0) + }, + { + MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8), + MAKE_AD(4, 0, 2, 1, 2, 8, 8, 8, 0), + MAKE_AD(4, 2, 0, 1, 1, 5, 6, 5, 0) + }, }; - unsigned int pix_fmt, arch_monitor; + unsigned int arch_monitor; + /* The DVI port is mis-wired on revision 1 of this board. */ arch_monitor = ((*pixis_arch == 0x01) && (monitor_port == 0))? 0 : 1; - /* DVI port for board version 0x01 */ - if (bits_per_pixel == 32) - pix_fmt = pixelformat[arch_monitor][0]; - else if (bits_per_pixel == 24) - pix_fmt = pixelformat[arch_monitor][1]; - else if (bits_per_pixel == 16) - pix_fmt = pixelformat[arch_monitor][2]; - else - pix_fmt = pixelformat[1][0]; - - return pix_fmt; + switch (bits_per_pixel) { + case 32: + return pixelformat[arch_monitor][0]; + case 24: + return pixelformat[arch_monitor][1]; + case 16: + return pixelformat[arch_monitor][2]; + default: + pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel); + return 0; + } } void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base) @@ -190,8 +222,7 @@ void mpc8610hpcd_set_pixel_clock(unsigned int pixclock) } /* Pixel Clock configuration */ - pr_debug("DIU: Bus Frequency = %d\n", get_busfreq()); - speed_ccb = get_busfreq(); + speed_ccb = fsl_get_sys_freq(); /* Calculate the pixel clock with the smallest error */ /* calculate the following in steps to avoid overflow */ diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c index eacea0e3fcc8..af09baee22cb 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c @@ -56,7 +56,7 @@ smp_86xx_release_core(int nr) } -static void __init +static int __init smp_86xx_kick_cpu(int nr) { unsigned int save_vector; @@ -65,7 +65,7 @@ smp_86xx_kick_cpu(int nr) unsigned int *vector = (unsigned int *)(KERNELBASE + 0x100); if (nr < 0 || nr >= NR_CPUS) - return; + return -ENOENT; pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr); @@ -92,6 +92,8 @@ smp_86xx_kick_cpu(int nr) local_irq_restore(flags); pr_debug("wait CPU #%d for %d msecs.\n", nr, n); + + return 0; } diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index 9ecce995dd4b..1e121088826f 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -150,7 +150,7 @@ void __init mpc8xx_calibrate_decr(void) */ cpu = of_find_node_by_type(NULL, "cpu"); virq= irq_of_parse_and_map(cpu, 0); - irq = irq_map[virq].hwirq; + irq = virq_to_hw(virq); sys_tmr2 = immr_map(im_sit); out_be16(&sys_tmr2->sit_tbscr, ((1 << (7 - (irq/2))) << 8) | diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index f7b07720aa30..f970ca2b180c 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -20,6 +20,7 @@ source "arch/powerpc/platforms/embedded6xx/Kconfig" source "arch/powerpc/platforms/44x/Kconfig" source "arch/powerpc/platforms/40x/Kconfig" source "arch/powerpc/platforms/amigaone/Kconfig" +source "arch/powerpc/platforms/wsp/Kconfig" config KVM_GUEST bool "KVM Guest support" @@ -56,16 +57,19 @@ config UDBG_RTAS_CONSOLE depends on PPC_RTAS default n +config PPC_SMP_MUXED_IPI + bool + help + Select this opton if your platform supports SMP and your + interrupt controller provides less than 4 interrupts to each + cpu. This will enable the generic code to multiplex the 4 + messages on to one ipi. + config PPC_UDBG_BEAT bool "BEAT based debug console" depends on PPC_CELLEB default n -config XICS - depends on PPC_PSERIES - bool - default y - config IPIC bool default n @@ -147,14 +151,27 @@ config PPC_970_NAP bool default n +config PPC_P7_NAP + bool + default n + config PPC_INDIRECT_IO bool select GENERIC_IOMAP - default n + +config PPC_INDIRECT_PIO + bool + select PPC_INDIRECT_IO + +config PPC_INDIRECT_MMIO + bool + select PPC_INDIRECT_IO + +config PPC_IO_WORKAROUNDS + bool config GENERIC_IOMAP bool - default n source "drivers/cpufreq/Kconfig" diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 111138c55f9c..2165b65876f9 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -73,6 +73,7 @@ config PPC_BOOK3S_64 config PPC_BOOK3E_64 bool "Embedded processors" select PPC_FPU # Make it a choice ? + select PPC_SMP_MUXED_IPI endchoice @@ -107,6 +108,10 @@ config POWER4 depends on PPC64 && PPC_BOOK3S def_bool y +config PPC_A2 + bool + depends on PPC_BOOK3E_64 + config TUNE_CELL bool "Optimize for Cell Broadband Engine" depends on PPC64 && PPC_BOOK3S @@ -174,6 +179,7 @@ config FSL_BOOKE config PPC_FSL_BOOK3E bool select FSL_EMB_PERFMON + select PPC_SMP_MUXED_IPI default y if FSL_BOOKE config PTE_64BIT @@ -226,6 +232,24 @@ config VSX If in doubt, say Y here. +config PPC_ICSWX + bool "Support for PowerPC icswx coprocessor instruction" + depends on POWER4 + default n + ---help--- + + This option enables kernel support for the PowerPC Initiate + Coprocessor Store Word (icswx) coprocessor instruction on POWER7 + or newer processors. + + This option is only useful if you have a processor that supports + the icswx coprocessor instruction. It does not have any effect + on processors without the icswx coprocessor instruction. + + This option slightly increases kernel memory usage. + + If in doubt, say N here. + config SPE bool "SPE Support" depends on E200 || (E500 && !PPC_E500MC) diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index fdb9f0b0d7a8..73e2116cfeed 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_PPC_CELL) += cell/ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/ obj-$(CONFIG_AMIGAONE) += amigaone/ +obj-$(CONFIG_PPC_WSP) += wsp/ diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 81239ebed83f..67d5009b4e86 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -6,7 +6,8 @@ config PPC_CELL_COMMON bool select PPC_CELL select PPC_DCR_MMIO - select PPC_INDIRECT_IO + select PPC_INDIRECT_PIO + select PPC_INDIRECT_MMIO select PPC_NATIVE select PPC_RTAS select IRQ_EDGE_EOI_HANDLER @@ -15,6 +16,7 @@ config PPC_CELL_NATIVE bool select PPC_CELL_COMMON select MPIC + select PPC_IO_WORKAROUNDS select IBM_NEW_EMAC_EMAC4 select IBM_NEW_EMAC_RGMII select IBM_NEW_EMAC_ZMII #test only diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index 83fafe922641..a4a89350bcfc 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_PPC_CELL_COMMON) += cbe_regs.o interrupt.o pervasive.o obj-$(CONFIG_PPC_CELL_NATIVE) += iommu.o setup.o spider-pic.o \ - pmu.o io-workarounds.o spider-pci.o + pmu.o spider-pci.o obj-$(CONFIG_CBE_RAS) += ras.o obj-$(CONFIG_CBE_THERM) += cbe_thermal.o @@ -39,11 +39,10 @@ obj-y += celleb_setup.o \ celleb_pci.o celleb_scc_epci.o \ celleb_scc_pciex.o \ celleb_scc_uhc.o \ - io-workarounds.o spider-pci.o \ - beat.o beat_htab.o beat_hvCall.o \ - beat_interrupt.o beat_iommu.o + spider-pci.o beat.o beat_htab.o \ + beat_hvCall.o beat_interrupt.o \ + beat_iommu.o -obj-$(CONFIG_SMP) += beat_smp.o obj-$(CONFIG_PPC_UDBG_BEAT) += beat_udbg.o obj-$(CONFIG_SERIAL_TXX9) += celleb_scc_sio.o obj-$(CONFIG_SPU_BASE) += beat_spu_priv1.o diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index bb5ebf8fa80b..ac06903e136a 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -113,7 +113,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc) pr_devel("axon_msi: woff %x roff %x msi %x\n", write_offset, msic->read_offset, msi); - if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host) { + if (msi < NR_IRQS && irq_get_chip_data(msi) == msic) { generic_handle_irq(msi); msic->fifo_virt[idx] = cpu_to_le32(0xffffffff); } else { @@ -320,6 +320,7 @@ static struct irq_chip msic_irq_chip = { static int msic_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { + irq_set_chip_data(virq, h->host_data); irq_set_chip_and_handler(virq, &msic_irq_chip, handle_simple_irq); return 0; diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index 4cb9e147c307..55015e1f6939 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -147,16 +147,6 @@ static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -/* - * Update binding hardware IRQ number (hw) and Virtuql - * IRQ number (virq). This is called only once for a given mapping. - */ -static void beatic_pic_host_remap(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) -{ - beat_construct_and_connect_irq_plug(virq, hw); -} - /* * Translate device-tree interrupt spec to irq_hw_number_t style (ulong), * to pass away to irq_create_mapping(). @@ -184,7 +174,6 @@ static int beatic_pic_host_match(struct irq_host *h, struct device_node *np) static struct irq_host_ops beatic_pic_host_ops = { .map = beatic_pic_host_map, - .remap = beatic_pic_host_remap, .unmap = beatic_pic_host_unmap, .xlate = beatic_pic_host_xlate, .match = beatic_pic_host_match, @@ -257,22 +246,6 @@ void __init beatic_init_IRQ(void) irq_set_default_host(beatic_host); } -#ifdef CONFIG_SMP - -/* Nullified to compile with SMP mode */ -void beatic_setup_cpu(int cpu) -{ -} - -void beatic_cause_IPI(int cpu, int mesg) -{ -} - -void beatic_request_IPIs(void) -{ -} -#endif /* CONFIG_SMP */ - void beatic_deinit_IRQ(void) { int i; diff --git a/arch/powerpc/platforms/cell/beat_interrupt.h b/arch/powerpc/platforms/cell/beat_interrupt.h index b470fd0051f1..a7e52f91a078 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.h +++ b/arch/powerpc/platforms/cell/beat_interrupt.h @@ -24,9 +24,6 @@ extern void beatic_init_IRQ(void); extern unsigned int beatic_get_irq(void); -extern void beatic_cause_IPI(int cpu, int mesg); -extern void beatic_request_IPIs(void); -extern void beatic_setup_cpu(int); extern void beatic_deinit_IRQ(void); #endif diff --git a/arch/powerpc/platforms/cell/beat_smp.c b/arch/powerpc/platforms/cell/beat_smp.c deleted file mode 100644 index 26efc204c47f..000000000000 --- a/arch/powerpc/platforms/cell/beat_smp.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * SMP support for Celleb platform. (Incomplete) - * - * (C) Copyright 2006 TOSHIBA CORPORATION - * - * This code is based on arch/powerpc/platforms/cell/smp.c: - * Dave Engebretsen, Peter Bergner, and - * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com - * Plus various changes from other IBM teams... - * - * 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. - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "beat_interrupt.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* - * The primary thread of each non-boot processor is recorded here before - * smp init. - */ -/* static cpumask_t of_spin_map; */ - -/** - * smp_startup_cpu() - start the given cpu - * - * At boot time, there is nothing to do for primary threads which were - * started from Open Firmware. For anything else, call RTAS with the - * appropriate start location. - * - * Returns: - * 0 - failure - * 1 - success - */ -static inline int __devinit smp_startup_cpu(unsigned int lcpu) -{ - return 0; -} - -static void smp_beatic_message_pass(int target, int msg) -{ - unsigned int i; - - if (target < NR_CPUS) { - beatic_cause_IPI(target, msg); - } else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - beatic_cause_IPI(i, msg); - } - } -} - -static int __init smp_beatic_probe(void) -{ - return cpus_weight(cpu_possible_map); -} - -static void __devinit smp_beatic_setup_cpu(int cpu) -{ - beatic_setup_cpu(cpu); -} - -static void __devinit smp_celleb_kick_cpu(int nr) -{ - BUG_ON(nr < 0 || nr >= NR_CPUS); - - if (!smp_startup_cpu(nr)) - return; -} - -static int smp_celleb_cpu_bootable(unsigned int nr) -{ - return 1; -} -static struct smp_ops_t bpa_beatic_smp_ops = { - .message_pass = smp_beatic_message_pass, - .probe = smp_beatic_probe, - .kick_cpu = smp_celleb_kick_cpu, - .setup_cpu = smp_beatic_setup_cpu, - .cpu_bootable = smp_celleb_cpu_bootable, -}; - -/* This is called very early */ -void __init smp_init_celleb(void) -{ - DBG(" -> smp_init_celleb()\n"); - - smp_ops = &bpa_beatic_smp_ops; - - DBG(" <- smp_init_celleb()\n"); -} diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c index dbc338f187a2..f3917e7a5b44 100644 --- a/arch/powerpc/platforms/cell/cbe_regs.c +++ b/arch/powerpc/platforms/cell/cbe_regs.c @@ -45,8 +45,8 @@ static struct cbe_thread_map unsigned int cbe_id; } cbe_thread_map[NR_CPUS]; -static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = CPU_MASK_NONE }; -static cpumask_t cbe_first_online_cpu = CPU_MASK_NONE; +static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = {CPU_BITS_NONE} }; +static cpumask_t cbe_first_online_cpu = { CPU_BITS_NONE }; static struct cbe_regs_map *cbe_find_map(struct device_node *np) { @@ -159,7 +159,8 @@ EXPORT_SYMBOL_GPL(cbe_cpu_to_node); u32 cbe_node_to_cpu(int node) { - return find_first_bit( (unsigned long *) &cbe_local_mask[node], sizeof(cpumask_t)); + return cpumask_first(&cbe_local_mask[node]); + } EXPORT_SYMBOL_GPL(cbe_node_to_cpu); @@ -268,9 +269,9 @@ void __init cbe_regs_init(void) thread->regs = map; thread->cbe_id = cbe_id; map->be_node = thread->be_node; - cpu_set(i, cbe_local_mask[cbe_id]); + cpumask_set_cpu(i, &cbe_local_mask[cbe_id]); if(thread->thread_id == 0) - cpu_set(i, cbe_first_online_cpu); + cpumask_set_cpu(i, &cbe_first_online_cpu); } } diff --git a/arch/powerpc/platforms/cell/celleb_pci.c b/arch/powerpc/platforms/cell/celleb_pci.c index 404d1fc04d59..5822141aa63f 100644 --- a/arch/powerpc/platforms/cell/celleb_pci.c +++ b/arch/powerpc/platforms/cell/celleb_pci.c @@ -41,7 +41,6 @@ #include #include -#include "io-workarounds.h" #include "celleb_pci.h" #define MAX_PCI_DEVICES 32 @@ -320,7 +319,7 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node, size = 256; config = &private->fake_config[devno][fn]; - *config = alloc_maybe_bootmem(size, GFP_KERNEL); + *config = zalloc_maybe_bootmem(size, GFP_KERNEL); if (*config == NULL) { printk(KERN_ERR "PCI: " "not enough memory for fake configuration space\n"); @@ -331,7 +330,7 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node, size = sizeof(struct celleb_pci_resource); res = &private->res[devno][fn]; - *res = alloc_maybe_bootmem(size, GFP_KERNEL); + *res = zalloc_maybe_bootmem(size, GFP_KERNEL); if (*res == NULL) { printk(KERN_ERR "PCI: not enough memory for resource data space\n"); @@ -432,7 +431,7 @@ static int __init phb_set_bus_ranges(struct device_node *dev, static void __init celleb_alloc_private_mem(struct pci_controller *hose) { hose->private_data = - alloc_maybe_bootmem(sizeof(struct celleb_pci_private), + zalloc_maybe_bootmem(sizeof(struct celleb_pci_private), GFP_KERNEL); } @@ -469,18 +468,6 @@ static struct of_device_id celleb_phb_match[] __initdata = { }, }; -static int __init celleb_io_workaround_init(struct pci_controller *phb, - struct celleb_phb_spec *phb_spec) -{ - if (phb_spec->ops) { - iowa_register_bus(phb, phb_spec->ops, phb_spec->iowa_init, - phb_spec->iowa_data); - io_workaround_init(); - } - - return 0; -} - int __init celleb_setup_phb(struct pci_controller *phb) { struct device_node *dev = phb->dn; @@ -500,7 +487,11 @@ int __init celleb_setup_phb(struct pci_controller *phb) if (rc) return 1; - return celleb_io_workaround_init(phb, phb_spec); + if (phb_spec->ops) + iowa_register_bus(phb, phb_spec->ops, + phb_spec->iowa_init, + phb_spec->iowa_data); + return 0; } int celleb_pci_probe_mode(struct pci_bus *bus) diff --git a/arch/powerpc/platforms/cell/celleb_pci.h b/arch/powerpc/platforms/cell/celleb_pci.h index 4cba1523ec50..a801fcc5f389 100644 --- a/arch/powerpc/platforms/cell/celleb_pci.h +++ b/arch/powerpc/platforms/cell/celleb_pci.h @@ -26,8 +26,9 @@ #include #include #include +#include -#include "io-workarounds.h" +struct iowa_bus; struct celleb_phb_spec { int (*setup)(struct device_node *, struct pci_controller *); diff --git a/arch/powerpc/platforms/cell/celleb_setup.c b/arch/powerpc/platforms/cell/celleb_setup.c index e53845579770..d58d9bae4b9b 100644 --- a/arch/powerpc/platforms/cell/celleb_setup.c +++ b/arch/powerpc/platforms/cell/celleb_setup.c @@ -128,10 +128,6 @@ static void __init celleb_setup_arch_beat(void) spu_management_ops = &spu_management_of_ops; #endif -#ifdef CONFIG_SMP - smp_init_celleb(); -#endif - celleb_setup_arch_common(); } diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 44cfd1bef89b..449c08c15862 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -196,8 +196,20 @@ static irqreturn_t iic_ipi_action(int irq, void *dev_id) { int ipi = (int)(long)dev_id; - smp_message_recv(ipi); - + switch(ipi) { + case PPC_MSG_CALL_FUNCTION: + generic_smp_call_function_interrupt(); + break; + case PPC_MSG_RESCHEDULE: + scheduler_ipi(); + break; + case PPC_MSG_CALL_FUNC_SINGLE: + generic_smp_call_function_single_interrupt(); + break; + case PPC_MSG_DEBUGGER_BREAK: + debug_ipi_action(0, NULL); + break; + } return IRQ_HANDLED; } static void iic_request_ipi(int ipi, const char *name) diff --git a/arch/powerpc/platforms/cell/qpace_setup.c b/arch/powerpc/platforms/cell/qpace_setup.c index d31c594cfdf3..51e290126bc1 100644 --- a/arch/powerpc/platforms/cell/qpace_setup.c +++ b/arch/powerpc/platforms/cell/qpace_setup.c @@ -42,7 +42,6 @@ #include "interrupt.h" #include "pervasive.h" #include "ras.h" -#include "io-workarounds.h" static void qpace_show_cpuinfo(struct seq_file *m) { diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index fd57bfe00edf..c73cf4c43fc2 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -51,11 +51,11 @@ #include #include #include +#include #include "interrupt.h" #include "pervasive.h" #include "ras.h" -#include "io-workarounds.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -136,8 +136,6 @@ static int __devinit cell_setup_phb(struct pci_controller *phb) iowa_register_bus(phb, &spiderpci_ops, &spiderpci_iowa_init, (void *)SPIDER_PCI_REG_BASE); - io_workaround_init(); - return 0; } diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c index f774530075b7..d176e6148e3f 100644 --- a/arch/powerpc/platforms/cell/smp.c +++ b/arch/powerpc/platforms/cell/smp.c @@ -77,7 +77,7 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) unsigned int pcpu; int start_cpu; - if (cpu_isset(lcpu, of_spin_map)) + if (cpumask_test_cpu(lcpu, &of_spin_map)) /* Already started by OF and sitting in spin loop */ return 1; @@ -103,27 +103,11 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) return 1; } -static void smp_iic_message_pass(int target, int msg) -{ - unsigned int i; - - if (target < NR_CPUS) { - iic_cause_IPI(target, msg); - } else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - iic_cause_IPI(i, msg); - } - } -} - static int __init smp_iic_probe(void) { iic_request_IPIs(); - return cpus_weight(cpu_possible_map); + return cpumask_weight(cpu_possible_mask); } static void __devinit smp_cell_setup_cpu(int cpu) @@ -137,12 +121,12 @@ static void __devinit smp_cell_setup_cpu(int cpu) mtspr(SPRN_DABRX, DABRX_KERNEL | DABRX_USER); } -static void __devinit smp_cell_kick_cpu(int nr) +static int __devinit smp_cell_kick_cpu(int nr) { BUG_ON(nr < 0 || nr >= NR_CPUS); if (!smp_startup_cpu(nr)) - return; + return -ENOENT; /* * The processor is currently spinning, waiting for the @@ -150,6 +134,8 @@ static void __devinit smp_cell_kick_cpu(int nr) * the processor will continue on to secondary_start */ paca[nr].cpu_start = 1; + + return 0; } static int smp_cell_cpu_bootable(unsigned int nr) @@ -166,7 +152,7 @@ static int smp_cell_cpu_bootable(unsigned int nr) return 1; } static struct smp_ops_t bpa_iic_smp_ops = { - .message_pass = smp_iic_message_pass, + .message_pass = iic_cause_IPI, .probe = smp_iic_probe, .kick_cpu = smp_cell_kick_cpu, .setup_cpu = smp_cell_setup_cpu, @@ -186,13 +172,12 @@ void __init smp_init_cell(void) if (cpu_has_feature(CPU_FTR_SMT)) { for_each_present_cpu(i) { if (cpu_thread_in_core(i) == 0) - cpu_set(i, of_spin_map); + cpumask_set_cpu(i, &of_spin_map); } - } else { - of_spin_map = cpu_present_map; - } + } else + cpumask_copy(&of_spin_map, cpu_present_mask); - cpu_clear(boot_cpuid, of_spin_map); + cpumask_clear_cpu(boot_cpuid, &of_spin_map); /* Non-lpar has additional take/give timebase */ if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) { diff --git a/arch/powerpc/platforms/cell/spider-pci.c b/arch/powerpc/platforms/cell/spider-pci.c index ca7731c0b595..f1f7878893f3 100644 --- a/arch/powerpc/platforms/cell/spider-pci.c +++ b/arch/powerpc/platforms/cell/spider-pci.c @@ -27,8 +27,7 @@ #include #include - -#include "io-workarounds.h" +#include #define SPIDER_PCI_DISABLE_PREFETCH diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index c5cf50e6b45a..442c28c00f88 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -68,9 +68,9 @@ struct spider_pic { }; static struct spider_pic spider_pics[SPIDER_CHIP_COUNT]; -static struct spider_pic *spider_virq_to_pic(unsigned int virq) +static struct spider_pic *spider_irq_data_to_pic(struct irq_data *d) { - return irq_map[virq].host->host_data; + return irq_data_get_irq_chip_data(d); } static void __iomem *spider_get_irq_config(struct spider_pic *pic, @@ -81,24 +81,24 @@ static void __iomem *spider_get_irq_config(struct spider_pic *pic, static void spider_unmask_irq(struct irq_data *d) { - struct spider_pic *pic = spider_virq_to_pic(d->irq); - void __iomem *cfg = spider_get_irq_config(pic, irq_map[d->irq].hwirq); + struct spider_pic *pic = spider_irq_data_to_pic(d); + void __iomem *cfg = spider_get_irq_config(pic, irqd_to_hwirq(d)); out_be32(cfg, in_be32(cfg) | 0x30000000u); } static void spider_mask_irq(struct irq_data *d) { - struct spider_pic *pic = spider_virq_to_pic(d->irq); - void __iomem *cfg = spider_get_irq_config(pic, irq_map[d->irq].hwirq); + struct spider_pic *pic = spider_irq_data_to_pic(d); + void __iomem *cfg = spider_get_irq_config(pic, irqd_to_hwirq(d)); out_be32(cfg, in_be32(cfg) & ~0x30000000u); } static void spider_ack_irq(struct irq_data *d) { - struct spider_pic *pic = spider_virq_to_pic(d->irq); - unsigned int src = irq_map[d->irq].hwirq; + struct spider_pic *pic = spider_irq_data_to_pic(d); + unsigned int src = irqd_to_hwirq(d); /* Reset edge detection logic if necessary */ @@ -116,8 +116,8 @@ static void spider_ack_irq(struct irq_data *d) static int spider_set_irq_type(struct irq_data *d, unsigned int type) { unsigned int sense = type & IRQ_TYPE_SENSE_MASK; - struct spider_pic *pic = spider_virq_to_pic(d->irq); - unsigned int hw = irq_map[d->irq].hwirq; + struct spider_pic *pic = spider_irq_data_to_pic(d); + unsigned int hw = irqd_to_hwirq(d); void __iomem *cfg = spider_get_irq_config(pic, hw); u32 old_mask; u32 ic; @@ -171,6 +171,7 @@ static struct irq_chip spider_pic = { static int spider_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { + irq_set_chip_data(virq, h->host_data); irq_set_chip_and_handler(virq, &spider_pic, handle_level_irq); /* Set default irq type */ diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index acfaccea5f4f..3675da73623f 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -521,18 +522,8 @@ void spu_init_channels(struct spu *spu) } EXPORT_SYMBOL_GPL(spu_init_channels); -static int spu_shutdown(struct sys_device *sysdev) -{ - struct spu *spu = container_of(sysdev, struct spu, sysdev); - - spu_free_irqs(spu); - spu_destroy_spu(spu); - return 0; -} - static struct sysdev_class spu_sysdev_class = { .name = "spu", - .shutdown = spu_shutdown, }; int spu_add_sysdev_attr(struct sysdev_attribute *attr) @@ -797,6 +788,22 @@ static inline void crash_register_spus(struct list_head *list) } #endif +static void spu_shutdown(void) +{ + struct spu *spu; + + mutex_lock(&spu_full_list_mutex); + list_for_each_entry(spu, &spu_full_list, full_list) { + spu_free_irqs(spu); + spu_destroy_spu(spu); + } + mutex_unlock(&spu_full_list_mutex); +} + +static struct syscore_ops spu_syscore_ops = { + .shutdown = spu_shutdown, +}; + static int __init init_spu_base(void) { int i, ret = 0; @@ -830,6 +837,7 @@ static int __init init_spu_base(void) crash_register_spus(&spu_full_list); mutex_unlock(&spu_full_list_mutex); spu_add_sysdev_attr(&attr_stat); + register_syscore_ops(&spu_syscore_ops); spu_init_affinity(); diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 65203857b0ce..32cb4e66d2cd 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -141,7 +141,7 @@ void __spu_update_sched_info(struct spu_context *ctx) * runqueue. The context will be rescheduled on the proper node * if it is timesliced or preempted. */ - ctx->cpus_allowed = current->cpus_allowed; + cpumask_copy(&ctx->cpus_allowed, tsk_cpus_allowed(current)); /* Save the current cpu id for spu interrupt routing. */ ctx->last_ran = raw_smp_processor_id(); diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c index 02cafecc90e3..a800122e4dda 100644 --- a/arch/powerpc/platforms/chrp/smp.c +++ b/arch/powerpc/platforms/chrp/smp.c @@ -30,10 +30,12 @@ #include #include -static void __devinit smp_chrp_kick_cpu(int nr) +static int __devinit smp_chrp_kick_cpu(int nr) { *(unsigned long *)KERNELBASE = nr; asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); + + return 0; } static void __devinit smp_chrp_setup_cpu(int cpu_nr) diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index 12aa62b6f227..f61a2dd96b99 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -48,7 +48,7 @@ static void flipper_pic_mask_and_ack(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); u32 mask = 1 << irq; @@ -59,7 +59,7 @@ static void flipper_pic_mask_and_ack(struct irq_data *d) static void flipper_pic_ack(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); /* this is at least needed for RSW */ @@ -68,7 +68,7 @@ static void flipper_pic_ack(struct irq_data *d) static void flipper_pic_mask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); clrbits32(io_base + FLIPPER_IMR, 1 << irq); @@ -76,7 +76,7 @@ static void flipper_pic_mask(struct irq_data *d) static void flipper_pic_unmask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); setbits32(io_base + FLIPPER_IMR, 1 << irq); @@ -107,12 +107,6 @@ static int flipper_pic_map(struct irq_host *h, unsigned int virq, return 0; } -static void flipper_pic_unmap(struct irq_host *h, unsigned int irq) -{ - irq_set_chip_data(irq, NULL); - irq_set_chip(irq, NULL); -} - static int flipper_pic_match(struct irq_host *h, struct device_node *np) { return 1; @@ -121,7 +115,6 @@ static int flipper_pic_match(struct irq_host *h, struct device_node *np) static struct irq_host_ops flipper_irq_host_ops = { .map = flipper_pic_map, - .unmap = flipper_pic_unmap, .match = flipper_pic_match, }; diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index 2bdddfc9d520..e4919170c6bc 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -43,7 +43,7 @@ static void hlwd_pic_mask_and_ack(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); u32 mask = 1 << irq; @@ -53,7 +53,7 @@ static void hlwd_pic_mask_and_ack(struct irq_data *d) static void hlwd_pic_ack(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); out_be32(io_base + HW_BROADWAY_ICR, 1 << irq); @@ -61,7 +61,7 @@ static void hlwd_pic_ack(struct irq_data *d) static void hlwd_pic_mask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); clrbits32(io_base + HW_BROADWAY_IMR, 1 << irq); @@ -69,7 +69,7 @@ static void hlwd_pic_mask(struct irq_data *d) static void hlwd_pic_unmask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); setbits32(io_base + HW_BROADWAY_IMR, 1 << irq); @@ -100,15 +100,8 @@ static int hlwd_pic_map(struct irq_host *h, unsigned int virq, return 0; } -static void hlwd_pic_unmap(struct irq_host *h, unsigned int irq) -{ - irq_set_chip_data(irq, NULL); - irq_set_chip(irq, NULL); -} - static struct irq_host_ops hlwd_irq_host_ops = { .map = hlwd_pic_map, - .unmap = hlwd_pic_unmap, }; static unsigned int __hlwd_pic_get_irq(struct irq_host *h) diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig index e5bc9f75d474..b57cda3a0817 100644 --- a/arch/powerpc/platforms/iseries/Kconfig +++ b/arch/powerpc/platforms/iseries/Kconfig @@ -1,7 +1,9 @@ config PPC_ISERIES bool "IBM Legacy iSeries" depends on PPC64 && PPC_BOOK3S - select PPC_INDIRECT_IO + select PPC_SMP_MUXED_IPI + select PPC_INDIRECT_PIO + select PPC_INDIRECT_MMIO select PPC_PCI_CHOICE if EXPERT menu "iSeries device drivers" diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S index 32a56c6dfa72..29c02f36b32f 100644 --- a/arch/powerpc/platforms/iseries/exception.S +++ b/arch/powerpc/platforms/iseries/exception.S @@ -31,6 +31,7 @@ #include #include #include +#include #include "exception.h" @@ -60,29 +61,31 @@ system_reset_iSeries: /* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */ /* In the UP case we'll yield() later, and we will not access the paca anyway */ #ifdef CONFIG_SMP -1: +iSeries_secondary_wait_paca: HMT_LOW LOAD_REG_ADDR(r23, __secondary_hold_spinloop) ld r23,0(r23) - sync - LOAD_REG_ADDR(r3,current_set) - sldi r28,r24,3 /* get current_set[cpu#] */ - ldx r3,r3,r28 - addi r1,r3,THREAD_SIZE - subi r1,r1,STACK_FRAME_OVERHEAD - cmpwi 0,r23,0 /* Keep poking the Hypervisor until */ - bne 2f /* we're released */ - /* Let the Hypervisor know we are alive */ + cmpdi 0,r23,0 + bne 2f /* go on when the master is ready */ + + /* Keep poking the Hypervisor until we're released */ /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ lis r3,0x8002 rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ li r0,-1 /* r0=-1 indicates a Hypervisor call */ sc /* Invoke the hypervisor via a system call */ - b 1b -#endif + b iSeries_secondary_wait_paca 2: + HMT_MEDIUM + sync + + LOAD_REG_ADDR(r3, nr_cpu_ids) /* get number of pacas allocated */ + lwz r3,0(r3) /* nr_cpus= or NR_CPUS can limit */ + cmpld 0,r24,r3 /* is our cpu number allocated? */ + bge iSeries_secondary_yield /* no, yield forever */ + /* Load our paca now that it's been allocated */ LOAD_REG_ADDR(r13, paca) ld r13,0(r13) @@ -93,10 +96,24 @@ system_reset_iSeries: ori r23,r23,MSR_RI mtmsrd r23 /* RI on */ - HMT_LOW -#ifdef CONFIG_SMP +iSeries_secondary_smp_loop: lbz r23,PACAPROCSTART(r13) /* Test if this processor * should start */ + cmpwi 0,r23,0 + bne 3f /* go on when we are told */ + + HMT_LOW + /* Let the Hypervisor know we are alive */ + /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ + lis r3,0x8002 + rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ + li r0,-1 /* r0=-1 indicates a Hypervisor call */ + sc /* Invoke the hypervisor via a system call */ + mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ + b iSeries_secondary_smp_loop /* wait for signal to start */ + +3: + HMT_MEDIUM sync LOAD_REG_ADDR(r3,current_set) sldi r28,r24,3 /* get current_set[cpu#] */ @@ -104,27 +121,22 @@ system_reset_iSeries: addi r1,r3,THREAD_SIZE subi r1,r1,STACK_FRAME_OVERHEAD - cmpwi 0,r23,0 - beq iSeries_secondary_smp_loop /* Loop until told to go */ b __secondary_start /* Loop until told to go */ -iSeries_secondary_smp_loop: - /* Let the Hypervisor know we are alive */ - /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ - lis r3,0x8002 - rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ -#else /* CONFIG_SMP */ +#endif /* CONFIG_SMP */ + +iSeries_secondary_yield: /* Yield the processor. This is required for non-SMP kernels which are running on multi-threaded machines. */ + HMT_LOW lis r3,0x8000 rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ li r4,0 /* "yield timed" */ li r5,-1 /* "yield forever" */ -#endif /* CONFIG_SMP */ li r0,-1 /* r0=-1 indicates a Hypervisor call */ sc /* Invoke the hypervisor via a system call */ mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ - b 2b /* If SMP not configured, secondaries + b iSeries_secondary_yield /* If SMP not configured, secondaries * loop forever */ /*** ISeries-LPAR interrupt handlers ***/ @@ -157,7 +169,7 @@ BEGIN_FTR_SECTION FTR_SECTION_ELSE EXCEPTION_PROLOG_1(PACA_EXGEN) EXCEPTION_PROLOG_ISERIES_1 -ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB) +ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB) b data_access_common .do_stab_bolted_iSeries: diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 52a6889832c7..b2103453eb01 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -42,7 +42,6 @@ #include "irq.h" #include "pci.h" #include "call_pci.h" -#include "smp.h" #ifdef CONFIG_PCI @@ -171,7 +170,7 @@ static void iseries_enable_IRQ(struct irq_data *d) { u32 bus, dev_id, function, mask; const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); /* The IRQ has already been locked by the caller */ bus = REAL_IRQ_TO_BUS(rirq); @@ -188,7 +187,7 @@ static unsigned int iseries_startup_IRQ(struct irq_data *d) { u32 bus, dev_id, function, mask; const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); bus = REAL_IRQ_TO_BUS(rirq); function = REAL_IRQ_TO_FUNC(rirq); @@ -234,7 +233,7 @@ static void iseries_shutdown_IRQ(struct irq_data *d) { u32 bus, dev_id, function, mask; const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); /* irq should be locked by the caller */ bus = REAL_IRQ_TO_BUS(rirq); @@ -257,7 +256,7 @@ static void iseries_disable_IRQ(struct irq_data *d) { u32 bus, dev_id, function, mask; const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); /* The IRQ has already been locked by the caller */ bus = REAL_IRQ_TO_BUS(rirq); @@ -271,7 +270,7 @@ static void iseries_disable_IRQ(struct irq_data *d) static void iseries_end_IRQ(struct irq_data *d) { - unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); @@ -316,7 +315,7 @@ unsigned int iSeries_get_irq(void) #ifdef CONFIG_SMP if (get_lppaca()->int_dword.fields.ipi_cnt) { get_lppaca()->int_dword.fields.ipi_cnt = 0; - iSeries_smp_message_recv(); + smp_ipi_demux(); } #endif /* CONFIG_SMP */ if (hvlpevent_is_pending()) diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 2946ae10fbfd..c25a0815c26b 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -249,7 +249,7 @@ static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array, unsigned long i; unsigned long mem_blocks = 0; - if (cpu_has_feature(CPU_FTR_SLB)) + if (mmu_has_feature(MMU_FTR_SLB)) mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array, max_entries); else @@ -634,7 +634,7 @@ static int __init iseries_probe(void) hpte_init_iSeries(); /* iSeries does not support 16M pages */ - cur_cpu_spec->cpu_features &= ~CPU_FTR_16M_PAGE; + cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE; return 1; } @@ -685,6 +685,11 @@ void * __init iSeries_early_setup(void) powerpc_firmware_features |= FW_FEATURE_ISERIES; powerpc_firmware_features |= FW_FEATURE_LPAR; +#ifdef CONFIG_SMP + /* On iSeries we know we can never have more than 64 cpus */ + nr_cpu_ids = max(nr_cpu_ids, 64); +#endif + iSeries_fixup_klimit(); /* diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c index 6c6029914dbc..e3265adde5d3 100644 --- a/arch/powerpc/platforms/iseries/smp.c +++ b/arch/powerpc/platforms/iseries/smp.c @@ -42,57 +42,23 @@ #include #include -#include "smp.h" - -static unsigned long iSeries_smp_message[NR_CPUS]; - -void iSeries_smp_message_recv(void) +static void smp_iSeries_cause_ipi(int cpu, unsigned long data) { - int cpu = smp_processor_id(); - int msg; - - if (num_online_cpus() < 2) - return; - - for (msg = 0; msg < 4; msg++) - if (test_and_clear_bit(msg, &iSeries_smp_message[cpu])) - smp_message_recv(msg); -} - -static inline void smp_iSeries_do_message(int cpu, int msg) -{ - set_bit(msg, &iSeries_smp_message[cpu]); HvCall_sendIPI(&(paca[cpu])); } -static void smp_iSeries_message_pass(int target, int msg) -{ - int i; - - if (target < NR_CPUS) - smp_iSeries_do_message(target, msg); - else { - for_each_online_cpu(i) { - if ((target == MSG_ALL_BUT_SELF) && - (i == smp_processor_id())) - continue; - smp_iSeries_do_message(i, msg); - } - } -} - static int smp_iSeries_probe(void) { return cpumask_weight(cpu_possible_mask); } -static void smp_iSeries_kick_cpu(int nr) +static int smp_iSeries_kick_cpu(int nr) { BUG_ON((nr < 0) || (nr >= NR_CPUS)); /* Verify that our partition has a processor nr */ if (lppaca_of(nr).dyn_proc_status >= 2) - return; + return -ENOENT; /* The processor is currently spinning, waiting * for the cpu_start field to become non-zero @@ -100,6 +66,8 @@ static void smp_iSeries_kick_cpu(int nr) * continue on to secondary_start in iSeries_head.S */ paca[nr].cpu_start = 1; + + return 0; } static void __devinit smp_iSeries_setup_cpu(int nr) @@ -107,7 +75,8 @@ static void __devinit smp_iSeries_setup_cpu(int nr) } static struct smp_ops_t iSeries_smp_ops = { - .message_pass = smp_iSeries_message_pass, + .message_pass = smp_muxed_ipi_message_pass, + .cause_ipi = smp_iSeries_cause_ipi, .probe = smp_iSeries_probe, .kick_cpu = smp_iSeries_kick_cpu, .setup_cpu = smp_iSeries_setup_cpu, diff --git a/arch/powerpc/platforms/iseries/smp.h b/arch/powerpc/platforms/iseries/smp.h deleted file mode 100644 index d501f7de01e7..000000000000 --- a/arch/powerpc/platforms/iseries/smp.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _PLATFORMS_ISERIES_SMP_H -#define _PLATFORMS_ISERIES_SMP_H - -extern void iSeries_smp_message_recv(void); - -#endif /* _PLATFORMS_ISERIES_SMP_H */ diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig index 1e1a0873e1dd..1afd10f67858 100644 --- a/arch/powerpc/platforms/powermac/Kconfig +++ b/arch/powerpc/platforms/powermac/Kconfig @@ -18,4 +18,13 @@ config PPC_PMAC64 select PPC_970_NAP default y - +config PPC_PMAC32_PSURGE + bool "Support for powersurge upgrade cards" if EXPERT + depends on SMP && PPC32 && PPC_PMAC + select PPC_SMP_MUXED_IPI + default y + help + The powersurge cpu boards can be used in the generation + of powermacs that have a socket for an upgradeable cpu card, + including the 7500, 8500, 9500, 9600. Support exists for + both dual and quad socket upgrade cards. diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 023f24086a0a..9089b0421191 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -84,7 +84,7 @@ static void __pmac_retrigger(unsigned int irq_nr) static void pmac_mask_and_ack_irq(struct irq_data *d) { - unsigned int src = irq_map[d->irq].hwirq; + unsigned int src = irqd_to_hwirq(d); unsigned long bit = 1UL << (src & 0x1f); int i = src >> 5; unsigned long flags; @@ -106,7 +106,7 @@ static void pmac_mask_and_ack_irq(struct irq_data *d) static void pmac_ack_irq(struct irq_data *d) { - unsigned int src = irq_map[d->irq].hwirq; + unsigned int src = irqd_to_hwirq(d); unsigned long bit = 1UL << (src & 0x1f); int i = src >> 5; unsigned long flags; @@ -152,7 +152,7 @@ static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) static unsigned int pmac_startup_irq(struct irq_data *d) { unsigned long flags; - unsigned int src = irq_map[d->irq].hwirq; + unsigned int src = irqd_to_hwirq(d); unsigned long bit = 1UL << (src & 0x1f); int i = src >> 5; @@ -169,7 +169,7 @@ static unsigned int pmac_startup_irq(struct irq_data *d) static void pmac_mask_irq(struct irq_data *d) { unsigned long flags; - unsigned int src = irq_map[d->irq].hwirq; + unsigned int src = irqd_to_hwirq(d); raw_spin_lock_irqsave(&pmac_pic_lock, flags); __clear_bit(src, ppc_cached_irq_mask); @@ -180,7 +180,7 @@ static void pmac_mask_irq(struct irq_data *d) static void pmac_unmask_irq(struct irq_data *d) { unsigned long flags; - unsigned int src = irq_map[d->irq].hwirq; + unsigned int src = irqd_to_hwirq(d); raw_spin_lock_irqsave(&pmac_pic_lock, flags); __set_bit(src, ppc_cached_irq_mask); @@ -193,7 +193,7 @@ static int pmac_retrigger(struct irq_data *d) unsigned long flags; raw_spin_lock_irqsave(&pmac_pic_lock, flags); - __pmac_retrigger(irq_map[d->irq].hwirq); + __pmac_retrigger(irqd_to_hwirq(d)); raw_spin_unlock_irqrestore(&pmac_pic_lock, flags); return 1; } @@ -239,15 +239,12 @@ static unsigned int pmac_pic_get_irq(void) unsigned long bits = 0; unsigned long flags; -#ifdef CONFIG_SMP - void psurge_smp_message_recv(void); - - /* IPI's are a hack on the powersurge -- Cort */ - if ( smp_processor_id() != 0 ) { - psurge_smp_message_recv(); - return NO_IRQ_IGNORE; /* ignore, already handled */ +#ifdef CONFIG_PPC_PMAC32_PSURGE + /* IPI's are a hack on the powersurge -- Cort */ + if (smp_processor_id() != 0) { + return psurge_secondary_virq; } -#endif /* CONFIG_SMP */ +#endif /* CONFIG_PPC_PMAC32_PSURGE */ raw_spin_lock_irqsave(&pmac_pic_lock, flags); for (irq = max_real_irqs; (irq -= 32) >= 0; ) { int i = irq >> 5; @@ -677,7 +674,7 @@ static int pmacpic_find_viaint(void) return viaint; } -static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state) +static int pmacpic_suspend(void) { int viaint = pmacpic_find_viaint(); @@ -698,7 +695,7 @@ static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state) return 0; } -static int pmacpic_resume(struct sys_device *sysdev) +static void pmacpic_resume(void) { int i; @@ -709,39 +706,19 @@ static int pmacpic_resume(struct sys_device *sysdev) for (i = 0; i < max_real_irqs; ++i) if (test_bit(i, sleep_save_mask)) pmac_unmask_irq(irq_get_irq_data(i)); - - return 0; } -#endif /* CONFIG_PM && CONFIG_PPC32 */ - -static struct sysdev_class pmacpic_sysclass = { - .name = "pmac_pic", +static struct syscore_ops pmacpic_syscore_ops = { + .suspend = pmacpic_suspend, + .resume = pmacpic_resume, }; -static struct sys_device device_pmacpic = { - .id = 0, - .cls = &pmacpic_sysclass, -}; - -static struct sysdev_driver driver_pmacpic = { -#if defined(CONFIG_PM) && defined(CONFIG_PPC32) - .suspend = &pmacpic_suspend, - .resume = &pmacpic_resume, -#endif /* CONFIG_PM && CONFIG_PPC32 */ -}; - -static int __init init_pmacpic_sysfs(void) +static int __init init_pmacpic_syscore(void) { -#ifdef CONFIG_PPC32 - if (max_irqs == 0) - return -ENODEV; -#endif - printk(KERN_DEBUG "Registering pmac pic with sysfs...\n"); - sysdev_class_register(&pmacpic_sysclass); - sysdev_register(&device_pmacpic); - sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic); + register_syscore_ops(&pmacpic_syscore_ops); return 0; } -machine_subsys_initcall(powermac, init_pmacpic_sysfs); +machine_subsys_initcall(powermac, init_pmacpic_syscore); + +#endif /* CONFIG_PM && CONFIG_PPC32 */ diff --git a/arch/powerpc/platforms/powermac/pic.h b/arch/powerpc/platforms/powermac/pic.h deleted file mode 100644 index d622a8345aaa..000000000000 --- a/arch/powerpc/platforms/powermac/pic.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __PPC_PLATFORMS_PMAC_PIC_H -#define __PPC_PLATFORMS_PMAC_PIC_H - -#include - -extern struct irq_chip pmac_pic; - -extern void pmac_pic_init(void); -extern int pmac_get_irq(void); - -#endif /* __PPC_PLATFORMS_PMAC_PIC_H */ diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h index 20468f49aec0..8327cce2bdb0 100644 --- a/arch/powerpc/platforms/powermac/pmac.h +++ b/arch/powerpc/platforms/powermac/pmac.h @@ -33,6 +33,7 @@ extern void pmac_setup_pci_dma(void); extern void pmac_check_ht_link(void); extern void pmac_setup_smp(void); +extern int psurge_secondary_virq; extern void low_cpu_die(void) __attribute__((noreturn)); extern int pmac_nvram_init(void); diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index a830c5e80657..db092d7c4c5b 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -70,7 +70,7 @@ static void (*pmac_tb_freeze)(int freeze); static u64 timebase; static int tb_req; -#ifdef CONFIG_PPC32 +#ifdef CONFIG_PPC_PMAC32_PSURGE /* * Powersurge (old powermac SMP) support. @@ -124,6 +124,10 @@ static volatile u32 __iomem *psurge_start; /* what sort of powersurge board we have */ static int psurge_type = PSURGE_NONE; +/* irq for secondary cpus to report */ +static struct irq_host *psurge_host; +int psurge_secondary_virq; + /* * Set and clear IPIs for powersurge. */ @@ -156,51 +160,52 @@ static inline void psurge_clr_ipi(int cpu) /* * On powersurge (old SMP powermac architecture) we don't have * separate IPIs for separate messages like openpic does. Instead - * we have a bitmap for each processor, where a 1 bit means that - * the corresponding message is pending for that processor. - * Ideally each cpu's entry would be in a different cache line. + * use the generic demux helpers * -- paulus. */ -static unsigned long psurge_smp_message[NR_CPUS]; - -void psurge_smp_message_recv(void) +static irqreturn_t psurge_ipi_intr(int irq, void *d) { - int cpu = smp_processor_id(); - int msg; + psurge_clr_ipi(smp_processor_id()); + smp_ipi_demux(); - /* clear interrupt */ - psurge_clr_ipi(cpu); - - if (num_online_cpus() < 2) - return; - - /* make sure there is a message there */ - for (msg = 0; msg < 4; msg++) - if (test_and_clear_bit(msg, &psurge_smp_message[cpu])) - smp_message_recv(msg); -} - -irqreturn_t psurge_primary_intr(int irq, void *d) -{ - psurge_smp_message_recv(); return IRQ_HANDLED; } -static void smp_psurge_message_pass(int target, int msg) +static void smp_psurge_cause_ipi(int cpu, unsigned long data) { - int i; + psurge_set_ipi(cpu); +} - if (num_online_cpus() < 2) - return; +static int psurge_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_percpu_irq); - for_each_online_cpu(i) { - if (target == MSG_ALL - || (target == MSG_ALL_BUT_SELF && i != smp_processor_id()) - || target == i) { - set_bit(msg, &psurge_smp_message[i]); - psurge_set_ipi(i); - } - } + return 0; +} + +struct irq_host_ops psurge_host_ops = { + .map = psurge_host_map, +}; + +static int psurge_secondary_ipi_init(void) +{ + int rc = -ENOMEM; + + psurge_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, + &psurge_host_ops, 0); + + if (psurge_host) + psurge_secondary_virq = irq_create_direct_mapping(psurge_host); + + if (psurge_secondary_virq) + rc = request_irq(psurge_secondary_virq, psurge_ipi_intr, + IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL); + + if (rc) + pr_err("Failed to setup secondary cpu IPI\n"); + + return rc; } /* @@ -311,6 +316,9 @@ static int __init smp_psurge_probe(void) ncpus = 2; } + if (psurge_secondary_ipi_init()) + return 1; + psurge_start = ioremap(PSURGE_START, 4); psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4); @@ -329,7 +337,7 @@ static int __init smp_psurge_probe(void) return ncpus; } -static void __init smp_psurge_kick_cpu(int nr) +static int __init smp_psurge_kick_cpu(int nr) { unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8; unsigned long a, flags; @@ -394,11 +402,13 @@ static void __init smp_psurge_kick_cpu(int nr) psurge_set_ipi(1); if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354); + + return 0; } static struct irqaction psurge_irqaction = { - .handler = psurge_primary_intr, - .flags = IRQF_DISABLED, + .handler = psurge_ipi_intr, + .flags = IRQF_DISABLED|IRQF_PERCPU, .name = "primary IPI", }; @@ -437,14 +447,15 @@ void __init smp_psurge_give_timebase(void) /* PowerSurge-style Macs */ struct smp_ops_t psurge_smp_ops = { - .message_pass = smp_psurge_message_pass, + .message_pass = smp_muxed_ipi_message_pass, + .cause_ipi = smp_psurge_cause_ipi, .probe = smp_psurge_probe, .kick_cpu = smp_psurge_kick_cpu, .setup_cpu = smp_psurge_setup_cpu, .give_timebase = smp_psurge_give_timebase, .take_timebase = smp_psurge_take_timebase, }; -#endif /* CONFIG_PPC32 - actually powersurge support */ +#endif /* CONFIG_PPC_PMAC32_PSURGE */ /* * Core 99 and later support @@ -791,14 +802,14 @@ static int __init smp_core99_probe(void) return ncpus; } -static void __devinit smp_core99_kick_cpu(int nr) +static int __devinit smp_core99_kick_cpu(int nr) { unsigned int save_vector; unsigned long target, flags; unsigned int *vector = (unsigned int *)(PAGE_OFFSET+0x100); if (nr < 0 || nr > 3) - return; + return -ENOENT; if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); @@ -830,6 +841,8 @@ static void __devinit smp_core99_kick_cpu(int nr) local_irq_restore(flags); if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); + + return 0; } static void __devinit smp_core99_setup_cpu(int cpu_nr) @@ -842,6 +855,7 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr) mpic_setup_this_cpu(); } +#ifdef CONFIG_PPC64 #ifdef CONFIG_HOTPLUG_CPU static int smp_core99_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) @@ -879,7 +893,6 @@ static struct notifier_block __cpuinitdata smp_core99_cpu_nb = { static void __init smp_core99_bringup_done(void) { -#ifdef CONFIG_PPC64 extern void g5_phy_disable_cpu1(void); /* Close i2c bus if it was used for tb sync */ @@ -894,14 +907,14 @@ static void __init smp_core99_bringup_done(void) set_cpu_present(1, false); g5_phy_disable_cpu1(); } -#endif /* CONFIG_PPC64 */ - #ifdef CONFIG_HOTPLUG_CPU register_cpu_notifier(&smp_core99_cpu_nb); #endif + if (ppc_md.progress) ppc_md.progress("smp_core99_bringup_done", 0x349); } +#endif /* CONFIG_PPC64 */ #ifdef CONFIG_HOTPLUG_CPU @@ -975,7 +988,9 @@ static void pmac_cpu_die(void) struct smp_ops_t core99_smp_ops = { .message_pass = smp_mpic_message_pass, .probe = smp_core99_probe, +#ifdef CONFIG_PPC64 .bringup_done = smp_core99_bringup_done, +#endif .kick_cpu = smp_core99_kick_cpu, .setup_cpu = smp_core99_setup_cpu, .give_timebase = smp_core99_give_timebase, @@ -1000,7 +1015,7 @@ void __init pmac_setup_smp(void) of_node_put(np); smp_ops = &core99_smp_ops; } -#ifdef CONFIG_PPC32 +#ifdef CONFIG_PPC_PMAC32_PSURGE else { /* We have to set bits in cpu_possible_mask here since the * secondary CPU(s) aren't in the device tree. Various @@ -1013,7 +1028,7 @@ void __init pmac_setup_smp(void) set_cpu_possible(cpu, true); smp_ops = &psurge_smp_ops; } -#endif /* CONFIG_PPC32 */ +#endif /* CONFIG_PPC_PMAC32_PSURGE */ #ifdef CONFIG_HOTPLUG_CPU ppc_md.cpu_die = pmac_cpu_die; diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index f2f6413b81d3..600ed2c0ed59 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -197,7 +197,7 @@ static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet, result = irq_set_chip_data(*virq, pd); if (result) { - pr_debug("%s:%d: set_irq_chip_data failed\n", + pr_debug("%s:%d: irq_set_chip_data failed\n", __func__, __LINE__); goto fail_set; } @@ -659,11 +659,6 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd, static void dump_bmp(struct ps3_private* pd) {}; #endif /* defined(DEBUG) */ -static void ps3_host_unmap(struct irq_host *h, unsigned int virq) -{ - irq_set_chip_data(virq, NULL); -} - static int ps3_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hwirq) { @@ -683,7 +678,6 @@ static int ps3_host_match(struct irq_host *h, struct device_node *np) static struct irq_host_ops ps3_host_ops = { .map = ps3_host_map, - .unmap = ps3_host_unmap, .match = ps3_host_match, }; diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index 51ffde40af2b..4c44794faac0 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c @@ -39,7 +39,7 @@ #define MSG_COUNT 4 static DEFINE_PER_CPU(unsigned int [MSG_COUNT], ps3_ipi_virqs); -static void do_message_pass(int target, int msg) +static void ps3_smp_message_pass(int cpu, int msg) { int result; unsigned int virq; @@ -49,28 +49,12 @@ static void do_message_pass(int target, int msg) return; } - virq = per_cpu(ps3_ipi_virqs, target)[msg]; + virq = per_cpu(ps3_ipi_virqs, cpu)[msg]; result = ps3_send_event_locally(virq); if (result) DBG("%s:%d: ps3_send_event_locally(%d, %d) failed" - " (%d)\n", __func__, __LINE__, target, msg, result); -} - -static void ps3_smp_message_pass(int target, int msg) -{ - int cpu; - - if (target < NR_CPUS) - do_message_pass(target, msg); - else if (target == MSG_ALL_BUT_SELF) { - for_each_online_cpu(cpu) - if (cpu != smp_processor_id()) - do_message_pass(cpu, msg); - } else { - for_each_online_cpu(cpu) - do_message_pass(cpu, msg); - } + " (%d)\n", __func__, __LINE__, cpu, msg, result); } static int ps3_smp_probe(void) diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index 39a472e9e80f..375a9f92158d 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -197,7 +197,7 @@ static void spu_unmap(struct spu *spu) * The current HV requires the spu shadow regs to be mapped with the * PTE page protection bits set as read-only (PP=3). This implementation * uses the low level __ioremap() to bypass the page protection settings - * inforced by ioremap_flags() to get the needed PTE bits set for the + * inforced by ioremap_prot() to get the needed PTE bits set for the * shadow regs. */ @@ -214,7 +214,7 @@ static int __init setup_areas(struct spu *spu) goto fail_ioremap; } - spu->local_store = (__force void *)ioremap_flags(spu->local_store_phys, + spu->local_store = (__force void *)ioremap_prot(spu->local_store_phys, LS_SIZE, _PAGE_NO_CACHE); if (!spu->local_store) { diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 5b3da4b4ea79..71af4c5d6c05 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -3,7 +3,10 @@ config PPC_PSERIES bool "IBM pSeries & new (POWER5-based) iSeries" select MPIC select PCI_MSI - select XICS + select PPC_XICS + select PPC_ICP_NATIVE + select PPC_ICP_HV + select PPC_ICS_RTAS select PPC_I8259 select PPC_RTAS select PPC_RTAS_DAEMON @@ -47,6 +50,24 @@ config SCANLOG tristate "Scanlog dump interface" depends on RTAS_PROC && PPC_PSERIES +config IO_EVENT_IRQ + bool "IO Event Interrupt support" + depends on PPC_PSERIES + default y + help + Select this option, if you want to enable support for IO Event + interrupts. IO event interrupt is a mechanism provided by RTAS + to return information about hardware error and non-error events + which may need OS attention. RTAS returns events for multiple + event types and scopes. Device drivers can register their handlers + to receive events. + + This option will only enable the IO event platform code. You + will still need to enable or compile the actual drivers + that use this infrastruture to handle IO event interrupts. + + Say Y if you are unsure. + config LPARCFG bool "LPAR Configuration Data" depends on PPC_PSERIES || PPC_ISERIES diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index fc5237810ece..3556e402cbf5 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -5,7 +5,6 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \ setup.o iommu.o event_sources.o ras.o \ firmware.o power.o dlpar.o mobility.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o obj-$(CONFIG_KEXEC) += kexec.o @@ -22,6 +21,7 @@ obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_DTL) += dtl.o +obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o ifeq ($(CONFIG_PPC_PSERIES),y) obj-$(CONFIG_SUSPEND) += suspend.o diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index c371bc06434b..e9190073bb97 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -52,10 +52,10 @@ static u8 dtl_event_mask = 0x7; /* - * Size of per-cpu log buffers. Default is just under 16 pages worth. + * Size of per-cpu log buffers. Firmware requires that the buffer does + * not cross a 4k boundary. */ -static int dtl_buf_entries = (16 * 85); - +static int dtl_buf_entries = N_DISPATCH_LOG; #ifdef CONFIG_VIRT_CPU_ACCOUNTING struct dtl_ring { @@ -151,7 +151,7 @@ static int dtl_start(struct dtl *dtl) /* Register our dtl buffer with the hypervisor. The HV expects the * buffer size to be passed in the second word of the buffer */ - ((u32 *)dtl->buf)[1] = dtl->buf_entries * sizeof(struct dtl_entry); + ((u32 *)dtl->buf)[1] = DISPATCH_LOG_BYTES; hwcpu = get_hard_smp_processor_id(dtl->cpu); addr = __pa(dtl->buf); @@ -196,13 +196,15 @@ static int dtl_enable(struct dtl *dtl) long int rc; struct dtl_entry *buf = NULL; + if (!dtl_cache) + return -ENOMEM; + /* only allow one reader */ if (dtl->buf) return -EBUSY; n_entries = dtl_buf_entries; - buf = kmalloc_node(n_entries * sizeof(struct dtl_entry), - GFP_KERNEL, cpu_to_node(dtl->cpu)); + buf = kmem_cache_alloc_node(dtl_cache, GFP_KERNEL, cpu_to_node(dtl->cpu)); if (!buf) { printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n", __func__, dtl->cpu); @@ -223,7 +225,7 @@ static int dtl_enable(struct dtl *dtl) spin_unlock(&dtl->lock); if (rc) - kfree(buf); + kmem_cache_free(dtl_cache, buf); return rc; } @@ -231,7 +233,7 @@ static void dtl_disable(struct dtl *dtl) { spin_lock(&dtl->lock); dtl_stop(dtl); - kfree(dtl->buf); + kmem_cache_free(dtl_cache, dtl->buf); dtl->buf = NULL; dtl->buf_entries = 0; spin_unlock(&dtl->lock); @@ -365,7 +367,7 @@ static int dtl_init(void) event_mask_file = debugfs_create_x8("dtl_event_mask", 0600, dtl_dir, &dtl_event_mask); - buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0600, + buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0400, dtl_dir, &dtl_buf_entries); if (!event_mask_file || !buf_entries_file) { diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 89649173d3a3..46b55cf563e3 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -93,6 +93,7 @@ static int ibm_slot_error_detail; static int ibm_get_config_addr_info; static int ibm_get_config_addr_info2; static int ibm_configure_bridge; +static int ibm_configure_pe; int eeh_subsystem_enabled; EXPORT_SYMBOL(eeh_subsystem_enabled); @@ -261,6 +262,8 @@ void eeh_slot_error_detail(struct pci_dn *pdn, int severity) pci_regs_buf[0] = 0; rtas_pci_enable(pdn, EEH_THAW_MMIO); + rtas_configure_bridge(pdn); + eeh_restore_bars(pdn); loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen); @@ -448,6 +451,39 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag) raw_spin_unlock_irqrestore(&confirm_error_lock, flags); } +void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) +{ + struct device_node *dn; + + for_each_child_of_node(parent, dn) { + if (PCI_DN(dn)) { + + struct pci_dev *dev = PCI_DN(dn)->pcidev; + + if (dev && dev->driver) + *freset |= dev->needs_freset; + + __eeh_set_pe_freset(dn, freset); + } + } +} + +void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) +{ + struct pci_dev *dev; + dn = find_device_pe(dn); + + /* Back up one, since config addrs might be shared */ + if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) + dn = dn->parent; + + dev = PCI_DN(dn)->pcidev; + if (dev) + *freset |= dev->needs_freset; + + __eeh_set_pe_freset(dn, freset); +} + /** * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze * @dn device node @@ -692,15 +728,24 @@ rtas_pci_slot_reset(struct pci_dn *pdn, int state) if (pdn->eeh_pe_config_addr) config_addr = pdn->eeh_pe_config_addr; - rc = rtas_call(ibm_set_slot_reset,4,1, NULL, + rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, config_addr, BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid), state); - if (rc) - printk (KERN_WARNING "EEH: Unable to reset the failed slot," - " (%d) #RST=%d dn=%s\n", - rc, state, pdn->node->full_name); + + /* Fundamental-reset not supported on this PE, try hot-reset */ + if (rc == -8 && state == 3) { + rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, + config_addr, + BUID_HI(pdn->phb->buid), + BUID_LO(pdn->phb->buid), 1); + if (rc) + printk(KERN_WARNING + "EEH: Unable to reset the failed slot," + " #RST=%d dn=%s\n", + rc, pdn->node->full_name); + } } /** @@ -736,18 +781,21 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat /** * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second * @pdn: pci device node to be reset. - * - * Return 0 if success, else a non-zero value. */ static void __rtas_set_slot_reset(struct pci_dn *pdn) { - struct pci_dev *dev = pdn->pcidev; + unsigned int freset = 0; - /* Determine type of EEH reset required by device, - * default hot reset or fundamental reset - */ - if (dev && dev->needs_freset) + /* Determine type of EEH reset required for + * Partitionable Endpoint, a hot-reset (1) + * or a fundamental reset (3). + * A fundamental reset required by any device under + * Partitionable Endpoint trumps hot-reset. + */ + eeh_set_pe_freset(pdn->node, &freset); + + if (freset) rtas_pci_slot_reset(pdn, 3); else rtas_pci_slot_reset(pdn, 1); @@ -895,13 +943,20 @@ rtas_configure_bridge(struct pci_dn *pdn) { int config_addr; int rc; + int token; /* Use PE configuration address, if present */ config_addr = pdn->eeh_config_addr; if (pdn->eeh_pe_config_addr) config_addr = pdn->eeh_pe_config_addr; - rc = rtas_call(ibm_configure_bridge,3,1, NULL, + /* Use new configure-pe function, if supported */ + if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) + token = ibm_configure_pe; + else + token = ibm_configure_bridge; + + rc = rtas_call(token, 3, 1, NULL, config_addr, BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); @@ -1077,6 +1132,7 @@ void __init eeh_init(void) ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); + ibm_configure_pe = rtas_token("ibm,configure-pe"); if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) return; diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index b8d70f5d9aa9..1b6cb10589e0 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -328,7 +328,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) struct pci_bus *frozen_bus; int rc = 0; enum pci_ers_result result = PCI_ERS_RESULT_NONE; - const char *location, *pci_str, *drv_str; + const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str; frozen_dn = find_device_pe(event->dn); if (!frozen_dn) { @@ -364,13 +364,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) frozen_pdn = PCI_DN(frozen_dn); frozen_pdn->eeh_freeze_count++; - if (frozen_pdn->pcidev) { - pci_str = pci_name (frozen_pdn->pcidev); - drv_str = pcid_name (frozen_pdn->pcidev); - } else { - pci_str = eeh_pci_name(event->dev); - drv_str = pcid_name (event->dev); - } + pci_str = eeh_pci_name(event->dev); + drv_str = pcid_name(event->dev); if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) goto excess_failures; @@ -378,8 +373,17 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) printk(KERN_WARNING "EEH: This PCI device has failed %d times in the last hour:\n", frozen_pdn->eeh_freeze_count); + + if (frozen_pdn->pcidev) { + bus_pci_str = pci_name(frozen_pdn->pcidev); + bus_drv_str = pcid_name(frozen_pdn->pcidev); + printk(KERN_WARNING + "EEH: Bus location=%s driver=%s pci addr=%s\n", + location, bus_drv_str, bus_pci_str); + } + printk(KERN_WARNING - "EEH: location=%s driver=%s pci addr=%s\n", + "EEH: Device location=%s driver=%s pci addr=%s\n", location, drv_str, pci_str); /* Walk the various device drivers attached to this slot through diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index ef8c45489e20..46f13a3c5d09 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -28,7 +29,7 @@ #include #include #include -#include "xics.h" +#include #include "plpar_wrappers.h" #include "offline_states.h" @@ -280,7 +281,7 @@ static int pseries_add_processor(struct device_node *np) } for_each_cpu(cpu, tmp) { - BUG_ON(cpumask_test_cpu(cpu, cpu_present_mask)); + BUG_ON(cpu_present(cpu)); set_cpu_present(cpu, true); set_hard_smp_processor_id(cpu, *intserv++); } diff --git a/arch/powerpc/platforms/pseries/io_event_irq.c b/arch/powerpc/platforms/pseries/io_event_irq.c new file mode 100644 index 000000000000..c829e6067d54 --- /dev/null +++ b/arch/powerpc/platforms/pseries/io_event_irq.c @@ -0,0 +1,231 @@ +/* + * Copyright 2010 2011 Mark Nelson and Tseng-Hui (Frank) Lin, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pseries.h" + +/* + * IO event interrupt is a mechanism provided by RTAS to return + * information about hardware error and non-error events. Device + * drivers can register their event handlers to receive events. + * Device drivers are expected to use atomic_notifier_chain_register() + * and atomic_notifier_chain_unregister() to register and unregister + * their event handlers. Since multiple IO event types and scopes + * share an IO event interrupt, the event handlers are called one + * by one until the IO event is claimed by one of the handlers. + * The event handlers are expected to return NOTIFY_OK if the + * event is handled by the event handler or NOTIFY_DONE if the + * event does not belong to the handler. + * + * Usage: + * + * Notifier function: + * #include + * int event_handler(struct notifier_block *nb, unsigned long val, void *data) { + * p = (struct pseries_io_event_sect_data *) data; + * if (! is_my_event(p->scope, p->event_type)) return NOTIFY_DONE; + * : + * : + * return NOTIFY_OK; + * } + * struct notifier_block event_nb = { + * .notifier_call = event_handler, + * } + * + * Registration: + * atomic_notifier_chain_register(&pseries_ioei_notifier_list, &event_nb); + * + * Unregistration: + * atomic_notifier_chain_unregister(&pseries_ioei_notifier_list, &event_nb); + */ + +ATOMIC_NOTIFIER_HEAD(pseries_ioei_notifier_list); +EXPORT_SYMBOL_GPL(pseries_ioei_notifier_list); + +static int ioei_check_exception_token; + +/* pSeries event log format */ + +/* Two bytes ASCII section IDs */ +#define PSERIES_ELOG_SECT_ID_PRIV_HDR (('P' << 8) | 'H') +#define PSERIES_ELOG_SECT_ID_USER_HDR (('U' << 8) | 'H') +#define PSERIES_ELOG_SECT_ID_PRIMARY_SRC (('P' << 8) | 'S') +#define PSERIES_ELOG_SECT_ID_EXTENDED_UH (('E' << 8) | 'H') +#define PSERIES_ELOG_SECT_ID_FAILING_MTMS (('M' << 8) | 'T') +#define PSERIES_ELOG_SECT_ID_SECONDARY_SRC (('S' << 8) | 'S') +#define PSERIES_ELOG_SECT_ID_DUMP_LOCATOR (('D' << 8) | 'H') +#define PSERIES_ELOG_SECT_ID_FW_ERROR (('S' << 8) | 'W') +#define PSERIES_ELOG_SECT_ID_IMPACT_PART_ID (('L' << 8) | 'P') +#define PSERIES_ELOG_SECT_ID_LOGIC_RESOURCE_ID (('L' << 8) | 'R') +#define PSERIES_ELOG_SECT_ID_HMC_ID (('H' << 8) | 'M') +#define PSERIES_ELOG_SECT_ID_EPOW (('E' << 8) | 'P') +#define PSERIES_ELOG_SECT_ID_IO_EVENT (('I' << 8) | 'E') +#define PSERIES_ELOG_SECT_ID_MANUFACT_INFO (('M' << 8) | 'I') +#define PSERIES_ELOG_SECT_ID_CALL_HOME (('C' << 8) | 'H') +#define PSERIES_ELOG_SECT_ID_USER_DEF (('U' << 8) | 'D') + +/* Vendor specific Platform Event Log Format, Version 6, section header */ +struct pseries_elog_section { + uint16_t id; /* 0x00 2-byte ASCII section ID */ + uint16_t length; /* 0x02 Section length in bytes */ + uint8_t version; /* 0x04 Section version */ + uint8_t subtype; /* 0x05 Section subtype */ + uint16_t creator_component; /* 0x06 Creator component ID */ + uint8_t data[]; /* 0x08 Start of section data */ +}; + +static char ioei_rtas_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned; + +/** + * Find data portion of a specific section in RTAS extended event log. + * @elog: RTAS error/event log. + * @sect_id: secsion ID. + * + * Return: + * pointer to the section data of the specified section + * NULL if not found + */ +static struct pseries_elog_section *find_xelog_section(struct rtas_error_log *elog, + uint16_t sect_id) +{ + struct rtas_ext_event_log_v6 *xelog = + (struct rtas_ext_event_log_v6 *) elog->buffer; + struct pseries_elog_section *sect; + unsigned char *p, *log_end; + + /* Check that we understand the format */ + if (elog->extended_log_length < sizeof(struct rtas_ext_event_log_v6) || + xelog->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG || + xelog->company_id != RTAS_V6EXT_COMPANY_ID_IBM) + return NULL; + + log_end = elog->buffer + elog->extended_log_length; + p = xelog->vendor_log; + while (p < log_end) { + sect = (struct pseries_elog_section *)p; + if (sect->id == sect_id) + return sect; + p += sect->length; + } + return NULL; +} + +/** + * Find the data portion of an IO Event section from event log. + * @elog: RTAS error/event log. + * + * Return: + * pointer to a valid IO event section data. NULL if not found. + */ +static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog) +{ + struct pseries_elog_section *sect; + + /* We should only ever get called for io-event interrupts, but if + * we do get called for another type then something went wrong so + * make some noise about it. + * RTAS_TYPE_IO only exists in extended event log version 6 or later. + * No need to check event log version. + */ + if (unlikely(elog->type != RTAS_TYPE_IO)) { + printk_once(KERN_WARNING "io_event_irq: Unexpected event type %d", + elog->type); + return NULL; + } + + sect = find_xelog_section(elog, PSERIES_ELOG_SECT_ID_IO_EVENT); + if (unlikely(!sect)) { + printk_once(KERN_WARNING "io_event_irq: RTAS extended event " + "log does not contain an IO Event section. " + "Could be a bug in system firmware!\n"); + return NULL; + } + return (struct pseries_io_event *) §->data; +} + +/* + * PAPR: + * - check-exception returns the first found error or event and clear that + * error or event so it is reported once. + * - Each interrupt returns one event. If a plateform chooses to report + * multiple events through a single interrupt, it must ensure that the + * interrupt remains asserted until check-exception has been used to + * process all out-standing events for that interrupt. + * + * Implementation notes: + * - Events must be processed in the order they are returned. Hence, + * sequential in nature. + * - The owner of an event is determined by combinations of scope, + * event type, and sub-type. There is no easy way to pre-sort clients + * by scope or event type alone. For example, Torrent ISR route change + * event is reported with scope 0x00 (Not Applicatable) rather than + * 0x3B (Torrent-hub). It is better to let the clients to identify + * who owns the the event. + */ + +static irqreturn_t ioei_interrupt(int irq, void *dev_id) +{ + struct pseries_io_event *event; + int rtas_rc; + + for (;;) { + rtas_rc = rtas_call(ioei_check_exception_token, 6, 1, NULL, + RTAS_VECTOR_EXTERNAL_INTERRUPT, + virq_to_hw(irq), + RTAS_IO_EVENTS, 1 /* Time Critical */, + __pa(ioei_rtas_buf), + RTAS_DATA_BUF_SIZE); + if (rtas_rc != 0) + break; + + event = ioei_find_event((struct rtas_error_log *)ioei_rtas_buf); + if (!event) + continue; + + atomic_notifier_call_chain(&pseries_ioei_notifier_list, + 0, event); + } + return IRQ_HANDLED; +} + +static int __init ioei_init(void) +{ + struct device_node *np; + + ioei_check_exception_token = rtas_token("check-exception"); + if (ioei_check_exception_token == RTAS_UNKNOWN_SERVICE) { + pr_warning("IO Event IRQ not supported on this system !\n"); + return -ENODEV; + } + np = of_find_node_by_path("/event-sources/ibm,io-events"); + if (np) { + request_event_sources_irqs(np, ioei_interrupt, "IO_EVENT"); + of_node_put(np); + } else { + pr_err("io_event_irq: No ibm,io-events on system! " + "IO Event interrupt disabled.\n"); + return -ENODEV; + } + return 0; +} +machine_subsys_initcall(pseries, ioei_init); + diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 6d5412a18b26..01faab9456ca 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -659,15 +659,18 @@ static void remove_ddw(struct device_node *np) { struct dynamic_dma_window_prop *dwp; struct property *win64; - const u32 *ddr_avail; + const u32 *ddw_avail; u64 liobn; int len, ret; - ddr_avail = of_get_property(np, "ibm,ddw-applicable", &len); + ddw_avail = of_get_property(np, "ibm,ddw-applicable", &len); win64 = of_find_property(np, DIRECT64_PROPNAME, NULL); - if (!win64 || !ddr_avail || len < 3 * sizeof(u32)) + if (!win64) return; + if (!ddw_avail || len < 3 * sizeof(u32) || win64->length < sizeof(*dwp)) + goto delprop; + dwp = win64->value; liobn = (u64)be32_to_cpu(dwp->liobn); @@ -681,28 +684,29 @@ static void remove_ddw(struct device_node *np) pr_debug("%s successfully cleared tces in window.\n", np->full_name); - ret = rtas_call(ddr_avail[2], 1, 1, NULL, liobn); + ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn); if (ret) pr_warning("%s: failed to remove direct window: rtas returned " "%d to ibm,remove-pe-dma-window(%x) %llx\n", - np->full_name, ret, ddr_avail[2], liobn); + np->full_name, ret, ddw_avail[2], liobn); else pr_debug("%s: successfully removed direct window: rtas returned " "%d to ibm,remove-pe-dma-window(%x) %llx\n", - np->full_name, ret, ddr_avail[2], liobn); + np->full_name, ret, ddw_avail[2], liobn); + +delprop: + ret = prom_remove_property(np, win64); + if (ret) + pr_warning("%s: failed to remove direct window property: %d\n", + np->full_name, ret); } - -static int dupe_ddw_if_already_created(struct pci_dev *dev, struct device_node *pdn) +static u64 find_existing_ddw(struct device_node *pdn) { - struct device_node *dn; - struct pci_dn *pcidn; struct direct_window *window; const struct dynamic_dma_window_prop *direct64; u64 dma_addr = 0; - dn = pci_device_to_OF_node(dev); - pcidn = PCI_DN(dn); spin_lock(&direct_window_list_lock); /* check if we already created a window and dupe that config if so */ list_for_each_entry(window, &direct_window_list, list) { @@ -717,36 +721,40 @@ static int dupe_ddw_if_already_created(struct pci_dev *dev, struct device_node * return dma_addr; } -static u64 dupe_ddw_if_kexec(struct pci_dev *dev, struct device_node *pdn) +static int find_existing_ddw_windows(void) { - struct device_node *dn; - struct pci_dn *pcidn; int len; + struct device_node *pdn; struct direct_window *window; const struct dynamic_dma_window_prop *direct64; - u64 dma_addr = 0; - dn = pci_device_to_OF_node(dev); - pcidn = PCI_DN(dn); - direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len); - if (direct64) { + if (!firmware_has_feature(FW_FEATURE_LPAR)) + return 0; + + for_each_node_with_property(pdn, DIRECT64_PROPNAME) { + direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len); + if (!direct64) + continue; + window = kzalloc(sizeof(*window), GFP_KERNEL); - if (!window) { + if (!window || len < sizeof(struct dynamic_dma_window_prop)) { + kfree(window); remove_ddw(pdn); - } else { - window->device = pdn; - window->prop = direct64; - spin_lock(&direct_window_list_lock); - list_add(&window->list, &direct_window_list); - spin_unlock(&direct_window_list_lock); - dma_addr = direct64->dma_base; + continue; } + + window->device = pdn; + window->prop = direct64; + spin_lock(&direct_window_list_lock); + list_add(&window->list, &direct_window_list); + spin_unlock(&direct_window_list_lock); } - return dma_addr; + return 0; } +machine_arch_initcall(pseries, find_existing_ddw_windows); -static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail, +static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail, struct ddw_query_response *query) { struct device_node *dn; @@ -767,15 +775,15 @@ static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail, if (pcidn->eeh_pe_config_addr) cfg_addr = pcidn->eeh_pe_config_addr; buid = pcidn->phb->buid; - ret = rtas_call(ddr_avail[0], 3, 5, (u32 *)query, + ret = rtas_call(ddw_avail[0], 3, 5, (u32 *)query, cfg_addr, BUID_HI(buid), BUID_LO(buid)); dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x" - " returned %d\n", ddr_avail[0], cfg_addr, BUID_HI(buid), + " returned %d\n", ddw_avail[0], cfg_addr, BUID_HI(buid), BUID_LO(buid), ret); return ret; } -static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail, +static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail, struct ddw_create_response *create, int page_shift, int window_shift) { @@ -800,12 +808,12 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail, do { /* extra outputs are LIOBN and dma-addr (hi, lo) */ - ret = rtas_call(ddr_avail[1], 5, 4, (u32 *)create, cfg_addr, + ret = rtas_call(ddw_avail[1], 5, 4, (u32 *)create, cfg_addr, BUID_HI(buid), BUID_LO(buid), page_shift, window_shift); } while (rtas_busy_delay(ret)); dev_info(&dev->dev, "ibm,create-pe-dma-window(%x) %x %x %x %x %x returned %d " - "(liobn = 0x%x starting addr = %x %x)\n", ddr_avail[1], + "(liobn = 0x%x starting addr = %x %x)\n", ddw_avail[1], cfg_addr, BUID_HI(buid), BUID_LO(buid), page_shift, window_shift, ret, create->liobn, create->addr_hi, create->addr_lo); @@ -831,18 +839,14 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) int page_shift; u64 dma_addr, max_addr; struct device_node *dn; - const u32 *uninitialized_var(ddr_avail); + const u32 *uninitialized_var(ddw_avail); struct direct_window *window; - struct property *uninitialized_var(win64); + struct property *win64; struct dynamic_dma_window_prop *ddwprop; mutex_lock(&direct_window_init_mutex); - dma_addr = dupe_ddw_if_already_created(dev, pdn); - if (dma_addr != 0) - goto out_unlock; - - dma_addr = dupe_ddw_if_kexec(dev, pdn); + dma_addr = find_existing_ddw(pdn); if (dma_addr != 0) goto out_unlock; @@ -854,8 +858,8 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) * for the given node in that order. * the property is actually in the parent, not the PE */ - ddr_avail = of_get_property(pdn, "ibm,ddw-applicable", &len); - if (!ddr_avail || len < 3 * sizeof(u32)) + ddw_avail = of_get_property(pdn, "ibm,ddw-applicable", &len); + if (!ddw_avail || len < 3 * sizeof(u32)) goto out_unlock; /* @@ -865,7 +869,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) * of page sizes: supported and supported for migrate-dma. */ dn = pci_device_to_OF_node(dev); - ret = query_ddw(dev, ddr_avail, &query); + ret = query_ddw(dev, ddw_avail, &query); if (ret != 0) goto out_unlock; @@ -907,13 +911,14 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) } win64->name = kstrdup(DIRECT64_PROPNAME, GFP_KERNEL); win64->value = ddwprop = kmalloc(sizeof(*ddwprop), GFP_KERNEL); + win64->length = sizeof(*ddwprop); if (!win64->name || !win64->value) { dev_info(&dev->dev, "couldn't allocate property name and value\n"); goto out_free_prop; } - ret = create_ddw(dev, ddr_avail, &create, page_shift, len); + ret = create_ddw(dev, ddw_avail, &create, page_shift, len); if (ret != 0) goto out_free_prop; @@ -1021,13 +1026,16 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) const void *dma_window = NULL; u64 dma_offset; - if (!dev->dma_mask || !dma_supported(dev, dma_mask)) + if (!dev->dma_mask) return -EIO; + if (!dev_is_pci(dev)) + goto check_mask; + + pdev = to_pci_dev(dev); + /* only attempt to use a new window if 64-bit DMA is requested */ if (!disable_ddw && dma_mask == DMA_BIT_MASK(64)) { - pdev = to_pci_dev(dev); - dn = pci_device_to_OF_node(pdev); dev_dbg(dev, "node is %s\n", dn->full_name); @@ -1054,12 +1062,17 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) } } - /* fall-through to iommu ops */ - if (!ddw_enabled) { - dev_info(dev, "Using 32-bit DMA via iommu\n"); + /* fall back on iommu ops, restore table pointer with ops */ + if (!ddw_enabled && get_dma_ops(dev) != &dma_iommu_ops) { + dev_info(dev, "Restoring 32-bit DMA via iommu\n"); set_dma_ops(dev, &dma_iommu_ops); + pci_dma_dev_setup_pSeriesLP(pdev); } +check_mask: + if (!dma_supported(dev, dma_mask)) + return -EIO; + *dev->dma_mask = dma_mask; return 0; } diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c index 77d38a5e2ff9..54cf3a4aa16b 100644 --- a/arch/powerpc/platforms/pseries/kexec.c +++ b/arch/powerpc/platforms/pseries/kexec.c @@ -7,15 +7,18 @@ * 2 of the License, or (at your option) any later version. */ +#include +#include + #include #include #include #include #include +#include #include #include "pseries.h" -#include "xics.h" #include "plpar_wrappers.h" static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index ca5d5898d320..39e6e0a7b2fa 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -329,6 +329,8 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, /* Make pHyp happy */ if ((rflags & _PAGE_NO_CACHE) & !(rflags & _PAGE_WRITETHRU)) hpte_r &= ~_PAGE_COHERENT; + if (firmware_has_feature(FW_FEATURE_XCMO) && !(hpte_r & HPTE_R_N)) + flags |= H_COALESCE_CAND; lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot); if (unlikely(lpar_rc == H_PTEG_FULL)) { @@ -573,7 +575,7 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) unsigned long i, pix, rc; unsigned long flags = 0; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); - int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); + int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); unsigned long param[9]; unsigned long va; unsigned long hash, index, shift, hidx, slot; @@ -771,3 +773,47 @@ void __trace_hcall_exit(long opcode, unsigned long retval, local_irq_restore(flags); } #endif + +/** + * h_get_mpp + * H_GET_MPP hcall returns info in 7 parms + */ +int h_get_mpp(struct hvcall_mpp_data *mpp_data) +{ + int rc; + unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; + + rc = plpar_hcall9(H_GET_MPP, retbuf); + + mpp_data->entitled_mem = retbuf[0]; + mpp_data->mapped_mem = retbuf[1]; + + mpp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff; + mpp_data->pool_num = retbuf[2] & 0xffff; + + mpp_data->mem_weight = (retbuf[3] >> 7 * 8) & 0xff; + mpp_data->unallocated_mem_weight = (retbuf[3] >> 6 * 8) & 0xff; + mpp_data->unallocated_entitlement = retbuf[3] & 0xffffffffffff; + + mpp_data->pool_size = retbuf[4]; + mpp_data->loan_request = retbuf[5]; + mpp_data->backing_mem = retbuf[6]; + + return rc; +} +EXPORT_SYMBOL(h_get_mpp); + +int h_get_mpp_x(struct hvcall_mpp_x_data *mpp_x_data) +{ + int rc; + unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = { 0 }; + + rc = plpar_hcall9(H_GET_MPP_X, retbuf); + + mpp_x_data->coalesced_bytes = retbuf[0]; + mpp_x_data->pool_coalesced_bytes = retbuf[1]; + mpp_x_data->pool_purr_cycles = retbuf[2]; + mpp_x_data->pool_spurr_cycles = retbuf[3]; + + return rc; +} diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h index d9801117124b..4bf21207d7d3 100644 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h @@ -270,31 +270,4 @@ static inline long plpar_put_term_char(unsigned long termno, unsigned long len, lbuf[1]); } -static inline long plpar_eoi(unsigned long xirr) -{ - return plpar_hcall_norets(H_EOI, xirr); -} - -static inline long plpar_cppr(unsigned long cppr) -{ - return plpar_hcall_norets(H_CPPR, cppr); -} - -static inline long plpar_ipi(unsigned long servernum, unsigned long mfrr) -{ - return plpar_hcall_norets(H_IPI, servernum, mfrr); -} - -static inline long plpar_xirr(unsigned long *xirr_ret, unsigned char cppr) -{ - long rc; - unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; - - rc = plpar_hcall(H_XIRR, retbuf, cppr); - - *xirr_ret = retbuf[0]; - - return rc; -} - #endif /* _PSERIES_PLPAR_WRAPPERS_H */ diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index c55d7ad9c648..086d2ae4e06a 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -122,7 +122,7 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id) status = rtas_call(ras_check_exception_token, 6, 1, NULL, RTAS_VECTOR_EXTERNAL_INTERRUPT, - irq_map[irq].hwirq, + virq_to_hw(irq), RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, critical, __pa(&ras_log_buf), rtas_get_error_log_max()); @@ -157,7 +157,7 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id) status = rtas_call(ras_check_exception_token, 6, 1, NULL, RTAS_VECTOR_EXTERNAL_INTERRUPT, - irq_map[irq].hwirq, + virq_to_hw(irq), RTAS_INTERNAL_ERROR, 1 /*Time Critical */, __pa(&ras_log_buf), rtas_get_error_log_max()); @@ -227,7 +227,7 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) struct rtas_error_log *h, *errhdr = NULL; if (!VALID_FWNMI_BUFFER(regs->gpr[3])) { - printk(KERN_ERR "FWNMI: corrupt r3\n"); + printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]); return NULL; } diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 000724149089..593acceeff96 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -53,9 +53,9 @@ #include #include #include -#include "xics.h" #include #include +#include #include #include #include @@ -205,6 +205,9 @@ static void __init pseries_mpic_init_IRQ(void) mpic_assign_isu(mpic, n, isuaddr); } + /* Setup top-level get_irq */ + ppc_md.get_irq = mpic_get_irq; + /* All ISUs are setup, complete initialization */ mpic_init(mpic); @@ -214,7 +217,7 @@ static void __init pseries_mpic_init_IRQ(void) static void __init pseries_xics_init_IRQ(void) { - xics_init_IRQ(); + xics_init(); pseries_setup_i8259_cascade(); } @@ -238,7 +241,6 @@ static void __init pseries_discover_pic(void) if (strstr(typep, "open-pic")) { pSeries_mpic_node = of_node_get(np); ppc_md.init_IRQ = pseries_mpic_init_IRQ; - ppc_md.get_irq = mpic_get_irq; setup_kexec_cpu_down_mpic(); smp_init_pseries_mpic(); return; @@ -276,6 +278,8 @@ static struct notifier_block pci_dn_reconfig_nb = { .notifier_call = pci_dn_reconfig_notifier, }; +struct kmem_cache *dtl_cache; + #ifdef CONFIG_VIRT_CPU_ACCOUNTING /* * Allocate space for the dispatch trace log for all possible cpus @@ -291,10 +295,12 @@ static int alloc_dispatch_logs(void) if (!firmware_has_feature(FW_FEATURE_SPLPAR)) return 0; + if (!dtl_cache) + return 0; + for_each_possible_cpu(cpu) { pp = &paca[cpu]; - dtl = kmalloc_node(DISPATCH_LOG_BYTES, GFP_KERNEL, - cpu_to_node(cpu)); + dtl = kmem_cache_alloc(dtl_cache, GFP_KERNEL); if (!dtl) { pr_warn("Failed to allocate dispatch trace log for cpu %d\n", cpu); @@ -324,10 +330,27 @@ static int alloc_dispatch_logs(void) return 0; } - -early_initcall(alloc_dispatch_logs); +#else /* !CONFIG_VIRT_CPU_ACCOUNTING */ +static inline int alloc_dispatch_logs(void) +{ + return 0; +} #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ +static int alloc_dispatch_log_kmem_cache(void) +{ + dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES, + DISPATCH_LOG_BYTES, 0, NULL); + if (!dtl_cache) { + pr_warn("Failed to create dispatch trace log buffer cache\n"); + pr_warn("Stolen time statistics will be unreliable\n"); + return 0; + } + + return alloc_dispatch_logs(); +} +early_initcall(alloc_dispatch_log_kmem_cache); + static void __init pSeries_setup_arch(void) { /* Discover PIC type and setup ppc_md accordingly */ @@ -395,6 +418,16 @@ static int pseries_set_xdabr(unsigned long dabr) #define CMO_CHARACTERISTICS_TOKEN 44 #define CMO_MAXLENGTH 1026 +void pSeries_coalesce_init(void) +{ + struct hvcall_mpp_x_data mpp_x_data; + + if (firmware_has_feature(FW_FEATURE_CMO) && !h_get_mpp_x(&mpp_x_data)) + powerpc_firmware_features |= FW_FEATURE_XCMO; + else + powerpc_firmware_features &= ~FW_FEATURE_XCMO; +} + /** * fw_cmo_feature_init - FW_FEATURE_CMO is not stored in ibm,hypertas-functions, * handle that here. (Stolen from parse_system_parameter_string) @@ -464,6 +497,7 @@ void pSeries_cmo_feature_init(void) pr_debug("CMO enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP, CMO_SecPSP); powerpc_firmware_features |= FW_FEATURE_CMO; + pSeries_coalesce_init(); } else pr_debug("CMO not enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP, CMO_SecPSP); diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index a509c5292a67..fbffd7e47ab8 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -44,10 +44,11 @@ #include #include #include +#include +#include #include "plpar_wrappers.h" #include "pseries.h" -#include "xics.h" #include "offline_states.h" @@ -136,7 +137,6 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) return 1; } -#ifdef CONFIG_XICS static void __devinit smp_xics_setup_cpu(int cpu) { if (cpu != boot_cpuid) @@ -151,14 +151,13 @@ static void __devinit smp_xics_setup_cpu(int cpu) set_default_offline_state(cpu); #endif } -#endif /* CONFIG_XICS */ -static void __devinit smp_pSeries_kick_cpu(int nr) +static int __devinit smp_pSeries_kick_cpu(int nr) { BUG_ON(nr < 0 || nr >= NR_CPUS); if (!smp_startup_cpu(nr)) - return; + return -ENOENT; /* * The processor is currently spinning, waiting for the @@ -180,6 +179,8 @@ static void __devinit smp_pSeries_kick_cpu(int nr) "Ret= %ld\n", nr, rc); } #endif + + return 0; } static int smp_pSeries_cpu_bootable(unsigned int nr) @@ -197,23 +198,22 @@ static int smp_pSeries_cpu_bootable(unsigned int nr) return 1; } -#ifdef CONFIG_MPIC + static struct smp_ops_t pSeries_mpic_smp_ops = { .message_pass = smp_mpic_message_pass, .probe = smp_mpic_probe, .kick_cpu = smp_pSeries_kick_cpu, .setup_cpu = smp_mpic_setup_cpu, }; -#endif -#ifdef CONFIG_XICS + static struct smp_ops_t pSeries_xics_smp_ops = { - .message_pass = smp_xics_message_pass, - .probe = smp_xics_probe, + .message_pass = smp_muxed_ipi_message_pass, + .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */ + .probe = xics_smp_probe, .kick_cpu = smp_pSeries_kick_cpu, .setup_cpu = smp_xics_setup_cpu, .cpu_bootable = smp_pSeries_cpu_bootable, }; -#endif /* This is called very early */ static void __init smp_init_pseries(void) @@ -245,14 +245,12 @@ static void __init smp_init_pseries(void) pr_debug(" <- smp_init_pSeries()\n"); } -#ifdef CONFIG_MPIC void __init smp_init_pseries_mpic(void) { smp_ops = &pSeries_mpic_smp_ops; smp_init_pseries(); } -#endif void __init smp_init_pseries_xics(void) { diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c deleted file mode 100644 index d6901334d66e..000000000000 --- a/arch/powerpc/platforms/pseries/xics.c +++ /dev/null @@ -1,949 +0,0 @@ -/* - * arch/powerpc/platforms/pseries/xics.c - * - * Copyright 2000 IBM Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "xics.h" -#include "plpar_wrappers.h" - -static struct irq_host *xics_host; - -#define XICS_IPI 2 -#define XICS_IRQ_SPURIOUS 0 - -/* Want a priority other than 0. Various HW issues require this. */ -#define DEFAULT_PRIORITY 5 - -/* - * Mark IPIs as higher priority so we can take them inside interrupts that - * arent marked IRQF_DISABLED - */ -#define IPI_PRIORITY 4 - -/* The least favored priority */ -#define LOWEST_PRIORITY 0xFF - -/* The number of priorities defined above */ -#define MAX_NUM_PRIORITIES 3 - -static unsigned int default_server = 0xFF; -static unsigned int default_distrib_server = 0; -static unsigned int interrupt_server_size = 8; - -/* RTAS service tokens */ -static int ibm_get_xive; -static int ibm_set_xive; -static int ibm_int_on; -static int ibm_int_off; - -struct xics_cppr { - unsigned char stack[MAX_NUM_PRIORITIES]; - int index; -}; - -static DEFINE_PER_CPU(struct xics_cppr, xics_cppr); - -/* Direct hardware low level accessors */ - -/* The part of the interrupt presentation layer that we care about */ -struct xics_ipl { - union { - u32 word; - u8 bytes[4]; - } xirr_poll; - union { - u32 word; - u8 bytes[4]; - } xirr; - u32 dummy; - union { - u32 word; - u8 bytes[4]; - } qirr; -}; - -static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; - -static inline unsigned int direct_xirr_info_get(void) -{ - int cpu = smp_processor_id(); - - return in_be32(&xics_per_cpu[cpu]->xirr.word); -} - -static inline void direct_xirr_info_set(unsigned int value) -{ - int cpu = smp_processor_id(); - - out_be32(&xics_per_cpu[cpu]->xirr.word, value); -} - -static inline void direct_cppr_info(u8 value) -{ - int cpu = smp_processor_id(); - - out_8(&xics_per_cpu[cpu]->xirr.bytes[0], value); -} - -static inline void direct_qirr_info(int n_cpu, u8 value) -{ - out_8(&xics_per_cpu[n_cpu]->qirr.bytes[0], value); -} - - -/* LPAR low level accessors */ - -static inline unsigned int lpar_xirr_info_get(unsigned char cppr) -{ - unsigned long lpar_rc; - unsigned long return_value; - - lpar_rc = plpar_xirr(&return_value, cppr); - if (lpar_rc != H_SUCCESS) - panic(" bad return code xirr - rc = %lx\n", lpar_rc); - return (unsigned int)return_value; -} - -static inline void lpar_xirr_info_set(unsigned int value) -{ - unsigned long lpar_rc; - - lpar_rc = plpar_eoi(value); - if (lpar_rc != H_SUCCESS) - panic("bad return code EOI - rc = %ld, value=%x\n", lpar_rc, - value); -} - -static inline void lpar_cppr_info(u8 value) -{ - unsigned long lpar_rc; - - lpar_rc = plpar_cppr(value); - if (lpar_rc != H_SUCCESS) - panic("bad return code cppr - rc = %lx\n", lpar_rc); -} - -static inline void lpar_qirr_info(int n_cpu , u8 value) -{ - unsigned long lpar_rc; - - lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu), value); - if (lpar_rc != H_SUCCESS) - panic("bad return code qirr - rc = %lx\n", lpar_rc); -} - - -/* Interface to generic irq subsystem */ - -#ifdef CONFIG_SMP -/* - * For the moment we only implement delivery to all cpus or one cpu. - * - * If the requested affinity is cpu_all_mask, we set global affinity. - * If not we set it to the first cpu in the mask, even if multiple cpus - * are set. This is so things like irqbalance (which set core and package - * wide affinities) do the right thing. - */ -static int get_irq_server(unsigned int virq, const struct cpumask *cpumask, - unsigned int strict_check) -{ - - if (!distribute_irqs) - return default_server; - - if (!cpumask_subset(cpu_possible_mask, cpumask)) { - int server = cpumask_first_and(cpu_online_mask, cpumask); - - if (server < nr_cpu_ids) - return get_hard_smp_processor_id(server); - - if (strict_check) - return -1; - } - - /* - * Workaround issue with some versions of JS20 firmware that - * deliver interrupts to cpus which haven't been started. This - * happens when using the maxcpus= boot option. - */ - if (cpumask_equal(cpu_online_mask, cpu_present_mask)) - return default_distrib_server; - - return default_server; -} -#else -#define get_irq_server(virq, cpumask, strict_check) (default_server) -#endif - -static void xics_unmask_irq(struct irq_data *d) -{ - unsigned int hwirq; - int call_status; - int server; - - pr_devel("xics: unmask virq %d\n", d->irq); - - hwirq = (unsigned int)irq_map[d->irq].hwirq; - pr_devel(" -> map to hwirq 0x%x\n", hwirq); - if (hwirq == XICS_IPI || hwirq == XICS_IRQ_SPURIOUS) - return; - - server = get_irq_server(d->irq, d->affinity, 0); - - call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hwirq, server, - DEFAULT_PRIORITY); - if (call_status != 0) { - printk(KERN_ERR - "%s: ibm_set_xive irq %u server %x returned %d\n", - __func__, hwirq, server, call_status); - return; - } - - /* Now unmask the interrupt (often a no-op) */ - call_status = rtas_call(ibm_int_on, 1, 1, NULL, hwirq); - if (call_status != 0) { - printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n", - __func__, hwirq, call_status); - return; - } -} - -static unsigned int xics_startup(struct irq_data *d) -{ - /* - * The generic MSI code returns with the interrupt disabled on the - * card, using the MSI mask bits. Firmware doesn't appear to unmask - * at that level, so we do it here by hand. - */ - if (d->msi_desc) - unmask_msi_irq(d); - - /* unmask it */ - xics_unmask_irq(d); - return 0; -} - -static void xics_mask_real_irq(unsigned int hwirq) -{ - int call_status; - - if (hwirq == XICS_IPI) - return; - - call_status = rtas_call(ibm_int_off, 1, 1, NULL, hwirq); - if (call_status != 0) { - printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n", - __func__, hwirq, call_status); - return; - } - - /* Have to set XIVE to 0xff to be able to remove a slot */ - call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hwirq, - default_server, 0xff); - if (call_status != 0) { - printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n", - __func__, hwirq, call_status); - return; - } -} - -static void xics_mask_irq(struct irq_data *d) -{ - unsigned int hwirq; - - pr_devel("xics: mask virq %d\n", d->irq); - - hwirq = (unsigned int)irq_map[d->irq].hwirq; - if (hwirq == XICS_IPI || hwirq == XICS_IRQ_SPURIOUS) - return; - xics_mask_real_irq(hwirq); -} - -static void xics_mask_unknown_vec(unsigned int vec) -{ - printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec); - xics_mask_real_irq(vec); -} - -static inline unsigned int xics_xirr_vector(unsigned int xirr) -{ - /* - * The top byte is the old cppr, to be restored on EOI. - * The remaining 24 bits are the vector. - */ - return xirr & 0x00ffffff; -} - -static void push_cppr(unsigned int vec) -{ - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); - - if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1)) - return; - - if (vec == XICS_IPI) - os_cppr->stack[++os_cppr->index] = IPI_PRIORITY; - else - os_cppr->stack[++os_cppr->index] = DEFAULT_PRIORITY; -} - -static unsigned int xics_get_irq_direct(void) -{ - unsigned int xirr = direct_xirr_info_get(); - unsigned int vec = xics_xirr_vector(xirr); - unsigned int irq; - - if (vec == XICS_IRQ_SPURIOUS) - return NO_IRQ; - - irq = irq_radix_revmap_lookup(xics_host, vec); - if (likely(irq != NO_IRQ)) { - push_cppr(vec); - return irq; - } - - /* We don't have a linux mapping, so have rtas mask it. */ - xics_mask_unknown_vec(vec); - - /* We might learn about it later, so EOI it */ - direct_xirr_info_set(xirr); - return NO_IRQ; -} - -static unsigned int xics_get_irq_lpar(void) -{ - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); - unsigned int xirr = lpar_xirr_info_get(os_cppr->stack[os_cppr->index]); - unsigned int vec = xics_xirr_vector(xirr); - unsigned int irq; - - if (vec == XICS_IRQ_SPURIOUS) - return NO_IRQ; - - irq = irq_radix_revmap_lookup(xics_host, vec); - if (likely(irq != NO_IRQ)) { - push_cppr(vec); - return irq; - } - - /* We don't have a linux mapping, so have RTAS mask it. */ - xics_mask_unknown_vec(vec); - - /* We might learn about it later, so EOI it */ - lpar_xirr_info_set(xirr); - return NO_IRQ; -} - -static unsigned char pop_cppr(void) -{ - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); - - if (WARN_ON(os_cppr->index < 1)) - return LOWEST_PRIORITY; - - return os_cppr->stack[--os_cppr->index]; -} - -static void xics_eoi_direct(struct irq_data *d) -{ - unsigned int hwirq = (unsigned int)irq_map[d->irq].hwirq; - - iosync(); - direct_xirr_info_set((pop_cppr() << 24) | hwirq); -} - -static void xics_eoi_lpar(struct irq_data *d) -{ - unsigned int hwirq = (unsigned int)irq_map[d->irq].hwirq; - - iosync(); - lpar_xirr_info_set((pop_cppr() << 24) | hwirq); -} - -static int -xics_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force) -{ - unsigned int hwirq; - int status; - int xics_status[2]; - int irq_server; - - hwirq = (unsigned int)irq_map[d->irq].hwirq; - if (hwirq == XICS_IPI || hwirq == XICS_IRQ_SPURIOUS) - return -1; - - status = rtas_call(ibm_get_xive, 1, 3, xics_status, hwirq); - - if (status) { - printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n", - __func__, hwirq, status); - return -1; - } - - irq_server = get_irq_server(d->irq, cpumask, 1); - if (irq_server == -1) { - char cpulist[128]; - cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); - printk(KERN_WARNING - "%s: No online cpus in the mask %s for irq %d\n", - __func__, cpulist, d->irq); - return -1; - } - - status = rtas_call(ibm_set_xive, 3, 1, NULL, - hwirq, irq_server, xics_status[1]); - - if (status) { - printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n", - __func__, hwirq, status); - return -1; - } - - return 0; -} - -static struct irq_chip xics_pic_direct = { - .name = "XICS", - .irq_startup = xics_startup, - .irq_mask = xics_mask_irq, - .irq_unmask = xics_unmask_irq, - .irq_eoi = xics_eoi_direct, - .irq_set_affinity = xics_set_affinity -}; - -static struct irq_chip xics_pic_lpar = { - .name = "XICS", - .irq_startup = xics_startup, - .irq_mask = xics_mask_irq, - .irq_unmask = xics_unmask_irq, - .irq_eoi = xics_eoi_lpar, - .irq_set_affinity = xics_set_affinity -}; - - -/* Interface to arch irq controller subsystem layer */ - -/* Points to the irq_chip we're actually using */ -static struct irq_chip *xics_irq_chip; - -static int xics_host_match(struct irq_host *h, struct device_node *node) -{ - /* IBM machines have interrupt parents of various funky types for things - * like vdevices, events, etc... The trick we use here is to match - * everything here except the legacy 8259 which is compatible "chrp,iic" - */ - return !of_device_is_compatible(node, "chrp,iic"); -} - -static int xics_host_map(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) -{ - pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hw); - - /* Insert the interrupt mapping into the radix tree for fast lookup */ - irq_radix_revmap_insert(xics_host, virq, hw); - - irq_set_status_flags(virq, IRQ_LEVEL); - irq_set_chip_and_handler(virq, xics_irq_chip, handle_fasteoi_irq); - return 0; -} - -static int xics_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_flags) - -{ - /* Current xics implementation translates everything - * to level. It is not technically right for MSIs but this - * is irrelevant at this point. We might get smarter in the future - */ - *out_hwirq = intspec[0]; - *out_flags = IRQ_TYPE_LEVEL_LOW; - - return 0; -} - -static struct irq_host_ops xics_host_ops = { - .match = xics_host_match, - .map = xics_host_map, - .xlate = xics_host_xlate, -}; - -static void __init xics_init_host(void) -{ - if (firmware_has_feature(FW_FEATURE_LPAR)) - xics_irq_chip = &xics_pic_lpar; - else - xics_irq_chip = &xics_pic_direct; - - xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops, - XICS_IRQ_SPURIOUS); - BUG_ON(xics_host == NULL); - irq_set_default_host(xics_host); -} - - -/* Inter-processor interrupt support */ - -#ifdef CONFIG_SMP -/* - * XICS only has a single IPI, so encode the messages per CPU - */ -static DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message); - -static inline void smp_xics_do_message(int cpu, int msg) -{ - unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); - - set_bit(msg, tgt); - mb(); - if (firmware_has_feature(FW_FEATURE_LPAR)) - lpar_qirr_info(cpu, IPI_PRIORITY); - else - direct_qirr_info(cpu, IPI_PRIORITY); -} - -void smp_xics_message_pass(int target, int msg) -{ - unsigned int i; - - if (target < NR_CPUS) { - smp_xics_do_message(target, msg); - } else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - smp_xics_do_message(i, msg); - } - } -} - -static irqreturn_t xics_ipi_dispatch(int cpu) -{ - unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); - - mb(); /* order mmio clearing qirr */ - while (*tgt) { - if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) { - smp_message_recv(PPC_MSG_CALL_FUNCTION); - } - if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt)) { - smp_message_recv(PPC_MSG_RESCHEDULE); - } - if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt)) { - smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE); - } -#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) - if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt)) { - smp_message_recv(PPC_MSG_DEBUGGER_BREAK); - } -#endif - } - return IRQ_HANDLED; -} - -static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id) -{ - int cpu = smp_processor_id(); - - direct_qirr_info(cpu, 0xff); - - return xics_ipi_dispatch(cpu); -} - -static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id) -{ - int cpu = smp_processor_id(); - - lpar_qirr_info(cpu, 0xff); - - return xics_ipi_dispatch(cpu); -} - -static void xics_request_ipi(void) -{ - unsigned int ipi; - int rc; - - ipi = irq_create_mapping(xics_host, XICS_IPI); - BUG_ON(ipi == NO_IRQ); - - /* - * IPIs are marked IRQF_DISABLED as they must run with irqs - * disabled - */ - irq_set_handler(ipi, handle_percpu_irq); - if (firmware_has_feature(FW_FEATURE_LPAR)) - rc = request_irq(ipi, xics_ipi_action_lpar, - IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL); - else - rc = request_irq(ipi, xics_ipi_action_direct, - IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL); - BUG_ON(rc); -} - -int __init smp_xics_probe(void) -{ - xics_request_ipi(); - - return cpumask_weight(cpu_possible_mask); -} - -#endif /* CONFIG_SMP */ - - -/* Initialization */ - -static void xics_update_irq_servers(void) -{ - int i, j; - struct device_node *np; - u32 ilen; - const u32 *ireg; - u32 hcpuid; - - /* Find the server numbers for the boot cpu. */ - np = of_get_cpu_node(boot_cpuid, NULL); - BUG_ON(!np); - - ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); - if (!ireg) { - of_node_put(np); - return; - } - - i = ilen / sizeof(int); - hcpuid = get_hard_smp_processor_id(boot_cpuid); - - /* Global interrupt distribution server is specified in the last - * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last - * entry fom this property for current boot cpu id and use it as - * default distribution server - */ - for (j = 0; j < i; j += 2) { - if (ireg[j] == hcpuid) { - default_server = hcpuid; - default_distrib_server = ireg[j+1]; - } - } - - of_node_put(np); -} - -static void __init xics_map_one_cpu(int hw_id, unsigned long addr, - unsigned long size) -{ - int i; - - /* This may look gross but it's good enough for now, we don't quite - * have a hard -> linux processor id matching. - */ - for_each_possible_cpu(i) { - if (!cpu_present(i)) - continue; - if (hw_id == get_hard_smp_processor_id(i)) { - xics_per_cpu[i] = ioremap(addr, size); - return; - } - } -} - -static void __init xics_init_one_node(struct device_node *np, - unsigned int *indx) -{ - unsigned int ilen; - const u32 *ireg; - - /* This code does the theorically broken assumption that the interrupt - * server numbers are the same as the hard CPU numbers. - * This happens to be the case so far but we are playing with fire... - * should be fixed one of these days. -BenH. - */ - ireg = of_get_property(np, "ibm,interrupt-server-ranges", NULL); - - /* Do that ever happen ? we'll know soon enough... but even good'old - * f80 does have that property .. - */ - WARN_ON(ireg == NULL); - if (ireg) { - /* - * set node starting index for this node - */ - *indx = *ireg; - } - ireg = of_get_property(np, "reg", &ilen); - if (!ireg) - panic("xics_init_IRQ: can't find interrupt reg property"); - - while (ilen >= (4 * sizeof(u32))) { - unsigned long addr, size; - - /* XXX Use proper OF parsing code here !!! */ - addr = (unsigned long)*ireg++ << 32; - ilen -= sizeof(u32); - addr |= *ireg++; - ilen -= sizeof(u32); - size = (unsigned long)*ireg++ << 32; - ilen -= sizeof(u32); - size |= *ireg++; - ilen -= sizeof(u32); - xics_map_one_cpu(*indx, addr, size); - (*indx)++; - } -} - -void __init xics_init_IRQ(void) -{ - struct device_node *np; - u32 indx = 0; - int found = 0; - const u32 *isize; - - ppc64_boot_msg(0x20, "XICS Init"); - - ibm_get_xive = rtas_token("ibm,get-xive"); - ibm_set_xive = rtas_token("ibm,set-xive"); - ibm_int_on = rtas_token("ibm,int-on"); - ibm_int_off = rtas_token("ibm,int-off"); - - for_each_node_by_type(np, "PowerPC-External-Interrupt-Presentation") { - found = 1; - if (firmware_has_feature(FW_FEATURE_LPAR)) { - of_node_put(np); - break; - } - xics_init_one_node(np, &indx); - } - if (found == 0) - return; - - /* get the bit size of server numbers */ - found = 0; - - for_each_compatible_node(np, NULL, "ibm,ppc-xics") { - isize = of_get_property(np, "ibm,interrupt-server#-size", NULL); - - if (!isize) - continue; - - if (!found) { - interrupt_server_size = *isize; - found = 1; - } else if (*isize != interrupt_server_size) { - printk(KERN_WARNING "XICS: " - "mismatched ibm,interrupt-server#-size\n"); - interrupt_server_size = max(*isize, - interrupt_server_size); - } - } - - xics_update_irq_servers(); - xics_init_host(); - - if (firmware_has_feature(FW_FEATURE_LPAR)) - ppc_md.get_irq = xics_get_irq_lpar; - else - ppc_md.get_irq = xics_get_irq_direct; - - xics_setup_cpu(); - - ppc64_boot_msg(0x21, "XICS Done"); -} - -/* Cpu startup, shutdown, and hotplug */ - -static void xics_set_cpu_priority(unsigned char cppr) -{ - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); - - /* - * we only really want to set the priority when there's - * just one cppr value on the stack - */ - WARN_ON(os_cppr->index != 0); - - os_cppr->stack[0] = cppr; - - if (firmware_has_feature(FW_FEATURE_LPAR)) - lpar_cppr_info(cppr); - else - direct_cppr_info(cppr); - iosync(); -} - -/* Have the calling processor join or leave the specified global queue */ -static void xics_set_cpu_giq(unsigned int gserver, unsigned int join) -{ - int index; - int status; - - if (!rtas_indicator_present(GLOBAL_INTERRUPT_QUEUE, NULL)) - return; - - index = (1UL << interrupt_server_size) - 1 - gserver; - - status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, index, join); - - WARN(status < 0, "set-indicator(%d, %d, %u) returned %d\n", - GLOBAL_INTERRUPT_QUEUE, index, join, status); -} - -void xics_setup_cpu(void) -{ - xics_set_cpu_priority(LOWEST_PRIORITY); - - xics_set_cpu_giq(default_distrib_server, 1); -} - -void xics_teardown_cpu(void) -{ - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); - int cpu = smp_processor_id(); - - /* - * we have to reset the cppr index to 0 because we're - * not going to return from the IPI - */ - os_cppr->index = 0; - xics_set_cpu_priority(0); - - /* Clear any pending IPI request */ - if (firmware_has_feature(FW_FEATURE_LPAR)) - lpar_qirr_info(cpu, 0xff); - else - direct_qirr_info(cpu, 0xff); -} - -void xics_kexec_teardown_cpu(int secondary) -{ - xics_teardown_cpu(); - - /* - * we take the ipi irq but and never return so we - * need to EOI the IPI, but want to leave our priority 0 - * - * should we check all the other interrupts too? - * should we be flagging idle loop instead? - * or creating some task to be scheduled? - */ - - if (firmware_has_feature(FW_FEATURE_LPAR)) - lpar_xirr_info_set((0x00 << 24) | XICS_IPI); - else - direct_xirr_info_set((0x00 << 24) | XICS_IPI); - - /* - * Some machines need to have at least one cpu in the GIQ, - * so leave the master cpu in the group. - */ - if (secondary) - xics_set_cpu_giq(default_distrib_server, 0); -} - -#ifdef CONFIG_HOTPLUG_CPU - -/* Interrupts are disabled. */ -void xics_migrate_irqs_away(void) -{ - int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id(); - int virq; - - /* If we used to be the default server, move to the new "boot_cpuid" */ - if (hw_cpu == default_server) - xics_update_irq_servers(); - - /* Reject any interrupt that was queued to us... */ - xics_set_cpu_priority(0); - - /* Remove ourselves from the global interrupt queue */ - xics_set_cpu_giq(default_distrib_server, 0); - - /* Allow IPIs again... */ - xics_set_cpu_priority(DEFAULT_PRIORITY); - - for_each_irq(virq) { - struct irq_desc *desc; - struct irq_chip *chip; - unsigned int hwirq; - int xics_status[2]; - int status; - unsigned long flags; - - /* We can't set affinity on ISA interrupts */ - if (virq < NUM_ISA_INTERRUPTS) - continue; - if (irq_map[virq].host != xics_host) - continue; - hwirq = (unsigned int)irq_map[virq].hwirq; - /* We need to get IPIs still. */ - if (hwirq == XICS_IPI || hwirq == XICS_IRQ_SPURIOUS) - continue; - - desc = irq_to_desc(virq); - - /* We only need to migrate enabled IRQS */ - if (desc == NULL || desc->action == NULL) - continue; - - chip = irq_desc_get_chip(desc); - if (chip == NULL || chip->irq_set_affinity == NULL) - continue; - - raw_spin_lock_irqsave(&desc->lock, flags); - - status = rtas_call(ibm_get_xive, 1, 3, xics_status, hwirq); - if (status) { - printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n", - __func__, hwirq, status); - goto unlock; - } - - /* - * We only support delivery to all cpus or to one cpu. - * The irq has to be migrated only in the single cpu - * case. - */ - if (xics_status[0] != hw_cpu) - goto unlock; - - /* This is expected during cpu offline. */ - if (cpu_online(cpu)) - printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", - virq, cpu); - - /* Reset affinity to all cpus */ - cpumask_setall(desc->irq_data.affinity); - chip->irq_set_affinity(&desc->irq_data, cpu_all_mask, true); -unlock: - raw_spin_unlock_irqrestore(&desc->lock, flags); - } -} -#endif diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h deleted file mode 100644 index d1d5a83039ae..000000000000 --- a/arch/powerpc/platforms/pseries/xics.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * arch/powerpc/platforms/pseries/xics.h - * - * Copyright 2000 IBM Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _POWERPC_KERNEL_XICS_H -#define _POWERPC_KERNEL_XICS_H - -extern void xics_init_IRQ(void); -extern void xics_setup_cpu(void); -extern void xics_teardown_cpu(void); -extern void xics_kexec_teardown_cpu(int secondary); -extern void xics_migrate_irqs_away(void); -extern int smp_xics_probe(void); -extern void smp_xics_message_pass(int target, int msg); - -#endif /* _POWERPC_KERNEL_XICS_H */ diff --git a/arch/powerpc/platforms/wsp/Kconfig b/arch/powerpc/platforms/wsp/Kconfig new file mode 100644 index 000000000000..c3c48eb62cc1 --- /dev/null +++ b/arch/powerpc/platforms/wsp/Kconfig @@ -0,0 +1,28 @@ +config PPC_WSP + bool + default n + +menu "WSP platform selection" + depends on PPC_BOOK3E_64 + +config PPC_PSR2 + bool "PSR-2 platform" + select PPC_A2 + select GENERIC_TBSYNC + select PPC_SCOM + select EPAPR_BOOT + select PPC_WSP + select PPC_XICS + select PPC_ICP_NATIVE + default y + +endmenu + +config PPC_A2_DD2 + bool "Support for DD2 based A2/WSP systems" + depends on PPC_A2 + +config WORKAROUND_ERRATUM_463 + depends on PPC_A2_DD2 + bool "Workaround erratum 463" + default y diff --git a/arch/powerpc/platforms/wsp/Makefile b/arch/powerpc/platforms/wsp/Makefile new file mode 100644 index 000000000000..095be73d6cd4 --- /dev/null +++ b/arch/powerpc/platforms/wsp/Makefile @@ -0,0 +1,6 @@ +ccflags-y += -mno-minimal-toc + +obj-y += setup.o ics.o +obj-$(CONFIG_PPC_PSR2) += psr2.o opb_pic.o +obj-$(CONFIG_PPC_WSP) += scom_wsp.o +obj-$(CONFIG_SMP) += smp.o scom_smp.o diff --git a/arch/powerpc/platforms/wsp/ics.c b/arch/powerpc/platforms/wsp/ics.c new file mode 100644 index 000000000000..e53bd9e7b125 --- /dev/null +++ b/arch/powerpc/platforms/wsp/ics.c @@ -0,0 +1,712 @@ +/* + * Copyright 2008-2011 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "wsp.h" +#include "ics.h" + + +/* WSP ICS */ + +struct wsp_ics { + struct ics ics; + struct device_node *dn; + void __iomem *regs; + spinlock_t lock; + unsigned long *bitmap; + u32 chip_id; + u32 lsi_base; + u32 lsi_count; + u64 hwirq_start; + u64 count; +#ifdef CONFIG_SMP + int *hwirq_cpu_map; +#endif +}; + +#define to_wsp_ics(ics) container_of(ics, struct wsp_ics, ics) + +#define INT_SRC_LAYER_BUID_REG(base) ((base) + 0x00) +#define IODA_TBL_ADDR_REG(base) ((base) + 0x18) +#define IODA_TBL_DATA_REG(base) ((base) + 0x20) +#define XIVE_UPDATE_REG(base) ((base) + 0x28) +#define ICS_INT_CAPS_REG(base) ((base) + 0x30) + +#define TBL_AUTO_INCREMENT ((1UL << 63) | (1UL << 15)) +#define TBL_SELECT_XIST (1UL << 48) +#define TBL_SELECT_XIVT (1UL << 49) + +#define IODA_IRQ(irq) ((irq) & (0x7FFULL)) /* HRM 5.1.3.4 */ + +#define XIST_REQUIRED 0x8 +#define XIST_REJECTED 0x4 +#define XIST_PRESENTED 0x2 +#define XIST_PENDING 0x1 + +#define XIVE_SERVER_SHIFT 42 +#define XIVE_SERVER_MASK 0xFFFFULL +#define XIVE_PRIORITY_MASK 0xFFULL +#define XIVE_PRIORITY_SHIFT 32 +#define XIVE_WRITE_ENABLE (1ULL << 63) + +/* + * The docs refer to a 6 bit field called ChipID, which consists of a + * 3 bit NodeID and a 3 bit ChipID. On WSP the ChipID is always zero + * so we ignore it, and every where we use "chip id" in this code we + * mean the NodeID. + */ +#define WSP_ICS_CHIP_SHIFT 17 + + +static struct wsp_ics *ics_list; +static int num_ics; + +/* ICS Source controller accessors */ + +static u64 wsp_ics_get_xive(struct wsp_ics *ics, unsigned int irq) +{ + unsigned long flags; + u64 xive; + + spin_lock_irqsave(&ics->lock, flags); + out_be64(IODA_TBL_ADDR_REG(ics->regs), TBL_SELECT_XIVT | IODA_IRQ(irq)); + xive = in_be64(IODA_TBL_DATA_REG(ics->regs)); + spin_unlock_irqrestore(&ics->lock, flags); + + return xive; +} + +static void wsp_ics_set_xive(struct wsp_ics *ics, unsigned int irq, u64 xive) +{ + xive &= ~XIVE_ADDR_MASK; + xive |= (irq & XIVE_ADDR_MASK); + xive |= XIVE_WRITE_ENABLE; + + out_be64(XIVE_UPDATE_REG(ics->regs), xive); +} + +static u64 xive_set_server(u64 xive, unsigned int server) +{ + u64 mask = ~(XIVE_SERVER_MASK << XIVE_SERVER_SHIFT); + + xive &= mask; + xive |= (server & XIVE_SERVER_MASK) << XIVE_SERVER_SHIFT; + + return xive; +} + +static u64 xive_set_priority(u64 xive, unsigned int priority) +{ + u64 mask = ~(XIVE_PRIORITY_MASK << XIVE_PRIORITY_SHIFT); + + xive &= mask; + xive |= (priority & XIVE_PRIORITY_MASK) << XIVE_PRIORITY_SHIFT; + + return xive; +} + + +#ifdef CONFIG_SMP +/* Find logical CPUs within mask on a given chip and store result in ret */ +void cpus_on_chip(int chip_id, cpumask_t *mask, cpumask_t *ret) +{ + int cpu, chip; + struct device_node *cpu_dn, *dn; + const u32 *prop; + + cpumask_clear(ret); + for_each_cpu(cpu, mask) { + cpu_dn = of_get_cpu_node(cpu, NULL); + if (!cpu_dn) + continue; + + prop = of_get_property(cpu_dn, "at-node", NULL); + if (!prop) { + of_node_put(cpu_dn); + continue; + } + + dn = of_find_node_by_phandle(*prop); + of_node_put(cpu_dn); + + chip = wsp_get_chip_id(dn); + if (chip == chip_id) + cpumask_set_cpu(cpu, ret); + + of_node_put(dn); + } +} + +/* Store a suitable CPU to handle a hwirq in the ics->hwirq_cpu_map cache */ +static int cache_hwirq_map(struct wsp_ics *ics, unsigned int hwirq, + const cpumask_t *affinity) +{ + cpumask_var_t avail, newmask; + int ret = -ENOMEM, cpu, cpu_rover = 0, target; + int index = hwirq - ics->hwirq_start; + unsigned int nodeid; + + BUG_ON(index < 0 || index >= ics->count); + + if (!ics->hwirq_cpu_map) + return -ENOMEM; + + if (!distribute_irqs) { + ics->hwirq_cpu_map[hwirq - ics->hwirq_start] = xics_default_server; + return 0; + } + + /* Allocate needed CPU masks */ + if (!alloc_cpumask_var(&avail, GFP_KERNEL)) + goto ret; + if (!alloc_cpumask_var(&newmask, GFP_KERNEL)) + goto freeavail; + + /* Find PBus attached to the source of this IRQ */ + nodeid = (hwirq >> WSP_ICS_CHIP_SHIFT) & 0x3; /* 12:14 */ + + /* Find CPUs that could handle this IRQ */ + if (affinity) + cpumask_and(avail, cpu_online_mask, affinity); + else + cpumask_copy(avail, cpu_online_mask); + + /* Narrow selection down to logical CPUs on the same chip */ + cpus_on_chip(nodeid, avail, newmask); + + /* Ensure we haven't narrowed it down to 0 */ + if (unlikely(cpumask_empty(newmask))) { + if (unlikely(cpumask_empty(avail))) { + ret = -1; + goto out; + } + cpumask_copy(newmask, avail); + } + + /* Choose a CPU out of those we narrowed it down to in round robin */ + target = hwirq % cpumask_weight(newmask); + for_each_cpu(cpu, newmask) { + if (cpu_rover++ >= target) { + ics->hwirq_cpu_map[index] = get_hard_smp_processor_id(cpu); + ret = 0; + goto out; + } + } + + /* Shouldn't happen */ + WARN_ON(1); + +out: + free_cpumask_var(newmask); +freeavail: + free_cpumask_var(avail); +ret: + if (ret < 0) { + ics->hwirq_cpu_map[index] = cpumask_first(cpu_online_mask); + pr_warning("Error, falling hwirq 0x%x routing back to CPU %i\n", + hwirq, ics->hwirq_cpu_map[index]); + } + return ret; +} + +static void alloc_irq_map(struct wsp_ics *ics) +{ + int i; + + ics->hwirq_cpu_map = kmalloc(sizeof(int) * ics->count, GFP_KERNEL); + if (!ics->hwirq_cpu_map) { + pr_warning("Allocate hwirq_cpu_map failed, " + "IRQ balancing disabled\n"); + return; + } + + for (i=0; i < ics->count; i++) + ics->hwirq_cpu_map[i] = xics_default_server; +} + +static int get_irq_server(struct wsp_ics *ics, unsigned int hwirq) +{ + int index = hwirq - ics->hwirq_start; + + BUG_ON(index < 0 || index >= ics->count); + + if (!ics->hwirq_cpu_map) + return xics_default_server; + + return ics->hwirq_cpu_map[index]; +} +#else /* !CONFIG_SMP */ +static int cache_hwirq_map(struct wsp_ics *ics, unsigned int hwirq, + const cpumask_t *affinity) +{ + return 0; +} + +static int get_irq_server(struct wsp_ics *ics, unsigned int hwirq) +{ + return xics_default_server; +} + +static void alloc_irq_map(struct wsp_ics *ics) { } +#endif + +static void wsp_chip_unmask_irq(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + struct wsp_ics *ics; + int server; + u64 xive; + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return; + + ics = d->chip_data; + if (WARN_ON(!ics)) + return; + + server = get_irq_server(ics, hw_irq); + + xive = wsp_ics_get_xive(ics, hw_irq); + xive = xive_set_server(xive, server); + xive = xive_set_priority(xive, DEFAULT_PRIORITY); + wsp_ics_set_xive(ics, hw_irq, xive); +} + +static unsigned int wsp_chip_startup(struct irq_data *d) +{ + /* unmask it */ + wsp_chip_unmask_irq(d); + return 0; +} + +static void wsp_mask_real_irq(unsigned int hw_irq, struct wsp_ics *ics) +{ + u64 xive; + + if (hw_irq == XICS_IPI) + return; + + if (WARN_ON(!ics)) + return; + xive = wsp_ics_get_xive(ics, hw_irq); + xive = xive_set_server(xive, xics_default_server); + xive = xive_set_priority(xive, LOWEST_PRIORITY); + wsp_ics_set_xive(ics, hw_irq, xive); +} + +static void wsp_chip_mask_irq(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + struct wsp_ics *ics = d->chip_data; + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return; + + wsp_mask_real_irq(hw_irq, ics); +} + +static int wsp_chip_set_affinity(struct irq_data *d, + const struct cpumask *cpumask, bool force) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + struct wsp_ics *ics; + int ret; + u64 xive; + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return -1; + + ics = d->chip_data; + if (WARN_ON(!ics)) + return -1; + xive = wsp_ics_get_xive(ics, hw_irq); + + /* + * For the moment only implement delivery to all cpus or one cpu. + * Get current irq_server for the given irq + */ + ret = cache_hwirq_map(ics, d->irq, cpumask); + if (ret == -1) { + char cpulist[128]; + cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); + pr_warning("%s: No online cpus in the mask %s for irq %d\n", + __func__, cpulist, d->irq); + return -1; + } else if (ret == -ENOMEM) { + pr_warning("%s: Out of memory\n", __func__); + return -1; + } + + xive = xive_set_server(xive, get_irq_server(ics, hw_irq)); + wsp_ics_set_xive(ics, hw_irq, xive); + + return 0; +} + +static struct irq_chip wsp_irq_chip = { + .name = "WSP ICS", + .irq_startup = wsp_chip_startup, + .irq_mask = wsp_chip_mask_irq, + .irq_unmask = wsp_chip_unmask_irq, + .irq_set_affinity = wsp_chip_set_affinity +}; + +static int wsp_ics_host_match(struct ics *ics, struct device_node *dn) +{ + /* All ICSs in the system implement a global irq number space, + * so match against them all. */ + return of_device_is_compatible(dn, "ibm,ppc-xics"); +} + +static int wsp_ics_match_hwirq(struct wsp_ics *wsp_ics, unsigned int hwirq) +{ + if (hwirq >= wsp_ics->hwirq_start && + hwirq < wsp_ics->hwirq_start + wsp_ics->count) + return 1; + + return 0; +} + +static int wsp_ics_map(struct ics *ics, unsigned int virq) +{ + struct wsp_ics *wsp_ics = to_wsp_ics(ics); + unsigned int hw_irq = virq_to_hw(virq); + unsigned long flags; + + if (!wsp_ics_match_hwirq(wsp_ics, hw_irq)) + return -ENOENT; + + irq_set_chip_and_handler(virq, &wsp_irq_chip, handle_fasteoi_irq); + + irq_set_chip_data(virq, wsp_ics); + + spin_lock_irqsave(&wsp_ics->lock, flags); + bitmap_allocate_region(wsp_ics->bitmap, hw_irq - wsp_ics->hwirq_start, 0); + spin_unlock_irqrestore(&wsp_ics->lock, flags); + + return 0; +} + +static void wsp_ics_mask_unknown(struct ics *ics, unsigned long hw_irq) +{ + struct wsp_ics *wsp_ics = to_wsp_ics(ics); + + if (!wsp_ics_match_hwirq(wsp_ics, hw_irq)) + return; + + pr_err("%s: IRQ %lu (real) is invalid, disabling it.\n", __func__, hw_irq); + wsp_mask_real_irq(hw_irq, wsp_ics); +} + +static long wsp_ics_get_server(struct ics *ics, unsigned long hw_irq) +{ + struct wsp_ics *wsp_ics = to_wsp_ics(ics); + + if (!wsp_ics_match_hwirq(wsp_ics, hw_irq)) + return -ENOENT; + + return get_irq_server(wsp_ics, hw_irq); +} + +/* HW Number allocation API */ + +static struct wsp_ics *wsp_ics_find_dn_ics(struct device_node *dn) +{ + struct device_node *iparent; + int i; + + iparent = of_irq_find_parent(dn); + if (!iparent) { + pr_err("wsp_ics: Failed to find interrupt parent!\n"); + return NULL; + } + + for(i = 0; i < num_ics; i++) { + if(ics_list[i].dn == iparent) + break; + } + + if (i >= num_ics) { + pr_err("wsp_ics: Unable to find parent bitmap!\n"); + return NULL; + } + + return &ics_list[i]; +} + +int wsp_ics_alloc_irq(struct device_node *dn, int num) +{ + struct wsp_ics *ics; + int order, offset; + + ics = wsp_ics_find_dn_ics(dn); + if (!ics) + return -ENODEV; + + /* Fast, but overly strict if num isn't a power of two */ + order = get_count_order(num); + + spin_lock_irq(&ics->lock); + offset = bitmap_find_free_region(ics->bitmap, ics->count, order); + spin_unlock_irq(&ics->lock); + + if (offset < 0) + return offset; + + return offset + ics->hwirq_start; +} + +void wsp_ics_free_irq(struct device_node *dn, unsigned int irq) +{ + struct wsp_ics *ics; + + ics = wsp_ics_find_dn_ics(dn); + if (WARN_ON(!ics)) + return; + + spin_lock_irq(&ics->lock); + bitmap_release_region(ics->bitmap, irq, 0); + spin_unlock_irq(&ics->lock); +} + +/* Initialisation */ + +static int __init wsp_ics_bitmap_setup(struct wsp_ics *ics, + struct device_node *dn) +{ + int len, i, j, size; + u32 start, count; + const u32 *p; + + size = BITS_TO_LONGS(ics->count) * sizeof(long); + ics->bitmap = kzalloc(size, GFP_KERNEL); + if (!ics->bitmap) { + pr_err("wsp_ics: ENOMEM allocating IRQ bitmap!\n"); + return -ENOMEM; + } + + spin_lock_init(&ics->lock); + + p = of_get_property(dn, "available-ranges", &len); + if (!p || !len) { + /* FIXME this should be a WARN() once mambo is updated */ + pr_err("wsp_ics: No available-ranges defined for %s\n", + dn->full_name); + return 0; + } + + if (len % (2 * sizeof(u32)) != 0) { + /* FIXME this should be a WARN() once mambo is updated */ + pr_err("wsp_ics: Invalid available-ranges for %s\n", + dn->full_name); + return 0; + } + + bitmap_fill(ics->bitmap, ics->count); + + for (i = 0; i < len / sizeof(u32); i += 2) { + start = of_read_number(p + i, 1); + count = of_read_number(p + i + 1, 1); + + pr_devel("%s: start: %d count: %d\n", __func__, start, count); + + if ((start + count) > (ics->hwirq_start + ics->count) || + start < ics->hwirq_start) { + pr_err("wsp_ics: Invalid range! -> %d to %d\n", + start, start + count); + break; + } + + for (j = 0; j < count; j++) + bitmap_release_region(ics->bitmap, + (start + j) - ics->hwirq_start, 0); + } + + /* Ensure LSIs are not available for allocation */ + bitmap_allocate_region(ics->bitmap, ics->lsi_base, + get_count_order(ics->lsi_count)); + + return 0; +} + +static int __init wsp_ics_setup(struct wsp_ics *ics, struct device_node *dn) +{ + u32 lsi_buid, msi_buid, msi_base, msi_count; + void __iomem *regs; + const u32 *p; + int rc, len, i; + u64 caps, buid; + + p = of_get_property(dn, "interrupt-ranges", &len); + if (!p || len < (2 * sizeof(u32))) { + pr_err("wsp_ics: No/bad interrupt-ranges found on %s\n", + dn->full_name); + return -ENOENT; + } + + if (len > (2 * sizeof(u32))) { + pr_err("wsp_ics: Multiple ics ranges not supported.\n"); + return -EINVAL; + } + + regs = of_iomap(dn, 0); + if (!regs) { + pr_err("wsp_ics: of_iomap(%s) failed\n", dn->full_name); + return -ENXIO; + } + + ics->hwirq_start = of_read_number(p, 1); + ics->count = of_read_number(p + 1, 1); + ics->regs = regs; + + ics->chip_id = wsp_get_chip_id(dn); + if (WARN_ON(ics->chip_id < 0)) + ics->chip_id = 0; + + /* Get some informations about the critter */ + caps = in_be64(ICS_INT_CAPS_REG(ics->regs)); + buid = in_be64(INT_SRC_LAYER_BUID_REG(ics->regs)); + ics->lsi_count = caps >> 56; + msi_count = (caps >> 44) & 0x7ff; + + /* Note: LSI BUID is 9 bits, but really only 3 are BUID and the + * rest is mixed in the interrupt number. We store the whole + * thing though + */ + lsi_buid = (buid >> 48) & 0x1ff; + ics->lsi_base = (ics->chip_id << WSP_ICS_CHIP_SHIFT) | lsi_buid << 5; + msi_buid = (buid >> 37) & 0x7; + msi_base = (ics->chip_id << WSP_ICS_CHIP_SHIFT) | msi_buid << 11; + + pr_info("wsp_ics: Found %s\n", dn->full_name); + pr_info("wsp_ics: irq range : 0x%06llx..0x%06llx\n", + ics->hwirq_start, ics->hwirq_start + ics->count - 1); + pr_info("wsp_ics: %4d LSIs : 0x%06x..0x%06x\n", + ics->lsi_count, ics->lsi_base, + ics->lsi_base + ics->lsi_count - 1); + pr_info("wsp_ics: %4d MSIs : 0x%06x..0x%06x\n", + msi_count, msi_base, + msi_base + msi_count - 1); + + /* Let's check the HW config is sane */ + if (ics->lsi_base < ics->hwirq_start || + (ics->lsi_base + ics->lsi_count) > (ics->hwirq_start + ics->count)) + pr_warning("wsp_ics: WARNING ! LSIs out of interrupt-ranges !\n"); + if (msi_base < ics->hwirq_start || + (msi_base + msi_count) > (ics->hwirq_start + ics->count)) + pr_warning("wsp_ics: WARNING ! MSIs out of interrupt-ranges !\n"); + + /* We don't check for overlap between LSI and MSI, which will happen + * if we use the same BUID, I'm not sure yet how legit that is. + */ + + rc = wsp_ics_bitmap_setup(ics, dn); + if (rc) { + iounmap(regs); + return rc; + } + + ics->dn = of_node_get(dn); + alloc_irq_map(ics); + + for(i = 0; i < ics->count; i++) + wsp_mask_real_irq(ics->hwirq_start + i, ics); + + ics->ics.map = wsp_ics_map; + ics->ics.mask_unknown = wsp_ics_mask_unknown; + ics->ics.get_server = wsp_ics_get_server; + ics->ics.host_match = wsp_ics_host_match; + + xics_register_ics(&ics->ics); + + return 0; +} + +static void __init wsp_ics_set_default_server(void) +{ + struct device_node *np; + u32 hwid; + + /* Find the server number for the boot cpu. */ + np = of_get_cpu_node(boot_cpuid, NULL); + BUG_ON(!np); + + hwid = get_hard_smp_processor_id(boot_cpuid); + + pr_info("wsp_ics: default server is %#x, CPU %s\n", hwid, np->full_name); + xics_default_server = hwid; + + of_node_put(np); +} + +static int __init wsp_ics_init(void) +{ + struct device_node *dn; + struct wsp_ics *ics; + int rc, found; + + wsp_ics_set_default_server(); + + found = 0; + for_each_compatible_node(dn, NULL, "ibm,ppc-xics") + found++; + + if (found == 0) { + pr_err("wsp_ics: No ICS's found!\n"); + return -ENODEV; + } + + ics_list = kmalloc(sizeof(*ics) * found, GFP_KERNEL); + if (!ics_list) { + pr_err("wsp_ics: No memory for structs.\n"); + return -ENOMEM; + } + + num_ics = 0; + ics = ics_list; + for_each_compatible_node(dn, NULL, "ibm,wsp-xics") { + rc = wsp_ics_setup(ics, dn); + if (rc == 0) { + ics++; + num_ics++; + } + } + + if (found != num_ics) { + pr_err("wsp_ics: Failed setting up %d ICS's\n", + found - num_ics); + return -1; + } + + return 0; +} + +void __init wsp_init_irq(void) +{ + wsp_ics_init(); + xics_init(); + + /* We need to patch our irq chip's EOI to point to the right ICP */ + wsp_irq_chip.irq_eoi = icp_ops->eoi; +} diff --git a/arch/powerpc/platforms/wsp/ics.h b/arch/powerpc/platforms/wsp/ics.h new file mode 100644 index 000000000000..e34d53102640 --- /dev/null +++ b/arch/powerpc/platforms/wsp/ics.h @@ -0,0 +1,20 @@ +/* + * Copyright 2009 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef __ICS_H +#define __ICS_H + +#define XIVE_ADDR_MASK 0x7FFULL + +extern void wsp_init_irq(void); + +extern int wsp_ics_alloc_irq(struct device_node *dn, int num); +extern void wsp_ics_free_irq(struct device_node *dn, unsigned int irq); + +#endif /* __ICS_H */ diff --git a/arch/powerpc/platforms/wsp/opb_pic.c b/arch/powerpc/platforms/wsp/opb_pic.c new file mode 100644 index 000000000000..be05631a3c1c --- /dev/null +++ b/arch/powerpc/platforms/wsp/opb_pic.c @@ -0,0 +1,332 @@ +/* + * IBM Onboard Peripheral Bus Interrupt Controller + * + * Copyright 2010 Jack Miller, IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define OPB_NR_IRQS 32 + +#define OPB_MLSASIER 0x04 /* MLS Accumulated Status IER */ +#define OPB_MLSIR 0x50 /* MLS Interrupt Register */ +#define OPB_MLSIER 0x54 /* MLS Interrupt Enable Register */ +#define OPB_MLSIPR 0x58 /* MLS Interrupt Polarity Register */ +#define OPB_MLSIIR 0x5c /* MLS Interrupt Inputs Register */ + +static int opb_index = 0; + +struct opb_pic { + struct irq_host *host; + void *regs; + int index; + spinlock_t lock; +}; + +static u32 opb_in(struct opb_pic *opb, int offset) +{ + return in_be32(opb->regs + offset); +} + +static void opb_out(struct opb_pic *opb, int offset, u32 val) +{ + out_be32(opb->regs + offset, val); +} + +static void opb_unmask_irq(struct irq_data *d) +{ + struct opb_pic *opb; + unsigned long flags; + u32 ier, bitset; + + opb = d->chip_data; + bitset = (1 << (31 - irqd_to_hwirq(d))); + + spin_lock_irqsave(&opb->lock, flags); + + ier = opb_in(opb, OPB_MLSIER); + opb_out(opb, OPB_MLSIER, ier | bitset); + ier = opb_in(opb, OPB_MLSIER); + + spin_unlock_irqrestore(&opb->lock, flags); +} + +static void opb_mask_irq(struct irq_data *d) +{ + struct opb_pic *opb; + unsigned long flags; + u32 ier, mask; + + opb = d->chip_data; + mask = ~(1 << (31 - irqd_to_hwirq(d))); + + spin_lock_irqsave(&opb->lock, flags); + + ier = opb_in(opb, OPB_MLSIER); + opb_out(opb, OPB_MLSIER, ier & mask); + ier = opb_in(opb, OPB_MLSIER); // Flush posted writes + + spin_unlock_irqrestore(&opb->lock, flags); +} + +static void opb_ack_irq(struct irq_data *d) +{ + struct opb_pic *opb; + unsigned long flags; + u32 bitset; + + opb = d->chip_data; + bitset = (1 << (31 - irqd_to_hwirq(d))); + + spin_lock_irqsave(&opb->lock, flags); + + opb_out(opb, OPB_MLSIR, bitset); + opb_in(opb, OPB_MLSIR); // Flush posted writes + + spin_unlock_irqrestore(&opb->lock, flags); +} + +static void opb_mask_ack_irq(struct irq_data *d) +{ + struct opb_pic *opb; + unsigned long flags; + u32 bitset; + u32 ier, ir; + + opb = d->chip_data; + bitset = (1 << (31 - irqd_to_hwirq(d))); + + spin_lock_irqsave(&opb->lock, flags); + + ier = opb_in(opb, OPB_MLSIER); + opb_out(opb, OPB_MLSIER, ier & ~bitset); + ier = opb_in(opb, OPB_MLSIER); // Flush posted writes + + opb_out(opb, OPB_MLSIR, bitset); + ir = opb_in(opb, OPB_MLSIR); // Flush posted writes + + spin_unlock_irqrestore(&opb->lock, flags); +} + +static int opb_set_irq_type(struct irq_data *d, unsigned int flow) +{ + struct opb_pic *opb; + unsigned long flags; + int invert, ipr, mask, bit; + + opb = d->chip_data; + + /* The only information we're interested in in the type is whether it's + * a high or low trigger. For high triggered interrupts, the polarity + * set for it in the MLS Interrupt Polarity Register is 0, for low + * interrupts it's 1 so that the proper input in the MLS Interrupt Input + * Register is interrupted as asserting the interrupt. */ + + switch (flow) { + case IRQ_TYPE_NONE: + opb_mask_irq(d); + return 0; + + case IRQ_TYPE_LEVEL_HIGH: + invert = 0; + break; + + case IRQ_TYPE_LEVEL_LOW: + invert = 1; + break; + + default: + return -EINVAL; + } + + bit = (1 << (31 - irqd_to_hwirq(d))); + mask = ~bit; + + spin_lock_irqsave(&opb->lock, flags); + + ipr = opb_in(opb, OPB_MLSIPR); + ipr = (ipr & mask) | (invert ? bit : 0); + opb_out(opb, OPB_MLSIPR, ipr); + ipr = opb_in(opb, OPB_MLSIPR); // Flush posted writes + + spin_unlock_irqrestore(&opb->lock, flags); + + /* Record the type in the interrupt descriptor */ + irqd_set_trigger_type(d, flow); + + return 0; +} + +static struct irq_chip opb_irq_chip = { + .name = "OPB", + .irq_mask = opb_mask_irq, + .irq_unmask = opb_unmask_irq, + .irq_mask_ack = opb_mask_ack_irq, + .irq_ack = opb_ack_irq, + .irq_set_type = opb_set_irq_type +}; + +static int opb_host_map(struct irq_host *host, unsigned int virq, + irq_hw_number_t hwirq) +{ + struct opb_pic *opb; + + opb = host->host_data; + + /* Most of the important stuff is handled by the generic host code, like + * the lookup, so just attach some info to the virtual irq */ + + irq_set_chip_data(virq, opb); + irq_set_chip_and_handler(virq, &opb_irq_chip, handle_level_irq); + irq_set_irq_type(virq, IRQ_TYPE_NONE); + + return 0; +} + +static int opb_host_xlate(struct irq_host *host, struct device_node *dn, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type) +{ + /* Interrupt size must == 2 */ + BUG_ON(intsize != 2); + *out_hwirq = intspec[0]; + *out_type = intspec[1]; + return 0; +} + +static struct irq_host_ops opb_host_ops = { + .map = opb_host_map, + .xlate = opb_host_xlate, +}; + +irqreturn_t opb_irq_handler(int irq, void *private) +{ + struct opb_pic *opb; + u32 ir, src, subvirq; + + opb = (struct opb_pic *) private; + + /* Read the OPB MLS Interrupt Register for + * asserted interrupts */ + ir = opb_in(opb, OPB_MLSIR); + if (!ir) + return IRQ_NONE; + + do { + /* Get 1 - 32 source, *NOT* bit */ + src = 32 - ffs(ir); + + /* Translate from the OPB's conception of interrupt number to + * Linux's virtual IRQ */ + + subvirq = irq_linear_revmap(opb->host, src); + + generic_handle_irq(subvirq); + } while ((ir = opb_in(opb, OPB_MLSIR))); + + return IRQ_HANDLED; +} + +struct opb_pic *opb_pic_init_one(struct device_node *dn) +{ + struct opb_pic *opb; + struct resource res; + + if (of_address_to_resource(dn, 0, &res)) { + printk(KERN_ERR "opb: Couldn't translate resource\n"); + return NULL; + } + + opb = kzalloc(sizeof(struct opb_pic), GFP_KERNEL); + if (!opb) { + printk(KERN_ERR "opb: Failed to allocate opb struct!\n"); + return NULL; + } + + /* Get access to the OPB MMIO registers */ + opb->regs = ioremap(res.start + 0x10000, 0x1000); + if (!opb->regs) { + printk(KERN_ERR "opb: Failed to allocate register space!\n"); + goto free_opb; + } + + /* Allocate an irq host so that Linux knows that despite only + * having one interrupt to issue, we're the controller for multiple + * hardware IRQs, so later we can lookup their virtual IRQs. */ + + opb->host = irq_alloc_host(dn, IRQ_HOST_MAP_LINEAR, + OPB_NR_IRQS, &opb_host_ops, -1); + + if (!opb->host) { + printk(KERN_ERR "opb: Failed to allocate IRQ host!\n"); + goto free_regs; + } + + opb->index = opb_index++; + spin_lock_init(&opb->lock); + opb->host->host_data = opb; + + /* Disable all interrupts by default */ + opb_out(opb, OPB_MLSASIER, 0); + opb_out(opb, OPB_MLSIER, 0); + + /* ACK any interrupts left by FW */ + opb_out(opb, OPB_MLSIR, 0xFFFFFFFF); + + return opb; + +free_regs: + iounmap(opb->regs); +free_opb: + kfree(opb); + return NULL; +} + +void __init opb_pic_init(void) +{ + struct device_node *dn; + struct opb_pic *opb; + int virq; + int rc; + + /* Call init_one for each OPB device */ + for_each_compatible_node(dn, NULL, "ibm,opb") { + + /* Fill in an OPB struct */ + opb = opb_pic_init_one(dn); + if (!opb) { + printk(KERN_WARNING "opb: Failed to init node, skipped!\n"); + continue; + } + + /* Map / get opb's hardware virtual irq */ + virq = irq_of_parse_and_map(dn, 0); + if (virq <= 0) { + printk("opb: irq_op_parse_and_map failed!\n"); + continue; + } + + /* Attach opb interrupt handler to new virtual IRQ */ + rc = request_irq(virq, opb_irq_handler, 0, "OPB LS Cascade", opb); + if (rc) { + printk("opb: request_irq failed: %d\n", rc); + continue; + } + + printk("OPB%d init with %d IRQs at %p\n", opb->index, + OPB_NR_IRQS, opb->regs); + } +} diff --git a/arch/powerpc/platforms/wsp/psr2.c b/arch/powerpc/platforms/wsp/psr2.c new file mode 100644 index 000000000000..40f28916ff6c --- /dev/null +++ b/arch/powerpc/platforms/wsp/psr2.c @@ -0,0 +1,95 @@ +/* + * Copyright 2008-2011, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ics.h" +#include "wsp.h" + + +static void psr2_spin(void) +{ + hard_irq_disable(); + for (;;) ; +} + +static void psr2_restart(char *cmd) +{ + psr2_spin(); +} + +static int psr2_probe_devices(void) +{ + struct device_node *np; + + /* Our RTC is a ds1500. It seems to be programatically compatible + * with the ds1511 for which we have a driver so let's use that + */ + np = of_find_compatible_node(NULL, NULL, "dallas,ds1500"); + if (np != NULL) { + struct resource res; + if (of_address_to_resource(np, 0, &res) == 0) + platform_device_register_simple("ds1511", 0, &res, 1); + } + return 0; +} +machine_arch_initcall(psr2_md, psr2_probe_devices); + +static void __init psr2_setup_arch(void) +{ + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000; + + scom_init_wsp(); + + /* Setup SMP callback */ +#ifdef CONFIG_SMP + a2_setup_smp(); +#endif +} + +static int __init psr2_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "ibm,psr2")) + return 0; + + return 1; +} + +static void __init psr2_init_irq(void) +{ + wsp_init_irq(); + opb_pic_init(); +} + +define_machine(psr2_md) { + .name = "PSR2 A2", + .probe = psr2_probe, + .setup_arch = psr2_setup_arch, + .restart = psr2_restart, + .power_off = psr2_spin, + .halt = psr2_spin, + .calibrate_decr = generic_calibrate_decr, + .init_IRQ = psr2_init_irq, + .progress = udbg_progress, + .power_save = book3e_idle, +}; diff --git a/arch/powerpc/platforms/wsp/scom_smp.c b/arch/powerpc/platforms/wsp/scom_smp.c new file mode 100644 index 000000000000..141e78032097 --- /dev/null +++ b/arch/powerpc/platforms/wsp/scom_smp.c @@ -0,0 +1,427 @@ +/* + * SCOM support for A2 platforms + * + * Copyright 2007-2011 Benjamin Herrenschmidt, David Gibson, + * Michael Ellerman, IBM Corp. + * + * 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 "wsp.h" + +#define SCOM_RAMC 0x2a /* Ram Command */ +#define SCOM_RAMC_TGT1_EXT 0x80000000 +#define SCOM_RAMC_SRC1_EXT 0x40000000 +#define SCOM_RAMC_SRC2_EXT 0x20000000 +#define SCOM_RAMC_SRC3_EXT 0x10000000 +#define SCOM_RAMC_ENABLE 0x00080000 +#define SCOM_RAMC_THREADSEL 0x00060000 +#define SCOM_RAMC_EXECUTE 0x00010000 +#define SCOM_RAMC_MSR_OVERRIDE 0x00008000 +#define SCOM_RAMC_MSR_PR 0x00004000 +#define SCOM_RAMC_MSR_GS 0x00002000 +#define SCOM_RAMC_FORCE 0x00001000 +#define SCOM_RAMC_FLUSH 0x00000800 +#define SCOM_RAMC_INTERRUPT 0x00000004 +#define SCOM_RAMC_ERROR 0x00000002 +#define SCOM_RAMC_DONE 0x00000001 +#define SCOM_RAMI 0x29 /* Ram Instruction */ +#define SCOM_RAMIC 0x28 /* Ram Instruction and Command */ +#define SCOM_RAMIC_INSN 0xffffffff00000000 +#define SCOM_RAMD 0x2d /* Ram Data */ +#define SCOM_RAMDH 0x2e /* Ram Data High */ +#define SCOM_RAMDL 0x2f /* Ram Data Low */ +#define SCOM_PCCR0 0x33 /* PC Configuration Register 0 */ +#define SCOM_PCCR0_ENABLE_DEBUG 0x80000000 +#define SCOM_PCCR0_ENABLE_RAM 0x40000000 +#define SCOM_THRCTL 0x30 /* Thread Control and Status */ +#define SCOM_THRCTL_T0_STOP 0x80000000 +#define SCOM_THRCTL_T1_STOP 0x40000000 +#define SCOM_THRCTL_T2_STOP 0x20000000 +#define SCOM_THRCTL_T3_STOP 0x10000000 +#define SCOM_THRCTL_T0_STEP 0x08000000 +#define SCOM_THRCTL_T1_STEP 0x04000000 +#define SCOM_THRCTL_T2_STEP 0x02000000 +#define SCOM_THRCTL_T3_STEP 0x01000000 +#define SCOM_THRCTL_T0_RUN 0x00800000 +#define SCOM_THRCTL_T1_RUN 0x00400000 +#define SCOM_THRCTL_T2_RUN 0x00200000 +#define SCOM_THRCTL_T3_RUN 0x00100000 +#define SCOM_THRCTL_T0_PM 0x00080000 +#define SCOM_THRCTL_T1_PM 0x00040000 +#define SCOM_THRCTL_T2_PM 0x00020000 +#define SCOM_THRCTL_T3_PM 0x00010000 +#define SCOM_THRCTL_T0_UDE 0x00008000 +#define SCOM_THRCTL_T1_UDE 0x00004000 +#define SCOM_THRCTL_T2_UDE 0x00002000 +#define SCOM_THRCTL_T3_UDE 0x00001000 +#define SCOM_THRCTL_ASYNC_DIS 0x00000800 +#define SCOM_THRCTL_TB_DIS 0x00000400 +#define SCOM_THRCTL_DEC_DIS 0x00000200 +#define SCOM_THRCTL_AND 0x31 /* Thread Control and Status */ +#define SCOM_THRCTL_OR 0x32 /* Thread Control and Status */ + + +static DEFINE_PER_CPU(scom_map_t, scom_ptrs); + +static scom_map_t get_scom(int cpu, struct device_node *np, int *first_thread) +{ + scom_map_t scom = per_cpu(scom_ptrs, cpu); + int tcpu; + + if (scom_map_ok(scom)) { + *first_thread = 0; + return scom; + } + + *first_thread = 1; + + scom = scom_map_device(np, 0); + + for (tcpu = cpu_first_thread_sibling(cpu); + tcpu <= cpu_last_thread_sibling(cpu); tcpu++) + per_cpu(scom_ptrs, tcpu) = scom; + + /* Hack: for the boot core, this will actually get called on + * the second thread up, not the first so our test above will + * set first_thread incorrectly. */ + if (cpu_first_thread_sibling(cpu) == 0) + *first_thread = 0; + + return scom; +} + +static int a2_scom_ram(scom_map_t scom, int thread, u32 insn, int extmask) +{ + u64 cmd, mask, val; + int n = 0; + + cmd = ((u64)insn << 32) | (((u64)extmask & 0xf) << 28) + | ((u64)thread << 17) | SCOM_RAMC_ENABLE | SCOM_RAMC_EXECUTE; + mask = SCOM_RAMC_DONE | SCOM_RAMC_INTERRUPT | SCOM_RAMC_ERROR; + + scom_write(scom, SCOM_RAMIC, cmd); + + while (!((val = scom_read(scom, SCOM_RAMC)) & mask)) { + pr_devel("Waiting on RAMC = 0x%llx\n", val); + if (++n == 3) { + pr_err("RAMC timeout on instruction 0x%08x, thread %d\n", + insn, thread); + return -1; + } + } + + if (val & SCOM_RAMC_INTERRUPT) { + pr_err("RAMC interrupt on instruction 0x%08x, thread %d\n", + insn, thread); + return -SCOM_RAMC_INTERRUPT; + } + + if (val & SCOM_RAMC_ERROR) { + pr_err("RAMC error on instruction 0x%08x, thread %d\n", + insn, thread); + return -SCOM_RAMC_ERROR; + } + + return 0; +} + +static int a2_scom_getgpr(scom_map_t scom, int thread, int gpr, int alt, + u64 *out_gpr) +{ + int rc; + + /* or rN, rN, rN */ + u32 insn = 0x7c000378 | (gpr << 21) | (gpr << 16) | (gpr << 11); + rc = a2_scom_ram(scom, thread, insn, alt ? 0xf : 0x0); + if (rc) + return rc; + + *out_gpr = scom_read(scom, SCOM_RAMD); + + return 0; +} + +static int a2_scom_getspr(scom_map_t scom, int thread, int spr, u64 *out_spr) +{ + int rc, sprhi, sprlo; + u32 insn; + + sprhi = spr >> 5; + sprlo = spr & 0x1f; + insn = 0x7c2002a6 | (sprlo << 16) | (sprhi << 11); /* mfspr r1,spr */ + + if (spr == 0x0ff0) + insn = 0x7c2000a6; /* mfmsr r1 */ + + rc = a2_scom_ram(scom, thread, insn, 0xf); + if (rc) + return rc; + return a2_scom_getgpr(scom, thread, 1, 1, out_spr); +} + +static int a2_scom_setgpr(scom_map_t scom, int thread, int gpr, + int alt, u64 val) +{ + u32 lis = 0x3c000000 | (gpr << 21); + u32 li = 0x38000000 | (gpr << 21); + u32 oris = 0x64000000 | (gpr << 21) | (gpr << 16); + u32 ori = 0x60000000 | (gpr << 21) | (gpr << 16); + u32 rldicr32 = 0x780007c6 | (gpr << 21) | (gpr << 16); + u32 highest = val >> 48; + u32 higher = (val >> 32) & 0xffff; + u32 high = (val >> 16) & 0xffff; + u32 low = val & 0xffff; + int lext = alt ? 0x8 : 0x0; + int oext = alt ? 0xf : 0x0; + int rc = 0; + + if (highest) + rc |= a2_scom_ram(scom, thread, lis | highest, lext); + + if (higher) { + if (highest) + rc |= a2_scom_ram(scom, thread, oris | higher, oext); + else + rc |= a2_scom_ram(scom, thread, li | higher, lext); + } + + if (highest || higher) + rc |= a2_scom_ram(scom, thread, rldicr32, oext); + + if (high) { + if (highest || higher) + rc |= a2_scom_ram(scom, thread, oris | high, oext); + else + rc |= a2_scom_ram(scom, thread, lis | high, lext); + } + + if (highest || higher || high) + rc |= a2_scom_ram(scom, thread, ori | low, oext); + else + rc |= a2_scom_ram(scom, thread, li | low, lext); + + return rc; +} + +static int a2_scom_setspr(scom_map_t scom, int thread, int spr, u64 val) +{ + int sprhi = spr >> 5; + int sprlo = spr & 0x1f; + /* mtspr spr, r1 */ + u32 insn = 0x7c2003a6 | (sprlo << 16) | (sprhi << 11); + + if (spr == 0x0ff0) + insn = 0x7c200124; /* mtmsr r1 */ + + if (a2_scom_setgpr(scom, thread, 1, 1, val)) + return -1; + + return a2_scom_ram(scom, thread, insn, 0xf); +} + +static int a2_scom_initial_tlb(scom_map_t scom, int thread) +{ + extern u32 a2_tlbinit_code_start[], a2_tlbinit_code_end[]; + extern u32 a2_tlbinit_after_iprot_flush[]; + extern u32 a2_tlbinit_after_linear_map[]; + u32 assoc, entries, i; + u64 epn, tlbcfg; + u32 *p; + int rc; + + /* Invalidate all entries (including iprot) */ + + rc = a2_scom_getspr(scom, thread, SPRN_TLB0CFG, &tlbcfg); + if (rc) + goto scom_fail; + entries = tlbcfg & TLBnCFG_N_ENTRY; + assoc = (tlbcfg & TLBnCFG_ASSOC) >> 24; + epn = 0; + + /* Set MMUCR2 to enable 4K, 64K, 1M, 16M and 1G pages */ + a2_scom_setspr(scom, thread, SPRN_MMUCR2, 0x000a7531); + /* Set MMUCR3 to write all thids bit to the TLB */ + a2_scom_setspr(scom, thread, SPRN_MMUCR3, 0x0000000f); + + /* Set MAS1 for 1G page size, and MAS2 to our initial EPN */ + a2_scom_setspr(scom, thread, SPRN_MAS1, MAS1_TSIZE(BOOK3E_PAGESZ_1GB)); + a2_scom_setspr(scom, thread, SPRN_MAS2, epn); + for (i = 0; i < entries; i++) { + + a2_scom_setspr(scom, thread, SPRN_MAS0, MAS0_ESEL(i % assoc)); + + /* tlbwe */ + rc = a2_scom_ram(scom, thread, 0x7c0007a4, 0); + if (rc) + goto scom_fail; + + /* Next entry is new address? */ + if((i + 1) % assoc == 0) { + epn += (1 << 30); + a2_scom_setspr(scom, thread, SPRN_MAS2, epn); + } + } + + /* Setup args for linear mapping */ + rc = a2_scom_setgpr(scom, thread, 3, 0, MAS0_TLBSEL(0)); + if (rc) + goto scom_fail; + + /* Linear mapping */ + for (p = a2_tlbinit_code_start; p < a2_tlbinit_after_linear_map; p++) { + rc = a2_scom_ram(scom, thread, *p, 0); + if (rc) + goto scom_fail; + } + + /* + * For the boot thread, between the linear mapping and the debug + * mappings there is a loop to flush iprot mappings. Ramming doesn't do + * branches, but the secondary threads don't need to be nearly as smart + * (i.e. we don't need to worry about invalidating the mapping we're + * standing on). + */ + + /* Debug mappings. Expects r11 = MAS0 from linear map (set above) */ + for (p = a2_tlbinit_after_iprot_flush; p < a2_tlbinit_code_end; p++) { + rc = a2_scom_ram(scom, thread, *p, 0); + if (rc) + goto scom_fail; + } + +scom_fail: + if (rc) + pr_err("Setting up initial TLB failed, err %d\n", rc); + + if (rc == -SCOM_RAMC_INTERRUPT) { + /* Interrupt, dump some status */ + int rc[10]; + u64 iar, srr0, srr1, esr, mas0, mas1, mas2, mas7_3, mas8, ccr2; + rc[0] = a2_scom_getspr(scom, thread, SPRN_IAR, &iar); + rc[1] = a2_scom_getspr(scom, thread, SPRN_SRR0, &srr0); + rc[2] = a2_scom_getspr(scom, thread, SPRN_SRR1, &srr1); + rc[3] = a2_scom_getspr(scom, thread, SPRN_ESR, &esr); + rc[4] = a2_scom_getspr(scom, thread, SPRN_MAS0, &mas0); + rc[5] = a2_scom_getspr(scom, thread, SPRN_MAS1, &mas1); + rc[6] = a2_scom_getspr(scom, thread, SPRN_MAS2, &mas2); + rc[7] = a2_scom_getspr(scom, thread, SPRN_MAS7_MAS3, &mas7_3); + rc[8] = a2_scom_getspr(scom, thread, SPRN_MAS8, &mas8); + rc[9] = a2_scom_getspr(scom, thread, SPRN_A2_CCR2, &ccr2); + pr_err(" -> retreived IAR =0x%llx (err %d)\n", iar, rc[0]); + pr_err(" retreived SRR0=0x%llx (err %d)\n", srr0, rc[1]); + pr_err(" retreived SRR1=0x%llx (err %d)\n", srr1, rc[2]); + pr_err(" retreived ESR =0x%llx (err %d)\n", esr, rc[3]); + pr_err(" retreived MAS0=0x%llx (err %d)\n", mas0, rc[4]); + pr_err(" retreived MAS1=0x%llx (err %d)\n", mas1, rc[5]); + pr_err(" retreived MAS2=0x%llx (err %d)\n", mas2, rc[6]); + pr_err(" retreived MS73=0x%llx (err %d)\n", mas7_3, rc[7]); + pr_err(" retreived MAS8=0x%llx (err %d)\n", mas8, rc[8]); + pr_err(" retreived CCR2=0x%llx (err %d)\n", ccr2, rc[9]); + } + + return rc; +} + +int __devinit a2_scom_startup_cpu(unsigned int lcpu, int thr_idx, + struct device_node *np) +{ + u64 init_iar, init_msr, init_ccr2; + unsigned long start_here; + int rc, core_setup; + scom_map_t scom; + u64 pccr0; + + scom = get_scom(lcpu, np, &core_setup); + if (!scom) { + printk(KERN_ERR "Couldn't map SCOM for CPU%d\n", lcpu); + return -1; + } + + pr_devel("Bringing up CPU%d using SCOM...\n", lcpu); + + pccr0 = scom_read(scom, SCOM_PCCR0); + scom_write(scom, SCOM_PCCR0, pccr0 | SCOM_PCCR0_ENABLE_DEBUG | + SCOM_PCCR0_ENABLE_RAM); + + /* Stop the thead with THRCTL. If we are setting up the TLB we stop all + * threads. We also disable asynchronous interrupts while RAMing. + */ + if (core_setup) + scom_write(scom, SCOM_THRCTL_OR, + SCOM_THRCTL_T0_STOP | + SCOM_THRCTL_T1_STOP | + SCOM_THRCTL_T2_STOP | + SCOM_THRCTL_T3_STOP | + SCOM_THRCTL_ASYNC_DIS); + else + scom_write(scom, SCOM_THRCTL_OR, SCOM_THRCTL_T0_STOP >> thr_idx); + + /* Flush its pipeline just in case */ + scom_write(scom, SCOM_RAMC, ((u64)thr_idx << 17) | + SCOM_RAMC_FLUSH | SCOM_RAMC_ENABLE); + + a2_scom_getspr(scom, thr_idx, SPRN_IAR, &init_iar); + a2_scom_getspr(scom, thr_idx, 0x0ff0, &init_msr); + a2_scom_getspr(scom, thr_idx, SPRN_A2_CCR2, &init_ccr2); + + /* Set MSR to MSR_CM (0x0ff0 is magic value for MSR_CM) */ + rc = a2_scom_setspr(scom, thr_idx, 0x0ff0, MSR_CM); + if (rc) { + pr_err("Failed to set MSR ! err %d\n", rc); + return rc; + } + + /* RAM in an sync/isync for the sake of it */ + a2_scom_ram(scom, thr_idx, 0x7c0004ac, 0); + a2_scom_ram(scom, thr_idx, 0x4c00012c, 0); + + if (core_setup) { + pr_devel("CPU%d is first thread in core, initializing TLB...\n", + lcpu); + rc = a2_scom_initial_tlb(scom, thr_idx); + if (rc) + goto fail; + } + + start_here = *(unsigned long *)(core_setup ? generic_secondary_smp_init + : generic_secondary_thread_init); + pr_devel("CPU%d entry point at 0x%lx...\n", lcpu, start_here); + + rc |= a2_scom_setspr(scom, thr_idx, SPRN_IAR, start_here); + rc |= a2_scom_setgpr(scom, thr_idx, 3, 0, + get_hard_smp_processor_id(lcpu)); + /* + * Tell book3e_secondary_core_init not to set up the TLB, we've + * already done that. + */ + rc |= a2_scom_setgpr(scom, thr_idx, 4, 0, 1); + + rc |= a2_scom_setspr(scom, thr_idx, SPRN_TENS, 0x1 << thr_idx); + + scom_write(scom, SCOM_RAMC, 0); + scom_write(scom, SCOM_THRCTL_AND, ~(SCOM_THRCTL_T0_STOP >> thr_idx)); + scom_write(scom, SCOM_PCCR0, pccr0); +fail: + pr_devel(" SCOM initialization %s\n", rc ? "failed" : "succeeded"); + if (rc) { + pr_err("Old IAR=0x%08llx MSR=0x%08llx CCR2=0x%08llx\n", + init_iar, init_msr, init_ccr2); + } + + return rc; +} diff --git a/arch/powerpc/platforms/wsp/scom_wsp.c b/arch/powerpc/platforms/wsp/scom_wsp.c new file mode 100644 index 000000000000..4052e2259f30 --- /dev/null +++ b/arch/powerpc/platforms/wsp/scom_wsp.c @@ -0,0 +1,77 @@ +/* + * SCOM backend for WSP + * + * Copyright 2010 Benjamin Herrenschmidt, IBM Corp. + * + * 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 "wsp.h" + + +static scom_map_t wsp_scom_map(struct device_node *dev, u64 reg, u64 count) +{ + struct resource r; + u64 xscom_addr; + + if (!of_get_property(dev, "scom-controller", NULL)) { + pr_err("%s: device %s is not a SCOM controller\n", + __func__, dev->full_name); + return SCOM_MAP_INVALID; + } + + if (of_address_to_resource(dev, 0, &r)) { + pr_debug("Failed to find SCOM controller address\n"); + return 0; + } + + /* Transform the SCOM address into an XSCOM offset */ + xscom_addr = ((reg & 0x7f000000) >> 1) | ((reg & 0xfffff) << 3); + + return (scom_map_t)ioremap(r.start + xscom_addr, count << 3); +} + +static void wsp_scom_unmap(scom_map_t map) +{ + iounmap((void *)map); +} + +static u64 wsp_scom_read(scom_map_t map, u32 reg) +{ + u64 __iomem *addr = (u64 __iomem *)map; + + return in_be64(addr + reg); +} + +static void wsp_scom_write(scom_map_t map, u32 reg, u64 value) +{ + u64 __iomem *addr = (u64 __iomem *)map; + + return out_be64(addr + reg, value); +} + +static const struct scom_controller wsp_scom_controller = { + .map = wsp_scom_map, + .unmap = wsp_scom_unmap, + .read = wsp_scom_read, + .write = wsp_scom_write +}; + +void scom_init_wsp(void) +{ + scom_init(&wsp_scom_controller); +} diff --git a/arch/powerpc/platforms/wsp/setup.c b/arch/powerpc/platforms/wsp/setup.c new file mode 100644 index 000000000000..11ac2f05e01c --- /dev/null +++ b/arch/powerpc/platforms/wsp/setup.c @@ -0,0 +1,36 @@ +/* + * Copyright 2010 Michael Ellerman, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include + +#include "wsp.h" + +/* + * Find chip-id by walking up device tree looking for ibm,wsp-chip-id property. + * Won't work for nodes that are not a descendant of a wsp node. + */ +int wsp_get_chip_id(struct device_node *dn) +{ + const u32 *p; + int rc; + + /* Start looking at the specified node, not its parent */ + dn = of_node_get(dn); + while (dn && !(p = of_get_property(dn, "ibm,wsp-chip-id", NULL))) + dn = of_get_next_parent(dn); + + if (!dn) + return -1; + + rc = *p; + of_node_put(dn); + + return rc; +} diff --git a/arch/powerpc/platforms/wsp/smp.c b/arch/powerpc/platforms/wsp/smp.c new file mode 100644 index 000000000000..9d20fa9d3710 --- /dev/null +++ b/arch/powerpc/platforms/wsp/smp.c @@ -0,0 +1,88 @@ +/* + * SMP Support for A2 platforms + * + * Copyright 2007 Benjamin Herrenschmidt, IBM Corp. + * + * 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 "ics.h" +#include "wsp.h" + +static void __devinit smp_a2_setup_cpu(int cpu) +{ + doorbell_setup_this_cpu(); + + if (cpu != boot_cpuid) + xics_setup_cpu(); +} + +int __devinit smp_a2_kick_cpu(int nr) +{ + const char *enable_method; + struct device_node *np; + int thr_idx; + + if (nr < 0 || nr >= NR_CPUS) + return -ENOENT; + + np = of_get_cpu_node(nr, &thr_idx); + if (!np) + return -ENODEV; + + enable_method = of_get_property(np, "enable-method", NULL); + pr_devel("CPU%d has enable-method: \"%s\"\n", nr, enable_method); + + if (!enable_method) { + printk(KERN_ERR "CPU%d has no enable-method\n", nr); + return -ENOENT; + } else if (strcmp(enable_method, "ibm,a2-scom") == 0) { + if (a2_scom_startup_cpu(nr, thr_idx, np)) + return -1; + } else { + printk(KERN_ERR "CPU%d: Don't understand enable-method \"%s\"\n", + nr, enable_method); + return -EINVAL; + } + + /* + * The processor is currently spinning, waiting for the + * cpu_start field to become non-zero After we set cpu_start, + * the processor will continue on to secondary_start + */ + paca[nr].cpu_start = 1; + + return 0; +} + +static int __init smp_a2_probe(void) +{ + return cpus_weight(cpu_possible_map); +} + +static struct smp_ops_t a2_smp_ops = { + .message_pass = smp_muxed_ipi_message_pass, + .cause_ipi = doorbell_cause_ipi, + .probe = smp_a2_probe, + .kick_cpu = smp_a2_kick_cpu, + .setup_cpu = smp_a2_setup_cpu, +}; + +void __init a2_setup_smp(void) +{ + smp_ops = &a2_smp_ops; +} diff --git a/arch/powerpc/platforms/wsp/wsp.h b/arch/powerpc/platforms/wsp/wsp.h new file mode 100644 index 000000000000..7c3e087fd2f2 --- /dev/null +++ b/arch/powerpc/platforms/wsp/wsp.h @@ -0,0 +1,17 @@ +#ifndef __WSP_H +#define __WSP_H + +#include + +extern void wsp_setup_pci(void); +extern void scom_init_wsp(void); + +extern void a2_setup_smp(void); +extern int a2_scom_startup_cpu(unsigned int lcpu, int thr_idx, + struct device_node *np); +int smp_a2_cpu_bootable(unsigned int nr); +int __devinit smp_a2_kick_cpu(int nr); + +void opb_pic_init(void); + +#endif /* __WSP_H */ diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 396582835cb5..d775fd148d13 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -12,3 +12,13 @@ config PPC_MSI_BITMAP depends on PCI_MSI default y if MPIC default y if FSL_PCI + +source "arch/powerpc/sysdev/xics/Kconfig" + +config PPC_SCOM + bool + +config SCOM_DEBUGFS + bool "Expose SCOM controllers via debugfs" + depends on PPC_SCOM + default n diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 1e0c933ef772..6076e0074a87 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -57,3 +57,9 @@ obj-$(CONFIG_PPC_MPC52xx) += mpc5xxx_clocks.o ifeq ($(CONFIG_SUSPEND),y) obj-$(CONFIG_6xx) += 6xx-suspend.o endif + +obj-$(CONFIG_PPC_SCOM) += scom.o + +subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror + +obj-$(CONFIG_PPC_XICS) += xics/ diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 1636dd896707..bd0d54060b94 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -216,7 +216,7 @@ static int axon_ram_probe(struct platform_device *device) AXON_RAM_DEVICE_NAME, axon_ram_bank_id, bank->size >> 20); bank->ph_addr = resource.start; - bank->io_addr = (unsigned long) ioremap_flags( + bank->io_addr = (unsigned long) ioremap_prot( bank->ph_addr, bank->size, _PAGE_NO_CACHE); if (bank->io_addr == 0) { dev_err(&device->dev, "ioremap() failed\n"); diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index e0bc944eb23f..350787c83e22 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -58,21 +58,21 @@ static struct irq_host *cpm_pic_host; static void cpm_mask_irq(struct irq_data *d) { - unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq; + unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); } static void cpm_unmask_irq(struct irq_data *d) { - unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq; + unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); } static void cpm_end_irq(struct irq_data *d) { - unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq; + unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec)); } @@ -157,7 +157,7 @@ unsigned int cpm_pic_init(void) goto end; /* Initialize the CPM interrupt controller. */ - hwirq = (unsigned int)irq_map[sirq].hwirq; + hwirq = (unsigned int)virq_to_hw(sirq); out_be32(&cpic_reg->cpic_cicr, (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | ((hwirq/2) << 13) | CICR_HP_MASK); diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index 5495c1be472b..bcab50e2a9eb 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -81,7 +81,7 @@ static const u_char irq_to_siubit[] = { static void cpm2_mask_irq(struct irq_data *d) { int bit, word; - unsigned int irq_nr = virq_to_hw(d->irq); + unsigned int irq_nr = irqd_to_hwirq(d); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; @@ -93,7 +93,7 @@ static void cpm2_mask_irq(struct irq_data *d) static void cpm2_unmask_irq(struct irq_data *d) { int bit, word; - unsigned int irq_nr = virq_to_hw(d->irq); + unsigned int irq_nr = irqd_to_hwirq(d); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; @@ -105,7 +105,7 @@ static void cpm2_unmask_irq(struct irq_data *d) static void cpm2_ack(struct irq_data *d) { int bit, word; - unsigned int irq_nr = virq_to_hw(d->irq); + unsigned int irq_nr = irqd_to_hwirq(d); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; @@ -116,7 +116,7 @@ static void cpm2_ack(struct irq_data *d) static void cpm2_end_irq(struct irq_data *d) { int bit, word; - unsigned int irq_nr = virq_to_hw(d->irq); + unsigned int irq_nr = irqd_to_hwirq(d); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; @@ -133,7 +133,7 @@ static void cpm2_end_irq(struct irq_data *d) static int cpm2_set_irq_type(struct irq_data *d, unsigned int flow_type) { - unsigned int src = virq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned int vold, vnew, edibit; /* Port C interrupts are either IRQ_TYPE_EDGE_FALLING or diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c index 54fb1922fe30..116415899176 100644 --- a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c +++ b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c @@ -106,10 +106,10 @@ int __init instantiate_cache_sram(struct platform_device *dev, goto out_free; } - cache_sram->base_virt = ioremap_flags(cache_sram->base_phys, + cache_sram->base_virt = ioremap_prot(cache_sram->base_phys, cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL); if (!cache_sram->base_virt) { - dev_err(&dev->dev, "%s: ioremap_flags failed\n", + dev_err(&dev->dev, "%s: ioremap_prot failed\n", dev->dev.of_node->full_name); ret = -ENOMEM; goto out_release; diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index d5679dc1e20f..92e78333c47c 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -110,7 +110,7 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev) list_for_each_entry(entry, &pdev->msi_list, list) { if (entry->irq == NO_IRQ) continue; - msi_data = irq_get_handler_data(entry->irq); + msi_data = irq_get_chip_data(entry->irq); irq_set_msi_desc(entry->irq, NULL); msi_bitmap_free_hwirqs(&msi_data->bitmap, virq_to_hw(entry->irq), 1); @@ -168,7 +168,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) rc = -ENOSPC; goto out_free; } - irq_set_handler_data(virq, msi_data); + /* chip_data is msi_data via host->hostdata in host->map() */ irq_set_msi_desc(virq, entry); fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data); @@ -193,7 +193,7 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) u32 have_shift = 0; struct fsl_msi_cascade_data *cascade_data; - cascade_data = (struct fsl_msi_cascade_data *)irq_get_handler_data(irq); + cascade_data = irq_get_handler_data(irq); msi_data = cascade_data->msi_data; raw_spin_lock(&desc->lock); @@ -253,7 +253,7 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) static int fsl_of_msi_remove(struct platform_device *ofdev) { - struct fsl_msi *msi = ofdev->dev.platform_data; + struct fsl_msi *msi = platform_get_drvdata(ofdev); int virq, i; struct fsl_msi_cascade_data *cascade_data; @@ -304,8 +304,10 @@ static int __devinit fsl_msi_setup_hwirq(struct fsl_msi *msi, return 0; } +static const struct of_device_id fsl_of_msi_ids[]; static int __devinit fsl_of_msi_probe(struct platform_device *dev) { + const struct of_device_id *match; struct fsl_msi *msi; struct resource res; int err, i, j, irq_index, count; @@ -316,9 +318,10 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) u32 offset; static const u32 all_avail[] = { 0, NR_MSI_IRQS }; - if (!dev->dev.of_match) + match = of_match_device(fsl_of_msi_ids, &dev->dev); + if (!match) return -EINVAL; - features = dev->dev.of_match->data; + features = match->data; printk(KERN_DEBUG "Setting up Freescale MSI support\n"); @@ -327,7 +330,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) dev_err(&dev->dev, "No memory for MSI structure\n"); return -ENOMEM; } - dev->dev.platform_data = msi; + platform_set_drvdata(dev, msi); msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR, NR_MSI_IRQS, &fsl_msi_host_ops, 0); diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index f8f7f28c6343..68ca9290df94 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -324,6 +324,11 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) struct resource rsrc; const int *bus_range; + if (!of_device_is_available(dev)) { + pr_warning("%s: disabled\n", dev->full_name); + return -ENODEV; + } + pr_debug("Adding PCI host bridge %s\n", dev->full_name); /* Fetch host bridge registers address */ diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index 142770cb84b6..d18bb27e4df9 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -185,18 +185,6 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq, return 0; } -static void i8259_host_unmap(struct irq_host *h, unsigned int virq) -{ - /* Make sure irq is masked in hardware */ - i8259_mask_irq(irq_get_irq_data(virq)); - - /* remove chip and handler */ - irq_set_chip_and_handler(virq, NULL, NULL); - - /* Make sure it's completed */ - synchronize_irq(virq); -} - static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -220,7 +208,6 @@ static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, static struct irq_host_ops i8259_host_ops = { .match = i8259_host_match, .map = i8259_host_map, - .unmap = i8259_host_unmap, .xlate = i8259_host_xlate, }; diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index fa438be962b7..7367d17364cb 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -521,12 +521,10 @@ static inline struct ipic * ipic_from_irq(unsigned int virq) return primary_ipic; } -#define ipic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) - static void ipic_unmask_irq(struct irq_data *d) { struct ipic *ipic = ipic_from_irq(d->irq); - unsigned int src = ipic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; @@ -542,7 +540,7 @@ static void ipic_unmask_irq(struct irq_data *d) static void ipic_mask_irq(struct irq_data *d) { struct ipic *ipic = ipic_from_irq(d->irq); - unsigned int src = ipic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; @@ -562,7 +560,7 @@ static void ipic_mask_irq(struct irq_data *d) static void ipic_ack_irq(struct irq_data *d) { struct ipic *ipic = ipic_from_irq(d->irq); - unsigned int src = ipic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; @@ -581,7 +579,7 @@ static void ipic_ack_irq(struct irq_data *d) static void ipic_mask_irq_and_ack(struct irq_data *d) { struct ipic *ipic = ipic_from_irq(d->irq); - unsigned int src = ipic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; @@ -604,7 +602,7 @@ static void ipic_mask_irq_and_ack(struct irq_data *d) static int ipic_set_irq_type(struct irq_data *d, unsigned int flow_type) { struct ipic *ipic = ipic_from_irq(d->irq); - unsigned int src = ipic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned int vold, vnew, edibit; if (flow_type == IRQ_TYPE_NONE) @@ -793,7 +791,7 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) int ipic_set_priority(unsigned int virq, unsigned int priority) { struct ipic *ipic = ipic_from_irq(virq); - unsigned int src = ipic_irq_to_hw(virq); + unsigned int src = virq_to_hw(virq); u32 temp; if (priority > 7) @@ -821,7 +819,7 @@ int ipic_set_priority(unsigned int virq, unsigned int priority) void ipic_set_highest_priority(unsigned int virq) { struct ipic *ipic = ipic_from_irq(virq); - unsigned int src = ipic_irq_to_hw(virq); + unsigned int src = virq_to_hw(virq); u32 temp; temp = ipic_read(ipic->regs, IPIC_SICFR); @@ -902,7 +900,7 @@ static struct { u32 sercr; } ipic_saved_state; -static int ipic_suspend(struct sys_device *sdev, pm_message_t state) +static int ipic_suspend(void) { struct ipic *ipic = primary_ipic; @@ -933,7 +931,7 @@ static int ipic_suspend(struct sys_device *sdev, pm_message_t state) return 0; } -static int ipic_resume(struct sys_device *sdev) +static void ipic_resume(void) { struct ipic *ipic = primary_ipic; @@ -949,44 +947,26 @@ static int ipic_resume(struct sys_device *sdev) ipic_write(ipic->regs, IPIC_SECNR, ipic_saved_state.secnr); ipic_write(ipic->regs, IPIC_SERMR, ipic_saved_state.sermr); ipic_write(ipic->regs, IPIC_SERCR, ipic_saved_state.sercr); - - return 0; } #else #define ipic_suspend NULL #define ipic_resume NULL #endif -static struct sysdev_class ipic_sysclass = { - .name = "ipic", +static struct syscore_ops ipic_syscore_ops = { .suspend = ipic_suspend, .resume = ipic_resume, }; -static struct sys_device device_ipic = { - .id = 0, - .cls = &ipic_sysclass, -}; - -static int __init init_ipic_sysfs(void) +static int __init init_ipic_syscore(void) { - int rc; - if (!primary_ipic || !primary_ipic->regs) return -ENODEV; - printk(KERN_DEBUG "Registering ipic with sysfs...\n"); - rc = sysdev_class_register(&ipic_sysclass); - if (rc) { - printk(KERN_ERR "Failed registering ipic sys class\n"); - return -ENODEV; - } - rc = sysdev_register(&device_ipic); - if (rc) { - printk(KERN_ERR "Failed registering ipic sys device\n"); - return -ENODEV; - } + printk(KERN_DEBUG "Registering ipic system core operations\n"); + register_syscore_ops(&ipic_syscore_ops); + return 0; } -subsys_initcall(init_ipic_sysfs); +subsys_initcall(init_ipic_syscore); diff --git a/arch/powerpc/sysdev/mmio_nvram.c b/arch/powerpc/sysdev/mmio_nvram.c index 207324209065..ddc877a3a23a 100644 --- a/arch/powerpc/sysdev/mmio_nvram.c +++ b/arch/powerpc/sysdev/mmio_nvram.c @@ -115,6 +115,8 @@ int __init mmio_nvram_init(void) int ret; nvram_node = of_find_node_by_type(NULL, "nvram"); + if (!nvram_node) + nvram_node = of_find_compatible_node(NULL, NULL, "nvram"); if (!nvram_node) { printk(KERN_WARNING "nvram: no node found in device-tree\n"); return -ENODEV; diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index a88800ff4d01..20924f2246f0 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -28,7 +28,7 @@ int cpm_get_irq(struct pt_regs *regs); static void mpc8xx_unmask_irq(struct irq_data *d) { int bit, word; - unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq; + unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); bit = irq_nr & 0x1f; word = irq_nr >> 5; @@ -40,7 +40,7 @@ static void mpc8xx_unmask_irq(struct irq_data *d) static void mpc8xx_mask_irq(struct irq_data *d) { int bit, word; - unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq; + unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); bit = irq_nr & 0x1f; word = irq_nr >> 5; @@ -52,7 +52,7 @@ static void mpc8xx_mask_irq(struct irq_data *d) static void mpc8xx_ack(struct irq_data *d) { int bit; - unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq; + unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); bit = irq_nr & 0x1f; out_be32(&siu_reg->sc_sipend, 1 << (31-bit)); @@ -61,7 +61,7 @@ static void mpc8xx_ack(struct irq_data *d) static void mpc8xx_end_irq(struct irq_data *d) { int bit, word; - unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq; + unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); bit = irq_nr & 0x1f; word = irq_nr >> 5; @@ -73,7 +73,7 @@ static void mpc8xx_end_irq(struct irq_data *d) static int mpc8xx_set_irq_type(struct irq_data *d, unsigned int flow_type) { if (flow_type & IRQ_TYPE_EDGE_FALLING) { - irq_hw_number_t hw = (unsigned int)irq_map[d->irq].hwirq; + irq_hw_number_t hw = (unsigned int)irqd_to_hwirq(d); unsigned int siel = in_be32(&siu_reg->sc_siel); /* only external IRQ senses are programmable */ diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c index 0892a2841c2b..fb4963abdf55 100644 --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c @@ -163,7 +163,7 @@ static void mpc8xxx_irq_unmask(struct irq_data *d) spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(d->irq))); + setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } @@ -176,7 +176,7 @@ static void mpc8xxx_irq_mask(struct irq_data *d) spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(d->irq))); + clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } @@ -186,7 +186,7 @@ static void mpc8xxx_irq_ack(struct irq_data *d) struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; - out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(virq_to_hw(d->irq))); + out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); } static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) @@ -199,14 +199,14 @@ static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) case IRQ_TYPE_EDGE_FALLING: spin_lock_irqsave(&mpc8xxx_gc->lock, flags); setbits32(mm->regs + GPIO_ICR, - mpc8xxx_gpio2mask(virq_to_hw(d->irq))); + mpc8xxx_gpio2mask(irqd_to_hwirq(d))); spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; case IRQ_TYPE_EDGE_BOTH: spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(mm->regs + GPIO_ICR, - mpc8xxx_gpio2mask(virq_to_hw(d->irq))); + mpc8xxx_gpio2mask(irqd_to_hwirq(d))); spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; @@ -221,7 +221,7 @@ static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type) { struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; - unsigned long gpio = virq_to_hw(d->irq); + unsigned long gpio = irqd_to_hwirq(d); void __iomem *reg; unsigned int shift; unsigned long flags; diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index f91c065bed5a..3a8de5bb628a 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -6,6 +6,7 @@ * with various broken implementations of this HW. * * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. + * Copyright 2010-2011 Freescale Semiconductor, Inc. * * 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 @@ -27,6 +28,7 @@ #include #include #include +#include #include #include @@ -218,6 +220,28 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); } +static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm) +{ + unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + + ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); + + if (tm >= 4) + offset += 0x1000 / 4; + + return _mpic_read(mpic->reg_type, &mpic->tmregs, offset); +} + +static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value) +{ + unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + + ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); + + if (tm >= 4) + offset += 0x1000 / 4; + + _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value); +} + static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) { unsigned int cpu = mpic_processor_id(mpic); @@ -268,6 +292,8 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v)) #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) +#define mpic_tm_read(i) _mpic_tm_read(mpic,(i)) +#define mpic_tm_write(i,v) _mpic_tm_write(mpic,(i),(v)) #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) #define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) #define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) @@ -607,8 +633,6 @@ static int irq_choose_cpu(const struct cpumask *mask) } #endif -#define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) - /* Find an mpic associated with a given linux interrupt */ static struct mpic *mpic_find(unsigned int irq) { @@ -621,11 +645,18 @@ static struct mpic *mpic_find(unsigned int irq) /* Determine if the linux irq is an IPI */ static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq) { - unsigned int src = mpic_irq_to_hw(irq); + unsigned int src = virq_to_hw(irq); return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); } +/* Determine if the linux irq is a timer */ +static unsigned int mpic_is_tm(struct mpic *mpic, unsigned int irq) +{ + unsigned int src = virq_to_hw(irq); + + return (src >= mpic->timer_vecs[0] && src <= mpic->timer_vecs[7]); +} /* Convert a cpu mask from logical to physical cpu numbers. */ static inline u32 mpic_physmask(u32 cpumask) @@ -633,7 +664,7 @@ static inline u32 mpic_physmask(u32 cpumask) int i; u32 mask = 0; - for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1) + for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1) mask |= (cpumask & 1) << get_hard_smp_processor_id(i); return mask; } @@ -674,7 +705,7 @@ void mpic_unmask_irq(struct irq_data *d) { unsigned int loops = 100000; struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, d->irq, src); @@ -695,7 +726,7 @@ void mpic_mask_irq(struct irq_data *d) { unsigned int loops = 100000; struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); DBG("%s: disable_irq: %d (src %d)\n", mpic->name, d->irq, src); @@ -733,7 +764,7 @@ void mpic_end_irq(struct irq_data *d) static void mpic_unmask_ht_irq(struct irq_data *d) { struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); mpic_unmask_irq(d); @@ -744,7 +775,7 @@ static void mpic_unmask_ht_irq(struct irq_data *d) static unsigned int mpic_startup_ht_irq(struct irq_data *d) { struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); mpic_unmask_irq(d); mpic_startup_ht_interrupt(mpic, src, irqd_is_level_type(d)); @@ -755,7 +786,7 @@ static unsigned int mpic_startup_ht_irq(struct irq_data *d) static void mpic_shutdown_ht_irq(struct irq_data *d) { struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); mpic_shutdown_ht_interrupt(mpic, src); mpic_mask_irq(d); @@ -764,7 +795,7 @@ static void mpic_shutdown_ht_irq(struct irq_data *d) static void mpic_end_ht_irq(struct irq_data *d) { struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); #ifdef DEBUG_IRQ DBG("%s: end_irq: %d\n", mpic->name, d->irq); @@ -785,7 +816,7 @@ static void mpic_end_ht_irq(struct irq_data *d) static void mpic_unmask_ipi(struct irq_data *d) { struct mpic *mpic = mpic_from_ipi(d); - unsigned int src = mpic_irq_to_hw(d->irq) - mpic->ipi_vecs[0]; + unsigned int src = virq_to_hw(d->irq) - mpic->ipi_vecs[0]; DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, d->irq, src); mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); @@ -812,27 +843,42 @@ static void mpic_end_ipi(struct irq_data *d) #endif /* CONFIG_SMP */ +static void mpic_unmask_tm(struct irq_data *d) +{ + struct mpic *mpic = mpic_from_irq_data(d); + unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; + + DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, irq, src); + mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK); + mpic_tm_read(src); +} + +static void mpic_mask_tm(struct irq_data *d) +{ + struct mpic *mpic = mpic_from_irq_data(d); + unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; + + mpic_tm_write(src, mpic_tm_read(src) | MPIC_VECPRI_MASK); + mpic_tm_read(src); +} + int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force) { struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); if (mpic->flags & MPIC_SINGLE_DEST_CPU) { int cpuid = irq_choose_cpu(cpumask); mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); } else { - cpumask_var_t tmp; + u32 mask = cpumask_bits(cpumask)[0]; - alloc_cpumask_var(&tmp, GFP_KERNEL); - - cpumask_and(tmp, cpumask, cpu_online_mask); + mask &= cpumask_bits(cpu_online_mask)[0]; mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), - mpic_physmask(cpumask_bits(tmp)[0])); - - free_cpumask_var(tmp); + mpic_physmask(mask)); } return 0; @@ -862,7 +908,7 @@ static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) { struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned int vecpri, vold, vnew; DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", @@ -898,7 +944,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) void mpic_set_vector(unsigned int virq, unsigned int vector) { struct mpic *mpic = mpic_from_irq(virq); - unsigned int src = mpic_irq_to_hw(virq); + unsigned int src = virq_to_hw(virq); unsigned int vecpri; DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", @@ -916,7 +962,7 @@ void mpic_set_vector(unsigned int virq, unsigned int vector) void mpic_set_destination(unsigned int virq, unsigned int cpuid) { struct mpic *mpic = mpic_from_irq(virq); - unsigned int src = mpic_irq_to_hw(virq); + unsigned int src = virq_to_hw(virq); DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", mpic, virq, src, cpuid); @@ -942,6 +988,12 @@ static struct irq_chip mpic_ipi_chip = { }; #endif /* CONFIG_SMP */ +static struct irq_chip mpic_tm_chip = { + .irq_mask = mpic_mask_tm, + .irq_unmask = mpic_unmask_tm, + .irq_eoi = mpic_end_irq, +}; + #ifdef CONFIG_MPIC_U3_HT_IRQS static struct irq_chip mpic_irq_ht_chip = { .irq_startup = mpic_startup_ht_irq, @@ -985,6 +1037,16 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, } #endif /* CONFIG_SMP */ + if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) { + WARN_ON(!(mpic->flags & MPIC_PRIMARY)); + + DBG("mpic: mapping as timer\n"); + irq_set_chip_data(virq, mpic); + irq_set_chip_and_handler(virq, &mpic->hc_tm, + handle_fasteoi_irq); + return 0; + } + if (hw >= mpic->irq_count) return -EINVAL; @@ -1025,6 +1087,7 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { + struct mpic *mpic = h->host_data; static unsigned char map_mpic_senses[4] = { IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW, @@ -1033,7 +1096,38 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, }; *out_hwirq = intspec[0]; - if (intsize > 1) { + if (intsize >= 4 && (mpic->flags & MPIC_FSL)) { + /* + * Freescale MPIC with extended intspec: + * First two cells are as usual. Third specifies + * an "interrupt type". Fourth is type-specific data. + * + * See Documentation/devicetree/bindings/powerpc/fsl/mpic.txt + */ + switch (intspec[2]) { + case 0: + case 1: /* no EISR/EIMR support for now, treat as shared IRQ */ + break; + case 2: + if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs)) + return -EINVAL; + + *out_hwirq = mpic->ipi_vecs[intspec[0]]; + break; + case 3: + if (intspec[0] >= ARRAY_SIZE(mpic->timer_vecs)) + return -EINVAL; + + *out_hwirq = mpic->timer_vecs[intspec[0]]; + break; + default: + pr_debug("%s: unknown irq type %u\n", + __func__, intspec[2]); + return -EINVAL; + } + + *out_flags = map_mpic_senses[intspec[1] & 3]; + } else if (intsize > 1) { u32 mask = 0x3; /* Apple invented a new race of encoding on machines with @@ -1109,6 +1203,9 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->hc_ipi.name = name; #endif /* CONFIG_SMP */ + mpic->hc_tm = mpic_tm_chip; + mpic->hc_tm.name = name; + mpic->flags = flags; mpic->isu_size = isu_size; mpic->irq_count = irq_count; @@ -1119,10 +1216,14 @@ struct mpic * __init mpic_alloc(struct device_node *node, else intvec_top = 255; - mpic->timer_vecs[0] = intvec_top - 8; - mpic->timer_vecs[1] = intvec_top - 7; - mpic->timer_vecs[2] = intvec_top - 6; - mpic->timer_vecs[3] = intvec_top - 5; + mpic->timer_vecs[0] = intvec_top - 12; + mpic->timer_vecs[1] = intvec_top - 11; + mpic->timer_vecs[2] = intvec_top - 10; + mpic->timer_vecs[3] = intvec_top - 9; + mpic->timer_vecs[4] = intvec_top - 8; + mpic->timer_vecs[5] = intvec_top - 7; + mpic->timer_vecs[6] = intvec_top - 6; + mpic->timer_vecs[7] = intvec_top - 5; mpic->ipi_vecs[0] = intvec_top - 4; mpic->ipi_vecs[1] = intvec_top - 3; mpic->ipi_vecs[2] = intvec_top - 2; @@ -1132,6 +1233,8 @@ struct mpic * __init mpic_alloc(struct device_node *node, /* Check for "big-endian" in device-tree */ if (node && of_get_property(node, "big-endian", NULL) != NULL) mpic->flags |= MPIC_BIG_ENDIAN; + if (node && of_device_is_compatible(node, "fsl,mpic")) + mpic->flags |= MPIC_FSL; /* Look for protected sources */ if (node) { @@ -1323,15 +1426,17 @@ void __init mpic_init(struct mpic *mpic) /* Set current processor priority to max */ mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); - /* Initialize timers: just disable them all */ + /* Initialize timers to our reserved vectors and mask them for now */ for (i = 0; i < 4; i++) { mpic_write(mpic->tmregs, i * MPIC_INFO(TIMER_STRIDE) + - MPIC_INFO(TIMER_DESTINATION), 0); + MPIC_INFO(TIMER_DESTINATION), + 1 << hard_smp_processor_id()); mpic_write(mpic->tmregs, i * MPIC_INFO(TIMER_STRIDE) + MPIC_INFO(TIMER_VECTOR_PRI), MPIC_VECPRI_MASK | + (9 << MPIC_VECPRI_PRIORITY_SHIFT) | (mpic->timer_vecs[0] + i)); } @@ -1427,7 +1532,7 @@ void __init mpic_set_serial_int(struct mpic *mpic, int enable) void mpic_irq_set_priority(unsigned int irq, unsigned int pri) { struct mpic *mpic = mpic_find(irq); - unsigned int src = mpic_irq_to_hw(irq); + unsigned int src = virq_to_hw(irq); unsigned long flags; u32 reg; @@ -1440,6 +1545,11 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri) ~MPIC_VECPRI_PRIORITY_MASK; mpic_ipi_write(src - mpic->ipi_vecs[0], reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); + } else if (mpic_is_tm(mpic, irq)) { + reg = mpic_tm_read(src - mpic->timer_vecs[0]) & + ~MPIC_VECPRI_PRIORITY_MASK; + mpic_tm_write(src - mpic->timer_vecs[0], + reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); } else { reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & ~MPIC_VECPRI_PRIORITY_MASK; @@ -1619,46 +1729,28 @@ void mpic_request_ipis(void) } } -static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask) +void smp_mpic_message_pass(int cpu, int msg) { struct mpic *mpic = mpic_primary; + u32 physmask; BUG_ON(mpic == NULL); -#ifdef DEBUG_IPI - DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); -#endif - - mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + - ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), - mpic_physmask(cpumask_bits(cpu_mask)[0])); -} - -void smp_mpic_message_pass(int target, int msg) -{ - cpumask_var_t tmp; - /* make sure we're sending something that translates to an IPI */ if ((unsigned int)msg > 3) { printk("SMP %d: smp_message_pass: unknown msg %d\n", smp_processor_id(), msg); return; } - switch (target) { - case MSG_ALL: - mpic_send_ipi(msg, cpu_online_mask); - break; - case MSG_ALL_BUT_SELF: - alloc_cpumask_var(&tmp, GFP_NOWAIT); - cpumask_andnot(tmp, cpu_online_mask, - cpumask_of(smp_processor_id())); - mpic_send_ipi(msg, tmp); - free_cpumask_var(tmp); - break; - default: - mpic_send_ipi(msg, cpumask_of(target)); - break; - } + +#ifdef DEBUG_IPI + DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, msg); +#endif + + physmask = 1 << get_hard_smp_processor_id(cpu); + + mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + + msg * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), physmask); } int __init smp_mpic_probe(void) @@ -1702,9 +1794,8 @@ void mpic_reset_core(int cpu) #endif /* CONFIG_SMP */ #ifdef CONFIG_PM -static int mpic_suspend(struct sys_device *dev, pm_message_t state) +static void mpic_suspend_one(struct mpic *mpic) { - struct mpic *mpic = container_of(dev, struct mpic, sysdev); int i; for (i = 0; i < mpic->num_sources; i++) { @@ -1713,13 +1804,22 @@ static int mpic_suspend(struct sys_device *dev, pm_message_t state) mpic->save_data[i].dest = mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); } +} + +static int mpic_suspend(void) +{ + struct mpic *mpic = mpics; + + while (mpic) { + mpic_suspend_one(mpic); + mpic = mpic->next; + } return 0; } -static int mpic_resume(struct sys_device *dev) +static void mpic_resume_one(struct mpic *mpic) { - struct mpic *mpic = container_of(dev, struct mpic, sysdev); int i; for (i = 0; i < mpic->num_sources; i++) { @@ -1746,33 +1846,28 @@ static int mpic_resume(struct sys_device *dev) } #endif } /* end for loop */ - - return 0; } -#endif -static struct sysdev_class mpic_sysclass = { -#ifdef CONFIG_PM +static void mpic_resume(void) +{ + struct mpic *mpic = mpics; + + while (mpic) { + mpic_resume_one(mpic); + mpic = mpic->next; + } +} + +static struct syscore_ops mpic_syscore_ops = { .resume = mpic_resume, .suspend = mpic_suspend, -#endif - .name = "mpic", }; static int mpic_init_sys(void) { - struct mpic *mpic = mpics; - int error, id = 0; - - error = sysdev_class_register(&mpic_sysclass); - - while (mpic && !error) { - mpic->sysdev.cls = &mpic_sysclass; - mpic->sysdev.id = id++; - error = sysdev_register(&mpic->sysdev); - mpic = mpic->next; - } - return error; + register_syscore_ops(&mpic_syscore_ops); + return 0; } device_initcall(mpic_init_sys); +#endif diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c index e9c633c7c083..14d130268e7a 100644 --- a/arch/powerpc/sysdev/mv64x60_pic.c +++ b/arch/powerpc/sysdev/mv64x60_pic.c @@ -78,7 +78,7 @@ static struct irq_host *mv64x60_irq_host; static void mv64x60_mask_low(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); @@ -91,7 +91,7 @@ static void mv64x60_mask_low(struct irq_data *d) static void mv64x60_unmask_low(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); @@ -115,7 +115,7 @@ static struct irq_chip mv64x60_chip_low = { static void mv64x60_mask_high(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); @@ -128,7 +128,7 @@ static void mv64x60_mask_high(struct irq_data *d) static void mv64x60_unmask_high(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); @@ -152,7 +152,7 @@ static struct irq_chip mv64x60_chip_high = { static void mv64x60_mask_gpp(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); @@ -165,7 +165,7 @@ static void mv64x60_mask_gpp(struct irq_data *d) static void mv64x60_mask_ack_gpp(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); @@ -180,7 +180,7 @@ static void mv64x60_mask_ack_gpp(struct irq_data *d) static void mv64x60_unmask_gpp(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 832d6924ad1c..b2acda07220d 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -197,12 +197,10 @@ static inline struct qe_ic *qe_ic_from_irq_data(struct irq_data *d) return irq_data_get_irq_chip_data(d); } -#define virq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) - static void qe_ic_unmask_irq(struct irq_data *d) { struct qe_ic *qe_ic = qe_ic_from_irq_data(d); - unsigned int src = virq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; @@ -218,7 +216,7 @@ static void qe_ic_unmask_irq(struct irq_data *d) static void qe_ic_mask_irq(struct irq_data *d) { struct qe_ic *qe_ic = qe_ic_from_irq_data(d); - unsigned int src = virq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; diff --git a/arch/powerpc/sysdev/scom.c b/arch/powerpc/sysdev/scom.c new file mode 100644 index 000000000000..b2593ce30c9b --- /dev/null +++ b/arch/powerpc/sysdev/scom.c @@ -0,0 +1,192 @@ +/* + * Copyright 2010 Benjamin Herrenschmidt, IBM Corp + * + * and David Gibson, IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 + +const struct scom_controller *scom_controller; +EXPORT_SYMBOL_GPL(scom_controller); + +struct device_node *scom_find_parent(struct device_node *node) +{ + struct device_node *par, *tmp; + const u32 *p; + + for (par = of_node_get(node); par;) { + if (of_get_property(par, "scom-controller", NULL)) + break; + p = of_get_property(par, "scom-parent", NULL); + tmp = par; + if (p == NULL) + par = of_get_parent(par); + else + par = of_find_node_by_phandle(*p); + of_node_put(tmp); + } + return par; +} +EXPORT_SYMBOL_GPL(scom_find_parent); + +scom_map_t scom_map_device(struct device_node *dev, int index) +{ + struct device_node *parent; + unsigned int cells, size; + const u32 *prop; + u64 reg, cnt; + scom_map_t ret; + + parent = scom_find_parent(dev); + + if (parent == NULL) + return 0; + + prop = of_get_property(parent, "#scom-cells", NULL); + cells = prop ? *prop : 1; + + prop = of_get_property(dev, "scom-reg", &size); + if (!prop) + return 0; + size >>= 2; + + if (index >= (size / (2*cells))) + return 0; + + reg = of_read_number(&prop[index * cells * 2], cells); + cnt = of_read_number(&prop[index * cells * 2 + cells], cells); + + ret = scom_map(parent, reg, cnt); + of_node_put(parent); + + return ret; +} +EXPORT_SYMBOL_GPL(scom_map_device); + +#ifdef CONFIG_SCOM_DEBUGFS +struct scom_debug_entry { + struct device_node *dn; + unsigned long addr; + scom_map_t map; + spinlock_t lock; + char name[8]; + struct debugfs_blob_wrapper blob; +}; + +static int scom_addr_set(void *data, u64 val) +{ + struct scom_debug_entry *ent = data; + + ent->addr = 0; + scom_unmap(ent->map); + + ent->map = scom_map(ent->dn, val, 1); + if (scom_map_ok(ent->map)) + ent->addr = val; + else + return -EFAULT; + + return 0; +} + +static int scom_addr_get(void *data, u64 *val) +{ + struct scom_debug_entry *ent = data; + *val = ent->addr; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(scom_addr_fops, scom_addr_get, scom_addr_set, + "0x%llx\n"); + +static int scom_val_set(void *data, u64 val) +{ + struct scom_debug_entry *ent = data; + + if (!scom_map_ok(ent->map)) + return -EFAULT; + + scom_write(ent->map, 0, val); + + return 0; +} + +static int scom_val_get(void *data, u64 *val) +{ + struct scom_debug_entry *ent = data; + + if (!scom_map_ok(ent->map)) + return -EFAULT; + + *val = scom_read(ent->map, 0); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(scom_val_fops, scom_val_get, scom_val_set, + "0x%llx\n"); + +static int scom_debug_init_one(struct dentry *root, struct device_node *dn, + int i) +{ + struct scom_debug_entry *ent; + struct dentry *dir; + + ent = kzalloc(sizeof(*ent), GFP_KERNEL); + if (!ent) + return -ENOMEM; + + ent->dn = of_node_get(dn); + ent->map = SCOM_MAP_INVALID; + spin_lock_init(&ent->lock); + snprintf(ent->name, 8, "scom%d", i); + ent->blob.data = dn->full_name; + ent->blob.size = strlen(dn->full_name); + + dir = debugfs_create_dir(ent->name, root); + if (!dir) { + of_node_put(dn); + kfree(ent); + return -1; + } + + debugfs_create_file("addr", 0600, dir, ent, &scom_addr_fops); + debugfs_create_file("value", 0600, dir, ent, &scom_val_fops); + debugfs_create_blob("path", 0400, dir, &ent->blob); + + return 0; +} + +static int scom_debug_init(void) +{ + struct device_node *dn; + struct dentry *root; + int i, rc; + + root = debugfs_create_dir("scom", powerpc_debugfs_root); + if (!root) + return -1; + + i = rc = 0; + for_each_node_with_property(dn, "scom-controller") + rc |= scom_debug_init_one(root, dn, i++); + + return rc; +} +device_initcall(scom_debug_init); +#endif /* CONFIG_SCOM_DEBUGFS */ diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 5d9138516628..984cd2029158 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -41,8 +41,6 @@ #define UIC_VR 0x7 #define UIC_VCR 0x8 -#define uic_irq_to_hw(virq) (irq_map[virq].hwirq) - struct uic *primary_uic; struct uic { @@ -58,7 +56,7 @@ struct uic { static void uic_unmask_irq(struct irq_data *d) { struct uic *uic = irq_data_get_irq_chip_data(d); - unsigned int src = uic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 er, sr; @@ -76,7 +74,7 @@ static void uic_unmask_irq(struct irq_data *d) static void uic_mask_irq(struct irq_data *d) { struct uic *uic = irq_data_get_irq_chip_data(d); - unsigned int src = uic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 er; @@ -90,7 +88,7 @@ static void uic_mask_irq(struct irq_data *d) static void uic_ack_irq(struct irq_data *d) { struct uic *uic = irq_data_get_irq_chip_data(d); - unsigned int src = uic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; spin_lock_irqsave(&uic->lock, flags); @@ -101,7 +99,7 @@ static void uic_ack_irq(struct irq_data *d) static void uic_mask_ack_irq(struct irq_data *d) { struct uic *uic = irq_data_get_irq_chip_data(d); - unsigned int src = uic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 er, sr; @@ -126,7 +124,7 @@ static void uic_mask_ack_irq(struct irq_data *d) static int uic_set_irq_type(struct irq_data *d, unsigned int flow_type) { struct uic *uic = irq_data_get_irq_chip_data(d); - unsigned int src = uic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; int trigger, polarity; u32 tr, pr, mask; diff --git a/arch/powerpc/sysdev/xics/Kconfig b/arch/powerpc/sysdev/xics/Kconfig new file mode 100644 index 000000000000..0031eda320c3 --- /dev/null +++ b/arch/powerpc/sysdev/xics/Kconfig @@ -0,0 +1,13 @@ +config PPC_XICS + def_bool n + select PPC_SMP_MUXED_IPI + +config PPC_ICP_NATIVE + def_bool n + +config PPC_ICP_HV + def_bool n + +config PPC_ICS_RTAS + def_bool n + diff --git a/arch/powerpc/sysdev/xics/Makefile b/arch/powerpc/sysdev/xics/Makefile new file mode 100644 index 000000000000..b75a6059337f --- /dev/null +++ b/arch/powerpc/sysdev/xics/Makefile @@ -0,0 +1,6 @@ +subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror + +obj-y += xics-common.o +obj-$(CONFIG_PPC_ICP_NATIVE) += icp-native.o +obj-$(CONFIG_PPC_ICP_HV) += icp-hv.o +obj-$(CONFIG_PPC_ICS_RTAS) += ics-rtas.o diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c new file mode 100644 index 000000000000..9518d367a64f --- /dev/null +++ b/arch/powerpc/sysdev/xics/icp-hv.c @@ -0,0 +1,164 @@ +/* + * Copyright 2011 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static inline unsigned int icp_hv_get_xirr(unsigned char cppr) +{ + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + long rc; + + rc = plpar_hcall(H_XIRR, retbuf, cppr); + if (rc != H_SUCCESS) + panic(" bad return code xirr - rc = %lx\n", rc); + return (unsigned int)retbuf[0]; +} + +static inline void icp_hv_set_xirr(unsigned int value) +{ + long rc = plpar_hcall_norets(H_EOI, value); + if (rc != H_SUCCESS) + panic("bad return code EOI - rc = %ld, value=%x\n", rc, value); +} + +static inline void icp_hv_set_cppr(u8 value) +{ + long rc = plpar_hcall_norets(H_CPPR, value); + if (rc != H_SUCCESS) + panic("bad return code cppr - rc = %lx\n", rc); +} + +static inline void icp_hv_set_qirr(int n_cpu , u8 value) +{ + long rc = plpar_hcall_norets(H_IPI, get_hard_smp_processor_id(n_cpu), + value); + if (rc != H_SUCCESS) + panic("bad return code qirr - rc = %lx\n", rc); +} + +static void icp_hv_eoi(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + + iosync(); + icp_hv_set_xirr((xics_pop_cppr() << 24) | hw_irq); +} + +static void icp_hv_teardown_cpu(void) +{ + int cpu = smp_processor_id(); + + /* Clear any pending IPI */ + icp_hv_set_qirr(cpu, 0xff); +} + +static void icp_hv_flush_ipi(void) +{ + /* We take the ipi irq but and never return so we + * need to EOI the IPI, but want to leave our priority 0 + * + * should we check all the other interrupts too? + * should we be flagging idle loop instead? + * or creating some task to be scheduled? + */ + + icp_hv_set_xirr((0x00 << 24) | XICS_IPI); +} + +static unsigned int icp_hv_get_irq(void) +{ + unsigned int xirr = icp_hv_get_xirr(xics_cppr_top()); + unsigned int vec = xirr & 0x00ffffff; + unsigned int irq; + + if (vec == XICS_IRQ_SPURIOUS) + return NO_IRQ; + + irq = irq_radix_revmap_lookup(xics_host, vec); + if (likely(irq != NO_IRQ)) { + xics_push_cppr(vec); + return irq; + } + + /* We don't have a linux mapping, so have rtas mask it. */ + xics_mask_unknown_vec(vec); + + /* We might learn about it later, so EOI it */ + icp_hv_set_xirr(xirr); + + return NO_IRQ; +} + +static void icp_hv_set_cpu_priority(unsigned char cppr) +{ + xics_set_base_cppr(cppr); + icp_hv_set_cppr(cppr); + iosync(); +} + +#ifdef CONFIG_SMP + +static void icp_hv_cause_ipi(int cpu, unsigned long data) +{ + icp_hv_set_qirr(cpu, IPI_PRIORITY); +} + +static irqreturn_t icp_hv_ipi_action(int irq, void *dev_id) +{ + int cpu = smp_processor_id(); + + icp_hv_set_qirr(cpu, 0xff); + + return smp_ipi_demux(); +} + +#endif /* CONFIG_SMP */ + +static const struct icp_ops icp_hv_ops = { + .get_irq = icp_hv_get_irq, + .eoi = icp_hv_eoi, + .set_priority = icp_hv_set_cpu_priority, + .teardown_cpu = icp_hv_teardown_cpu, + .flush_ipi = icp_hv_flush_ipi, +#ifdef CONFIG_SMP + .ipi_action = icp_hv_ipi_action, + .cause_ipi = icp_hv_cause_ipi, +#endif +}; + +int icp_hv_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "ibm,ppc-xicp"); + if (!np) + np = of_find_node_by_type(NULL, + "PowerPC-External-Interrupt-Presentation"); + if (!np) + return -ENODEV; + + icp_ops = &icp_hv_ops; + + return 0; +} + diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c new file mode 100644 index 000000000000..1f15ad436140 --- /dev/null +++ b/arch/powerpc/sysdev/xics/icp-native.c @@ -0,0 +1,293 @@ +/* + * Copyright 2011 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +struct icp_ipl { + union { + u32 word; + u8 bytes[4]; + } xirr_poll; + union { + u32 word; + u8 bytes[4]; + } xirr; + u32 dummy; + union { + u32 word; + u8 bytes[4]; + } qirr; + u32 link_a; + u32 link_b; + u32 link_c; +}; + +static struct icp_ipl __iomem *icp_native_regs[NR_CPUS]; + +static inline unsigned int icp_native_get_xirr(void) +{ + int cpu = smp_processor_id(); + + return in_be32(&icp_native_regs[cpu]->xirr.word); +} + +static inline void icp_native_set_xirr(unsigned int value) +{ + int cpu = smp_processor_id(); + + out_be32(&icp_native_regs[cpu]->xirr.word, value); +} + +static inline void icp_native_set_cppr(u8 value) +{ + int cpu = smp_processor_id(); + + out_8(&icp_native_regs[cpu]->xirr.bytes[0], value); +} + +static inline void icp_native_set_qirr(int n_cpu, u8 value) +{ + out_8(&icp_native_regs[n_cpu]->qirr.bytes[0], value); +} + +static void icp_native_set_cpu_priority(unsigned char cppr) +{ + xics_set_base_cppr(cppr); + icp_native_set_cppr(cppr); + iosync(); +} + +static void icp_native_eoi(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + + iosync(); + icp_native_set_xirr((xics_pop_cppr() << 24) | hw_irq); +} + +static void icp_native_teardown_cpu(void) +{ + int cpu = smp_processor_id(); + + /* Clear any pending IPI */ + icp_native_set_qirr(cpu, 0xff); +} + +static void icp_native_flush_ipi(void) +{ + /* We take the ipi irq but and never return so we + * need to EOI the IPI, but want to leave our priority 0 + * + * should we check all the other interrupts too? + * should we be flagging idle loop instead? + * or creating some task to be scheduled? + */ + + icp_native_set_xirr((0x00 << 24) | XICS_IPI); +} + +static unsigned int icp_native_get_irq(void) +{ + unsigned int xirr = icp_native_get_xirr(); + unsigned int vec = xirr & 0x00ffffff; + unsigned int irq; + + if (vec == XICS_IRQ_SPURIOUS) + return NO_IRQ; + + irq = irq_radix_revmap_lookup(xics_host, vec); + if (likely(irq != NO_IRQ)) { + xics_push_cppr(vec); + return irq; + } + + /* We don't have a linux mapping, so have rtas mask it. */ + xics_mask_unknown_vec(vec); + + /* We might learn about it later, so EOI it */ + icp_native_set_xirr(xirr); + + return NO_IRQ; +} + +#ifdef CONFIG_SMP + +static void icp_native_cause_ipi(int cpu, unsigned long data) +{ + icp_native_set_qirr(cpu, IPI_PRIORITY); +} + +static irqreturn_t icp_native_ipi_action(int irq, void *dev_id) +{ + int cpu = smp_processor_id(); + + icp_native_set_qirr(cpu, 0xff); + + return smp_ipi_demux(); +} + +#endif /* CONFIG_SMP */ + +static int __init icp_native_map_one_cpu(int hw_id, unsigned long addr, + unsigned long size) +{ + char *rname; + int i, cpu = -1; + + /* This may look gross but it's good enough for now, we don't quite + * have a hard -> linux processor id matching. + */ + for_each_possible_cpu(i) { + if (!cpu_present(i)) + continue; + if (hw_id == get_hard_smp_processor_id(i)) { + cpu = i; + break; + } + } + + /* Fail, skip that CPU. Don't print, it's normal, some XICS come up + * with way more entries in there than you have CPUs + */ + if (cpu == -1) + return 0; + + rname = kasprintf(GFP_KERNEL, "CPU %d [0x%x] Interrupt Presentation", + cpu, hw_id); + + if (!request_mem_region(addr, size, rname)) { + pr_warning("icp_native: Could not reserve ICP MMIO" + " for CPU %d, interrupt server #0x%x\n", + cpu, hw_id); + return -EBUSY; + } + + icp_native_regs[cpu] = ioremap(addr, size); + if (!icp_native_regs[cpu]) { + pr_warning("icp_native: Failed ioremap for CPU %d, " + "interrupt server #0x%x, addr %#lx\n", + cpu, hw_id, addr); + release_mem_region(addr, size); + return -ENOMEM; + } + return 0; +} + +static int __init icp_native_init_one_node(struct device_node *np, + unsigned int *indx) +{ + unsigned int ilen; + const u32 *ireg; + int i; + int reg_tuple_size; + int num_servers = 0; + + /* This code does the theorically broken assumption that the interrupt + * server numbers are the same as the hard CPU numbers. + * This happens to be the case so far but we are playing with fire... + * should be fixed one of these days. -BenH. + */ + ireg = of_get_property(np, "ibm,interrupt-server-ranges", &ilen); + + /* Do that ever happen ? we'll know soon enough... but even good'old + * f80 does have that property .. + */ + WARN_ON((ireg == NULL) || (ilen != 2*sizeof(u32))); + + if (ireg) { + *indx = of_read_number(ireg, 1); + if (ilen >= 2*sizeof(u32)) + num_servers = of_read_number(ireg + 1, 1); + } + + ireg = of_get_property(np, "reg", &ilen); + if (!ireg) { + pr_err("icp_native: Can't find interrupt reg property"); + return -1; + } + + reg_tuple_size = (of_n_addr_cells(np) + of_n_size_cells(np)) * 4; + if (((ilen % reg_tuple_size) != 0) + || (num_servers && (num_servers != (ilen / reg_tuple_size)))) { + pr_err("icp_native: ICP reg len (%d) != num servers (%d)", + ilen / reg_tuple_size, num_servers); + return -1; + } + + for (i = 0; i < (ilen / reg_tuple_size); i++) { + struct resource r; + int err; + + err = of_address_to_resource(np, i, &r); + if (err) { + pr_err("icp_native: Could not translate ICP MMIO" + " for interrupt server 0x%x (%d)\n", *indx, err); + return -1; + } + + if (icp_native_map_one_cpu(*indx, r.start, r.end - r.start)) + return -1; + + (*indx)++; + } + return 0; +} + +static const struct icp_ops icp_native_ops = { + .get_irq = icp_native_get_irq, + .eoi = icp_native_eoi, + .set_priority = icp_native_set_cpu_priority, + .teardown_cpu = icp_native_teardown_cpu, + .flush_ipi = icp_native_flush_ipi, +#ifdef CONFIG_SMP + .ipi_action = icp_native_ipi_action, + .cause_ipi = icp_native_cause_ipi, +#endif +}; + +int icp_native_init(void) +{ + struct device_node *np; + u32 indx = 0; + int found = 0; + + for_each_compatible_node(np, NULL, "ibm,ppc-xicp") + if (icp_native_init_one_node(np, &indx) == 0) + found = 1; + if (!found) { + for_each_node_by_type(np, + "PowerPC-External-Interrupt-Presentation") { + if (icp_native_init_one_node(np, &indx) == 0) + found = 1; + } + } + + if (found == 0) + return -ENODEV; + + icp_ops = &icp_native_ops; + + return 0; +} diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c new file mode 100644 index 000000000000..c782f85cf7e4 --- /dev/null +++ b/arch/powerpc/sysdev/xics/ics-rtas.c @@ -0,0 +1,240 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* RTAS service tokens */ +static int ibm_get_xive; +static int ibm_set_xive; +static int ibm_int_on; +static int ibm_int_off; + +static int ics_rtas_map(struct ics *ics, unsigned int virq); +static void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec); +static long ics_rtas_get_server(struct ics *ics, unsigned long vec); +static int ics_rtas_host_match(struct ics *ics, struct device_node *node); + +/* Only one global & state struct ics */ +static struct ics ics_rtas = { + .map = ics_rtas_map, + .mask_unknown = ics_rtas_mask_unknown, + .get_server = ics_rtas_get_server, + .host_match = ics_rtas_host_match, +}; + +static void ics_rtas_unmask_irq(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + int call_status; + int server; + + pr_devel("xics: unmask virq %d [hw 0x%x]\n", d->irq, hw_irq); + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return; + + server = xics_get_irq_server(d->irq, d->affinity, 0); + + call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hw_irq, server, + DEFAULT_PRIORITY); + if (call_status != 0) { + printk(KERN_ERR + "%s: ibm_set_xive irq %u server %x returned %d\n", + __func__, hw_irq, server, call_status); + return; + } + + /* Now unmask the interrupt (often a no-op) */ + call_status = rtas_call(ibm_int_on, 1, 1, NULL, hw_irq); + if (call_status != 0) { + printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n", + __func__, hw_irq, call_status); + return; + } +} + +static unsigned int ics_rtas_startup(struct irq_data *d) +{ +#ifdef CONFIG_PCI_MSI + /* + * The generic MSI code returns with the interrupt disabled on the + * card, using the MSI mask bits. Firmware doesn't appear to unmask + * at that level, so we do it here by hand. + */ + if (d->msi_desc) + unmask_msi_irq(d); +#endif + /* unmask it */ + ics_rtas_unmask_irq(d); + return 0; +} + +static void ics_rtas_mask_real_irq(unsigned int hw_irq) +{ + int call_status; + + if (hw_irq == XICS_IPI) + return; + + call_status = rtas_call(ibm_int_off, 1, 1, NULL, hw_irq); + if (call_status != 0) { + printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n", + __func__, hw_irq, call_status); + return; + } + + /* Have to set XIVE to 0xff to be able to remove a slot */ + call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hw_irq, + xics_default_server, 0xff); + if (call_status != 0) { + printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n", + __func__, hw_irq, call_status); + return; + } +} + +static void ics_rtas_mask_irq(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + + pr_devel("xics: mask virq %d [hw 0x%x]\n", d->irq, hw_irq); + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return; + ics_rtas_mask_real_irq(hw_irq); +} + +static int ics_rtas_set_affinity(struct irq_data *d, + const struct cpumask *cpumask, + bool force) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + int status; + int xics_status[2]; + int irq_server; + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return -1; + + status = rtas_call(ibm_get_xive, 1, 3, xics_status, hw_irq); + + if (status) { + printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n", + __func__, hw_irq, status); + return -1; + } + + irq_server = xics_get_irq_server(d->irq, cpumask, 1); + if (irq_server == -1) { + char cpulist[128]; + cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); + printk(KERN_WARNING + "%s: No online cpus in the mask %s for irq %d\n", + __func__, cpulist, d->irq); + return -1; + } + + status = rtas_call(ibm_set_xive, 3, 1, NULL, + hw_irq, irq_server, xics_status[1]); + + if (status) { + printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n", + __func__, hw_irq, status); + return -1; + } + + return IRQ_SET_MASK_OK; +} + +static struct irq_chip ics_rtas_irq_chip = { + .name = "XICS", + .irq_startup = ics_rtas_startup, + .irq_mask = ics_rtas_mask_irq, + .irq_unmask = ics_rtas_unmask_irq, + .irq_eoi = NULL, /* Patched at init time */ + .irq_set_affinity = ics_rtas_set_affinity +}; + +static int ics_rtas_map(struct ics *ics, unsigned int virq) +{ + unsigned int hw_irq = (unsigned int)virq_to_hw(virq); + int status[2]; + int rc; + + if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)) + return -EINVAL; + + /* Check if RTAS knows about this interrupt */ + rc = rtas_call(ibm_get_xive, 1, 3, status, hw_irq); + if (rc) + return -ENXIO; + + irq_set_chip_and_handler(virq, &ics_rtas_irq_chip, handle_fasteoi_irq); + irq_set_chip_data(virq, &ics_rtas); + + return 0; +} + +static void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec) +{ + ics_rtas_mask_real_irq(vec); +} + +static long ics_rtas_get_server(struct ics *ics, unsigned long vec) +{ + int rc, status[2]; + + rc = rtas_call(ibm_get_xive, 1, 3, status, vec); + if (rc) + return -1; + return status[0]; +} + +static int ics_rtas_host_match(struct ics *ics, struct device_node *node) +{ + /* IBM machines have interrupt parents of various funky types for things + * like vdevices, events, etc... The trick we use here is to match + * everything here except the legacy 8259 which is compatible "chrp,iic" + */ + return !of_device_is_compatible(node, "chrp,iic"); +} + +int ics_rtas_init(void) +{ + ibm_get_xive = rtas_token("ibm,get-xive"); + ibm_set_xive = rtas_token("ibm,set-xive"); + ibm_int_on = rtas_token("ibm,int-on"); + ibm_int_off = rtas_token("ibm,int-off"); + + /* We enable the RTAS "ICS" if RTAS is present with the + * appropriate tokens + */ + if (ibm_get_xive == RTAS_UNKNOWN_SERVICE || + ibm_set_xive == RTAS_UNKNOWN_SERVICE) + return -ENODEV; + + /* We need to patch our irq chip's EOI to point to the + * right ICP + */ + ics_rtas_irq_chip.irq_eoi = icp_ops->eoi; + + /* Register ourselves */ + xics_register_ics(&ics_rtas); + + return 0; +} + diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c new file mode 100644 index 000000000000..445c5a01b766 --- /dev/null +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -0,0 +1,443 @@ +/* + * Copyright 2011 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Globals common to all ICP/ICS implementations */ +const struct icp_ops *icp_ops; + +unsigned int xics_default_server = 0xff; +unsigned int xics_default_distrib_server = 0; +unsigned int xics_interrupt_server_size = 8; + +DEFINE_PER_CPU(struct xics_cppr, xics_cppr); + +struct irq_host *xics_host; + +static LIST_HEAD(ics_list); + +void xics_update_irq_servers(void) +{ + int i, j; + struct device_node *np; + u32 ilen; + const u32 *ireg; + u32 hcpuid; + + /* Find the server numbers for the boot cpu. */ + np = of_get_cpu_node(boot_cpuid, NULL); + BUG_ON(!np); + + hcpuid = get_hard_smp_processor_id(boot_cpuid); + xics_default_server = xics_default_distrib_server = hcpuid; + + pr_devel("xics: xics_default_server = 0x%x\n", xics_default_server); + + ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); + if (!ireg) { + of_node_put(np); + return; + } + + i = ilen / sizeof(int); + + /* Global interrupt distribution server is specified in the last + * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last + * entry fom this property for current boot cpu id and use it as + * default distribution server + */ + for (j = 0; j < i; j += 2) { + if (ireg[j] == hcpuid) { + xics_default_distrib_server = ireg[j+1]; + break; + } + } + pr_devel("xics: xics_default_distrib_server = 0x%x\n", + xics_default_distrib_server); + of_node_put(np); +} + +/* GIQ stuff, currently only supported on RTAS setups, will have + * to be sorted properly for bare metal + */ +void xics_set_cpu_giq(unsigned int gserver, unsigned int join) +{ +#ifdef CONFIG_PPC_RTAS + int index; + int status; + + if (!rtas_indicator_present(GLOBAL_INTERRUPT_QUEUE, NULL)) + return; + + index = (1UL << xics_interrupt_server_size) - 1 - gserver; + + status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, index, join); + + WARN(status < 0, "set-indicator(%d, %d, %u) returned %d\n", + GLOBAL_INTERRUPT_QUEUE, index, join, status); +#endif +} + +void xics_setup_cpu(void) +{ + icp_ops->set_priority(LOWEST_PRIORITY); + + xics_set_cpu_giq(xics_default_distrib_server, 1); +} + +void xics_mask_unknown_vec(unsigned int vec) +{ + struct ics *ics; + + pr_err("Interrupt 0x%x (real) is invalid, disabling it.\n", vec); + + list_for_each_entry(ics, &ics_list, link) + ics->mask_unknown(ics, vec); +} + + +#ifdef CONFIG_SMP + +static void xics_request_ipi(void) +{ + unsigned int ipi; + + ipi = irq_create_mapping(xics_host, XICS_IPI); + BUG_ON(ipi == NO_IRQ); + + /* + * IPIs are marked IRQF_DISABLED as they must run with irqs + * disabled, and PERCPU. The handler was set in map. + */ + BUG_ON(request_irq(ipi, icp_ops->ipi_action, + IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL)); +} + +int __init xics_smp_probe(void) +{ + /* Setup cause_ipi callback based on which ICP is used */ + smp_ops->cause_ipi = icp_ops->cause_ipi; + + /* Register all the IPIs */ + xics_request_ipi(); + + return cpumask_weight(cpu_possible_mask); +} + +#endif /* CONFIG_SMP */ + +void xics_teardown_cpu(void) +{ + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + + /* + * we have to reset the cppr index to 0 because we're + * not going to return from the IPI + */ + os_cppr->index = 0; + icp_ops->set_priority(0); + icp_ops->teardown_cpu(); +} + +void xics_kexec_teardown_cpu(int secondary) +{ + xics_teardown_cpu(); + + icp_ops->flush_ipi(); + + /* + * Some machines need to have at least one cpu in the GIQ, + * so leave the master cpu in the group. + */ + if (secondary) + xics_set_cpu_giq(xics_default_distrib_server, 0); +} + + +#ifdef CONFIG_HOTPLUG_CPU + +/* Interrupts are disabled. */ +void xics_migrate_irqs_away(void) +{ + int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id(); + unsigned int irq, virq; + + /* If we used to be the default server, move to the new "boot_cpuid" */ + if (hw_cpu == xics_default_server) + xics_update_irq_servers(); + + /* Reject any interrupt that was queued to us... */ + icp_ops->set_priority(0); + + /* Remove ourselves from the global interrupt queue */ + xics_set_cpu_giq(xics_default_distrib_server, 0); + + /* Allow IPIs again... */ + icp_ops->set_priority(DEFAULT_PRIORITY); + + for_each_irq(virq) { + struct irq_desc *desc; + struct irq_chip *chip; + long server; + unsigned long flags; + struct ics *ics; + + /* We can't set affinity on ISA interrupts */ + if (virq < NUM_ISA_INTERRUPTS) + continue; + if (!virq_is_host(virq, xics_host)) + continue; + irq = (unsigned int)virq_to_hw(virq); + /* We need to get IPIs still. */ + if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) + continue; + desc = irq_to_desc(virq); + /* We only need to migrate enabled IRQS */ + if (!desc || !desc->action) + continue; + chip = irq_desc_get_chip(desc); + if (!chip || !chip->irq_set_affinity) + continue; + + raw_spin_lock_irqsave(&desc->lock, flags); + + /* Locate interrupt server */ + server = -1; + ics = irq_get_chip_data(virq); + if (ics) + server = ics->get_server(ics, irq); + if (server < 0) { + printk(KERN_ERR "%s: Can't find server for irq %d\n", + __func__, irq); + goto unlock; + } + + /* We only support delivery to all cpus or to one cpu. + * The irq has to be migrated only in the single cpu + * case. + */ + if (server != hw_cpu) + goto unlock; + + /* This is expected during cpu offline. */ + if (cpu_online(cpu)) + pr_warning("IRQ %u affinity broken off cpu %u\n", + virq, cpu); + + /* Reset affinity to all cpus */ + raw_spin_unlock_irqrestore(&desc->lock, flags); + irq_set_affinity(virq, cpu_all_mask); + continue; +unlock: + raw_spin_unlock_irqrestore(&desc->lock, flags); + } +} +#endif /* CONFIG_HOTPLUG_CPU */ + +#ifdef CONFIG_SMP +/* + * For the moment we only implement delivery to all cpus or one cpu. + * + * If the requested affinity is cpu_all_mask, we set global affinity. + * If not we set it to the first cpu in the mask, even if multiple cpus + * are set. This is so things like irqbalance (which set core and package + * wide affinities) do the right thing. + * + * We need to fix this to implement support for the links + */ +int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask, + unsigned int strict_check) +{ + + if (!distribute_irqs) + return xics_default_server; + + if (!cpumask_subset(cpu_possible_mask, cpumask)) { + int server = cpumask_first_and(cpu_online_mask, cpumask); + + if (server < nr_cpu_ids) + return get_hard_smp_processor_id(server); + + if (strict_check) + return -1; + } + + /* + * Workaround issue with some versions of JS20 firmware that + * deliver interrupts to cpus which haven't been started. This + * happens when using the maxcpus= boot option. + */ + if (cpumask_equal(cpu_online_mask, cpu_present_mask)) + return xics_default_distrib_server; + + return xics_default_server; +} +#endif /* CONFIG_SMP */ + +static int xics_host_match(struct irq_host *h, struct device_node *node) +{ + struct ics *ics; + + list_for_each_entry(ics, &ics_list, link) + if (ics->host_match(ics, node)) + return 1; + + return 0; +} + +/* Dummies */ +static void xics_ipi_unmask(struct irq_data *d) { } +static void xics_ipi_mask(struct irq_data *d) { } + +static struct irq_chip xics_ipi_chip = { + .name = "XICS", + .irq_eoi = NULL, /* Patched at init time */ + .irq_mask = xics_ipi_mask, + .irq_unmask = xics_ipi_unmask, +}; + +static int xics_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct ics *ics; + + pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hw); + + /* Insert the interrupt mapping into the radix tree for fast lookup */ + irq_radix_revmap_insert(xics_host, virq, hw); + + /* They aren't all level sensitive but we just don't really know */ + irq_set_status_flags(virq, IRQ_LEVEL); + + /* Don't call into ICS for IPIs */ + if (hw == XICS_IPI) { + irq_set_chip_and_handler(virq, &xics_ipi_chip, + handle_percpu_irq); + return 0; + } + + /* Let the ICS setup the chip data */ + list_for_each_entry(ics, &ics_list, link) + if (ics->map(ics, virq) == 0) + return 0; + + return -EINVAL; +} + +static int xics_host_xlate(struct irq_host *h, struct device_node *ct, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_flags) + +{ + /* Current xics implementation translates everything + * to level. It is not technically right for MSIs but this + * is irrelevant at this point. We might get smarter in the future + */ + *out_hwirq = intspec[0]; + *out_flags = IRQ_TYPE_LEVEL_LOW; + + return 0; +} + +static struct irq_host_ops xics_host_ops = { + .match = xics_host_match, + .map = xics_host_map, + .xlate = xics_host_xlate, +}; + +static void __init xics_init_host(void) +{ + xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops, + XICS_IRQ_SPURIOUS); + BUG_ON(xics_host == NULL); + irq_set_default_host(xics_host); +} + +void __init xics_register_ics(struct ics *ics) +{ + list_add(&ics->link, &ics_list); +} + +static void __init xics_get_server_size(void) +{ + struct device_node *np; + const u32 *isize; + + /* We fetch the interrupt server size from the first ICS node + * we find if any + */ + np = of_find_compatible_node(NULL, NULL, "ibm,ppc-xics"); + if (!np) + return; + isize = of_get_property(np, "ibm,interrupt-server#-size", NULL); + if (!isize) + return; + xics_interrupt_server_size = *isize; + of_node_put(np); +} + +void __init xics_init(void) +{ + int rc = -1; + + /* Fist locate ICP */ +#ifdef CONFIG_PPC_ICP_HV + if (firmware_has_feature(FW_FEATURE_LPAR)) + rc = icp_hv_init(); +#endif +#ifdef CONFIG_PPC_ICP_NATIVE + if (rc < 0) + rc = icp_native_init(); +#endif + if (rc < 0) { + pr_warning("XICS: Cannot find a Presentation Controller !\n"); + return; + } + + /* Copy get_irq callback over to ppc_md */ + ppc_md.get_irq = icp_ops->get_irq; + + /* Patch up IPI chip EOI */ + xics_ipi_chip.irq_eoi = icp_ops->eoi; + + /* Now locate ICS */ +#ifdef CONFIG_PPC_ICS_RTAS + rc = ics_rtas_init(); +#endif + if (rc < 0) + pr_warning("XICS: Cannot find a Source Controller !\n"); + + /* Initialize common bits */ + xics_get_server_size(); + xics_update_irq_servers(); + xics_init_host(); + xics_setup_cpu(); +} diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c index 0a13fc19e287..6183799754af 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c @@ -71,7 +71,7 @@ static unsigned char xilinx_intc_map_senses[] = { */ static void xilinx_intc_mask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void * regs = irq_data_get_irq_chip_data(d); pr_debug("mask: %d\n", irq); out_be32(regs + XINTC_CIE, 1 << irq); @@ -87,7 +87,7 @@ static int xilinx_intc_set_type(struct irq_data *d, unsigned int flow_type) */ static void xilinx_intc_level_unmask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void * regs = irq_data_get_irq_chip_data(d); pr_debug("unmask: %d\n", irq); out_be32(regs + XINTC_SIE, 1 << irq); @@ -112,7 +112,7 @@ static struct irq_chip xilinx_intc_level_irqchip = { */ static void xilinx_intc_edge_unmask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void *regs = irq_data_get_irq_chip_data(d); pr_debug("unmask: %d\n", irq); out_be32(regs + XINTC_SIE, 1 << irq); @@ -120,7 +120,7 @@ static void xilinx_intc_edge_unmask(struct irq_data *d) static void xilinx_intc_edge_ack(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void * regs = irq_data_get_irq_chip_data(d); pr_debug("ack: %d\n", irq); out_be32(regs + XINTC_IAR, 1 << irq); diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 33794c1d92c3..42541bbcc7fa 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -334,7 +334,7 @@ static void release_output_lock(void) int cpus_are_in_xmon(void) { - return !cpus_empty(cpus_in_xmon); + return !cpumask_empty(&cpus_in_xmon); } #endif @@ -373,7 +373,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) #ifdef CONFIG_SMP cpu = smp_processor_id(); - if (cpu_isset(cpu, cpus_in_xmon)) { + if (cpumask_test_cpu(cpu, &cpus_in_xmon)) { get_output_lock(); excprint(regs); printf("cpu 0x%x: Exception %lx %s in xmon, " @@ -396,10 +396,10 @@ static int xmon_core(struct pt_regs *regs, int fromipi) } xmon_fault_jmp[cpu] = recurse_jmp; - cpu_set(cpu, cpus_in_xmon); + cpumask_set_cpu(cpu, &cpus_in_xmon); bp = NULL; - if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) + if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) bp = at_breakpoint(regs->nip); if (bp || unrecoverable_excp(regs)) fromipi = 0; @@ -437,10 +437,10 @@ static int xmon_core(struct pt_regs *regs, int fromipi) xmon_owner = cpu; mb(); if (ncpus > 1) { - smp_send_debugger_break(MSG_ALL_BUT_SELF); + smp_send_debugger_break(); /* wait for other cpus to come in */ for (timeout = 100000000; timeout != 0; --timeout) { - if (cpus_weight(cpus_in_xmon) >= ncpus) + if (cpumask_weight(&cpus_in_xmon) >= ncpus) break; barrier(); } @@ -484,7 +484,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) } } leave: - cpu_clear(cpu, cpus_in_xmon); + cpumask_clear_cpu(cpu, &cpus_in_xmon); xmon_fault_jmp[cpu] = NULL; #else /* UP is simple... */ @@ -529,7 +529,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) } } #else - if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) { + if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) { bp = at_breakpoint(regs->nip); if (bp != NULL) { int stepped = emulate_step(regs, bp->instr[0]); @@ -578,7 +578,7 @@ static int xmon_bpt(struct pt_regs *regs) struct bpt *bp; unsigned long offset; - if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) + if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT)) return 0; /* Are we at the trap at bp->instr[1] for some bp? */ @@ -609,7 +609,7 @@ static int xmon_sstep(struct pt_regs *regs) static int xmon_dabr_match(struct pt_regs *regs) { - if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) + if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT)) return 0; if (dabr.enabled == 0) return 0; @@ -619,7 +619,7 @@ static int xmon_dabr_match(struct pt_regs *regs) static int xmon_iabr_match(struct pt_regs *regs) { - if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) + if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT)) return 0; if (iabr == NULL) return 0; @@ -630,7 +630,7 @@ static int xmon_iabr_match(struct pt_regs *regs) static int xmon_ipi(struct pt_regs *regs) { #ifdef CONFIG_SMP - if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon)) + if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon)) xmon_core(regs, 1); #endif return 0; @@ -644,7 +644,7 @@ static int xmon_fault_handler(struct pt_regs *regs) if (in_xmon && catch_memory_errors) handle_fault(regs); /* doesn't return */ - if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) { + if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) { bp = in_breakpoint_table(regs->nip, &offset); if (bp != NULL) { regs->nip = bp->address + offset; @@ -929,7 +929,7 @@ static int do_step(struct pt_regs *regs) int stepped; /* check we are in 64-bit kernel mode, translation enabled */ - if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) { + if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) { if (mread(regs->nip, &instr, 4) == 4) { stepped = emulate_step(regs, instr); if (stepped < 0) { @@ -976,7 +976,7 @@ static int cpu_cmd(void) printf("cpus stopped:"); count = 0; for (cpu = 0; cpu < NR_CPUS; ++cpu) { - if (cpu_isset(cpu, cpus_in_xmon)) { + if (cpumask_test_cpu(cpu, &cpus_in_xmon)) { if (count == 0) printf(" %x", cpu); ++count; @@ -992,7 +992,7 @@ static int cpu_cmd(void) return 0; } /* try to switch to cpu specified */ - if (!cpu_isset(cpu, cpus_in_xmon)) { + if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) { printf("cpu 0x%x isn't in xmon\n", cpu); return 0; } @@ -1497,6 +1497,10 @@ static void prregs(struct pt_regs *fp) #endif printf("pc = "); xmon_print_symbol(fp->nip, " ", "\n"); + if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) { + printf("cfar= "); + xmon_print_symbol(fp->orig_gpr3, " ", "\n"); + } printf("lr = "); xmon_print_symbol(fp->link, " ", "\n"); printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr); @@ -2663,7 +2667,7 @@ static void dump_stab(void) void dump_segments(void) { - if (cpu_has_feature(CPU_FTR_SLB)) + if (mmu_has_feature(MMU_FTR_SLB)) dump_slb(); else dump_stab(); diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 2508a6f31588..4a7f14079e03 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -88,6 +88,7 @@ config S390 select HAVE_KERNEL_XZ select HAVE_GET_USER_PAGES_FAST select HAVE_ARCH_MUTEX_CPU_RELAX + select HAVE_ARCH_JUMP_LABEL if !MARCH_G5 select ARCH_INLINE_SPIN_TRYLOCK select ARCH_INLINE_SPIN_TRYLOCK_BH select ARCH_INLINE_SPIN_LOCK diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile index 1cf81d77c5a5..7f0b7cda6259 100644 --- a/arch/s390/crypto/Makefile +++ b/arch/s390/crypto/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_CRYPTO_SHA512_S390) += sha512_s390.o sha_common.o obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o obj-$(CONFIG_S390_PRNG) += prng.o +obj-$(CONFIG_CRYPTO_GHASH_S390) += ghash_s390.o diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 58f46734465f..a9ce135893f8 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -31,7 +31,8 @@ #define AES_KEYLEN_192 2 #define AES_KEYLEN_256 4 -static char keylen_flag = 0; +static u8 *ctrblk; +static char keylen_flag; struct s390_aes_ctx { u8 iv[AES_BLOCK_SIZE]; @@ -45,6 +46,24 @@ struct s390_aes_ctx { } fallback; }; +struct pcc_param { + u8 key[32]; + u8 tweak[16]; + u8 block[16]; + u8 bit[16]; + u8 xts[16]; +}; + +struct s390_xts_ctx { + u8 key[32]; + u8 xts_param[16]; + struct pcc_param pcc; + long enc; + long dec; + int key_len; + struct crypto_blkcipher *fallback; +}; + /* * Check if the key_len is supported by the HW. * Returns 0 if it is, a positive number if it is not and software fallback is @@ -504,15 +523,337 @@ static struct crypto_alg cbc_aes_alg = { } }; +static int xts_fallback_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int len) +{ + struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm); + unsigned int ret; + + xts_ctx->fallback->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + xts_ctx->fallback->base.crt_flags |= (tfm->crt_flags & + CRYPTO_TFM_REQ_MASK); + + ret = crypto_blkcipher_setkey(xts_ctx->fallback, key, len); + if (ret) { + tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; + tfm->crt_flags |= (xts_ctx->fallback->base.crt_flags & + CRYPTO_TFM_RES_MASK); + } + return ret; +} + +static int xts_fallback_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm); + struct crypto_blkcipher *tfm; + unsigned int ret; + + tfm = desc->tfm; + desc->tfm = xts_ctx->fallback; + + ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes); + + desc->tfm = tfm; + return ret; +} + +static int xts_fallback_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm); + struct crypto_blkcipher *tfm; + unsigned int ret; + + tfm = desc->tfm; + desc->tfm = xts_ctx->fallback; + + ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes); + + desc->tfm = tfm; + return ret; +} + +static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + + switch (key_len) { + case 32: + xts_ctx->enc = KM_XTS_128_ENCRYPT; + xts_ctx->dec = KM_XTS_128_DECRYPT; + memcpy(xts_ctx->key + 16, in_key, 16); + memcpy(xts_ctx->pcc.key + 16, in_key + 16, 16); + break; + case 48: + xts_ctx->enc = 0; + xts_ctx->dec = 0; + xts_fallback_setkey(tfm, in_key, key_len); + break; + case 64: + xts_ctx->enc = KM_XTS_256_ENCRYPT; + xts_ctx->dec = KM_XTS_256_DECRYPT; + memcpy(xts_ctx->key, in_key, 32); + memcpy(xts_ctx->pcc.key, in_key + 32, 32); + break; + default: + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + xts_ctx->key_len = key_len; + return 0; +} + +static int xts_aes_crypt(struct blkcipher_desc *desc, long func, + struct s390_xts_ctx *xts_ctx, + struct blkcipher_walk *walk) +{ + unsigned int offset = (xts_ctx->key_len >> 1) & 0x10; + int ret = blkcipher_walk_virt(desc, walk); + unsigned int nbytes = walk->nbytes; + unsigned int n; + u8 *in, *out; + void *param; + + if (!nbytes) + goto out; + + memset(xts_ctx->pcc.block, 0, sizeof(xts_ctx->pcc.block)); + memset(xts_ctx->pcc.bit, 0, sizeof(xts_ctx->pcc.bit)); + memset(xts_ctx->pcc.xts, 0, sizeof(xts_ctx->pcc.xts)); + memcpy(xts_ctx->pcc.tweak, walk->iv, sizeof(xts_ctx->pcc.tweak)); + param = xts_ctx->pcc.key + offset; + ret = crypt_s390_pcc(func, param); + BUG_ON(ret < 0); + + memcpy(xts_ctx->xts_param, xts_ctx->pcc.xts, 16); + param = xts_ctx->key + offset; + do { + /* only use complete blocks */ + n = nbytes & ~(AES_BLOCK_SIZE - 1); + out = walk->dst.virt.addr; + in = walk->src.virt.addr; + + ret = crypt_s390_km(func, param, out, in, n); + BUG_ON(ret < 0 || ret != n); + + nbytes &= AES_BLOCK_SIZE - 1; + ret = blkcipher_walk_done(desc, walk, nbytes); + } while ((nbytes = walk->nbytes)); +out: + return ret; +} + +static int xts_aes_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + if (unlikely(xts_ctx->key_len == 48)) + return xts_fallback_encrypt(desc, dst, src, nbytes); + + blkcipher_walk_init(&walk, dst, src, nbytes); + return xts_aes_crypt(desc, xts_ctx->enc, xts_ctx, &walk); +} + +static int xts_aes_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + if (unlikely(xts_ctx->key_len == 48)) + return xts_fallback_decrypt(desc, dst, src, nbytes); + + blkcipher_walk_init(&walk, dst, src, nbytes); + return xts_aes_crypt(desc, xts_ctx->dec, xts_ctx, &walk); +} + +static int xts_fallback_init(struct crypto_tfm *tfm) +{ + const char *name = tfm->__crt_alg->cra_name; + struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm); + + xts_ctx->fallback = crypto_alloc_blkcipher(name, 0, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + + if (IS_ERR(xts_ctx->fallback)) { + pr_err("Allocating XTS fallback algorithm %s failed\n", + name); + return PTR_ERR(xts_ctx->fallback); + } + return 0; +} + +static void xts_fallback_exit(struct crypto_tfm *tfm) +{ + struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm); + + crypto_free_blkcipher(xts_ctx->fallback); + xts_ctx->fallback = NULL; +} + +static struct crypto_alg xts_aes_alg = { + .cra_name = "xts(aes)", + .cra_driver_name = "xts-aes-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s390_xts_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(xts_aes_alg.cra_list), + .cra_init = xts_fallback_init, + .cra_exit = xts_fallback_exit, + .cra_u = { + .blkcipher = { + .min_keysize = 2 * AES_MIN_KEY_SIZE, + .max_keysize = 2 * AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = xts_aes_set_key, + .encrypt = xts_aes_encrypt, + .decrypt = xts_aes_decrypt, + } + } +}; + +static int ctr_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + + switch (key_len) { + case 16: + sctx->enc = KMCTR_AES_128_ENCRYPT; + sctx->dec = KMCTR_AES_128_DECRYPT; + break; + case 24: + sctx->enc = KMCTR_AES_192_ENCRYPT; + sctx->dec = KMCTR_AES_192_DECRYPT; + break; + case 32: + sctx->enc = KMCTR_AES_256_ENCRYPT; + sctx->dec = KMCTR_AES_256_DECRYPT; + break; + } + + return aes_set_key(tfm, in_key, key_len); +} + +static int ctr_aes_crypt(struct blkcipher_desc *desc, long func, + struct s390_aes_ctx *sctx, struct blkcipher_walk *walk) +{ + int ret = blkcipher_walk_virt_block(desc, walk, AES_BLOCK_SIZE); + unsigned int i, n, nbytes; + u8 buf[AES_BLOCK_SIZE]; + u8 *out, *in; + + if (!walk->nbytes) + return ret; + + memcpy(ctrblk, walk->iv, AES_BLOCK_SIZE); + while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) { + out = walk->dst.virt.addr; + in = walk->src.virt.addr; + while (nbytes >= AES_BLOCK_SIZE) { + /* only use complete blocks, max. PAGE_SIZE */ + n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : + nbytes & ~(AES_BLOCK_SIZE - 1); + for (i = AES_BLOCK_SIZE; i < n; i += AES_BLOCK_SIZE) { + memcpy(ctrblk + i, ctrblk + i - AES_BLOCK_SIZE, + AES_BLOCK_SIZE); + crypto_inc(ctrblk + i, AES_BLOCK_SIZE); + } + ret = crypt_s390_kmctr(func, sctx->key, out, in, n, ctrblk); + BUG_ON(ret < 0 || ret != n); + if (n > AES_BLOCK_SIZE) + memcpy(ctrblk, ctrblk + n - AES_BLOCK_SIZE, + AES_BLOCK_SIZE); + crypto_inc(ctrblk, AES_BLOCK_SIZE); + out += n; + in += n; + nbytes -= n; + } + ret = blkcipher_walk_done(desc, walk, nbytes); + } + /* + * final block may be < AES_BLOCK_SIZE, copy only nbytes + */ + if (nbytes) { + out = walk->dst.virt.addr; + in = walk->src.virt.addr; + ret = crypt_s390_kmctr(func, sctx->key, buf, in, + AES_BLOCK_SIZE, ctrblk); + BUG_ON(ret < 0 || ret != AES_BLOCK_SIZE); + memcpy(out, buf, nbytes); + crypto_inc(ctrblk, AES_BLOCK_SIZE); + ret = blkcipher_walk_done(desc, walk, 0); + } + memcpy(walk->iv, ctrblk, AES_BLOCK_SIZE); + return ret; +} + +static int ctr_aes_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ctr_aes_crypt(desc, sctx->enc, sctx, &walk); +} + +static int ctr_aes_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ctr_aes_crypt(desc, sctx->dec, sctx, &walk); +} + +static struct crypto_alg ctr_aes_alg = { + .cra_name = "ctr(aes)", + .cra_driver_name = "ctr-aes-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct s390_aes_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ctr_aes_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ctr_aes_set_key, + .encrypt = ctr_aes_encrypt, + .decrypt = ctr_aes_decrypt, + } + } +}; + static int __init aes_s390_init(void) { int ret; - if (crypt_s390_func_available(KM_AES_128_ENCRYPT)) + if (crypt_s390_func_available(KM_AES_128_ENCRYPT, CRYPT_S390_MSA)) keylen_flag |= AES_KEYLEN_128; - if (crypt_s390_func_available(KM_AES_192_ENCRYPT)) + if (crypt_s390_func_available(KM_AES_192_ENCRYPT, CRYPT_S390_MSA)) keylen_flag |= AES_KEYLEN_192; - if (crypt_s390_func_available(KM_AES_256_ENCRYPT)) + if (crypt_s390_func_available(KM_AES_256_ENCRYPT, CRYPT_S390_MSA)) keylen_flag |= AES_KEYLEN_256; if (!keylen_flag) @@ -535,9 +876,40 @@ static int __init aes_s390_init(void) if (ret) goto cbc_aes_err; + if (crypt_s390_func_available(KM_XTS_128_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4) && + crypt_s390_func_available(KM_XTS_256_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4)) { + ret = crypto_register_alg(&xts_aes_alg); + if (ret) + goto xts_aes_err; + } + + if (crypt_s390_func_available(KMCTR_AES_128_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4) && + crypt_s390_func_available(KMCTR_AES_192_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4) && + crypt_s390_func_available(KMCTR_AES_256_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4)) { + ctrblk = (u8 *) __get_free_page(GFP_KERNEL); + if (!ctrblk) { + ret = -ENOMEM; + goto ctr_aes_err; + } + ret = crypto_register_alg(&ctr_aes_alg); + if (ret) { + free_page((unsigned long) ctrblk); + goto ctr_aes_err; + } + } + out: return ret; +ctr_aes_err: + crypto_unregister_alg(&xts_aes_alg); +xts_aes_err: + crypto_unregister_alg(&cbc_aes_alg); cbc_aes_err: crypto_unregister_alg(&ecb_aes_alg); ecb_aes_err: @@ -548,6 +920,9 @@ static int __init aes_s390_init(void) static void __exit aes_s390_fini(void) { + crypto_unregister_alg(&ctr_aes_alg); + free_page((unsigned long) ctrblk); + crypto_unregister_alg(&xts_aes_alg); crypto_unregister_alg(&cbc_aes_alg); crypto_unregister_alg(&ecb_aes_alg); crypto_unregister_alg(&aes_alg); diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h index 7ee9a1b4ad9f..49676771bd66 100644 --- a/arch/s390/crypto/crypt_s390.h +++ b/arch/s390/crypto/crypt_s390.h @@ -24,13 +24,18 @@ #define CRYPT_S390_PRIORITY 300 #define CRYPT_S390_COMPOSITE_PRIORITY 400 +#define CRYPT_S390_MSA 0x1 +#define CRYPT_S390_MSA3 0x2 +#define CRYPT_S390_MSA4 0x4 + /* s390 cryptographic operations */ enum crypt_s390_operations { CRYPT_S390_KM = 0x0100, CRYPT_S390_KMC = 0x0200, CRYPT_S390_KIMD = 0x0300, CRYPT_S390_KLMD = 0x0400, - CRYPT_S390_KMAC = 0x0500 + CRYPT_S390_KMAC = 0x0500, + CRYPT_S390_KMCTR = 0x0600 }; /* @@ -51,6 +56,10 @@ enum crypt_s390_km_func { KM_AES_192_DECRYPT = CRYPT_S390_KM | 0x13 | 0x80, KM_AES_256_ENCRYPT = CRYPT_S390_KM | 0x14, KM_AES_256_DECRYPT = CRYPT_S390_KM | 0x14 | 0x80, + KM_XTS_128_ENCRYPT = CRYPT_S390_KM | 0x32, + KM_XTS_128_DECRYPT = CRYPT_S390_KM | 0x32 | 0x80, + KM_XTS_256_ENCRYPT = CRYPT_S390_KM | 0x34, + KM_XTS_256_DECRYPT = CRYPT_S390_KM | 0x34 | 0x80, }; /* @@ -74,6 +83,26 @@ enum crypt_s390_kmc_func { KMC_PRNG = CRYPT_S390_KMC | 0x43, }; +/* + * function codes for KMCTR (CIPHER MESSAGE WITH COUNTER) + * instruction + */ +enum crypt_s390_kmctr_func { + KMCTR_QUERY = CRYPT_S390_KMCTR | 0x0, + KMCTR_DEA_ENCRYPT = CRYPT_S390_KMCTR | 0x1, + KMCTR_DEA_DECRYPT = CRYPT_S390_KMCTR | 0x1 | 0x80, + KMCTR_TDEA_128_ENCRYPT = CRYPT_S390_KMCTR | 0x2, + KMCTR_TDEA_128_DECRYPT = CRYPT_S390_KMCTR | 0x2 | 0x80, + KMCTR_TDEA_192_ENCRYPT = CRYPT_S390_KMCTR | 0x3, + KMCTR_TDEA_192_DECRYPT = CRYPT_S390_KMCTR | 0x3 | 0x80, + KMCTR_AES_128_ENCRYPT = CRYPT_S390_KMCTR | 0x12, + KMCTR_AES_128_DECRYPT = CRYPT_S390_KMCTR | 0x12 | 0x80, + KMCTR_AES_192_ENCRYPT = CRYPT_S390_KMCTR | 0x13, + KMCTR_AES_192_DECRYPT = CRYPT_S390_KMCTR | 0x13 | 0x80, + KMCTR_AES_256_ENCRYPT = CRYPT_S390_KMCTR | 0x14, + KMCTR_AES_256_DECRYPT = CRYPT_S390_KMCTR | 0x14 | 0x80, +}; + /* * function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) * instruction @@ -83,6 +112,7 @@ enum crypt_s390_kimd_func { KIMD_SHA_1 = CRYPT_S390_KIMD | 1, KIMD_SHA_256 = CRYPT_S390_KIMD | 2, KIMD_SHA_512 = CRYPT_S390_KIMD | 3, + KIMD_GHASH = CRYPT_S390_KIMD | 65, }; /* @@ -283,6 +313,45 @@ static inline int crypt_s390_kmac(long func, void *param, return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } +/** + * crypt_s390_kmctr: + * @func: the function code passed to KMCTR; see crypt_s390_kmctr_func + * @param: address of parameter block; see POP for details on each func + * @dest: address of destination memory area + * @src: address of source memory area + * @src_len: length of src operand in bytes + * @counter: address of counter value + * + * Executes the KMCTR (CIPHER MESSAGE WITH COUNTER) operation of the CPU. + * + * Returns -1 for failure, 0 for the query func, number of processed + * bytes for encryption/decryption funcs + */ +static inline int crypt_s390_kmctr(long func, void *param, u8 *dest, + const u8 *src, long src_len, u8 *counter) +{ + register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; + register void *__param asm("1") = param; + register const u8 *__src asm("2") = src; + register long __src_len asm("3") = src_len; + register u8 *__dest asm("4") = dest; + register u8 *__ctr asm("6") = counter; + int ret = -1; + + asm volatile( + "0: .insn rrf,0xb92d0000,%3,%1,%4,0 \n" /* KMCTR opcode */ + "1: brc 1,0b \n" /* handle partial completion */ + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) + : "+d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest), + "+a" (__ctr) + : "d" (__func), "a" (__param) : "cc", "memory"); + if (ret < 0) + return ret; + return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; +} + /** * crypt_s390_func_available: * @func: the function code of the specific function; 0 if op in general @@ -291,13 +360,17 @@ static inline int crypt_s390_kmac(long func, void *param, * * Returns 1 if func available; 0 if func or op in general not available */ -static inline int crypt_s390_func_available(int func) +static inline int crypt_s390_func_available(int func, + unsigned int facility_mask) { unsigned char status[16]; int ret; - /* check if CPACF facility (bit 17) is available */ - if (!test_facility(17)) + if (facility_mask & CRYPT_S390_MSA && !test_facility(17)) + return 0; + if (facility_mask & CRYPT_S390_MSA3 && !test_facility(76)) + return 0; + if (facility_mask & CRYPT_S390_MSA4 && !test_facility(77)) return 0; switch (func & CRYPT_S390_OP_MASK) { @@ -316,6 +389,10 @@ static inline int crypt_s390_func_available(int func) case CRYPT_S390_KMAC: ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0); break; + case CRYPT_S390_KMCTR: + ret = crypt_s390_kmctr(KMCTR_QUERY, &status, NULL, NULL, 0, + NULL); + break; default: return 0; } @@ -326,4 +403,31 @@ static inline int crypt_s390_func_available(int func) return (status[func >> 3] & (0x80 >> (func & 7))) != 0; } +/** + * crypt_s390_pcc: + * @func: the function code passed to KM; see crypt_s390_km_func + * @param: address of parameter block; see POP for details on each func + * + * Executes the PCC (PERFORM CRYPTOGRAPHIC COMPUTATION) operation of the CPU. + * + * Returns -1 for failure, 0 for success. + */ +static inline int crypt_s390_pcc(long func, void *param) +{ + register long __func asm("0") = func & 0x7f; /* encrypt or decrypt */ + register void *__param asm("1") = param; + int ret = -1; + + asm volatile( + "0: .insn rre,0xb92c0000,0,0 \n" /* PCC opcode */ + "1: brc 1,0b \n" /* handle partial completion */ + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) + : "+d" (ret) + : "d" (__func), "a" (__param) : "cc", "memory"); + return ret; +} + + #endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */ diff --git a/arch/s390/crypto/des_check_key.c b/arch/s390/crypto/des_check_key.c deleted file mode 100644 index 5706af266442..000000000000 --- a/arch/s390/crypto/des_check_key.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Cryptographic API. - * - * Function for checking keys for the DES and Tripple DES Encryption - * algorithms. - * - * Originally released as descore by Dana L. How . - * Modified by Raimar Falke for the Linux-Kernel. - * Derived from Cryptoapi and Nettle implementations, adapted for in-place - * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL. - * - * s390 Version: - * Copyright IBM Corp. 2003 - * Author(s): Thomas Spatzier - * Jan Glauber (jan.glauber@de.ibm.com) - * - * Derived from "crypto/des.c" - * Copyright (c) 1992 Dana L. How. - * Copyright (c) Raimar Falke - * Copyright (c) Gisle Sflensminde - * Copyright (C) 2001 Niels Mvller. - * Copyright (c) 2002 James Morris - * - * 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 "crypto_des.h" - -#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o)) - -static const u8 parity[] = { - 8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3, - 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, - 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, - 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, - 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, - 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, - 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, - 4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8, -}; - -/* - * RFC2451: Weak key checks SHOULD be performed. - */ -int -crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags) -{ - u32 n, w; - - n = parity[key[0]]; n <<= 4; - n |= parity[key[1]]; n <<= 4; - n |= parity[key[2]]; n <<= 4; - n |= parity[key[3]]; n <<= 4; - n |= parity[key[4]]; n <<= 4; - n |= parity[key[5]]; n <<= 4; - n |= parity[key[6]]; n <<= 4; - n |= parity[key[7]]; - w = 0x88888888L; - - if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY) - && !((n - (w >> 3)) & w)) { /* 1 in 10^10 keys passes this test */ - if (n < 0x41415151) { - if (n < 0x31312121) { - if (n < 0x14141515) { - /* 01 01 01 01 01 01 01 01 */ - if (n == 0x11111111) goto weak; - /* 01 1F 01 1F 01 0E 01 0E */ - if (n == 0x13131212) goto weak; - } else { - /* 01 E0 01 E0 01 F1 01 F1 */ - if (n == 0x14141515) goto weak; - /* 01 FE 01 FE 01 FE 01 FE */ - if (n == 0x16161616) goto weak; - } - } else { - if (n < 0x34342525) { - /* 1F 01 1F 01 0E 01 0E 01 */ - if (n == 0x31312121) goto weak; - /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */ - if (n == 0x33332222) goto weak; - } else { - /* 1F E0 1F E0 0E F1 0E F1 */ - if (n == 0x34342525) goto weak; - /* 1F FE 1F FE 0E FE 0E FE */ - if (n == 0x36362626) goto weak; - } - } - } else { - if (n < 0x61616161) { - if (n < 0x44445555) { - /* E0 01 E0 01 F1 01 F1 01 */ - if (n == 0x41415151) goto weak; - /* E0 1F E0 1F F1 0E F1 0E */ - if (n == 0x43435252) goto weak; - } else { - /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */ - if (n == 0x44445555) goto weak; - /* E0 FE E0 FE F1 FE F1 FE */ - if (n == 0x46465656) goto weak; - } - } else { - if (n < 0x64646565) { - /* FE 01 FE 01 FE 01 FE 01 */ - if (n == 0x61616161) goto weak; - /* FE 1F FE 1F FE 0E FE 0E */ - if (n == 0x63636262) goto weak; - } else { - /* FE E0 FE E0 FE F1 FE F1 */ - if (n == 0x64646565) goto weak; - /* FE FE FE FE FE FE FE FE */ - if (n == 0x66666666) goto weak; - } - } - } - } - return 0; -weak: - *flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; -} - -EXPORT_SYMBOL(crypto_des_check_key); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Key Check function for DES & DES3 Cipher Algorithms"); diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index cc5420118393..a52bfd124d86 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -3,7 +3,7 @@ * * s390 implementation of the DES Cipher Algorithm. * - * Copyright IBM Corp. 2003,2007 + * Copyright IBM Corp. 2003,2011 * Author(s): Thomas Spatzier * Jan Glauber (jan.glauber@de.ibm.com) * @@ -22,22 +22,19 @@ #include "crypt_s390.h" -#define DES3_192_KEY_SIZE (3 * DES_KEY_SIZE) +#define DES3_KEY_SIZE (3 * DES_KEY_SIZE) -struct crypt_s390_des_ctx { - u8 iv[DES_BLOCK_SIZE]; - u8 key[DES_KEY_SIZE]; -}; +static u8 *ctrblk; -struct crypt_s390_des3_192_ctx { +struct s390_des_ctx { u8 iv[DES_BLOCK_SIZE]; - u8 key[DES3_192_KEY_SIZE]; + u8 key[DES3_KEY_SIZE]; }; static int des_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) + unsigned int key_len) { - struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm); + struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); u32 *flags = &tfm->crt_flags; u32 tmp[DES_EXPKEY_WORDS]; @@ -47,22 +44,22 @@ static int des_setkey(struct crypto_tfm *tfm, const u8 *key, return -EINVAL; } - memcpy(dctx->key, key, keylen); + memcpy(ctx->key, key, key_len); return 0; } static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { - struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm); + struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); - crypt_s390_km(KM_DEA_ENCRYPT, dctx->key, out, in, DES_BLOCK_SIZE); + crypt_s390_km(KM_DEA_ENCRYPT, ctx->key, out, in, DES_BLOCK_SIZE); } static void des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { - struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm); + struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); - crypt_s390_km(KM_DEA_DECRYPT, dctx->key, out, in, DES_BLOCK_SIZE); + crypt_s390_km(KM_DEA_DECRYPT, ctx->key, out, in, DES_BLOCK_SIZE); } static struct crypto_alg des_alg = { @@ -71,7 +68,7 @@ static struct crypto_alg des_alg = { .cra_priority = CRYPT_S390_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_des_ctx), + .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(des_alg.cra_list), .cra_u = { @@ -86,7 +83,7 @@ static struct crypto_alg des_alg = { }; static int ecb_desall_crypt(struct blkcipher_desc *desc, long func, - void *param, struct blkcipher_walk *walk) + u8 *key, struct blkcipher_walk *walk) { int ret = blkcipher_walk_virt(desc, walk); unsigned int nbytes; @@ -97,7 +94,7 @@ static int ecb_desall_crypt(struct blkcipher_desc *desc, long func, u8 *out = walk->dst.virt.addr; u8 *in = walk->src.virt.addr; - ret = crypt_s390_km(func, param, out, in, n); + ret = crypt_s390_km(func, key, out, in, n); BUG_ON((ret < 0) || (ret != n)); nbytes &= DES_BLOCK_SIZE - 1; @@ -108,7 +105,7 @@ static int ecb_desall_crypt(struct blkcipher_desc *desc, long func, } static int cbc_desall_crypt(struct blkcipher_desc *desc, long func, - void *param, struct blkcipher_walk *walk) + u8 *iv, struct blkcipher_walk *walk) { int ret = blkcipher_walk_virt(desc, walk); unsigned int nbytes = walk->nbytes; @@ -116,20 +113,20 @@ static int cbc_desall_crypt(struct blkcipher_desc *desc, long func, if (!nbytes) goto out; - memcpy(param, walk->iv, DES_BLOCK_SIZE); + memcpy(iv, walk->iv, DES_BLOCK_SIZE); do { /* only use complete blocks */ unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1); u8 *out = walk->dst.virt.addr; u8 *in = walk->src.virt.addr; - ret = crypt_s390_kmc(func, param, out, in, n); + ret = crypt_s390_kmc(func, iv, out, in, n); BUG_ON((ret < 0) || (ret != n)); nbytes &= DES_BLOCK_SIZE - 1; ret = blkcipher_walk_done(desc, walk, nbytes); } while ((nbytes = walk->nbytes)); - memcpy(walk->iv, param, DES_BLOCK_SIZE); + memcpy(walk->iv, iv, DES_BLOCK_SIZE); out: return ret; @@ -139,22 +136,22 @@ static int ecb_des_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return ecb_desall_crypt(desc, KM_DEA_ENCRYPT, sctx->key, &walk); + return ecb_desall_crypt(desc, KM_DEA_ENCRYPT, ctx->key, &walk); } static int ecb_des_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return ecb_desall_crypt(desc, KM_DEA_DECRYPT, sctx->key, &walk); + return ecb_desall_crypt(desc, KM_DEA_DECRYPT, ctx->key, &walk); } static struct crypto_alg ecb_des_alg = { @@ -163,7 +160,7 @@ static struct crypto_alg ecb_des_alg = { .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_des_ctx), + .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list), @@ -182,22 +179,22 @@ static int cbc_des_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, sctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, ctx->iv, &walk); } static int cbc_des_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, sctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, ctx->iv, &walk); } static struct crypto_alg cbc_des_alg = { @@ -206,7 +203,7 @@ static struct crypto_alg cbc_des_alg = { .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_des_ctx), + .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list), @@ -235,10 +232,10 @@ static struct crypto_alg cbc_des_alg = { * property. * */ -static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) +static int des3_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int key_len) { - struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm); + struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); u32 *flags = &tfm->crt_flags; if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) && @@ -248,141 +245,276 @@ static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key, *flags |= CRYPTO_TFM_RES_WEAK_KEY; return -EINVAL; } - memcpy(dctx->key, key, keylen); + memcpy(ctx->key, key, key_len); return 0; } -static void des3_192_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void des3_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { - struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm); + struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); - crypt_s390_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src, - DES_BLOCK_SIZE); + crypt_s390_km(KM_TDEA_192_ENCRYPT, ctx->key, dst, src, DES_BLOCK_SIZE); } -static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void des3_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { - struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm); + struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); - crypt_s390_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src, - DES_BLOCK_SIZE); + crypt_s390_km(KM_TDEA_192_DECRYPT, ctx->key, dst, src, DES_BLOCK_SIZE); } -static struct crypto_alg des3_192_alg = { +static struct crypto_alg des3_alg = { .cra_name = "des3_ede", .cra_driver_name = "des3_ede-s390", .cra_priority = CRYPT_S390_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx), + .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list), + .cra_list = LIST_HEAD_INIT(des3_alg.cra_list), .cra_u = { .cipher = { - .cia_min_keysize = DES3_192_KEY_SIZE, - .cia_max_keysize = DES3_192_KEY_SIZE, - .cia_setkey = des3_192_setkey, - .cia_encrypt = des3_192_encrypt, - .cia_decrypt = des3_192_decrypt, + .cia_min_keysize = DES3_KEY_SIZE, + .cia_max_keysize = DES3_KEY_SIZE, + .cia_setkey = des3_setkey, + .cia_encrypt = des3_encrypt, + .cia_decrypt = des3_decrypt, } } }; -static int ecb_des3_192_encrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int ecb_des3_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) { - struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return ecb_desall_crypt(desc, KM_TDEA_192_ENCRYPT, sctx->key, &walk); + return ecb_desall_crypt(desc, KM_TDEA_192_ENCRYPT, ctx->key, &walk); } -static int ecb_des3_192_decrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int ecb_des3_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) { - struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return ecb_desall_crypt(desc, KM_TDEA_192_DECRYPT, sctx->key, &walk); + return ecb_desall_crypt(desc, KM_TDEA_192_DECRYPT, ctx->key, &walk); } -static struct crypto_alg ecb_des3_192_alg = { +static struct crypto_alg ecb_des3_alg = { .cra_name = "ecb(des3_ede)", .cra_driver_name = "ecb-des3_ede-s390", .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx), + .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT( - ecb_des3_192_alg.cra_list), + ecb_des3_alg.cra_list), .cra_u = { .blkcipher = { - .min_keysize = DES3_192_KEY_SIZE, - .max_keysize = DES3_192_KEY_SIZE, - .setkey = des3_192_setkey, - .encrypt = ecb_des3_192_encrypt, - .decrypt = ecb_des3_192_decrypt, + .min_keysize = DES3_KEY_SIZE, + .max_keysize = DES3_KEY_SIZE, + .setkey = des3_setkey, + .encrypt = ecb_des3_encrypt, + .decrypt = ecb_des3_decrypt, } } }; -static int cbc_des3_192_encrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int cbc_des3_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) { - struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, sctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, ctx->iv, &walk); } -static int cbc_des3_192_decrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int cbc_des3_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) { - struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, sctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, ctx->iv, &walk); } -static struct crypto_alg cbc_des3_192_alg = { +static struct crypto_alg cbc_des3_alg = { .cra_name = "cbc(des3_ede)", .cra_driver_name = "cbc-des3_ede-s390", .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx), + .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT( - cbc_des3_192_alg.cra_list), + cbc_des3_alg.cra_list), .cra_u = { .blkcipher = { - .min_keysize = DES3_192_KEY_SIZE, - .max_keysize = DES3_192_KEY_SIZE, + .min_keysize = DES3_KEY_SIZE, + .max_keysize = DES3_KEY_SIZE, .ivsize = DES_BLOCK_SIZE, - .setkey = des3_192_setkey, - .encrypt = cbc_des3_192_encrypt, - .decrypt = cbc_des3_192_decrypt, + .setkey = des3_setkey, + .encrypt = cbc_des3_encrypt, + .decrypt = cbc_des3_decrypt, } } }; -static int des_s390_init(void) +static int ctr_desall_crypt(struct blkcipher_desc *desc, long func, + struct s390_des_ctx *ctx, struct blkcipher_walk *walk) +{ + int ret = blkcipher_walk_virt_block(desc, walk, DES_BLOCK_SIZE); + unsigned int i, n, nbytes; + u8 buf[DES_BLOCK_SIZE]; + u8 *out, *in; + + memcpy(ctrblk, walk->iv, DES_BLOCK_SIZE); + while ((nbytes = walk->nbytes) >= DES_BLOCK_SIZE) { + out = walk->dst.virt.addr; + in = walk->src.virt.addr; + while (nbytes >= DES_BLOCK_SIZE) { + /* align to block size, max. PAGE_SIZE */ + n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : + nbytes & ~(DES_BLOCK_SIZE - 1); + for (i = DES_BLOCK_SIZE; i < n; i += DES_BLOCK_SIZE) { + memcpy(ctrblk + i, ctrblk + i - DES_BLOCK_SIZE, + DES_BLOCK_SIZE); + crypto_inc(ctrblk + i, DES_BLOCK_SIZE); + } + ret = crypt_s390_kmctr(func, ctx->key, out, in, n, ctrblk); + BUG_ON((ret < 0) || (ret != n)); + if (n > DES_BLOCK_SIZE) + memcpy(ctrblk, ctrblk + n - DES_BLOCK_SIZE, + DES_BLOCK_SIZE); + crypto_inc(ctrblk, DES_BLOCK_SIZE); + out += n; + in += n; + nbytes -= n; + } + ret = blkcipher_walk_done(desc, walk, nbytes); + } + + /* final block may be < DES_BLOCK_SIZE, copy only nbytes */ + if (nbytes) { + out = walk->dst.virt.addr; + in = walk->src.virt.addr; + ret = crypt_s390_kmctr(func, ctx->key, buf, in, + DES_BLOCK_SIZE, ctrblk); + BUG_ON(ret < 0 || ret != DES_BLOCK_SIZE); + memcpy(out, buf, nbytes); + crypto_inc(ctrblk, DES_BLOCK_SIZE); + ret = blkcipher_walk_done(desc, walk, 0); + } + memcpy(walk->iv, ctrblk, DES_BLOCK_SIZE); + return ret; +} + +static int ctr_des_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ctr_desall_crypt(desc, KMCTR_DEA_ENCRYPT, ctx, &walk); +} + +static int ctr_des_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ctr_desall_crypt(desc, KMCTR_DEA_DECRYPT, ctx, &walk); +} + +static struct crypto_alg ctr_des_alg = { + .cra_name = "ctr(des)", + .cra_driver_name = "ctr-des-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct s390_des_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ctr_des_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = des_setkey, + .encrypt = ctr_des_encrypt, + .decrypt = ctr_des_decrypt, + } + } +}; + +static int ctr_des3_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ctr_desall_crypt(desc, KMCTR_TDEA_192_ENCRYPT, ctx, &walk); +} + +static int ctr_des3_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ctr_desall_crypt(desc, KMCTR_TDEA_192_DECRYPT, ctx, &walk); +} + +static struct crypto_alg ctr_des3_alg = { + .cra_name = "ctr(des3_ede)", + .cra_driver_name = "ctr-des3_ede-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct s390_des_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ctr_des3_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES3_KEY_SIZE, + .max_keysize = DES3_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = des3_setkey, + .encrypt = ctr_des3_encrypt, + .decrypt = ctr_des3_decrypt, + } + } +}; + +static int __init des_s390_init(void) { int ret; - if (!crypt_s390_func_available(KM_DEA_ENCRYPT) || - !crypt_s390_func_available(KM_TDEA_192_ENCRYPT)) + if (!crypt_s390_func_available(KM_DEA_ENCRYPT, CRYPT_S390_MSA) || + !crypt_s390_func_available(KM_TDEA_192_ENCRYPT, CRYPT_S390_MSA)) return -EOPNOTSUPP; ret = crypto_register_alg(&des_alg); @@ -394,23 +526,46 @@ static int des_s390_init(void) ret = crypto_register_alg(&cbc_des_alg); if (ret) goto cbc_des_err; - ret = crypto_register_alg(&des3_192_alg); + ret = crypto_register_alg(&des3_alg); if (ret) - goto des3_192_err; - ret = crypto_register_alg(&ecb_des3_192_alg); + goto des3_err; + ret = crypto_register_alg(&ecb_des3_alg); if (ret) - goto ecb_des3_192_err; - ret = crypto_register_alg(&cbc_des3_192_alg); + goto ecb_des3_err; + ret = crypto_register_alg(&cbc_des3_alg); if (ret) - goto cbc_des3_192_err; + goto cbc_des3_err; + + if (crypt_s390_func_available(KMCTR_DEA_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4) && + crypt_s390_func_available(KMCTR_TDEA_192_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4)) { + ret = crypto_register_alg(&ctr_des_alg); + if (ret) + goto ctr_des_err; + ret = crypto_register_alg(&ctr_des3_alg); + if (ret) + goto ctr_des3_err; + ctrblk = (u8 *) __get_free_page(GFP_KERNEL); + if (!ctrblk) { + ret = -ENOMEM; + goto ctr_mem_err; + } + } out: return ret; -cbc_des3_192_err: - crypto_unregister_alg(&ecb_des3_192_alg); -ecb_des3_192_err: - crypto_unregister_alg(&des3_192_alg); -des3_192_err: +ctr_mem_err: + crypto_unregister_alg(&ctr_des3_alg); +ctr_des3_err: + crypto_unregister_alg(&ctr_des_alg); +ctr_des_err: + crypto_unregister_alg(&cbc_des3_alg); +cbc_des3_err: + crypto_unregister_alg(&ecb_des3_alg); +ecb_des3_err: + crypto_unregister_alg(&des3_alg); +des3_err: crypto_unregister_alg(&cbc_des_alg); cbc_des_err: crypto_unregister_alg(&ecb_des_alg); @@ -422,9 +577,14 @@ static int des_s390_init(void) static void __exit des_s390_exit(void) { - crypto_unregister_alg(&cbc_des3_192_alg); - crypto_unregister_alg(&ecb_des3_192_alg); - crypto_unregister_alg(&des3_192_alg); + if (ctrblk) { + crypto_unregister_alg(&ctr_des_alg); + crypto_unregister_alg(&ctr_des3_alg); + free_page((unsigned long) ctrblk); + } + crypto_unregister_alg(&cbc_des3_alg); + crypto_unregister_alg(&ecb_des3_alg); + crypto_unregister_alg(&des3_alg); crypto_unregister_alg(&cbc_des_alg); crypto_unregister_alg(&ecb_des_alg); crypto_unregister_alg(&des_alg); diff --git a/arch/s390/crypto/ghash_s390.c b/arch/s390/crypto/ghash_s390.c new file mode 100644 index 000000000000..b1bd170f24b1 --- /dev/null +++ b/arch/s390/crypto/ghash_s390.c @@ -0,0 +1,162 @@ +/* + * Cryptographic API. + * + * s390 implementation of the GHASH algorithm for GCM (Galois/Counter Mode). + * + * Copyright IBM Corp. 2011 + * Author(s): Gerald Schaefer + */ + +#include +#include + +#include "crypt_s390.h" + +#define GHASH_BLOCK_SIZE 16 +#define GHASH_DIGEST_SIZE 16 + +struct ghash_ctx { + u8 icv[16]; + u8 key[16]; +}; + +struct ghash_desc_ctx { + u8 buffer[GHASH_BLOCK_SIZE]; + u32 bytes; +}; + +static int ghash_init(struct shash_desc *desc) +{ + struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); + + memset(dctx, 0, sizeof(*dctx)); + + return 0; +} + +static int ghash_setkey(struct crypto_shash *tfm, + const u8 *key, unsigned int keylen) +{ + struct ghash_ctx *ctx = crypto_shash_ctx(tfm); + + if (keylen != GHASH_BLOCK_SIZE) { + crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + memcpy(ctx->key, key, GHASH_BLOCK_SIZE); + memset(ctx->icv, 0, GHASH_BLOCK_SIZE); + + return 0; +} + +static int ghash_update(struct shash_desc *desc, + const u8 *src, unsigned int srclen) +{ + struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); + struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); + unsigned int n; + u8 *buf = dctx->buffer; + int ret; + + if (dctx->bytes) { + u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); + + n = min(srclen, dctx->bytes); + dctx->bytes -= n; + srclen -= n; + + memcpy(pos, src, n); + src += n; + + if (!dctx->bytes) { + ret = crypt_s390_kimd(KIMD_GHASH, ctx, buf, + GHASH_BLOCK_SIZE); + BUG_ON(ret != GHASH_BLOCK_SIZE); + } + } + + n = srclen & ~(GHASH_BLOCK_SIZE - 1); + if (n) { + ret = crypt_s390_kimd(KIMD_GHASH, ctx, src, n); + BUG_ON(ret != n); + src += n; + srclen -= n; + } + + if (srclen) { + dctx->bytes = GHASH_BLOCK_SIZE - srclen; + memcpy(buf, src, srclen); + } + + return 0; +} + +static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx) +{ + u8 *buf = dctx->buffer; + int ret; + + if (dctx->bytes) { + u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); + + memset(pos, 0, dctx->bytes); + + ret = crypt_s390_kimd(KIMD_GHASH, ctx, buf, GHASH_BLOCK_SIZE); + BUG_ON(ret != GHASH_BLOCK_SIZE); + } + + dctx->bytes = 0; +} + +static int ghash_final(struct shash_desc *desc, u8 *dst) +{ + struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); + struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); + + ghash_flush(ctx, dctx); + memcpy(dst, ctx->icv, GHASH_BLOCK_SIZE); + + return 0; +} + +static struct shash_alg ghash_alg = { + .digestsize = GHASH_DIGEST_SIZE, + .init = ghash_init, + .update = ghash_update, + .final = ghash_final, + .setkey = ghash_setkey, + .descsize = sizeof(struct ghash_desc_ctx), + .base = { + .cra_name = "ghash", + .cra_driver_name = "ghash-s390", + .cra_priority = CRYPT_S390_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = GHASH_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ghash_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list), + }, +}; + +static int __init ghash_mod_init(void) +{ + if (!crypt_s390_func_available(KIMD_GHASH, + CRYPT_S390_MSA | CRYPT_S390_MSA4)) + return -EOPNOTSUPP; + + return crypto_register_shash(&ghash_alg); +} + +static void __exit ghash_mod_exit(void) +{ + crypto_unregister_shash(&ghash_alg); +} + +module_init(ghash_mod_init); +module_exit(ghash_mod_exit); + +MODULE_ALIAS("ghash"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GHASH Message Digest Algorithm, s390 implementation"); diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c index 975e3ab13cb5..0808fbf0f7d3 100644 --- a/arch/s390/crypto/prng.c +++ b/arch/s390/crypto/prng.c @@ -76,7 +76,7 @@ static void prng_seed(int nbytes) /* Add the entropy */ while (nbytes >= 8) { - *((__u64 *)parm_block) ^= *((__u64 *)buf+i*8); + *((__u64 *)parm_block) ^= *((__u64 *)(buf+i)); prng_add_entropy(); i += 8; nbytes -= 8; @@ -166,7 +166,7 @@ static int __init prng_init(void) int ret; /* check if the CPU has a PRNG */ - if (!crypt_s390_func_available(KMC_PRNG)) + if (!crypt_s390_func_available(KMC_PRNG, CRYPT_S390_MSA)) return -EOPNOTSUPP; if (prng_chunk_size < 8) diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index f6de7826c979..e9868c6e0a08 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -90,7 +90,7 @@ static struct shash_alg alg = { static int __init sha1_s390_init(void) { - if (!crypt_s390_func_available(KIMD_SHA_1)) + if (!crypt_s390_func_available(KIMD_SHA_1, CRYPT_S390_MSA)) return -EOPNOTSUPP; return crypto_register_shash(&alg); } diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index 61a7db372121..5ed8d64fc2ed 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -86,7 +86,7 @@ static struct shash_alg alg = { static int sha256_s390_init(void) { - if (!crypt_s390_func_available(KIMD_SHA_256)) + if (!crypt_s390_func_available(KIMD_SHA_256, CRYPT_S390_MSA)) return -EOPNOTSUPP; return crypto_register_shash(&alg); diff --git a/arch/s390/crypto/sha512_s390.c b/arch/s390/crypto/sha512_s390.c index 4bf73d0dc525..32a81383b69c 100644 --- a/arch/s390/crypto/sha512_s390.c +++ b/arch/s390/crypto/sha512_s390.c @@ -132,7 +132,7 @@ static int __init init(void) { int ret; - if (!crypt_s390_func_available(KIMD_SHA_512)) + if (!crypt_s390_func_available(KIMD_SHA_512, CRYPT_S390_MSA)) return -EOPNOTSUPP; if ((ret = crypto_register_shash(&sha512_alg)) < 0) goto out; diff --git a/arch/s390/include/asm/cacheflush.h b/arch/s390/include/asm/cacheflush.h index 43a5c78046db..3e20383d0921 100644 --- a/arch/s390/include/asm/cacheflush.h +++ b/arch/s390/include/asm/cacheflush.h @@ -11,5 +11,6 @@ void kernel_map_pages(struct page *page, int numpages, int enable); int set_memory_ro(unsigned long addr, int numpages); int set_memory_rw(unsigned long addr, int numpages); int set_memory_nx(unsigned long addr, int numpages); +int set_memory_x(unsigned long addr, int numpages); #endif /* _S390_CACHEFLUSH_H */ diff --git a/arch/s390/include/asm/diag.h b/arch/s390/include/asm/diag.h index 72b2e2f2d32d..7e91c58072e2 100644 --- a/arch/s390/include/asm/diag.h +++ b/arch/s390/include/asm/diag.h @@ -9,9 +9,22 @@ #define _ASM_S390_DIAG_H /* - * Diagnose 10: Release pages + * Diagnose 10: Release page range */ -extern void diag10(unsigned long addr); +static inline void diag10_range(unsigned long start_pfn, unsigned long num_pfn) +{ + unsigned long start_addr, end_addr; + + start_addr = start_pfn << PAGE_SHIFT; + end_addr = (start_pfn + num_pfn - 1) << PAGE_SHIFT; + + asm volatile( + "0: diag %0,%1,0x10\n" + "1:\n" + EX_TABLE(0b, 1b) + EX_TABLE(1b, 1b) + : : "a" (start_addr), "a" (end_addr)); +} /* * Diagnose 14: Input spool file manipulation diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h index 3c29be4836ed..b7931faaef6d 100644 --- a/arch/s390/include/asm/ftrace.h +++ b/arch/s390/include/asm/ftrace.h @@ -11,15 +11,13 @@ struct dyn_arch_ftrace { }; #ifdef CONFIG_64BIT #define MCOUNT_INSN_SIZE 12 -#define MCOUNT_OFFSET 8 #else #define MCOUNT_INSN_SIZE 20 -#define MCOUNT_OFFSET 4 #endif static inline unsigned long ftrace_call_adjust(unsigned long addr) { - return addr - MCOUNT_OFFSET; + return addr; } #endif /* __ASSEMBLY__ */ diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h new file mode 100644 index 000000000000..95a6cf2b5b67 --- /dev/null +++ b/arch/s390/include/asm/jump_label.h @@ -0,0 +1,37 @@ +#ifndef _ASM_S390_JUMP_LABEL_H +#define _ASM_S390_JUMP_LABEL_H + +#include + +#define JUMP_LABEL_NOP_SIZE 6 + +#ifdef CONFIG_64BIT +#define ASM_PTR ".quad" +#define ASM_ALIGN ".balign 8" +#else +#define ASM_PTR ".long" +#define ASM_ALIGN ".balign 4" +#endif + +static __always_inline bool arch_static_branch(struct jump_label_key *key) +{ + asm goto("0: brcl 0,0\n" + ".pushsection __jump_table, \"aw\"\n" + ASM_ALIGN "\n" + ASM_PTR " 0b, %l[label], %0\n" + ".popsection\n" + : : "X" (key) : : label); + return false; +label: + return true; +} + +typedef unsigned long jump_label_t; + +struct jump_entry { + jump_label_t code; + jump_label_t target; + jump_label_t key; +}; + +#endif diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index a6f0e7cc9cde..8c277caa8d3a 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -23,7 +23,7 @@ static inline int init_new_context(struct task_struct *tsk, #ifdef CONFIG_64BIT mm->context.asce_bits |= _ASCE_TYPE_REGION3; #endif - if (current->mm->context.alloc_pgste) { + if (current->mm && current->mm->context.alloc_pgste) { /* * alloc_pgste indicates, that any NEW context will be created * with extended page tables. The old context is unchanged. The diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 64230bc392fa..5ff15dacb571 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -23,7 +23,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o \ processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o \ - vdso.o vtime.o sysinfo.o nmi.o sclp.o + vdso.o vtime.o sysinfo.o nmi.o sclp.o jump_label.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) diff --git a/arch/s390/kernel/diag.c b/arch/s390/kernel/diag.c index c032d11da8a1..8237fc07ac79 100644 --- a/arch/s390/kernel/diag.c +++ b/arch/s390/kernel/diag.c @@ -8,27 +8,6 @@ #include #include -/* - * Diagnose 10: Release pages - */ -void diag10(unsigned long addr) -{ - if (addr >= 0x7ff00000) - return; - asm volatile( -#ifdef CONFIG_64BIT - " sam31\n" - " diag %0,%0,0x10\n" - "0: sam64\n" -#else - " diag %0,%0,0x10\n" - "0:\n" -#endif - EX_TABLE(0b, 0b) - : : "a" (addr)); -} -EXPORT_SYMBOL(diag10); - /* * Diagnose 14: Input spool file manipulation */ diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index c83726c9fe03..3d4a78fc1adc 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -672,6 +672,7 @@ static struct insn opcode_b2[] = { { "rp", 0x77, INSTR_S_RD }, { "stcke", 0x78, INSTR_S_RD }, { "sacf", 0x79, INSTR_S_RD }, + { "spp", 0x80, INSTR_S_RD }, { "stsi", 0x7d, INSTR_S_RD }, { "srnm", 0x99, INSTR_S_RD }, { "stfpc", 0x9c, INSTR_S_RD }, diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 648f64239a9d..1b67fc6ebdc2 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -836,7 +836,7 @@ restart_base: stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on basr %r14,0 l %r14,restart_addr-.(%r14) - br %r14 # branch to start_secondary + basr %r14,%r14 # branch to start_secondary restart_addr: .long start_secondary .align 8 diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 9d3603d6c511..9fd864563499 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -841,7 +841,7 @@ restart_base: mvc __LC_SYSTEM_TIMER(8),__TI_system_timer(%r1) xc __LC_STEAL_TIMER(8),__LC_STEAL_TIMER stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on - jg start_secondary + brasl %r14,start_secondary .align 8 restart_vtime: .long 0x7fffffff,0xffffffff diff --git a/arch/s390/kernel/jump_label.c b/arch/s390/kernel/jump_label.c new file mode 100644 index 000000000000..44cc06bedf77 --- /dev/null +++ b/arch/s390/kernel/jump_label.c @@ -0,0 +1,59 @@ +/* + * Jump label s390 support + * + * Copyright IBM Corp. 2011 + * Author(s): Jan Glauber + */ +#include +#include +#include +#include +#include + +#ifdef HAVE_JUMP_LABEL + +struct insn { + u16 opcode; + s32 offset; +} __packed; + +struct insn_args { + unsigned long *target; + struct insn *insn; + ssize_t size; +}; + +static int __arch_jump_label_transform(void *data) +{ + struct insn_args *args = data; + int rc; + + rc = probe_kernel_write(args->target, args->insn, args->size); + WARN_ON_ONCE(rc < 0); + return 0; +} + +void arch_jump_label_transform(struct jump_entry *entry, + enum jump_label_type type) +{ + struct insn_args args; + struct insn insn; + + if (type == JUMP_LABEL_ENABLE) { + /* brcl 15,offset */ + insn.opcode = 0xc0f4; + insn.offset = (entry->target - entry->code) >> 1; + } else { + /* brcl 0,0 */ + insn.opcode = 0xc004; + insn.offset = 0; + } + + args.target = (void *) entry->code; + args.insn = &insn; + args.size = JUMP_LABEL_NOP_SIZE; + + stop_machine(__arch_jump_label_transform, &args, NULL); +} + +#endif diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 63a97db83f96..63c7d9ff220d 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -165,12 +165,12 @@ static void do_ext_call_interrupt(unsigned int ext_int_code, kstat_cpu(smp_processor_id()).irqs[EXTINT_IPI]++; /* * handle bit signal external calls - * - * For the ec_schedule signal we have to do nothing. All the work - * is done automatically when we return from the interrupt. */ bits = xchg(&S390_lowcore.ext_call_fast, 0); + if (test_bit(ec_schedule, &bits)) + scheduler_ipi(); + if (test_bit(ec_call_function, &bits)) generic_smp_call_function_interrupt(); diff --git a/arch/s390/kvm/sie64a.S b/arch/s390/kvm/sie64a.S index 7e9d30d567b0..ab0e041ac54c 100644 --- a/arch/s390/kvm/sie64a.S +++ b/arch/s390/kvm/sie64a.S @@ -48,10 +48,10 @@ sie_irq_handler: tm __TI_flags+7(%r2),_TIF_EXIT_SIE jz 0f larl %r2,sie_exit # work pending, leave sie - stg %r2,__LC_RETURN_PSW+8 + stg %r2,SPI_PSW+8(0,%r15) br %r14 0: larl %r2,sie_reenter # re-enter with guest id - stg %r2,__LC_RETURN_PSW+8 + stg %r2,SPI_PSW+8(0,%r15) 1: br %r14 /* diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index c66ffd8dbbb7..1f1dba9dcf58 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -91,7 +91,7 @@ static long cmm_alloc_pages(long nr, long *counter, } else free_page((unsigned long) npa); } - diag10(addr); + diag10_range(addr >> PAGE_SHIFT, 1); pa->pages[pa->index++] = addr; (*counter)++; spin_unlock(&cmm_lock); diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 9217e332b118..ab988135e5c6 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -543,7 +543,6 @@ static void pfault_interrupt(unsigned int ext_int_code, struct task_struct *tsk; __u16 subcode; - kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++; /* * Get the external interruption subcode & pfault * initial/completion signal bit. VM stores this @@ -553,14 +552,15 @@ static void pfault_interrupt(unsigned int ext_int_code, subcode = ext_int_code >> 16; if ((subcode & 0xff00) != __SUBCODE_MASK) return; + kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++; /* * Get the token (= address of the task structure of the affected task). */ #ifdef CONFIG_64BIT - tsk = *(struct task_struct **) param64; + tsk = (struct task_struct *) param64; #else - tsk = *(struct task_struct **) param32; + tsk = (struct task_struct *) param32; #endif if (subcode & 0x0080) { diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index 122ffbd08ce0..f05edcc3beff 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c @@ -24,12 +24,13 @@ static void change_page_attr(unsigned long addr, int numpages, WARN_ON_ONCE(1); continue; } - ptep = pte_offset_kernel(pmdp, addr + i * PAGE_SIZE); + ptep = pte_offset_kernel(pmdp, addr); pte = *ptep; pte = set(pte); - ptep_invalidate(&init_mm, addr + i * PAGE_SIZE, ptep); + ptep_invalidate(&init_mm, addr, ptep); *ptep = pte; + addr += PAGE_SIZE; } } @@ -53,3 +54,8 @@ int set_memory_nx(unsigned long addr, int numpages) return 0; } EXPORT_SYMBOL_GPL(set_memory_nx); + +int set_memory_x(unsigned long addr, int numpages) +{ + return 0; +} diff --git a/arch/s390/oprofile/hwsampler.c b/arch/s390/oprofile/hwsampler.c index 4952872d6f0a..33cbd373cce4 100644 --- a/arch/s390/oprofile/hwsampler.c +++ b/arch/s390/oprofile/hwsampler.c @@ -1021,20 +1021,14 @@ int hwsampler_deallocate() return rc; } -long hwsampler_query_min_interval(void) +unsigned long hwsampler_query_min_interval(void) { - if (min_sampler_rate) - return min_sampler_rate; - else - return -EINVAL; + return min_sampler_rate; } -long hwsampler_query_max_interval(void) +unsigned long hwsampler_query_max_interval(void) { - if (max_sampler_rate) - return max_sampler_rate; - else - return -EINVAL; + return max_sampler_rate; } unsigned long hwsampler_get_sample_overflow_count(unsigned int cpu) diff --git a/arch/s390/oprofile/hwsampler.h b/arch/s390/oprofile/hwsampler.h index 8c72b59316b5..1912f3bb190c 100644 --- a/arch/s390/oprofile/hwsampler.h +++ b/arch/s390/oprofile/hwsampler.h @@ -102,8 +102,8 @@ int hwsampler_setup(void); int hwsampler_shutdown(void); int hwsampler_allocate(unsigned long sdbt, unsigned long sdb); int hwsampler_deallocate(void); -long hwsampler_query_min_interval(void); -long hwsampler_query_max_interval(void); +unsigned long hwsampler_query_min_interval(void); +unsigned long hwsampler_query_max_interval(void); int hwsampler_start_all(unsigned long interval); int hwsampler_stop_all(void); int hwsampler_deactivate(unsigned int cpu); diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index c63d7e58352b..5995e9bc72d9 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c @@ -145,15 +145,11 @@ static int oprofile_hwsampler_init(struct oprofile_operations *ops) * create hwsampler files only if hwsampler_setup() succeeds. */ oprofile_min_interval = hwsampler_query_min_interval(); - if (oprofile_min_interval < 0) { - oprofile_min_interval = 0; + if (oprofile_min_interval == 0) return -ENODEV; - } oprofile_max_interval = hwsampler_query_max_interval(); - if (oprofile_max_interval < 0) { - oprofile_max_interval = 0; + if (oprofile_max_interval == 0) return -ENODEV; - } if (oprofile_timer_init(ops)) return -ENODEV; diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 4b89da248d17..bc439de48cd1 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -24,7 +24,6 @@ config SUPERH select RTC_LIB select GENERIC_ATOMIC64 select GENERIC_IRQ_SHOW - select ARCH_NO_SYSDEV_OPS help The SuperH is a RISC processor targeted for use in embedded systems and consumer electronics; it was also used in the Sega Dreamcast diff --git a/arch/sh/configs/apsh4ad0a_defconfig b/arch/sh/configs/apsh4ad0a_defconfig index e71a531f1e31..77ec0e7b8ddf 100644 --- a/arch/sh/configs/apsh4ad0a_defconfig +++ b/arch/sh/configs/apsh4ad0a_defconfig @@ -48,7 +48,6 @@ CONFIG_PREEMPT=y CONFIG_BINFMT_MISC=y CONFIG_PM=y CONFIG_PM_DEBUG=y -CONFIG_PM_VERBOSE=y CONFIG_PM_RUNTIME=y CONFIG_CPU_IDLE=y CONFIG_NET=y diff --git a/arch/sh/configs/sdk7786_defconfig b/arch/sh/configs/sdk7786_defconfig index dc4a2eb6a616..c41650572d79 100644 --- a/arch/sh/configs/sdk7786_defconfig +++ b/arch/sh/configs/sdk7786_defconfig @@ -83,7 +83,6 @@ CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_BINFMT_MISC=y CONFIG_PM=y CONFIG_PM_DEBUG=y -CONFIG_PM_VERBOSE=y CONFIG_PM_RUNTIME=y CONFIG_CPU_IDLE=y CONFIG_NET=y diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 14726eef1ce0..f0907995b4c9 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/sh/kernel/cpu/shmobile/pm_runtime.c b/arch/sh/kernel/cpu/shmobile/pm_runtime.c index 6dcb8166a64d..22db127afa7b 100644 --- a/arch/sh/kernel/cpu/shmobile/pm_runtime.c +++ b/arch/sh/kernel/cpu/shmobile/pm_runtime.c @@ -139,7 +139,7 @@ void platform_pm_runtime_suspend_idle(void) queue_work(pm_wq, &hwblk_work); } -int platform_pm_runtime_suspend(struct device *dev) +static int default_platform_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct pdev_archdata *ad = &pdev->archdata; @@ -147,7 +147,7 @@ int platform_pm_runtime_suspend(struct device *dev) int hwblk = ad->hwblk_id; int ret = 0; - dev_dbg(dev, "platform_pm_runtime_suspend() [%d]\n", hwblk); + dev_dbg(dev, "%s() [%d]\n", __func__, hwblk); /* ignore off-chip platform devices */ if (!hwblk) @@ -183,20 +183,20 @@ int platform_pm_runtime_suspend(struct device *dev) mutex_unlock(&ad->mutex); out: - dev_dbg(dev, "platform_pm_runtime_suspend() [%d] returns %d\n", - hwblk, ret); + dev_dbg(dev, "%s() [%d] returns %d\n", + __func__, hwblk, ret); return ret; } -int platform_pm_runtime_resume(struct device *dev) +static int default_platform_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct pdev_archdata *ad = &pdev->archdata; int hwblk = ad->hwblk_id; int ret = 0; - dev_dbg(dev, "platform_pm_runtime_resume() [%d]\n", hwblk); + dev_dbg(dev, "%s() [%d]\n", __func__, hwblk); /* ignore off-chip platform devices */ if (!hwblk) @@ -228,19 +228,19 @@ int platform_pm_runtime_resume(struct device *dev) */ mutex_unlock(&ad->mutex); out: - dev_dbg(dev, "platform_pm_runtime_resume() [%d] returns %d\n", - hwblk, ret); + dev_dbg(dev, "%s() [%d] returns %d\n", + __func__, hwblk, ret); return ret; } -int platform_pm_runtime_idle(struct device *dev) +static int default_platform_runtime_idle(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); int hwblk = pdev->archdata.hwblk_id; int ret = 0; - dev_dbg(dev, "platform_pm_runtime_idle() [%d]\n", hwblk); + dev_dbg(dev, "%s() [%d]\n", __func__, hwblk); /* ignore off-chip platform devices */ if (!hwblk) @@ -252,10 +252,19 @@ int platform_pm_runtime_idle(struct device *dev) /* suspend synchronously to disable clocks immediately */ ret = pm_runtime_suspend(dev); out: - dev_dbg(dev, "platform_pm_runtime_idle() [%d] done!\n", hwblk); + dev_dbg(dev, "%s() [%d] done!\n", __func__, hwblk); return ret; } +static struct dev_power_domain default_power_domain = { + .ops = { + .runtime_suspend = default_platform_runtime_suspend, + .runtime_resume = default_platform_runtime_resume, + .runtime_idle = default_platform_runtime_idle, + USE_PLATFORM_PM_SLEEP_OPS + }, +}; + static int platform_bus_notify(struct notifier_block *nb, unsigned long action, void *data) { @@ -276,6 +285,7 @@ static int platform_bus_notify(struct notifier_block *nb, hwblk_disable(hwblk_info, hwblk); /* make sure driver re-inits itself once */ __set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags); + dev->pwr_domain = &default_power_domain; break; /* TODO: add BUS_NOTIFY_BIND_DRIVER and increase idle count */ case BUS_NOTIFY_BOUND_DRIVER: @@ -289,6 +299,7 @@ static int platform_bus_notify(struct notifier_block *nb, __set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags); break; case BUS_NOTIFY_DEL_DEVICE: + dev->pwr_domain = NULL; break; } return 0; diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 2130ca674e9b..3d7b209b2178 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -117,7 +117,11 @@ void user_enable_single_step(struct task_struct *child) set_tsk_thread_flag(child, TIF_SINGLESTEP); + if (ptrace_get_breakpoints(child) < 0) + return; + set_single_step(child, pc); + ptrace_put_breakpoints(child); } void user_disable_single_step(struct task_struct *child) diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index 509b36b45115..6207561ea34a 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -323,6 +324,7 @@ void smp_message_recv(unsigned int msg) generic_smp_call_function_interrupt(); break; case SMP_MSG_RESCHEDULE: + scheduler_ipi(); break; case SMP_MSG_FUNCTION_SINGLE: generic_smp_call_function_single_interrupt(); diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 3484c2f65aba..b51a17104b5f 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -87,7 +87,6 @@ void die(const char * str, struct pt_regs * regs, long err) bust_spinlocks(1); printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); - sysfs_printk_last_file(); print_modules(); show_regs(regs); diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h index 427d4684e0d2..fc73a82366f8 100644 --- a/arch/sparc/include/asm/jump_label.h +++ b/arch/sparc/include/asm/jump_label.h @@ -7,17 +7,20 @@ #define JUMP_LABEL_NOP_SIZE 4 -#define JUMP_LABEL(key, label) \ - do { \ - asm goto("1:\n\t" \ - "nop\n\t" \ - "nop\n\t" \ - ".pushsection __jump_table, \"a\"\n\t"\ - ".align 4\n\t" \ - ".word 1b, %l[" #label "], %c0\n\t" \ - ".popsection \n\t" \ - : : "i" (key) : : label);\ - } while (0) +static __always_inline bool arch_static_branch(struct jump_label_key *key) +{ + asm goto("1:\n\t" + "nop\n\t" + "nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".align 4\n\t" + ".word 1b, %l[l_yes], %c0\n\t" + ".popsection \n\t" + : : "i" (key) : : l_yes); + return false; +l_yes: + return true; +} #endif /* __KERNEL__ */ diff --git a/arch/sparc/include/asm/topology_64.h b/arch/sparc/include/asm/topology_64.h index 1c79f32734a0..8b9c556d630b 100644 --- a/arch/sparc/include/asm/topology_64.h +++ b/arch/sparc/include/asm/topology_64.h @@ -65,6 +65,10 @@ static inline int pcibus_to_node(struct pci_bus *pbus) #define smt_capable() (sparc64_multi_core) #endif /* CONFIG_SMP */ -#define cpu_coregroup_mask(cpu) (&cpu_core_map[cpu]) +extern cpumask_t cpu_core_map[NR_CPUS]; +static inline const struct cpumask *cpu_coregroup_mask(int cpu) +{ + return &cpu_core_map[cpu]; +} #endif /* _ASM_SPARC64_TOPOLOGY_H */ diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index 9d897b6db983..c5387ed0add8 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h @@ -404,8 +404,9 @@ #define __NR_open_by_handle_at 333 #define __NR_clock_adjtime 334 #define __NR_syncfs 335 +#define __NR_sendmmsg 336 -#define NR_syscalls 336 +#define NR_syscalls 337 #ifdef __32bit_syscall_numbers__ /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c index f679c57644d5..1e34f29e58bb 100644 --- a/arch/sparc/kernel/apc.c +++ b/arch/sparc/kernel/apc.c @@ -165,7 +165,7 @@ static int __devinit apc_probe(struct platform_device *op) return 0; } -static struct of_device_id __initdata apc_match[] = { +static struct of_device_id apc_match[] = { { .name = APC_OBPNAME, }, diff --git a/arch/sparc/kernel/pci_sabre.c b/arch/sparc/kernel/pci_sabre.c index 948068a083fc..d1840dbdaa2f 100644 --- a/arch/sparc/kernel/pci_sabre.c +++ b/arch/sparc/kernel/pci_sabre.c @@ -452,8 +452,10 @@ static void __devinit sabre_pbm_init(struct pci_pbm_info *pbm, sabre_scan_bus(pbm, &op->dev); } +static const struct of_device_id sabre_match[]; static int __devinit sabre_probe(struct platform_device *op) { + const struct of_device_id *match; const struct linux_prom64_registers *pr_regs; struct device_node *dp = op->dev.of_node; struct pci_pbm_info *pbm; @@ -463,7 +465,8 @@ static int __devinit sabre_probe(struct platform_device *op) const u32 *vdma; u64 clear_irq; - hummingbird_p = op->dev.of_match && (op->dev.of_match->data != NULL); + match = of_match_device(sabre_match, &op->dev); + hummingbird_p = match && (match->data != NULL); if (!hummingbird_p) { struct device_node *cpu_dp; diff --git a/arch/sparc/kernel/pci_schizo.c b/arch/sparc/kernel/pci_schizo.c index fecfcb2063c8..283fbc329a43 100644 --- a/arch/sparc/kernel/pci_schizo.c +++ b/arch/sparc/kernel/pci_schizo.c @@ -1458,11 +1458,15 @@ static int __devinit __schizo_init(struct platform_device *op, unsigned long chi return err; } +static const struct of_device_id schizo_match[]; static int __devinit schizo_probe(struct platform_device *op) { - if (!op->dev.of_match) + const struct of_device_id *match; + + match = of_match_device(schizo_match, &op->dev); + if (!match) return -EINVAL; - return __schizo_init(op, (unsigned long) op->dev.of_match->data); + return __schizo_init(op, (unsigned long)match->data); } /* The ordering of this table is very important. Some Tomatillo diff --git a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c index 93d7b4465f8d..6a585d393580 100644 --- a/arch/sparc/kernel/pmc.c +++ b/arch/sparc/kernel/pmc.c @@ -69,7 +69,7 @@ static int __devinit pmc_probe(struct platform_device *op) return 0; } -static struct of_device_id __initdata pmc_match[] = { +static struct of_device_id pmc_match[] = { { .name = PMC_OBPNAME, }, diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c index 91c10fb70858..442286d83435 100644 --- a/arch/sparc/kernel/smp_32.c +++ b/arch/sparc/kernel/smp_32.c @@ -53,6 +53,7 @@ cpumask_t smp_commenced_mask = CPU_MASK_NONE; void __cpuinit smp_store_cpu_info(int id) { int cpu_node; + int mid; cpu_data(id).udelay_val = loops_per_jiffy; @@ -60,10 +61,13 @@ void __cpuinit smp_store_cpu_info(int id) cpu_data(id).clock_tick = prom_getintdefault(cpu_node, "clock-frequency", 0); cpu_data(id).prom_node = cpu_node; - cpu_data(id).mid = cpu_get_hwmid(cpu_node); + mid = cpu_get_hwmid(cpu_node); - if (cpu_data(id).mid < 0) - panic("No MID found for CPU%d at node 0x%08d", id, cpu_node); + if (mid < 0) { + printk(KERN_NOTICE "No MID found for CPU%d at node 0x%08d", id, cpu_node); + mid = 0; + } + cpu_data(id).mid = mid; } void __init smp_cpus_done(unsigned int max_cpus) @@ -125,7 +129,9 @@ struct linux_prom_registers smp_penguin_ctable __cpuinitdata = { 0 }; void smp_send_reschedule(int cpu) { - /* See sparc64 */ + /* + * XXX missing reschedule IPI, see scheduler_ipi() + */ } void smp_send_stop(void) diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 3e94a8c23238..9478da7fdb3e 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -1368,6 +1368,7 @@ void smp_send_reschedule(int cpu) void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs) { clear_softint(1 << irq); + scheduler_ipi(); } /* This is a nop because we capture all other cpus diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 47ac73c32e88..332c83ff7701 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -84,4 +84,4 @@ sys_call_table: /*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv /*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init /*330*/ .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime -/*335*/ .long sys_syncfs +/*335*/ .long sys_syncfs, sys_sendmmsg diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 4f3170c1ef47..43887ca0be0e 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -85,7 +85,7 @@ sys_call_table32: /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init /*330*/ .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime - .word sys_syncfs + .word sys_syncfs, compat_sys_sendmmsg #endif /* CONFIG_COMPAT */ @@ -162,4 +162,4 @@ sys_call_table: /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init /*330*/ .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime - .word sys_syncfs + .word sys_syncfs, sys_sendmmsg diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c index 4e236391b635..96046a4024c2 100644 --- a/arch/sparc/kernel/time_32.c +++ b/arch/sparc/kernel/time_32.c @@ -168,7 +168,7 @@ static int __devinit clock_probe(struct platform_device *op) return 0; } -static struct of_device_id __initdata clock_match[] = { +static struct of_device_id clock_match[] = { { .name = "eeprom", }, diff --git a/arch/sparc/lib/checksum_32.S b/arch/sparc/lib/checksum_32.S index 3632cb34e914..0084c3361e15 100644 --- a/arch/sparc/lib/checksum_32.S +++ b/arch/sparc/lib/checksum_32.S @@ -289,10 +289,16 @@ cc_end_cruft: /* Also, handle the alignment code out of band. */ cc_dword_align: - cmp %g1, 6 - bl,a ccte + cmp %g1, 16 + bge 1f + srl %g1, 1, %o3 +2: cmp %o3, 0 + be,a ccte andcc %g1, 0xf, %o3 - andcc %o0, 0x1, %g0 + andcc %o3, %o0, %g0 ! Check %o0 only (%o1 has the same last 2 bits) + be,a 2b + srl %o3, 1, %o3 +1: andcc %o0, 0x1, %g0 bne ccslow andcc %o0, 0x2, %g0 be 1f diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c index a4293102ef81..c52224d5ed45 100644 --- a/arch/tile/kernel/smp.c +++ b/arch/tile/kernel/smp.c @@ -189,12 +189,8 @@ void flush_icache_range(unsigned long start, unsigned long end) /* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */ static irqreturn_t handle_reschedule_ipi(int irq, void *token) { - /* - * Nothing to do here; when we return from interrupt, the - * rescheduling will occur there. But do bump the interrupt - * profiler count in the meantime. - */ __get_cpu_var(irq_stat).irq_resched_count++; + scheduler_ipi(); return IRQ_HANDLED; } diff --git a/arch/um/Kconfig.um b/arch/um/Kconfig.um index 90a438acbfaf..b5e675e370c6 100644 --- a/arch/um/Kconfig.um +++ b/arch/um/Kconfig.um @@ -47,7 +47,7 @@ config HOSTFS config HPPFS tristate "HoneyPot ProcFS (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && PROC_FS help hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc entries to be overridden, removed, or fabricated from the host. diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h index e2cf786bda0a..5bd1bad33fab 100644 --- a/arch/um/include/asm/thread_info.h +++ b/arch/um/include/asm/thread_info.h @@ -49,7 +49,10 @@ static inline struct thread_info *current_thread_info(void) { struct thread_info *ti; unsigned long mask = THREAD_SIZE - 1; - ti = (struct thread_info *) (((unsigned long) &ti) & ~mask); + void *p; + + asm volatile ("" : "=r" (p) : "0" (&ti)); + ti = (struct thread_info *) (((unsigned long)p) & ~mask); return ti; } diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index 106bf27e2a9a..eefb107d2d73 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c @@ -173,7 +173,7 @@ void IPI_handler(int cpu) break; case 'R': - set_tsk_need_resched(current); + scheduler_ipi(); break; case 'S': diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index 6ea77979531c..42827cafa6af 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -75,6 +76,26 @@ void setup_hostinfo(char *buf, int len) host.release, host.version, host.machine); } +/* + * We cannot use glibc's abort(). It makes use of tgkill() which + * has no effect within UML's kernel threads. + * After that glibc would execute an invalid instruction to kill + * the calling process and UML crashes with SIGSEGV. + */ +static inline void __attribute__ ((noreturn)) uml_abort(void) +{ + sigset_t sig; + + fflush(NULL); + + if (!sigemptyset(&sig) && !sigaddset(&sig, SIGABRT)) + sigprocmask(SIG_UNBLOCK, &sig, 0); + + for (;;) + if (kill(getpid(), SIGABRT) < 0) + exit(127); +} + void os_dump_core(void) { int pid; @@ -116,5 +137,5 @@ void os_dump_core(void) while ((pid = waitpid(-1, NULL, WNOHANG | __WALL)) > 0) os_kill_ptraced_process(pid, 0); - abort(); + uml_abort(); } diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 804b28dd0328..b1da91c1b200 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -4,7 +4,7 @@ obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ ptrace_user.o setjmp.o signal.o stub.o stub_segv.o syscalls.o sysrq.o \ - sys_call_table.o tls.o + sys_call_table.o tls.o atomic64_cx8_32.o obj-$(CONFIG_BINFMT_ELF) += elfcore.o diff --git a/arch/um/sys-i386/atomic64_cx8_32.S b/arch/um/sys-i386/atomic64_cx8_32.S new file mode 100644 index 000000000000..1e901d3d4a95 --- /dev/null +++ b/arch/um/sys-i386/atomic64_cx8_32.S @@ -0,0 +1,225 @@ +/* + * atomic64_t for 586+ + * + * Copied from arch/x86/lib/atomic64_cx8_32.S + * + * Copyright © 2010 Luca Barbieri + * + * 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 + +.macro SAVE reg + pushl_cfi %\reg + CFI_REL_OFFSET \reg, 0 +.endm + +.macro RESTORE reg + popl_cfi %\reg + CFI_RESTORE \reg +.endm + +.macro read64 reg + movl %ebx, %eax + movl %ecx, %edx +/* we need LOCK_PREFIX since otherwise cmpxchg8b always does the write */ + LOCK_PREFIX + cmpxchg8b (\reg) +.endm + +ENTRY(atomic64_read_cx8) + CFI_STARTPROC + + read64 %ecx + ret + CFI_ENDPROC +ENDPROC(atomic64_read_cx8) + +ENTRY(atomic64_set_cx8) + CFI_STARTPROC + +1: +/* we don't need LOCK_PREFIX since aligned 64-bit writes + * are atomic on 586 and newer */ + cmpxchg8b (%esi) + jne 1b + + ret + CFI_ENDPROC +ENDPROC(atomic64_set_cx8) + +ENTRY(atomic64_xchg_cx8) + CFI_STARTPROC + + movl %ebx, %eax + movl %ecx, %edx +1: + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + + ret + CFI_ENDPROC +ENDPROC(atomic64_xchg_cx8) + +.macro addsub_return func ins insc +ENTRY(atomic64_\func\()_return_cx8) + CFI_STARTPROC + SAVE ebp + SAVE ebx + SAVE esi + SAVE edi + + movl %eax, %esi + movl %edx, %edi + movl %ecx, %ebp + + read64 %ebp +1: + movl %eax, %ebx + movl %edx, %ecx + \ins\()l %esi, %ebx + \insc\()l %edi, %ecx + LOCK_PREFIX + cmpxchg8b (%ebp) + jne 1b + +10: + movl %ebx, %eax + movl %ecx, %edx + RESTORE edi + RESTORE esi + RESTORE ebx + RESTORE ebp + ret + CFI_ENDPROC +ENDPROC(atomic64_\func\()_return_cx8) +.endm + +addsub_return add add adc +addsub_return sub sub sbb + +.macro incdec_return func ins insc +ENTRY(atomic64_\func\()_return_cx8) + CFI_STARTPROC + SAVE ebx + + read64 %esi +1: + movl %eax, %ebx + movl %edx, %ecx + \ins\()l $1, %ebx + \insc\()l $0, %ecx + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + +10: + movl %ebx, %eax + movl %ecx, %edx + RESTORE ebx + ret + CFI_ENDPROC +ENDPROC(atomic64_\func\()_return_cx8) +.endm + +incdec_return inc add adc +incdec_return dec sub sbb + +ENTRY(atomic64_dec_if_positive_cx8) + CFI_STARTPROC + SAVE ebx + + read64 %esi +1: + movl %eax, %ebx + movl %edx, %ecx + subl $1, %ebx + sbb $0, %ecx + js 2f + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + +2: + movl %ebx, %eax + movl %ecx, %edx + RESTORE ebx + ret + CFI_ENDPROC +ENDPROC(atomic64_dec_if_positive_cx8) + +ENTRY(atomic64_add_unless_cx8) + CFI_STARTPROC + SAVE ebp + SAVE ebx +/* these just push these two parameters on the stack */ + SAVE edi + SAVE esi + + movl %ecx, %ebp + movl %eax, %esi + movl %edx, %edi + + read64 %ebp +1: + cmpl %eax, 0(%esp) + je 4f +2: + movl %eax, %ebx + movl %edx, %ecx + addl %esi, %ebx + adcl %edi, %ecx + LOCK_PREFIX + cmpxchg8b (%ebp) + jne 1b + + movl $1, %eax +3: + addl $8, %esp + CFI_ADJUST_CFA_OFFSET -8 + RESTORE ebx + RESTORE ebp + ret +4: + cmpl %edx, 4(%esp) + jne 2b + xorl %eax, %eax + jmp 3b + CFI_ENDPROC +ENDPROC(atomic64_add_unless_cx8) + +ENTRY(atomic64_inc_not_zero_cx8) + CFI_STARTPROC + SAVE ebx + + read64 %esi +1: + testl %eax, %eax + je 4f +2: + movl %eax, %ebx + movl %edx, %ecx + addl $1, %ebx + adcl $0, %ecx + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + + movl $1, %eax +3: + RESTORE ebx + ret +4: + testl %edx, %edx + jne 2b + jmp 3b + CFI_ENDPROC +ENDPROC(atomic64_inc_not_zero_cx8) diff --git a/arch/unicore32/kernel/irq.c b/arch/unicore32/kernel/irq.c index 2aa30a364bbe..d4efa7d679ff 100644 --- a/arch/unicore32/kernel/irq.c +++ b/arch/unicore32/kernel/irq.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -237,7 +237,7 @@ static struct puv3_irq_state { unsigned int iccr; } puv3_irq_state; -static int puv3_irq_suspend(struct sys_device *dev, pm_message_t state) +static int puv3_irq_suspend(void) { struct puv3_irq_state *st = &puv3_irq_state; @@ -265,7 +265,7 @@ static int puv3_irq_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int puv3_irq_resume(struct sys_device *dev) +static void puv3_irq_resume(void) { struct puv3_irq_state *st = &puv3_irq_state; @@ -278,27 +278,20 @@ static int puv3_irq_resume(struct sys_device *dev) writel(st->icmr, INTC_ICMR); } - return 0; } -static struct sysdev_class puv3_irq_sysclass = { - .name = "pkunity-irq", +static struct syscore_ops puv3_irq_syscore_ops = { .suspend = puv3_irq_suspend, .resume = puv3_irq_resume, }; -static struct sys_device puv3_irq_device = { - .id = 0, - .cls = &puv3_irq_sysclass, -}; - -static int __init puv3_irq_init_devicefs(void) +static int __init puv3_irq_init_syscore(void) { - sysdev_class_register(&puv3_irq_sysclass); - return sysdev_register(&puv3_irq_device); + register_syscore_ops(&puv3_irq_syscore_ops); + return 0; } -device_initcall(puv3_irq_init_devicefs); +device_initcall(puv3_irq_init_syscore); void __init init_IRQ(void) { diff --git a/arch/unicore32/kernel/traps.c b/arch/unicore32/kernel/traps.c index 254e36fa9513..b9a26465e728 100644 --- a/arch/unicore32/kernel/traps.c +++ b/arch/unicore32/kernel/traps.c @@ -192,7 +192,6 @@ static int __die(const char *str, int err, struct thread_info *thread, printk(KERN_EMERG "Internal error: %s: %x [#%d]\n", str, err, ++die_counter); - sysfs_printk_last_file(); /* trap and error numbers are mostly meaningless on UniCore */ ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, \ diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild index 0e103236b754..0e9dec6cadd1 100644 --- a/arch/x86/Kbuild +++ b/arch/x86/Kbuild @@ -15,3 +15,4 @@ obj-y += vdso/ obj-$(CONFIG_IA32_EMULATION) += ia32/ obj-y += platform/ +obj-y += net/ diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index cc6c53a95bfd..880fcb6c86f4 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -8,6 +8,7 @@ config 64BIT config X86_32 def_bool !64BIT + select CLKSRC_I8253 config X86_64 def_bool 64BIT @@ -71,7 +72,7 @@ config X86 select GENERIC_IRQ_SHOW select IRQ_FORCED_THREADING select USE_GENERIC_SMP_HELPERS if SMP - select ARCH_NO_SYSDEV_OPS + select HAVE_BPF_JIT if (X86_64 && NET) config INSTRUCTION_DECODER def_bool (KPROBES || PERF_EVENTS) @@ -112,7 +113,14 @@ config MMU def_bool y config ZONE_DMA - def_bool y + bool "DMA memory allocation support" if EXPERT + default y + help + DMA memory allocation support allows devices with less than 32-bit + addressing to allocate within the first 16MB of address space. + Disable if no such devices will be used. + + If unsure, say Y. config SBUS bool @@ -365,17 +373,6 @@ config X86_UV # Following is an alphabetically sorted list of 32 bit extended platforms # Please maintain the alphabetic order if and when there are additions -config X86_ELAN - bool "AMD Elan" - depends on X86_32 - depends on X86_EXTENDED_PLATFORM - ---help--- - Select this for an AMD Elan processor. - - Do not use this option for K6/Athlon/Opteron processors! - - If unsure, choose "PC-compatible" instead. - config X86_INTEL_CE bool "CE4100 TV platform" depends on PCI @@ -690,6 +687,7 @@ config AMD_IOMMU bool "AMD IOMMU support" select SWIOTLB select PCI_MSI + select PCI_IOV depends on X86_64 && PCI && ACPI ---help--- With this option you can enable support for AMD IOMMU hardware in @@ -1174,7 +1172,7 @@ comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI" config AMD_NUMA def_bool y prompt "Old style AMD Opteron NUMA detection" - depends on X86_64 && NUMA && PCI + depends on NUMA && PCI ---help--- Enable AMD NUMA node topology detection. You should say Y here if you have a multi processor AMD system. This uses an old method to @@ -1201,7 +1199,7 @@ config NODES_SPAN_OTHER_NODES config NUMA_EMU bool "NUMA emulation" - depends on X86_64 && NUMA + depends on NUMA ---help--- Enable NUMA emulation. A flat machine will be split into virtual nodes when booted with "numa=fake=N", where N is the @@ -1223,6 +1221,10 @@ config HAVE_ARCH_BOOTMEM def_bool y depends on X86_32 && NUMA +config HAVE_ARCH_ALLOC_REMAP + def_bool y + depends on X86_32 && NUMA + config ARCH_HAVE_MEMORY_PRESENT def_bool y depends on X86_32 && DISCONTIGMEM @@ -1231,13 +1233,9 @@ config NEED_NODE_MEMMAP_SIZE def_bool y depends on X86_32 && (DISCONTIGMEM || SPARSEMEM) -config HAVE_ARCH_ALLOC_REMAP - def_bool y - depends on X86_32 && NUMA - config ARCH_FLATMEM_ENABLE def_bool y - depends on X86_32 && ARCH_SELECT_MEMORY_MODEL && !NUMA + depends on X86_32 && !NUMA config ARCH_DISCONTIGMEM_ENABLE def_bool y @@ -1247,20 +1245,16 @@ config ARCH_DISCONTIGMEM_DEFAULT def_bool y depends on NUMA && X86_32 -config ARCH_PROC_KCORE_TEXT - def_bool y - depends on X86_64 && PROC_KCORE - -config ARCH_SPARSEMEM_DEFAULT - def_bool y - depends on X86_64 - config ARCH_SPARSEMEM_ENABLE def_bool y depends on X86_64 || NUMA || (EXPERIMENTAL && X86_32) || X86_32_NON_STANDARD select SPARSEMEM_STATIC if X86_32 select SPARSEMEM_VMEMMAP_ENABLE if X86_64 +config ARCH_SPARSEMEM_DEFAULT + def_bool y + depends on X86_64 + config ARCH_SELECT_MEMORY_MODEL def_bool y depends on ARCH_SPARSEMEM_ENABLE @@ -1269,6 +1263,10 @@ config ARCH_MEMORY_PROBE def_bool X86_64 depends on MEMORY_HOTPLUG +config ARCH_PROC_KCORE_TEXT + def_bool y + depends on X86_64 && PROC_KCORE + config ILLEGAL_POINTER_VALUE hex default 0 if X86_32 @@ -1703,10 +1701,6 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE def_bool y depends on MEMORY_HOTPLUG -config HAVE_ARCH_EARLY_PFN_TO_NID - def_bool X86_64 - depends on NUMA - config USE_PERCPU_NUMA_NODE_ID def_bool y depends on NUMA @@ -1848,7 +1842,7 @@ config APM_ALLOW_INTS endif # APM -source "arch/x86/kernel/cpu/cpufreq/Kconfig" +source "drivers/cpufreq/Kconfig" source "drivers/cpuidle/Kconfig" @@ -2076,7 +2070,7 @@ config OLPC depends on !X86_PAE select GPIOLIB select OF - select OF_PROMTREE if PROC_DEVICETREE + select OF_PROMTREE ---help--- Add support for detecting the unique features of the OLPC XO hardware. diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index d161e939df62..6a7cfdf8ff69 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -1,6 +1,4 @@ # Put here option for CPU selection and depending optimization -if !X86_ELAN - choice prompt "Processor family" default M686 if X86_32 @@ -203,6 +201,14 @@ config MWINCHIP3D stores for this CPU, which can increase performance of some operations. +config MELAN + bool "AMD Elan" + depends on X86_32 + ---help--- + Select this for an AMD Elan processor. + + Do not use this option for K6/Athlon/Opteron processors! + config MGEODEGX1 bool "GeodeGX1" depends on X86_32 @@ -292,8 +298,6 @@ config X86_GENERIC This is really intended for distributors who need more generic optimizations. -endif - # # Define implied options from the CPU selection here config X86_INTERNODE_CACHE_SHIFT @@ -312,7 +316,7 @@ config X86_L1_CACHE_SHIFT int default "7" if MPENTIUM4 || MPSC default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU - default "4" if X86_ELAN || M486 || M386 || MGEODEGX1 + default "4" if MELAN || M486 || M386 || MGEODEGX1 default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX config X86_XADD @@ -358,7 +362,7 @@ config X86_POPAD_OK config X86_ALIGNMENT_16 def_bool y - depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 + depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 config X86_INTEL_USERCOPY def_bool y diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu index f2ee1abb1df9..86cee7b749e1 100644 --- a/arch/x86/Makefile_32.cpu +++ b/arch/x86/Makefile_32.cpu @@ -37,7 +37,7 @@ cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom,$(call cc-option,-march= $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic)) # AMD Elan support -cflags-$(CONFIG_X86_ELAN) += -march=i486 +cflags-$(CONFIG_MELAN) += -march=i486 # Geode GX1 support cflags-$(CONFIG_MGEODEGX1) += -march=pentium-mmx diff --git a/arch/x86/boot/memory.c b/arch/x86/boot/memory.c index cae3feb1035e..db75d07c3645 100644 --- a/arch/x86/boot/memory.c +++ b/arch/x86/boot/memory.c @@ -91,7 +91,7 @@ static int detect_memory_e801(void) if (oreg.ax > 15*1024) { return -1; /* Bogus! */ } else if (oreg.ax == 15*1024) { - boot_params.alt_mem_k = (oreg.dx << 6) + oreg.ax; + boot_params.alt_mem_k = (oreg.bx << 6) + oreg.ax; } else { /* * This ignores memory above 16MB if we have a memory diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index 1a58ad89fdf7..c04f1b7a9139 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -2,8 +2,6 @@ # Arch-specific CryptoAPI modules. # -obj-$(CONFIG_CRYPTO_FPU) += fpu.o - obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o @@ -24,6 +22,6 @@ aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o salsa20-x86_64-y := salsa20-x86_64-asm_64.o salsa20_glue.o -aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o +aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o fpu.o ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index 2577613fb32b..feee8ff1d05e 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -94,6 +94,10 @@ asmlinkage void aesni_cbc_enc(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len, u8 *iv); asmlinkage void aesni_cbc_dec(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len, u8 *iv); + +int crypto_fpu_init(void); +void crypto_fpu_exit(void); + #ifdef CONFIG_X86_64 asmlinkage void aesni_ctr_enc(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len, u8 *iv); @@ -1257,6 +1261,8 @@ static int __init aesni_init(void) return -ENODEV; } + if ((err = crypto_fpu_init())) + goto fpu_err; if ((err = crypto_register_alg(&aesni_alg))) goto aes_err; if ((err = crypto_register_alg(&__aesni_alg))) @@ -1334,6 +1340,7 @@ static int __init aesni_init(void) __aes_err: crypto_unregister_alg(&aesni_alg); aes_err: +fpu_err: return err; } @@ -1363,6 +1370,8 @@ static void __exit aesni_exit(void) crypto_unregister_alg(&blk_ecb_alg); crypto_unregister_alg(&__aesni_alg); crypto_unregister_alg(&aesni_alg); + + crypto_fpu_exit(); } module_init(aesni_init); diff --git a/arch/x86/crypto/fpu.c b/arch/x86/crypto/fpu.c index 1a8f8649c035..98d7a188f46b 100644 --- a/arch/x86/crypto/fpu.c +++ b/arch/x86/crypto/fpu.c @@ -150,18 +150,12 @@ static struct crypto_template crypto_fpu_tmpl = { .module = THIS_MODULE, }; -static int __init crypto_fpu_module_init(void) +int __init crypto_fpu_init(void) { return crypto_register_template(&crypto_fpu_tmpl); } -static void __exit crypto_fpu_module_exit(void) +void __exit crypto_fpu_exit(void) { crypto_unregister_template(&crypto_fpu_tmpl); } - -module_init(crypto_fpu_module_init); -module_exit(crypto_fpu_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("FPU block cipher wrapper"); diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 849a9d23c71d..95f5826be458 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -848,4 +848,5 @@ ia32_sys_call_table: .quad compat_sys_open_by_handle_at .quad compat_sys_clock_adjtime .quad sys_syncfs + .quad compat_sys_sendmmsg /* 345 */ ia32_syscall_end: diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index 12e0e7dd869c..416d865eae39 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -183,8 +183,6 @@ static inline void disable_acpi(void) { } #define ARCH_HAS_POWER_INIT 1 -struct bootnode; - #ifdef CONFIG_ACPI_NUMA extern int acpi_numa; extern int x86_acpi_numa_init(void); diff --git a/arch/x86/include/asm/alternative-asm.h b/arch/x86/include/asm/alternative-asm.h index a63a68be1cce..94d420b360d1 100644 --- a/arch/x86/include/asm/alternative-asm.h +++ b/arch/x86/include/asm/alternative-asm.h @@ -15,4 +15,13 @@ .endm #endif +.macro altinstruction_entry orig alt feature orig_len alt_len + .align 8 + .quad \orig + .quad \alt + .word \feature + .byte \orig_len + .byte \alt_len +.endm + #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 13009d1af99a..bf535f947e8c 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -4,7 +4,6 @@ #include #include #include -#include #include /* @@ -191,12 +190,4 @@ extern void *text_poke(void *addr, const void *opcode, size_t len); extern void *text_poke_smp(void *addr, const void *opcode, size_t len); extern void text_poke_smp_batch(struct text_poke_param *params, int n); -#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) -#define IDEAL_NOP_SIZE_5 5 -extern unsigned char ideal_nop5[IDEAL_NOP_SIZE_5]; -extern void arch_init_ideal_nop5(void); -#else -static inline void arch_init_ideal_nop5(void) {} -#endif - #endif /* _ASM_X86_ALTERNATIVE_H */ diff --git a/arch/x86/include/asm/amd_iommu_proto.h b/arch/x86/include/asm/amd_iommu_proto.h index 916bc8111a01..55d95eb789b3 100644 --- a/arch/x86/include/asm/amd_iommu_proto.h +++ b/arch/x86/include/asm/amd_iommu_proto.h @@ -19,13 +19,12 @@ #ifndef _ASM_X86_AMD_IOMMU_PROTO_H #define _ASM_X86_AMD_IOMMU_PROTO_H -struct amd_iommu; +#include extern int amd_iommu_init_dma_ops(void); extern int amd_iommu_init_passthrough(void); +extern irqreturn_t amd_iommu_int_thread(int irq, void *data); extern irqreturn_t amd_iommu_int_handler(int irq, void *data); -extern void amd_iommu_flush_all_domains(void); -extern void amd_iommu_flush_all_devices(void); extern void amd_iommu_apply_erratum_63(u16 devid); extern void amd_iommu_reset_cmd_buffer(struct amd_iommu *iommu); extern int amd_iommu_init_devices(void); @@ -44,4 +43,12 @@ static inline bool is_rd890_iommu(struct pci_dev *pdev) (pdev->device == PCI_DEVICE_ID_RD890_IOMMU); } +static inline bool iommu_feature(struct amd_iommu *iommu, u64 f) +{ + if (!(iommu->cap & (1 << IOMMU_CAP_EFR))) + return false; + + return !!(iommu->features & f); +} + #endif /* _ASM_X86_AMD_IOMMU_PROTO_H */ diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index e3509fc303bf..4c9982995414 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -68,12 +68,25 @@ #define MMIO_CONTROL_OFFSET 0x0018 #define MMIO_EXCL_BASE_OFFSET 0x0020 #define MMIO_EXCL_LIMIT_OFFSET 0x0028 +#define MMIO_EXT_FEATURES 0x0030 #define MMIO_CMD_HEAD_OFFSET 0x2000 #define MMIO_CMD_TAIL_OFFSET 0x2008 #define MMIO_EVT_HEAD_OFFSET 0x2010 #define MMIO_EVT_TAIL_OFFSET 0x2018 #define MMIO_STATUS_OFFSET 0x2020 + +/* Extended Feature Bits */ +#define FEATURE_PREFETCH (1ULL<<0) +#define FEATURE_PPR (1ULL<<1) +#define FEATURE_X2APIC (1ULL<<2) +#define FEATURE_NX (1ULL<<3) +#define FEATURE_GT (1ULL<<4) +#define FEATURE_IA (1ULL<<6) +#define FEATURE_GA (1ULL<<7) +#define FEATURE_HE (1ULL<<8) +#define FEATURE_PC (1ULL<<9) + /* MMIO status bits */ #define MMIO_STATUS_COM_WAIT_INT_MASK 0x04 @@ -113,7 +126,9 @@ /* command specific defines */ #define CMD_COMPL_WAIT 0x01 #define CMD_INV_DEV_ENTRY 0x02 -#define CMD_INV_IOMMU_PAGES 0x03 +#define CMD_INV_IOMMU_PAGES 0x03 +#define CMD_INV_IOTLB_PAGES 0x04 +#define CMD_INV_ALL 0x08 #define CMD_COMPL_WAIT_STORE_MASK 0x01 #define CMD_COMPL_WAIT_INT_MASK 0x02 @@ -215,6 +230,8 @@ #define IOMMU_PTE_IR (1ULL << 61) #define IOMMU_PTE_IW (1ULL << 62) +#define DTE_FLAG_IOTLB 0x01 + #define IOMMU_PAGE_MASK (((1ULL << 52) - 1) & ~0xfffULL) #define IOMMU_PTE_PRESENT(pte) ((pte) & IOMMU_PTE_P) #define IOMMU_PTE_PAGE(pte) (phys_to_virt((pte) & IOMMU_PAGE_MASK)) @@ -227,6 +244,7 @@ /* IOMMU capabilities */ #define IOMMU_CAP_IOTLB 24 #define IOMMU_CAP_NPCACHE 26 +#define IOMMU_CAP_EFR 27 #define MAX_DOMAIN_ID 65536 @@ -249,6 +267,8 @@ extern bool amd_iommu_dump; /* global flag if IOMMUs cache non-present entries */ extern bool amd_iommu_np_cache; +/* Only true if all IOMMUs support device IOTLBs */ +extern bool amd_iommu_iotlb_sup; /* * Make iterating over all IOMMUs easier @@ -371,6 +391,9 @@ struct amd_iommu { /* flags read from acpi table */ u8 acpi_flags; + /* Extended features */ + u64 features; + /* * Capability pointer. There could be more than one IOMMU per PCI * device function if there are more than one AMD IOMMU capability @@ -409,9 +432,6 @@ struct amd_iommu { /* if one, we need to send a completion wait command */ bool need_sync; - /* becomes true if a command buffer reset is running */ - bool reset_in_progress; - /* default dma_ops domain for that IOMMU */ struct dma_ops_domain *default_dom; diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h index 331682231bb4..67f87f257611 100644 --- a/arch/x86/include/asm/amd_nb.h +++ b/arch/x86/include/asm/amd_nb.h @@ -11,7 +11,6 @@ struct amd_nb_bus_dev_range { extern const struct pci_device_id amd_nb_misc_ids[]; extern const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[]; -struct bootnode; extern bool early_is_amd_nb(u32 value); extern int amd_cache_northbridges(void); diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 2b7d573be549..a0c46f061210 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -363,7 +363,12 @@ struct apic { */ int (*x86_32_early_logical_apicid)(int cpu); - /* determine CPU -> NUMA node mapping */ + /* + * Optional method called from setup_local_APIC() after logical + * apicid is guaranteed to be known to initialize apicid -> node + * mapping if NUMA initialization hasn't done so already. Don't + * add new users. + */ int (*x86_32_numa_cpu_node)(int cpu); #endif }; @@ -537,8 +542,6 @@ static inline int default_phys_pkg_id(int cpuid_apic, int index_msb) return cpuid_apic >> index_msb; } -extern int default_x86_32_numa_cpu_node(int cpu); - #endif static inline unsigned int diff --git a/arch/x86/include/asm/apicdef.h b/arch/x86/include/asm/apicdef.h index d87988bacf3e..34595d5e1038 100644 --- a/arch/x86/include/asm/apicdef.h +++ b/arch/x86/include/asm/apicdef.h @@ -78,6 +78,7 @@ #define APIC_DEST_LOGICAL 0x00800 #define APIC_DEST_PHYSICAL 0x00000 #define APIC_DM_FIXED 0x00000 +#define APIC_DM_FIXED_MASK 0x00700 #define APIC_DM_LOWEST 0x00100 #define APIC_DM_SMI 0x00200 #define APIC_DM_REMRD 0x00300 diff --git a/arch/x86/include/asm/bios_ebda.h b/arch/x86/include/asm/bios_ebda.h index 3c7521063d3f..aa6a3170ab5a 100644 --- a/arch/x86/include/asm/bios_ebda.h +++ b/arch/x86/include/asm/bios_ebda.h @@ -4,16 +4,40 @@ #include /* - * there is a real-mode segmented pointer pointing to the - * 4K EBDA area at 0x40E. + * Returns physical address of EBDA. Returns 0 if there is no EBDA. */ static inline unsigned int get_bios_ebda(void) { + /* + * There is a real-mode segmented pointer pointing to the + * 4K EBDA area at 0x40E. + */ unsigned int address = *(unsigned short *)phys_to_virt(0x40E); address <<= 4; return address; /* 0 means none */ } +/* + * Return the sanitized length of the EBDA in bytes, if it exists. + */ +static inline unsigned int get_bios_ebda_length(void) +{ + unsigned int address; + unsigned int length; + + address = get_bios_ebda(); + if (!address) + return 0; + + /* EBDA length is byte 0 of the EBDA (stored in KiB) */ + length = *(unsigned char *)phys_to_virt(address); + length <<= 10; + + /* Trim the length if it extends beyond 640KiB */ + length = min_t(unsigned int, (640 * 1024) - address, length); + return length; +} + void reserve_ebda_region(void); #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 91f3e087cf21..5dc6acc98dbd 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -195,6 +195,8 @@ /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */ #define X86_FEATURE_FSGSBASE (9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/ +#define X86_FEATURE_SMEP (9*32+ 7) /* Supervisor Mode Execution Protection */ +#define X86_FEATURE_ERMS (9*32+ 9) /* Enhanced REP MOVSB/STOSB */ #if defined(__KERNEL__) && !defined(__ASSEMBLY__) @@ -207,8 +209,7 @@ extern const char * const x86_power_flags[32]; #define test_cpu_cap(c, bit) \ test_bit(bit, (unsigned long *)((c)->x86_capability)) -#define cpu_has(c, bit) \ - (__builtin_constant_p(bit) && \ +#define REQUIRED_MASK_BIT_SET(bit) \ ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) || \ (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1)) || \ (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2)) || \ @@ -218,10 +219,16 @@ extern const char * const x86_power_flags[32]; (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6)) || \ (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7)) || \ (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8)) || \ - (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) ) \ - ? 1 : \ + (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) ) + +#define cpu_has(c, bit) \ + (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ test_cpu_cap(c, bit)) +#define this_cpu_has(bit) \ + (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ + x86_this_cpu_test_bit(bit, (unsigned long *)&cpu_info.x86_capability)) + #define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit) #define set_cpu_cap(c, bit) set_bit(bit, (unsigned long *)((c)->x86_capability)) diff --git a/arch/x86/include/asm/dma.h b/arch/x86/include/asm/dma.h index 057099e5faba..0bdb0c54d9a1 100644 --- a/arch/x86/include/asm/dma.h +++ b/arch/x86/include/asm/dma.h @@ -69,22 +69,18 @@ #define MAX_DMA_CHANNELS 8 -#ifdef CONFIG_X86_32 - -/* The maximum address that we can perform a DMA transfer to on this platform */ -#define MAX_DMA_ADDRESS (PAGE_OFFSET + 0x1000000) - -#else - /* 16MB ISA DMA zone */ #define MAX_DMA_PFN ((16 * 1024 * 1024) >> PAGE_SHIFT) /* 4GB broken PCI/AGP hardware bus master zone */ #define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT) +#ifdef CONFIG_X86_32 +/* The maximum address that we can perform a DMA transfer to on this platform */ +#define MAX_DMA_ADDRESS (PAGE_OFFSET + 0x1000000) +#else /* Compat define for old dma zone */ #define MAX_DMA_ADDRESS ((unsigned long)__va(MAX_DMA_PFN << PAGE_SHIFT)) - #endif /* 8237 DMA controllers */ diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 8e4a16508d4e..7093e4a6a0bc 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -90,6 +90,7 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, #endif /* CONFIG_X86_32 */ extern int add_efi_memmap; +extern void efi_set_executable(efi_memory_desc_t *md, bool executable); extern void efi_memblock_x86_reserve_range(void); extern void efi_call_phys_prelog(void); extern void efi_call_phys_epilog(void); diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h index db24c2278be0..268c783ab1c0 100644 --- a/arch/x86/include/asm/ftrace.h +++ b/arch/x86/include/asm/ftrace.h @@ -38,11 +38,10 @@ extern void mcount(void); static inline unsigned long ftrace_call_adjust(unsigned long addr) { /* - * call mcount is "e8 <4 byte offset>" - * The addr points to the 4 byte offset and the caller of this - * function wants the pointer to e8. Simply subtract one. + * addr is the address of the mcount call instruction. + * recordmcount does the necessary offset calculation. */ - return addr - 1; + return addr; } #ifdef CONFIG_DYNAMIC_FTRACE diff --git a/arch/x86/include/asm/gart.h b/arch/x86/include/asm/gart.h index 43085bfc99c3..156cd5d18d2a 100644 --- a/arch/x86/include/asm/gart.h +++ b/arch/x86/include/asm/gart.h @@ -66,7 +66,7 @@ static inline void gart_set_size_and_enable(struct pci_dev *dev, u32 order) * Don't enable translation but enable GART IO and CPU accesses. * Also, set DISTLBWALKPRB since GART tables memory is UC. */ - ctl = DISTLBWALKPRB | order << 1; + ctl = order << 1; pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); } @@ -75,17 +75,17 @@ static inline void enable_gart_translation(struct pci_dev *dev, u64 addr) { u32 tmp, ctl; - /* address of the mappings table */ - addr >>= 12; - tmp = (u32) addr<<4; - tmp &= ~0xf; - pci_write_config_dword(dev, AMD64_GARTTABLEBASE, tmp); + /* address of the mappings table */ + addr >>= 12; + tmp = (u32) addr<<4; + tmp &= ~0xf; + pci_write_config_dword(dev, AMD64_GARTTABLEBASE, tmp); - /* Enable GART translation for this hammer. */ - pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl); - ctl |= GARTEN; - ctl &= ~(DISGARTCPU | DISGARTIO); - pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); + /* Enable GART translation for this hammer. */ + pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl); + ctl |= GARTEN | DISTLBWALKPRB; + ctl &= ~(DISGARTCPU | DISGARTIO); + pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); } static inline int aperture_valid(u64 aper_base, u32 aper_size, u32 min_size) diff --git a/arch/x86/include/asm/i8253.h b/arch/x86/include/asm/i8253.h index fc1f579fb965..65aaa91d5850 100644 --- a/arch/x86/include/asm/i8253.h +++ b/arch/x86/include/asm/i8253.h @@ -6,6 +6,8 @@ #define PIT_CH0 0x40 #define PIT_CH2 0x42 +#define PIT_LATCH LATCH + extern raw_spinlock_t i8253_lock; extern struct clock_event_device *global_clock_event; diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index c4bd267dfc50..a97a240f67f3 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -150,7 +150,7 @@ void setup_IO_APIC_irq_extra(u32 gsi); extern void ioapic_and_gsi_init(void); extern void ioapic_insert_resources(void); -int io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr); +int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr); extern struct IO_APIC_route_entry **alloc_ioapic_entries(void); extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries); diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h index 574dbc22893a..a32b18ce6ead 100644 --- a/arch/x86/include/asm/jump_label.h +++ b/arch/x86/include/asm/jump_label.h @@ -5,20 +5,25 @@ #include #include +#include #define JUMP_LABEL_NOP_SIZE 5 -# define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t" +#define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t" -# define JUMP_LABEL(key, label) \ - do { \ - asm goto("1:" \ - JUMP_LABEL_INITIAL_NOP \ - ".pushsection __jump_table, \"aw\" \n\t"\ - _ASM_PTR "1b, %l[" #label "], %c0 \n\t" \ - ".popsection \n\t" \ - : : "i" (key) : : label); \ - } while (0) +static __always_inline bool arch_static_branch(struct jump_label_key *key) +{ + asm goto("1:" + JUMP_LABEL_INITIAL_NOP + ".pushsection __jump_table, \"aw\" \n\t" + _ASM_ALIGN "\n\t" + _ASM_PTR "1b, %l[l_yes], %c0 \n\t" + ".popsection \n\t" + : : "i" (key) : : l_yes); + return false; +l_yes: + return true; +} #endif /* __KERNEL__ */ diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index eb16e94ae04f..021979a6e23f 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -142,8 +142,6 @@ static inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {} static inline void enable_p5_mce(void) {} #endif -extern void (*x86_mce_decode_callback)(struct mce *m); - void mce_setup(struct mce *m); void mce_log(struct mce *m); DECLARE_PER_CPU(struct sys_device, mce_dev); diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h index 91df7c51806c..5e83a416eca8 100644 --- a/arch/x86/include/asm/mmzone_32.h +++ b/arch/x86/include/asm/mmzone_32.h @@ -13,31 +13,11 @@ extern struct pglist_data *node_data[]; #define NODE_DATA(nid) (node_data[nid]) #include -/* summit or generic arch */ -#include - -extern int get_memcfg_numa_flat(void); -/* - * This allows any one NUMA architecture to be compiled - * for, and still fall back to the flat function if it - * fails. - */ -static inline void get_memcfg_numa(void) -{ - - if (get_memcfg_numaq()) - return; - if (get_memcfg_from_srat()) - return; - get_memcfg_numa_flat(); -} extern void resume_map_numa_kva(pgd_t *pgd); #else /* !CONFIG_NUMA */ -#define get_memcfg_numa get_memcfg_numa_flat - static inline void resume_map_numa_kva(pgd_t *pgd) {} #endif /* CONFIG_NUMA */ diff --git a/arch/x86/include/asm/mmzone_64.h b/arch/x86/include/asm/mmzone_64.h index 288b96f815a6..b3f88d7867c7 100644 --- a/arch/x86/include/asm/mmzone_64.h +++ b/arch/x86/include/asm/mmzone_64.h @@ -4,36 +4,13 @@ #ifndef _ASM_X86_MMZONE_64_H #define _ASM_X86_MMZONE_64_H - #ifdef CONFIG_NUMA #include - #include -/* Simple perfect hash to map physical addresses to node numbers */ -struct memnode { - int shift; - unsigned int mapsize; - s16 *map; - s16 embedded_map[64 - 8]; -} ____cacheline_aligned; /* total size = 128 bytes */ -extern struct memnode memnode; -#define memnode_shift memnode.shift -#define memnodemap memnode.map -#define memnodemapsize memnode.mapsize - extern struct pglist_data *node_data[]; -static inline __attribute__((pure)) int phys_to_nid(unsigned long addr) -{ - unsigned nid; - VIRTUAL_BUG_ON(!memnodemap); - nid = memnodemap[addr >> memnode_shift]; - VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]); - return nid; -} - #define NODE_DATA(nid) (node_data[nid]) #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h index 67763c5d8b4e..9eae7752ae9b 100644 --- a/arch/x86/include/asm/module.h +++ b/arch/x86/include/asm/module.h @@ -35,7 +35,7 @@ #define MODULE_PROC_FAMILY "K7 " #elif defined CONFIG_MK8 #define MODULE_PROC_FAMILY "K8 " -#elif defined CONFIG_X86_ELAN +#elif defined CONFIG_MELAN #define MODULE_PROC_FAMILY "ELAN " #elif defined CONFIG_MCRUSOE #define MODULE_PROC_FAMILY "CRUSOE " diff --git a/arch/x86/include/asm/nops.h b/arch/x86/include/asm/nops.h index af788496020b..405b4032a60b 100644 --- a/arch/x86/include/asm/nops.h +++ b/arch/x86/include/asm/nops.h @@ -1,7 +1,13 @@ #ifndef _ASM_X86_NOPS_H #define _ASM_X86_NOPS_H -/* Define nops for use with alternative() */ +/* + * Define nops for use with alternative() and for tracing. + * + * *_NOP5_ATOMIC must be a single instruction. + */ + +#define NOP_DS_PREFIX 0x3e /* generic versions from gas 1: nop @@ -13,14 +19,15 @@ 6: leal 0x00000000(%esi),%esi 7: leal 0x00000000(,%esi,1),%esi */ -#define GENERIC_NOP1 ".byte 0x90\n" -#define GENERIC_NOP2 ".byte 0x89,0xf6\n" -#define GENERIC_NOP3 ".byte 0x8d,0x76,0x00\n" -#define GENERIC_NOP4 ".byte 0x8d,0x74,0x26,0x00\n" -#define GENERIC_NOP5 GENERIC_NOP1 GENERIC_NOP4 -#define GENERIC_NOP6 ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n" -#define GENERIC_NOP7 ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n" -#define GENERIC_NOP8 GENERIC_NOP1 GENERIC_NOP7 +#define GENERIC_NOP1 0x90 +#define GENERIC_NOP2 0x89,0xf6 +#define GENERIC_NOP3 0x8d,0x76,0x00 +#define GENERIC_NOP4 0x8d,0x74,0x26,0x00 +#define GENERIC_NOP5 GENERIC_NOP1,GENERIC_NOP4 +#define GENERIC_NOP6 0x8d,0xb6,0x00,0x00,0x00,0x00 +#define GENERIC_NOP7 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00 +#define GENERIC_NOP8 GENERIC_NOP1,GENERIC_NOP7 +#define GENERIC_NOP5_ATOMIC NOP_DS_PREFIX,GENERIC_NOP4 /* Opteron 64bit nops 1: nop @@ -29,13 +36,14 @@ 4: osp osp osp nop */ #define K8_NOP1 GENERIC_NOP1 -#define K8_NOP2 ".byte 0x66,0x90\n" -#define K8_NOP3 ".byte 0x66,0x66,0x90\n" -#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n" -#define K8_NOP5 K8_NOP3 K8_NOP2 -#define K8_NOP6 K8_NOP3 K8_NOP3 -#define K8_NOP7 K8_NOP4 K8_NOP3 -#define K8_NOP8 K8_NOP4 K8_NOP4 +#define K8_NOP2 0x66,K8_NOP1 +#define K8_NOP3 0x66,K8_NOP2 +#define K8_NOP4 0x66,K8_NOP3 +#define K8_NOP5 K8_NOP3,K8_NOP2 +#define K8_NOP6 K8_NOP3,K8_NOP3 +#define K8_NOP7 K8_NOP4,K8_NOP3 +#define K8_NOP8 K8_NOP4,K8_NOP4 +#define K8_NOP5_ATOMIC 0x66,K8_NOP4 /* K7 nops uses eax dependencies (arbitrary choice) @@ -47,13 +55,14 @@ 7: leal 0x00000000(,%eax,1),%eax */ #define K7_NOP1 GENERIC_NOP1 -#define K7_NOP2 ".byte 0x8b,0xc0\n" -#define K7_NOP3 ".byte 0x8d,0x04,0x20\n" -#define K7_NOP4 ".byte 0x8d,0x44,0x20,0x00\n" -#define K7_NOP5 K7_NOP4 ASM_NOP1 -#define K7_NOP6 ".byte 0x8d,0x80,0,0,0,0\n" -#define K7_NOP7 ".byte 0x8D,0x04,0x05,0,0,0,0\n" -#define K7_NOP8 K7_NOP7 ASM_NOP1 +#define K7_NOP2 0x8b,0xc0 +#define K7_NOP3 0x8d,0x04,0x20 +#define K7_NOP4 0x8d,0x44,0x20,0x00 +#define K7_NOP5 K7_NOP4,K7_NOP1 +#define K7_NOP6 0x8d,0x80,0,0,0,0 +#define K7_NOP7 0x8D,0x04,0x05,0,0,0,0 +#define K7_NOP8 K7_NOP7,K7_NOP1 +#define K7_NOP5_ATOMIC NOP_DS_PREFIX,K7_NOP4 /* P6 nops uses eax dependencies (Intel-recommended choice) @@ -69,52 +78,65 @@ There is kernel code that depends on this. */ #define P6_NOP1 GENERIC_NOP1 -#define P6_NOP2 ".byte 0x66,0x90\n" -#define P6_NOP3 ".byte 0x0f,0x1f,0x00\n" -#define P6_NOP4 ".byte 0x0f,0x1f,0x40,0\n" -#define P6_NOP5 ".byte 0x0f,0x1f,0x44,0x00,0\n" -#define P6_NOP6 ".byte 0x66,0x0f,0x1f,0x44,0x00,0\n" -#define P6_NOP7 ".byte 0x0f,0x1f,0x80,0,0,0,0\n" -#define P6_NOP8 ".byte 0x0f,0x1f,0x84,0x00,0,0,0,0\n" +#define P6_NOP2 0x66,0x90 +#define P6_NOP3 0x0f,0x1f,0x00 +#define P6_NOP4 0x0f,0x1f,0x40,0 +#define P6_NOP5 0x0f,0x1f,0x44,0x00,0 +#define P6_NOP6 0x66,0x0f,0x1f,0x44,0x00,0 +#define P6_NOP7 0x0f,0x1f,0x80,0,0,0,0 +#define P6_NOP8 0x0f,0x1f,0x84,0x00,0,0,0,0 +#define P6_NOP5_ATOMIC P6_NOP5 + +#define _ASM_MK_NOP(x) ".byte " __stringify(x) "\n" #if defined(CONFIG_MK7) -#define ASM_NOP1 K7_NOP1 -#define ASM_NOP2 K7_NOP2 -#define ASM_NOP3 K7_NOP3 -#define ASM_NOP4 K7_NOP4 -#define ASM_NOP5 K7_NOP5 -#define ASM_NOP6 K7_NOP6 -#define ASM_NOP7 K7_NOP7 -#define ASM_NOP8 K7_NOP8 +#define ASM_NOP1 _ASM_MK_NOP(K7_NOP1) +#define ASM_NOP2 _ASM_MK_NOP(K7_NOP2) +#define ASM_NOP3 _ASM_MK_NOP(K7_NOP3) +#define ASM_NOP4 _ASM_MK_NOP(K7_NOP4) +#define ASM_NOP5 _ASM_MK_NOP(K7_NOP5) +#define ASM_NOP6 _ASM_MK_NOP(K7_NOP6) +#define ASM_NOP7 _ASM_MK_NOP(K7_NOP7) +#define ASM_NOP8 _ASM_MK_NOP(K7_NOP8) +#define ASM_NOP5_ATOMIC _ASM_MK_NOP(K7_NOP5_ATOMIC) #elif defined(CONFIG_X86_P6_NOP) -#define ASM_NOP1 P6_NOP1 -#define ASM_NOP2 P6_NOP2 -#define ASM_NOP3 P6_NOP3 -#define ASM_NOP4 P6_NOP4 -#define ASM_NOP5 P6_NOP5 -#define ASM_NOP6 P6_NOP6 -#define ASM_NOP7 P6_NOP7 -#define ASM_NOP8 P6_NOP8 +#define ASM_NOP1 _ASM_MK_NOP(P6_NOP1) +#define ASM_NOP2 _ASM_MK_NOP(P6_NOP2) +#define ASM_NOP3 _ASM_MK_NOP(P6_NOP3) +#define ASM_NOP4 _ASM_MK_NOP(P6_NOP4) +#define ASM_NOP5 _ASM_MK_NOP(P6_NOP5) +#define ASM_NOP6 _ASM_MK_NOP(P6_NOP6) +#define ASM_NOP7 _ASM_MK_NOP(P6_NOP7) +#define ASM_NOP8 _ASM_MK_NOP(P6_NOP8) +#define ASM_NOP5_ATOMIC _ASM_MK_NOP(P6_NOP5_ATOMIC) #elif defined(CONFIG_X86_64) -#define ASM_NOP1 K8_NOP1 -#define ASM_NOP2 K8_NOP2 -#define ASM_NOP3 K8_NOP3 -#define ASM_NOP4 K8_NOP4 -#define ASM_NOP5 K8_NOP5 -#define ASM_NOP6 K8_NOP6 -#define ASM_NOP7 K8_NOP7 -#define ASM_NOP8 K8_NOP8 +#define ASM_NOP1 _ASM_MK_NOP(K8_NOP1) +#define ASM_NOP2 _ASM_MK_NOP(K8_NOP2) +#define ASM_NOP3 _ASM_MK_NOP(K8_NOP3) +#define ASM_NOP4 _ASM_MK_NOP(K8_NOP4) +#define ASM_NOP5 _ASM_MK_NOP(K8_NOP5) +#define ASM_NOP6 _ASM_MK_NOP(K8_NOP6) +#define ASM_NOP7 _ASM_MK_NOP(K8_NOP7) +#define ASM_NOP8 _ASM_MK_NOP(K8_NOP8) +#define ASM_NOP5_ATOMIC _ASM_MK_NOP(K8_NOP5_ATOMIC) #else -#define ASM_NOP1 GENERIC_NOP1 -#define ASM_NOP2 GENERIC_NOP2 -#define ASM_NOP3 GENERIC_NOP3 -#define ASM_NOP4 GENERIC_NOP4 -#define ASM_NOP5 GENERIC_NOP5 -#define ASM_NOP6 GENERIC_NOP6 -#define ASM_NOP7 GENERIC_NOP7 -#define ASM_NOP8 GENERIC_NOP8 +#define ASM_NOP1 _ASM_MK_NOP(GENERIC_NOP1) +#define ASM_NOP2 _ASM_MK_NOP(GENERIC_NOP2) +#define ASM_NOP3 _ASM_MK_NOP(GENERIC_NOP3) +#define ASM_NOP4 _ASM_MK_NOP(GENERIC_NOP4) +#define ASM_NOP5 _ASM_MK_NOP(GENERIC_NOP5) +#define ASM_NOP6 _ASM_MK_NOP(GENERIC_NOP6) +#define ASM_NOP7 _ASM_MK_NOP(GENERIC_NOP7) +#define ASM_NOP8 _ASM_MK_NOP(GENERIC_NOP8) +#define ASM_NOP5_ATOMIC _ASM_MK_NOP(GENERIC_NOP5_ATOMIC) #endif #define ASM_NOP_MAX 8 +#define NOP_ATOMIC5 (ASM_NOP_MAX+1) /* Entry for the 5-byte atomic NOP */ + +#ifndef __ASSEMBLY__ +extern const unsigned char * const *ideal_nops; +extern void arch_init_ideal_nops(void); +#endif #endif /* _ASM_X86_NOPS_H */ diff --git a/arch/x86/include/asm/numa.h b/arch/x86/include/asm/numa.h index 3d4dab43c994..bfacd2ccf651 100644 --- a/arch/x86/include/asm/numa.h +++ b/arch/x86/include/asm/numa.h @@ -1,12 +1,24 @@ #ifndef _ASM_X86_NUMA_H #define _ASM_X86_NUMA_H +#include + #include #include #ifdef CONFIG_NUMA #define NR_NODE_MEMBLKS (MAX_NUMNODES*2) +#define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT)) + +/* + * Too small node sizes may confuse the VM badly. Usually they + * result from BIOS bugs. So dont recognize nodes as standalone + * NUMA entities that have less than this amount of RAM listed: + */ +#define NODE_MIN_SIZE (4*1024*1024) + +extern int numa_off; /* * __apicid_to_node[] stores the raw mapping between physical apicid and @@ -17,15 +29,27 @@ * numa_cpu_node(). */ extern s16 __apicid_to_node[MAX_LOCAL_APIC]; +extern nodemask_t numa_nodes_parsed __initdata; + +extern int __init numa_add_memblk(int nodeid, u64 start, u64 end); +extern void __init numa_set_distance(int from, int to, int distance); static inline void set_apicid_to_node(int apicid, s16 node) { __apicid_to_node[apicid] = node; } + +extern int __cpuinit numa_cpu_node(int cpu); + #else /* CONFIG_NUMA */ static inline void set_apicid_to_node(int apicid, s16 node) { } + +static inline int numa_cpu_node(int cpu) +{ + return NUMA_NO_NODE; +} #endif /* CONFIG_NUMA */ #ifdef CONFIG_X86_32 @@ -37,21 +61,25 @@ static inline void set_apicid_to_node(int apicid, s16 node) #ifdef CONFIG_NUMA extern void __cpuinit numa_set_node(int cpu, int node); extern void __cpuinit numa_clear_node(int cpu); -extern void __init numa_init_array(void); extern void __init init_cpu_to_node(void); extern void __cpuinit numa_add_cpu(int cpu); extern void __cpuinit numa_remove_cpu(int cpu); #else /* CONFIG_NUMA */ static inline void numa_set_node(int cpu, int node) { } static inline void numa_clear_node(int cpu) { } -static inline void numa_init_array(void) { } static inline void init_cpu_to_node(void) { } static inline void numa_add_cpu(int cpu) { } static inline void numa_remove_cpu(int cpu) { } #endif /* CONFIG_NUMA */ #ifdef CONFIG_DEBUG_PER_CPU_MAPS -struct cpumask __cpuinit *debug_cpumask_set_cpu(int cpu, int enable); +void debug_cpumask_set_cpu(int cpu, int node, bool enable); #endif +#ifdef CONFIG_NUMA_EMU +#define FAKE_NODE_MIN_SIZE ((u64)32 << 20) +#define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1UL)) +void numa_emu_cmdline(char *); +#endif /* CONFIG_NUMA_EMU */ + #endif /* _ASM_X86_NUMA_H */ diff --git a/arch/x86/include/asm/numa_32.h b/arch/x86/include/asm/numa_32.h index c6beed1ef103..e7d6b8254742 100644 --- a/arch/x86/include/asm/numa_32.h +++ b/arch/x86/include/asm/numa_32.h @@ -1,16 +1,6 @@ #ifndef _ASM_X86_NUMA_32_H #define _ASM_X86_NUMA_32_H -extern int numa_off; - -extern int pxm_to_nid(int pxm); - -#ifdef CONFIG_NUMA -extern int __cpuinit numa_cpu_node(int cpu); -#else /* CONFIG_NUMA */ -static inline int numa_cpu_node(int cpu) { return NUMA_NO_NODE; } -#endif /* CONFIG_NUMA */ - #ifdef CONFIG_HIGHMEM extern void set_highmem_pages_init(void); #else diff --git a/arch/x86/include/asm/numa_64.h b/arch/x86/include/asm/numa_64.h index 344eb1790b46..0c05f7ae46e8 100644 --- a/arch/x86/include/asm/numa_64.h +++ b/arch/x86/include/asm/numa_64.h @@ -1,42 +1,6 @@ #ifndef _ASM_X86_NUMA_64_H #define _ASM_X86_NUMA_64_H -#include - -struct bootnode { - u64 start; - u64 end; -}; - -#define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT)) - -extern int numa_off; - extern unsigned long numa_free_all_bootmem(void); -extern void setup_node_bootmem(int nodeid, unsigned long start, - unsigned long end); - -#ifdef CONFIG_NUMA -/* - * Too small node sizes may confuse the VM badly. Usually they - * result from BIOS bugs. So dont recognize nodes as standalone - * NUMA entities that have less than this amount of RAM listed: - */ -#define NODE_MIN_SIZE (4*1024*1024) - -extern nodemask_t numa_nodes_parsed __initdata; - -extern int __cpuinit numa_cpu_node(int cpu); -extern int __init numa_add_memblk(int nodeid, u64 start, u64 end); -extern void __init numa_set_distance(int from, int to, int distance); - -#ifdef CONFIG_NUMA_EMU -#define FAKE_NODE_MIN_SIZE ((u64)32 << 20) -#define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1UL)) -void numa_emu_cmdline(char *); -#endif /* CONFIG_NUMA_EMU */ -#else -static inline int numa_cpu_node(int cpu) { return NUMA_NO_NODE; } -#endif #endif /* _ASM_X86_NUMA_64_H */ diff --git a/arch/x86/include/asm/numaq.h b/arch/x86/include/asm/numaq.h index 37c516545ec8..c3b3c322fd87 100644 --- a/arch/x86/include/asm/numaq.h +++ b/arch/x86/include/asm/numaq.h @@ -29,7 +29,7 @@ #ifdef CONFIG_X86_NUMAQ extern int found_numaq; -extern int get_memcfg_numaq(void); +extern int numaq_numa_init(void); extern int pci_numaq_init(void); extern void *xquad_portio; @@ -166,11 +166,6 @@ struct sys_cfg_data { void numaq_tsc_disable(void); -#else -static inline int get_memcfg_numaq(void) -{ - return 0; -} #endif /* CONFIG_X86_NUMAQ */ #endif /* _ASM_X86_NUMAQ_H */ diff --git a/arch/x86/include/asm/olpc_ofw.h b/arch/x86/include/asm/olpc_ofw.h index c5d3a5abbb9f..24487712e0b1 100644 --- a/arch/x86/include/asm/olpc_ofw.h +++ b/arch/x86/include/asm/olpc_ofw.h @@ -26,15 +26,12 @@ extern void setup_olpc_ofw_pgd(void); /* check if OFW was detected during boot */ extern bool olpc_ofw_present(void); +extern void olpc_dt_build_devicetree(void); + #else /* !CONFIG_OLPC */ static inline void olpc_ofw_detect(void) { } static inline void setup_olpc_ofw_pgd(void) { } +static inline void olpc_dt_build_devicetree(void) { } #endif /* !CONFIG_OLPC */ -#ifdef CONFIG_OF_PROMTREE -extern void olpc_dt_build_devicetree(void); -#else -static inline void olpc_dt_build_devicetree(void) { } -#endif - #endif /* _ASM_X86_OLPC_OFW_H */ diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index d475b4398d8b..53278b0dfdf6 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -517,7 +517,7 @@ do { \ typeof(o2) __o2 = o2; \ typeof(o2) __n2 = n2; \ typeof(o2) __dummy; \ - alternative_io("call this_cpu_cmpxchg16b_emu\n\t" P6_NOP4, \ + alternative_io("call this_cpu_cmpxchg16b_emu\n\t" ASM_NOP4, \ "cmpxchg16b " __percpu_prefix "(%%rsi)\n\tsetz %0\n\t", \ X86_FEATURE_CX16, \ ASM_OUTPUT2("=a"(__ret), "=d"(__dummy)), \ @@ -542,6 +542,33 @@ do { \ old__; \ }) +static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr, + const unsigned long __percpu *addr) +{ + unsigned long __percpu *a = (unsigned long *)addr + nr / BITS_PER_LONG; + + return ((1UL << (nr % BITS_PER_LONG)) & percpu_read(*a)) != 0; +} + +static inline int x86_this_cpu_variable_test_bit(int nr, + const unsigned long __percpu *addr) +{ + int oldbit; + + asm volatile("bt "__percpu_arg(2)",%1\n\t" + "sbb %0,%0" + : "=r" (oldbit) + : "m" (*(unsigned long *)addr), "Ir" (nr)); + + return oldbit; +} + +#define x86_this_cpu_test_bit(nr, addr) \ + (__builtin_constant_p((nr)) \ + ? x86_this_cpu_constant_test_bit((nr), (addr)) \ + : x86_this_cpu_variable_test_bit((nr), (addr))) + + #include /* We can use this directly for local CPU (faster). */ diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 7db7723d1f32..d56187c6b838 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -299,6 +299,7 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, /* Install a pte for a particular vaddr in kernel space. */ void set_pte_vaddr(unsigned long vaddr, pte_t pte); +extern void native_pagetable_reserve(u64 start, u64 end); #ifdef CONFIG_X86_32 extern void native_pagetable_setup_start(pgd_t *base); extern void native_pagetable_setup_done(pgd_t *base); diff --git a/arch/x86/include/asm/probe_roms.h b/arch/x86/include/asm/probe_roms.h new file mode 100644 index 000000000000..4950a0b1d09c --- /dev/null +++ b/arch/x86/include/asm/probe_roms.h @@ -0,0 +1,8 @@ +#ifndef _PROBE_ROMS_H_ +#define _PROBE_ROMS_H_ +struct pci_dev; + +extern void __iomem *pci_map_biosrom(struct pci_dev *pdev); +extern void pci_unmap_biosrom(void __iomem *rom); +extern size_t pci_biosrom_size(struct pci_dev *pdev); +#endif diff --git a/arch/x86/include/asm/processor-flags.h b/arch/x86/include/asm/processor-flags.h index a898a2b6e10c..59ab4dffa377 100644 --- a/arch/x86/include/asm/processor-flags.h +++ b/arch/x86/include/asm/processor-flags.h @@ -60,6 +60,7 @@ #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */ #define X86_CR4_VMXE 0x00002000 /* enable VMX virtualization */ #define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */ +#define X86_CR4_SMEP 0x00100000 /* enable SMEP support */ /* * x86-64 Task Priority Register, CR8 diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index db8aa19a08a2..9756551ec760 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -88,7 +88,7 @@ void *extend_brk(size_t size, size_t align); * executable.) */ #define RESERVE_BRK(name,sz) \ - static void __section(.discard.text) __used \ + static void __section(.discard.text) __used notrace \ __brk_reservation_fn_##name##__(void) { \ asm volatile ( \ ".pushsection .brk_reservation,\"aw\",@nobits;" \ @@ -104,10 +104,10 @@ void *extend_brk(size_t size, size_t align); type *name; \ RESERVE_BRK(name, sizeof(type) * entries) +extern void probe_roms(void); #ifdef __i386__ void __init i386_start_kernel(void); -extern void probe_roms(void); #else void __init x86_64_start_kernel(char *real_mode); diff --git a/arch/x86/include/asm/srat.h b/arch/x86/include/asm/srat.h deleted file mode 100644 index b508d639d1a7..000000000000 --- a/arch/x86/include/asm/srat.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Some of the code in this file has been gleaned from the 64 bit - * discontigmem support code base. - * - * Copyright (C) 2002, IBM 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 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU 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. - * - * Send feedback to Pat Gaughen - */ - -#ifndef _ASM_X86_SRAT_H -#define _ASM_X86_SRAT_H - -#ifdef CONFIG_ACPI_NUMA -extern int get_memcfg_from_srat(void); -#else -static inline int get_memcfg_from_srat(void) -{ - return 0; -} -#endif - -#endif /* _ASM_X86_SRAT_H */ diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h index d7e89c83645d..70bbe39043a9 100644 --- a/arch/x86/include/asm/stacktrace.h +++ b/arch/x86/include/asm/stacktrace.h @@ -37,9 +37,6 @@ print_context_stack_bp(struct thread_info *tinfo, /* Generic stack tracer with callbacks */ struct stacktrace_ops { - void (*warning)(void *data, char *msg); - /* msg must contain %s for the symbol */ - void (*warning_symbol)(void *data, char *msg, unsigned long symbol); void (*address)(void *data, unsigned long address, int reliable); /* On negative return stop dumping */ int (*stack)(void *data, char *name); diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h index 12569e691ce3..c2ff2a1d845e 100644 --- a/arch/x86/include/asm/system.h +++ b/arch/x86/include/asm/system.h @@ -303,24 +303,81 @@ static inline void native_wbinvd(void) #ifdef CONFIG_PARAVIRT #include #else -#define read_cr0() (native_read_cr0()) -#define write_cr0(x) (native_write_cr0(x)) -#define read_cr2() (native_read_cr2()) -#define write_cr2(x) (native_write_cr2(x)) -#define read_cr3() (native_read_cr3()) -#define write_cr3(x) (native_write_cr3(x)) -#define read_cr4() (native_read_cr4()) -#define read_cr4_safe() (native_read_cr4_safe()) -#define write_cr4(x) (native_write_cr4(x)) -#define wbinvd() (native_wbinvd()) + +static inline unsigned long read_cr0(void) +{ + return native_read_cr0(); +} + +static inline void write_cr0(unsigned long x) +{ + native_write_cr0(x); +} + +static inline unsigned long read_cr2(void) +{ + return native_read_cr2(); +} + +static inline void write_cr2(unsigned long x) +{ + native_write_cr2(x); +} + +static inline unsigned long read_cr3(void) +{ + return native_read_cr3(); +} + +static inline void write_cr3(unsigned long x) +{ + native_write_cr3(x); +} + +static inline unsigned long read_cr4(void) +{ + return native_read_cr4(); +} + +static inline unsigned long read_cr4_safe(void) +{ + return native_read_cr4_safe(); +} + +static inline void write_cr4(unsigned long x) +{ + native_write_cr4(x); +} + +static inline void wbinvd(void) +{ + native_wbinvd(); +} + #ifdef CONFIG_X86_64 -#define read_cr8() (native_read_cr8()) -#define write_cr8(x) (native_write_cr8(x)) -#define load_gs_index native_load_gs_index + +static inline unsigned long read_cr8(void) +{ + return native_read_cr8(); +} + +static inline void write_cr8(unsigned long x) +{ + native_write_cr8(x); +} + +static inline void load_gs_index(unsigned selector) +{ + native_load_gs_index(selector); +} + #endif /* Clear the 'TS' bit */ -#define clts() (native_clts()) +static inline void clts(void) +{ + native_clts(); +} #endif/* CONFIG_PARAVIRT */ diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index 910a7084f7f2..c00692476e9f 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -93,19 +93,11 @@ extern void setup_node_to_cpumask_map(void); #define pcibus_to_node(bus) __pcibus_to_node(bus) #ifdef CONFIG_X86_32 -extern unsigned long node_start_pfn[]; -extern unsigned long node_end_pfn[]; -extern unsigned long node_remap_size[]; -#define node_has_online_mem(nid) (node_start_pfn[nid] != node_end_pfn[nid]) - # define SD_CACHE_NICE_TRIES 1 # define SD_IDLE_IDX 1 - #else - # define SD_CACHE_NICE_TRIES 2 # define SD_IDLE_IDX 2 - #endif /* sched_domains SD_NODE_INIT for NUMA machines */ diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index abd3e0ea762a..99ddd148a760 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -42,7 +41,7 @@ * Returns 0 if the range is valid, nonzero otherwise. * * This is equivalent to the following test: - * (u33)addr + (u33)size >= (u33)current->addr_limit.seg (u65 for x86_64) + * (u33)addr + (u33)size > (u33)current->addr_limit.seg (u65 for x86_64) * * This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry... */ diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h index 088d09fb1615..566e803cc602 100644 --- a/arch/x86/include/asm/uaccess_32.h +++ b/arch/x86/include/asm/uaccess_32.h @@ -6,7 +6,6 @@ */ #include #include -#include #include #include #include diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index 316708d5af92..1c66d30971ad 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h @@ -6,7 +6,6 @@ */ #include #include -#include #include #include #include diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h index a755ef5e5977..fb6a625c99bf 100644 --- a/arch/x86/include/asm/unistd_32.h +++ b/arch/x86/include/asm/unistd_32.h @@ -350,10 +350,11 @@ #define __NR_open_by_handle_at 342 #define __NR_clock_adjtime 343 #define __NR_syncfs 344 +#define __NR_sendmmsg 345 #ifdef __KERNEL__ -#define NR_syscalls 345 +#define NR_syscalls 346 #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h index 160fa76bd578..79f90eb15aad 100644 --- a/arch/x86/include/asm/unistd_64.h +++ b/arch/x86/include/asm/unistd_64.h @@ -677,6 +677,8 @@ __SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at) __SYSCALL(__NR_clock_adjtime, sys_clock_adjtime) #define __NR_syncfs 306 __SYSCALL(__NR_syncfs, sys_syncfs) +#define __NR_sendmmsg 307 +__SYSCALL(__NR_sendmmsg, sys_sendmmsg) #ifndef __NO_STUBS #define __ARCH_WANT_OLD_READDIR diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h index 3e094af443c3..130f1eeee5fe 100644 --- a/arch/x86/include/asm/uv/uv_bau.h +++ b/arch/x86/include/asm/uv/uv_bau.h @@ -94,6 +94,8 @@ /* after this # consecutive successes, bump up the throttle if it was lowered */ #define COMPLETE_THRESHOLD 5 +#define UV_LB_SUBNODEID 0x10 + /* * number of entries in the destination side payload queue */ @@ -124,7 +126,7 @@ * The distribution specification (32 bytes) is interpreted as a 256-bit * distribution vector. Adjacent bits correspond to consecutive even numbered * nodeIDs. The result of adding the index of a given bit to the 15-bit - * 'base_dest_nodeid' field of the header corresponds to the + * 'base_dest_nasid' field of the header corresponds to the * destination nodeID associated with that specified bit. */ struct bau_target_uvhubmask { @@ -176,7 +178,7 @@ struct bau_msg_payload { struct bau_msg_header { unsigned int dest_subnodeid:6; /* must be 0x10, for the LB */ /* bits 5:0 */ - unsigned int base_dest_nodeid:15; /* nasid of the */ + unsigned int base_dest_nasid:15; /* nasid of the */ /* bits 20:6 */ /* first bit in uvhub map */ unsigned int command:8; /* message type */ /* bits 28:21 */ @@ -378,6 +380,10 @@ struct ptc_stats { unsigned long d_rcanceled; /* number of messages canceled by resets */ }; +struct hub_and_pnode { + short uvhub; + short pnode; +}; /* * one per-cpu; to locate the software tables */ @@ -399,10 +405,12 @@ struct bau_control { int baudisabled; int set_bau_off; short cpu; + short osnode; short uvhub_cpu; short uvhub; short cpus_in_socket; short cpus_in_uvhub; + short partition_base_pnode; unsigned short message_number; unsigned short uvhub_quiesce; short socket_acknowledge_count[DEST_Q_SIZE]; @@ -422,15 +430,16 @@ struct bau_control { int congested_period; cycles_t period_time; long period_requests; + struct hub_and_pnode *target_hub_and_pnode; }; static inline int bau_uvhub_isset(int uvhub, struct bau_target_uvhubmask *dstp) { return constant_test_bit(uvhub, &dstp->bits[0]); } -static inline void bau_uvhub_set(int uvhub, struct bau_target_uvhubmask *dstp) +static inline void bau_uvhub_set(int pnode, struct bau_target_uvhubmask *dstp) { - __set_bit(uvhub, &dstp->bits[0]); + __set_bit(pnode, &dstp->bits[0]); } static inline void bau_uvhubs_clear(struct bau_target_uvhubmask *dstp, int nbits) diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index a501741c2335..4298002d0c83 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -398,6 +398,8 @@ struct uv_blade_info { unsigned short nr_online_cpus; unsigned short pnode; short memory_nid; + spinlock_t nmi_lock; + unsigned long nmi_count; }; extern struct uv_blade_info *uv_blade_info; extern short *uv_node_to_blade; diff --git a/arch/x86/include/asm/uv/uv_mmrs.h b/arch/x86/include/asm/uv/uv_mmrs.h index 20cafeac7455..f5bb64a823d7 100644 --- a/arch/x86/include/asm/uv/uv_mmrs.h +++ b/arch/x86/include/asm/uv/uv_mmrs.h @@ -5,7 +5,7 @@ * * SGI UV MMR definitions * - * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2007-2011 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_X86_UV_UV_MMRS_H @@ -1099,5 +1099,19 @@ union uvh_rtc1_int_config_u { } s; }; +/* ========================================================================= */ +/* UVH_SCRATCH5 */ +/* ========================================================================= */ +#define UVH_SCRATCH5 0x2d0200UL +#define UVH_SCRATCH5_32 0x00778 + +#define UVH_SCRATCH5_SCRATCH5_SHFT 0 +#define UVH_SCRATCH5_SCRATCH5_MASK 0xffffffffffffffffUL +union uvh_scratch5_u { + unsigned long v; + struct uvh_scratch5_s { + unsigned long scratch5 : 64; /* RW, W1CS */ + } s; +}; #endif /* __ASM_UV_MMRS_X86_H__ */ diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 643ebf2e2ad8..d3d859035af9 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -67,6 +67,17 @@ struct x86_init_oem { void (*banner)(void); }; +/** + * struct x86_init_mapping - platform specific initial kernel pagetable setup + * @pagetable_reserve: reserve a range of addresses for kernel pagetable usage + * + * For more details on the purpose of this hook, look in + * init_memory_mapping and the commit that added it. + */ +struct x86_init_mapping { + void (*pagetable_reserve)(u64 start, u64 end); +}; + /** * struct x86_init_paging - platform specific paging functions * @pagetable_setup_start: platform specific pre paging_init() call @@ -123,6 +134,7 @@ struct x86_init_ops { struct x86_init_mpparse mpparse; struct x86_init_irqs irqs; struct x86_init_oem oem; + struct x86_init_mapping mapping; struct x86_init_paging paging; struct x86_init_timers timers; struct x86_init_iommu iommu; diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index c61934fbf22a..64a619d47d34 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -47,8 +47,9 @@ extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn); extern unsigned long set_phys_range_identity(unsigned long pfn_s, unsigned long pfn_e); -extern int m2p_add_override(unsigned long mfn, struct page *page); -extern int m2p_remove_override(struct page *page); +extern int m2p_add_override(unsigned long mfn, struct page *page, + bool clear_pte); +extern int m2p_remove_override(struct page *page, bool clear_pte); extern struct page *m2p_find_override(unsigned long mfn); extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); diff --git a/arch/x86/include/asm/xen/pci.h b/arch/x86/include/asm/xen/pci.h index aa8620989162..4fbda9a3f339 100644 --- a/arch/x86/include/asm/xen/pci.h +++ b/arch/x86/include/asm/xen/pci.h @@ -15,10 +15,26 @@ static inline int pci_xen_hvm_init(void) #endif #if defined(CONFIG_XEN_DOM0) void __init xen_setup_pirqs(void); +int xen_find_device_domain_owner(struct pci_dev *dev); +int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain); +int xen_unregister_device_domain_owner(struct pci_dev *dev); #else static inline void __init xen_setup_pirqs(void) { } +static inline int xen_find_device_domain_owner(struct pci_dev *dev) +{ + return -1; +} +static inline int xen_register_device_domain_owner(struct pci_dev *dev, + uint16_t domain) +{ + return -1; +} +static inline int xen_unregister_device_domain_owner(struct pci_dev *dev) +{ + return -1; +} #endif #if defined(CONFIG_PCI_MSI) diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 7338ef2218bc..250806472a7e 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -36,7 +36,7 @@ obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o obj-y += time.o ioport.o ldt.o dumpstack.o obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o obj-$(CONFIG_IRQ_WORK) += irq_work.o -obj-$(CONFIG_X86_32) += probe_roms_32.o +obj-y += probe_roms.o obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o obj-$(CONFIG_X86_64) += syscall_64.o vsyscall_64.o @@ -117,7 +117,7 @@ obj-$(CONFIG_OF) += devicetree.o ifeq ($(CONFIG_X86_64),y) obj-$(CONFIG_AUDIT) += audit_64.o - obj-$(CONFIG_GART_IOMMU) += pci-gart_64.o aperture_64.o + obj-$(CONFIG_GART_IOMMU) += amd_gart_64.o aperture_64.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o obj-$(CONFIG_AMD_IOMMU) += amd_iommu_init.o amd_iommu.o diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index ff93bc1b09c3..18a857ba7a25 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -112,11 +112,6 @@ static int __init acpi_sleep_setup(char *str) #ifdef CONFIG_HIBERNATION if (strncmp(str, "s4_nohwsig", 10) == 0) acpi_no_s4_hw_signature(); - if (strncmp(str, "s4_nonvs", 8) == 0) { - pr_warning("ACPI: acpi_sleep=s4_nonvs is deprecated, " - "please use acpi_sleep=nonvs instead"); - acpi_nvs_nosave(); - } #endif if (strncmp(str, "nonvs", 5) == 0) acpi_nvs_nosave(); diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 4a234677e213..a81f2d52f869 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -67,17 +67,30 @@ __setup("noreplace-paravirt", setup_noreplace_paravirt); #define DPRINTK(fmt, args...) if (debug_alternative) \ printk(KERN_DEBUG fmt, args) +/* + * Each GENERIC_NOPX is of X bytes, and defined as an array of bytes + * that correspond to that nop. Getting from one nop to the next, we + * add to the array the offset that is equal to the sum of all sizes of + * nops preceding the one we are after. + * + * Note: The GENERIC_NOP5_ATOMIC is at the end, as it breaks the + * nice symmetry of sizes of the previous nops. + */ #if defined(GENERIC_NOP1) && !defined(CONFIG_X86_64) -/* Use inline assembly to define this because the nops are defined - as inline assembly strings in the include files and we cannot - get them easily into strings. */ -asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nintelnops: " - GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6 - GENERIC_NOP7 GENERIC_NOP8 - "\t.previous"); -extern const unsigned char intelnops[]; -static const unsigned char *const __initconst_or_module -intel_nops[ASM_NOP_MAX+1] = { +static const unsigned char intelnops[] = +{ + GENERIC_NOP1, + GENERIC_NOP2, + GENERIC_NOP3, + GENERIC_NOP4, + GENERIC_NOP5, + GENERIC_NOP6, + GENERIC_NOP7, + GENERIC_NOP8, + GENERIC_NOP5_ATOMIC +}; +static const unsigned char * const intel_nops[ASM_NOP_MAX+2] = +{ NULL, intelnops, intelnops + 1, @@ -87,17 +100,25 @@ intel_nops[ASM_NOP_MAX+1] = { intelnops + 1 + 2 + 3 + 4 + 5, intelnops + 1 + 2 + 3 + 4 + 5 + 6, intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7, + intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, }; #endif #ifdef K8_NOP1 -asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk8nops: " - K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6 - K8_NOP7 K8_NOP8 - "\t.previous"); -extern const unsigned char k8nops[]; -static const unsigned char *const __initconst_or_module -k8_nops[ASM_NOP_MAX+1] = { +static const unsigned char k8nops[] = +{ + K8_NOP1, + K8_NOP2, + K8_NOP3, + K8_NOP4, + K8_NOP5, + K8_NOP6, + K8_NOP7, + K8_NOP8, + K8_NOP5_ATOMIC +}; +static const unsigned char * const k8_nops[ASM_NOP_MAX+2] = +{ NULL, k8nops, k8nops + 1, @@ -107,17 +128,25 @@ k8_nops[ASM_NOP_MAX+1] = { k8nops + 1 + 2 + 3 + 4 + 5, k8nops + 1 + 2 + 3 + 4 + 5 + 6, k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, + k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, }; #endif #if defined(K7_NOP1) && !defined(CONFIG_X86_64) -asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk7nops: " - K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6 - K7_NOP7 K7_NOP8 - "\t.previous"); -extern const unsigned char k7nops[]; -static const unsigned char *const __initconst_or_module -k7_nops[ASM_NOP_MAX+1] = { +static const unsigned char k7nops[] = +{ + K7_NOP1, + K7_NOP2, + K7_NOP3, + K7_NOP4, + K7_NOP5, + K7_NOP6, + K7_NOP7, + K7_NOP8, + K7_NOP5_ATOMIC +}; +static const unsigned char * const k7_nops[ASM_NOP_MAX+2] = +{ NULL, k7nops, k7nops + 1, @@ -127,17 +156,25 @@ k7_nops[ASM_NOP_MAX+1] = { k7nops + 1 + 2 + 3 + 4 + 5, k7nops + 1 + 2 + 3 + 4 + 5 + 6, k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, + k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, }; #endif #ifdef P6_NOP1 -asm("\t" __stringify(__INITRODATA_OR_MODULE) "\np6nops: " - P6_NOP1 P6_NOP2 P6_NOP3 P6_NOP4 P6_NOP5 P6_NOP6 - P6_NOP7 P6_NOP8 - "\t.previous"); -extern const unsigned char p6nops[]; -static const unsigned char *const __initconst_or_module -p6_nops[ASM_NOP_MAX+1] = { +static const unsigned char __initconst_or_module p6nops[] = +{ + P6_NOP1, + P6_NOP2, + P6_NOP3, + P6_NOP4, + P6_NOP5, + P6_NOP6, + P6_NOP7, + P6_NOP8, + P6_NOP5_ATOMIC +}; +static const unsigned char * const p6_nops[ASM_NOP_MAX+2] = +{ NULL, p6nops, p6nops + 1, @@ -147,47 +184,65 @@ p6_nops[ASM_NOP_MAX+1] = { p6nops + 1 + 2 + 3 + 4 + 5, p6nops + 1 + 2 + 3 + 4 + 5 + 6, p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, + p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, }; #endif +/* Initialize these to a safe default */ #ifdef CONFIG_X86_64 +const unsigned char * const *ideal_nops = p6_nops; +#else +const unsigned char * const *ideal_nops = intel_nops; +#endif -extern char __vsyscall_0; -static const unsigned char *const *__init_or_module find_nop_table(void) +void __init arch_init_ideal_nops(void) { - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && - boot_cpu_has(X86_FEATURE_NOPL)) - return p6_nops; - else - return k8_nops; + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_INTEL: + /* + * Due to a decoder implementation quirk, some + * specific Intel CPUs actually perform better with + * the "k8_nops" than with the SDM-recommended NOPs. + */ + if (boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model >= 0x0f && + boot_cpu_data.x86_model != 0x1c && + boot_cpu_data.x86_model != 0x26 && + boot_cpu_data.x86_model != 0x27 && + boot_cpu_data.x86_model < 0x30) { + ideal_nops = k8_nops; + } else if (boot_cpu_has(X86_FEATURE_NOPL)) { + ideal_nops = p6_nops; + } else { +#ifdef CONFIG_X86_64 + ideal_nops = k8_nops; +#else + ideal_nops = intel_nops; +#endif + } + + default: +#ifdef CONFIG_X86_64 + ideal_nops = k8_nops; +#else + if (boot_cpu_has(X86_FEATURE_K8)) + ideal_nops = k8_nops; + else if (boot_cpu_has(X86_FEATURE_K7)) + ideal_nops = k7_nops; + else + ideal_nops = intel_nops; +#endif + } } -#else /* CONFIG_X86_64 */ - -static const unsigned char *const *__init_or_module find_nop_table(void) -{ - if (boot_cpu_has(X86_FEATURE_K8)) - return k8_nops; - else if (boot_cpu_has(X86_FEATURE_K7)) - return k7_nops; - else if (boot_cpu_has(X86_FEATURE_NOPL)) - return p6_nops; - else - return intel_nops; -} - -#endif /* CONFIG_X86_64 */ - /* Use this to add nops to a buffer, then text_poke the whole buffer. */ static void __init_or_module add_nops(void *insns, unsigned int len) { - const unsigned char *const *noptable = find_nop_table(); - while (len > 0) { unsigned int noplen = len; if (noplen > ASM_NOP_MAX) noplen = ASM_NOP_MAX; - memcpy(insns, noptable[noplen], noplen); + memcpy(insns, ideal_nops[noplen], noplen); insns += noplen; len -= noplen; } @@ -195,6 +250,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len) extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; extern s32 __smp_locks[], __smp_locks_end[]; +extern char __vsyscall_0; void *text_poke_early(void *addr, const void *opcode, size_t len); /* Replace instructions with better alternatives for this CPU type. @@ -210,6 +266,15 @@ void __init_or_module apply_alternatives(struct alt_instr *start, u8 insnbuf[MAX_PATCH_LEN]; DPRINTK("%s: alt table %p -> %p\n", __func__, start, end); + /* + * The scan order should be from start to end. A later scanned + * alternative code can overwrite a previous scanned alternative code. + * Some kernel functions (e.g. memcpy, memset, etc) use this order to + * patch code. + * + * So be careful if you want to change the scan order to any other + * order. + */ for (a = start; a < end; a++) { u8 *instr = a->instr; BUG_ON(a->replacementlen > a->instrlen); @@ -678,29 +743,3 @@ void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n) wrote_text = 0; __stop_machine(stop_machine_text_poke, (void *)&tpp, NULL); } - -#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) - -#ifdef CONFIG_X86_64 -unsigned char ideal_nop5[5] = { 0x66, 0x66, 0x66, 0x66, 0x90 }; -#else -unsigned char ideal_nop5[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; -#endif - -void __init arch_init_ideal_nop5(void) -{ - /* - * There is no good nop for all x86 archs. This selection - * algorithm should be unified with the one in find_nop_table(), - * but this should be good enough for now. - * - * For cases other than the ones below, use the safe (as in - * always functional) defaults above. - */ -#ifdef CONFIG_X86_64 - /* Don't use these on 32 bits due to broken virtualizers */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) - memcpy(ideal_nop5, p6_nops[5], 5); -#endif -} -#endif diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/amd_gart_64.c similarity index 98% rename from arch/x86/kernel/pci-gart_64.c rename to arch/x86/kernel/amd_gart_64.c index 82ada01625b9..b117efd24f71 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/amd_gart_64.c @@ -81,6 +81,9 @@ static u32 gart_unmapped_entry; #define AGPEXTERN #endif +/* GART can only remap to physical addresses < 1TB */ +#define GART_MAX_PHYS_ADDR (1ULL << 40) + /* backdoor interface to AGP driver */ AGPEXTERN int agp_memory_reserved; AGPEXTERN __u32 *agp_gatt_table; @@ -212,9 +215,13 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem, size_t size, int dir, unsigned long align_mask) { unsigned long npages = iommu_num_pages(phys_mem, size, PAGE_SIZE); - unsigned long iommu_page = alloc_iommu(dev, npages, align_mask); + unsigned long iommu_page; int i; + if (unlikely(phys_mem + size > GART_MAX_PHYS_ADDR)) + return bad_dma_addr; + + iommu_page = alloc_iommu(dev, npages, align_mask); if (iommu_page == -1) { if (!nonforced_iommu(dev, phys_mem, size)) return phys_mem; diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 57ca77787220..873e7e1ead7b 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +36,7 @@ #define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28)) -#define EXIT_LOOP_COUNT 10000000 +#define LOOP_TIMEOUT 100000 static DEFINE_RWLOCK(amd_iommu_devtable_lock); @@ -57,7 +59,6 @@ struct iommu_cmd { u32 data[4]; }; -static void reset_iommu_command_buffer(struct amd_iommu *iommu); static void update_domain(struct protection_domain *domain); /**************************************************************************** @@ -322,8 +323,6 @@ static void iommu_print_event(struct amd_iommu *iommu, void *__evt) break; case EVENT_TYPE_ILL_CMD: printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address); - iommu->reset_in_progress = true; - reset_iommu_command_buffer(iommu); dump_command(address); break; case EVENT_TYPE_CMD_HARD_ERR: @@ -367,7 +366,7 @@ static void iommu_poll_events(struct amd_iommu *iommu) spin_unlock_irqrestore(&iommu->lock, flags); } -irqreturn_t amd_iommu_int_handler(int irq, void *data) +irqreturn_t amd_iommu_int_thread(int irq, void *data) { struct amd_iommu *iommu; @@ -377,130 +376,360 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data) return IRQ_HANDLED; } +irqreturn_t amd_iommu_int_handler(int irq, void *data) +{ + return IRQ_WAKE_THREAD; +} + /**************************************************************************** * * IOMMU command queuing functions * ****************************************************************************/ -/* - * Writes the command to the IOMMUs command buffer and informs the - * hardware about the new command. Must be called with iommu->lock held. - */ -static int __iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) +static int wait_on_sem(volatile u64 *sem) { - u32 tail, head; - u8 *target; + int i = 0; - WARN_ON(iommu->cmd_buf_size & CMD_BUFFER_UNINITIALIZED); - tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); - target = iommu->cmd_buf + tail; - memcpy_toio(target, cmd, sizeof(*cmd)); - tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size; - head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET); - if (tail == head) - return -ENOMEM; - writel(tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); + while (*sem == 0 && i < LOOP_TIMEOUT) { + udelay(1); + i += 1; + } + + if (i == LOOP_TIMEOUT) { + pr_alert("AMD-Vi: Completion-Wait loop timed out\n"); + return -EIO; + } return 0; } -/* - * General queuing function for commands. Takes iommu->lock and calls - * __iommu_queue_command(). - */ -static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) +static void copy_cmd_to_buffer(struct amd_iommu *iommu, + struct iommu_cmd *cmd, + u32 tail) { - unsigned long flags; - int ret; + u8 *target; - spin_lock_irqsave(&iommu->lock, flags); - ret = __iommu_queue_command(iommu, cmd); - if (!ret) - iommu->need_sync = true; - spin_unlock_irqrestore(&iommu->lock, flags); + target = iommu->cmd_buf + tail; + tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size; - return ret; + /* Copy command to buffer */ + memcpy(target, cmd, sizeof(*cmd)); + + /* Tell the IOMMU about it */ + writel(tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); +} + +static void build_completion_wait(struct iommu_cmd *cmd, u64 address) +{ + WARN_ON(address & 0x7ULL); + + memset(cmd, 0, sizeof(*cmd)); + cmd->data[0] = lower_32_bits(__pa(address)) | CMD_COMPL_WAIT_STORE_MASK; + cmd->data[1] = upper_32_bits(__pa(address)); + cmd->data[2] = 1; + CMD_SET_TYPE(cmd, CMD_COMPL_WAIT); +} + +static void build_inv_dte(struct iommu_cmd *cmd, u16 devid) +{ + memset(cmd, 0, sizeof(*cmd)); + cmd->data[0] = devid; + CMD_SET_TYPE(cmd, CMD_INV_DEV_ENTRY); +} + +static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address, + size_t size, u16 domid, int pde) +{ + u64 pages; + int s; + + pages = iommu_num_pages(address, size, PAGE_SIZE); + s = 0; + + if (pages > 1) { + /* + * If we have to flush more than one page, flush all + * TLB entries for this domain + */ + address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; + s = 1; + } + + address &= PAGE_MASK; + + memset(cmd, 0, sizeof(*cmd)); + cmd->data[1] |= domid; + cmd->data[2] = lower_32_bits(address); + cmd->data[3] = upper_32_bits(address); + CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES); + if (s) /* size bit - we flush more than one 4kb page */ + cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK; + if (pde) /* PDE bit - we wan't flush everything not only the PTEs */ + cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK; +} + +static void build_inv_iotlb_pages(struct iommu_cmd *cmd, u16 devid, int qdep, + u64 address, size_t size) +{ + u64 pages; + int s; + + pages = iommu_num_pages(address, size, PAGE_SIZE); + s = 0; + + if (pages > 1) { + /* + * If we have to flush more than one page, flush all + * TLB entries for this domain + */ + address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; + s = 1; + } + + address &= PAGE_MASK; + + memset(cmd, 0, sizeof(*cmd)); + cmd->data[0] = devid; + cmd->data[0] |= (qdep & 0xff) << 24; + cmd->data[1] = devid; + cmd->data[2] = lower_32_bits(address); + cmd->data[3] = upper_32_bits(address); + CMD_SET_TYPE(cmd, CMD_INV_IOTLB_PAGES); + if (s) + cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK; +} + +static void build_inv_all(struct iommu_cmd *cmd) +{ + memset(cmd, 0, sizeof(*cmd)); + CMD_SET_TYPE(cmd, CMD_INV_ALL); } /* - * This function waits until an IOMMU has completed a completion - * wait command + * Writes the command to the IOMMUs command buffer and informs the + * hardware about the new command. */ -static void __iommu_wait_for_completion(struct amd_iommu *iommu) +static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) { - int ready = 0; - unsigned status = 0; - unsigned long i = 0; + u32 left, tail, head, next_tail; + unsigned long flags; - INC_STATS_COUNTER(compl_wait); + WARN_ON(iommu->cmd_buf_size & CMD_BUFFER_UNINITIALIZED); - while (!ready && (i < EXIT_LOOP_COUNT)) { - ++i; - /* wait for the bit to become one */ - status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); - ready = status & MMIO_STATUS_COM_WAIT_INT_MASK; +again: + spin_lock_irqsave(&iommu->lock, flags); + + head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET); + tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); + next_tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size; + left = (head - next_tail) % iommu->cmd_buf_size; + + if (left <= 2) { + struct iommu_cmd sync_cmd; + volatile u64 sem = 0; + int ret; + + build_completion_wait(&sync_cmd, (u64)&sem); + copy_cmd_to_buffer(iommu, &sync_cmd, tail); + + spin_unlock_irqrestore(&iommu->lock, flags); + + if ((ret = wait_on_sem(&sem)) != 0) + return ret; + + goto again; } - /* set bit back to zero */ - status &= ~MMIO_STATUS_COM_WAIT_INT_MASK; - writel(status, iommu->mmio_base + MMIO_STATUS_OFFSET); + copy_cmd_to_buffer(iommu, cmd, tail); - if (unlikely(i == EXIT_LOOP_COUNT)) - iommu->reset_in_progress = true; + /* We need to sync now to make sure all commands are processed */ + iommu->need_sync = true; + + spin_unlock_irqrestore(&iommu->lock, flags); + + return 0; } /* * This function queues a completion wait command into the command * buffer of an IOMMU */ -static int __iommu_completion_wait(struct amd_iommu *iommu) +static int iommu_completion_wait(struct amd_iommu *iommu) +{ + struct iommu_cmd cmd; + volatile u64 sem = 0; + int ret; + + if (!iommu->need_sync) + return 0; + + build_completion_wait(&cmd, (u64)&sem); + + ret = iommu_queue_command(iommu, &cmd); + if (ret) + return ret; + + return wait_on_sem(&sem); +} + +static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid) { struct iommu_cmd cmd; - memset(&cmd, 0, sizeof(cmd)); - cmd.data[0] = CMD_COMPL_WAIT_INT_MASK; - CMD_SET_TYPE(&cmd, CMD_COMPL_WAIT); + build_inv_dte(&cmd, devid); - return __iommu_queue_command(iommu, &cmd); + return iommu_queue_command(iommu, &cmd); +} + +static void iommu_flush_dte_all(struct amd_iommu *iommu) +{ + u32 devid; + + for (devid = 0; devid <= 0xffff; ++devid) + iommu_flush_dte(iommu, devid); + + iommu_completion_wait(iommu); } /* - * This function is called whenever we need to ensure that the IOMMU has - * completed execution of all commands we sent. It sends a - * COMPLETION_WAIT command and waits for it to finish. The IOMMU informs - * us about that by writing a value to a physical address we pass with - * the command. + * This function uses heavy locking and may disable irqs for some time. But + * this is no issue because it is only called during resume. */ -static int iommu_completion_wait(struct amd_iommu *iommu) +static void iommu_flush_tlb_all(struct amd_iommu *iommu) { - int ret = 0; - unsigned long flags; + u32 dom_id; - spin_lock_irqsave(&iommu->lock, flags); + for (dom_id = 0; dom_id <= 0xffff; ++dom_id) { + struct iommu_cmd cmd; + build_inv_iommu_pages(&cmd, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, + dom_id, 1); + iommu_queue_command(iommu, &cmd); + } - if (!iommu->need_sync) - goto out; - - ret = __iommu_completion_wait(iommu); - - iommu->need_sync = false; - - if (ret) - goto out; - - __iommu_wait_for_completion(iommu); - -out: - spin_unlock_irqrestore(&iommu->lock, flags); - - if (iommu->reset_in_progress) - reset_iommu_command_buffer(iommu); - - return 0; + iommu_completion_wait(iommu); } -static void iommu_flush_complete(struct protection_domain *domain) +static void iommu_flush_all(struct amd_iommu *iommu) +{ + struct iommu_cmd cmd; + + build_inv_all(&cmd); + + iommu_queue_command(iommu, &cmd); + iommu_completion_wait(iommu); +} + +void iommu_flush_all_caches(struct amd_iommu *iommu) +{ + if (iommu_feature(iommu, FEATURE_IA)) { + iommu_flush_all(iommu); + } else { + iommu_flush_dte_all(iommu); + iommu_flush_tlb_all(iommu); + } +} + +/* + * Command send function for flushing on-device TLB + */ +static int device_flush_iotlb(struct device *dev, u64 address, size_t size) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct amd_iommu *iommu; + struct iommu_cmd cmd; + u16 devid; + int qdep; + + qdep = pci_ats_queue_depth(pdev); + devid = get_device_id(dev); + iommu = amd_iommu_rlookup_table[devid]; + + build_inv_iotlb_pages(&cmd, devid, qdep, address, size); + + return iommu_queue_command(iommu, &cmd); +} + +/* + * Command send function for invalidating a device table entry + */ +static int device_flush_dte(struct device *dev) +{ + struct amd_iommu *iommu; + struct pci_dev *pdev; + u16 devid; + int ret; + + pdev = to_pci_dev(dev); + devid = get_device_id(dev); + iommu = amd_iommu_rlookup_table[devid]; + + ret = iommu_flush_dte(iommu, devid); + if (ret) + return ret; + + if (pci_ats_enabled(pdev)) + ret = device_flush_iotlb(dev, 0, ~0UL); + + return ret; +} + +/* + * TLB invalidation function which is called from the mapping functions. + * It invalidates a single PTE if the range to flush is within a single + * page. Otherwise it flushes the whole TLB of the IOMMU. + */ +static void __domain_flush_pages(struct protection_domain *domain, + u64 address, size_t size, int pde) +{ + struct iommu_dev_data *dev_data; + struct iommu_cmd cmd; + int ret = 0, i; + + build_inv_iommu_pages(&cmd, address, size, domain->id, pde); + + for (i = 0; i < amd_iommus_present; ++i) { + if (!domain->dev_iommu[i]) + continue; + + /* + * Devices of this domain are behind this IOMMU + * We need a TLB flush + */ + ret |= iommu_queue_command(amd_iommus[i], &cmd); + } + + list_for_each_entry(dev_data, &domain->dev_list, list) { + struct pci_dev *pdev = to_pci_dev(dev_data->dev); + + if (!pci_ats_enabled(pdev)) + continue; + + ret |= device_flush_iotlb(dev_data->dev, address, size); + } + + WARN_ON(ret); +} + +static void domain_flush_pages(struct protection_domain *domain, + u64 address, size_t size) +{ + __domain_flush_pages(domain, address, size, 0); +} + +/* Flush the whole IO/TLB for a given protection domain */ +static void domain_flush_tlb(struct protection_domain *domain) +{ + __domain_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 0); +} + +/* Flush the whole IO/TLB for a given protection domain - including PDE */ +static void domain_flush_tlb_pde(struct protection_domain *domain) +{ + __domain_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 1); +} + +static void domain_flush_complete(struct protection_domain *domain) { int i; @@ -516,118 +745,11 @@ static void iommu_flush_complete(struct protection_domain *domain) } } -/* - * Command send function for invalidating a device table entry - */ -static int iommu_flush_device(struct device *dev) -{ - struct amd_iommu *iommu; - struct iommu_cmd cmd; - u16 devid; - - devid = get_device_id(dev); - iommu = amd_iommu_rlookup_table[devid]; - - /* Build command */ - memset(&cmd, 0, sizeof(cmd)); - CMD_SET_TYPE(&cmd, CMD_INV_DEV_ENTRY); - cmd.data[0] = devid; - - return iommu_queue_command(iommu, &cmd); -} - -static void __iommu_build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address, - u16 domid, int pde, int s) -{ - memset(cmd, 0, sizeof(*cmd)); - address &= PAGE_MASK; - CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES); - cmd->data[1] |= domid; - cmd->data[2] = lower_32_bits(address); - cmd->data[3] = upper_32_bits(address); - if (s) /* size bit - we flush more than one 4kb page */ - cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK; - if (pde) /* PDE bit - we wan't flush everything not only the PTEs */ - cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK; -} - -/* - * Generic command send function for invalidaing TLB entries - */ -static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu, - u64 address, u16 domid, int pde, int s) -{ - struct iommu_cmd cmd; - int ret; - - __iommu_build_inv_iommu_pages(&cmd, address, domid, pde, s); - - ret = iommu_queue_command(iommu, &cmd); - - return ret; -} - -/* - * TLB invalidation function which is called from the mapping functions. - * It invalidates a single PTE if the range to flush is within a single - * page. Otherwise it flushes the whole TLB of the IOMMU. - */ -static void __iommu_flush_pages(struct protection_domain *domain, - u64 address, size_t size, int pde) -{ - int s = 0, i; - unsigned long pages = iommu_num_pages(address, size, PAGE_SIZE); - - address &= PAGE_MASK; - - if (pages > 1) { - /* - * If we have to flush more than one page, flush all - * TLB entries for this domain - */ - address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; - s = 1; - } - - - for (i = 0; i < amd_iommus_present; ++i) { - if (!domain->dev_iommu[i]) - continue; - - /* - * Devices of this domain are behind this IOMMU - * We need a TLB flush - */ - iommu_queue_inv_iommu_pages(amd_iommus[i], address, - domain->id, pde, s); - } - - return; -} - -static void iommu_flush_pages(struct protection_domain *domain, - u64 address, size_t size) -{ - __iommu_flush_pages(domain, address, size, 0); -} - -/* Flush the whole IO/TLB for a given protection domain */ -static void iommu_flush_tlb(struct protection_domain *domain) -{ - __iommu_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 0); -} - -/* Flush the whole IO/TLB for a given protection domain - including PDE */ -static void iommu_flush_tlb_pde(struct protection_domain *domain) -{ - __iommu_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 1); -} - /* * This function flushes the DTEs for all devices in domain */ -static void iommu_flush_domain_devices(struct protection_domain *domain) +static void domain_flush_devices(struct protection_domain *domain) { struct iommu_dev_data *dev_data; unsigned long flags; @@ -635,66 +757,11 @@ static void iommu_flush_domain_devices(struct protection_domain *domain) spin_lock_irqsave(&domain->lock, flags); list_for_each_entry(dev_data, &domain->dev_list, list) - iommu_flush_device(dev_data->dev); + device_flush_dte(dev_data->dev); spin_unlock_irqrestore(&domain->lock, flags); } -static void iommu_flush_all_domain_devices(void) -{ - struct protection_domain *domain; - unsigned long flags; - - spin_lock_irqsave(&amd_iommu_pd_lock, flags); - - list_for_each_entry(domain, &amd_iommu_pd_list, list) { - iommu_flush_domain_devices(domain); - iommu_flush_complete(domain); - } - - spin_unlock_irqrestore(&amd_iommu_pd_lock, flags); -} - -void amd_iommu_flush_all_devices(void) -{ - iommu_flush_all_domain_devices(); -} - -/* - * This function uses heavy locking and may disable irqs for some time. But - * this is no issue because it is only called during resume. - */ -void amd_iommu_flush_all_domains(void) -{ - struct protection_domain *domain; - unsigned long flags; - - spin_lock_irqsave(&amd_iommu_pd_lock, flags); - - list_for_each_entry(domain, &amd_iommu_pd_list, list) { - spin_lock(&domain->lock); - iommu_flush_tlb_pde(domain); - iommu_flush_complete(domain); - spin_unlock(&domain->lock); - } - - spin_unlock_irqrestore(&amd_iommu_pd_lock, flags); -} - -static void reset_iommu_command_buffer(struct amd_iommu *iommu) -{ - pr_err("AMD-Vi: Resetting IOMMU command buffer\n"); - - if (iommu->reset_in_progress) - panic("AMD-Vi: ILLEGAL_COMMAND_ERROR while resetting command buffer\n"); - - amd_iommu_reset_cmd_buffer(iommu); - amd_iommu_flush_all_devices(); - amd_iommu_flush_all_domains(); - - iommu->reset_in_progress = false; -} - /**************************************************************************** * * The functions below are used the create the page table mappings for @@ -1410,17 +1477,22 @@ static bool dma_ops_domain(struct protection_domain *domain) return domain->flags & PD_DMA_OPS_MASK; } -static void set_dte_entry(u16 devid, struct protection_domain *domain) +static void set_dte_entry(u16 devid, struct protection_domain *domain, bool ats) { u64 pte_root = virt_to_phys(domain->pt_root); + u32 flags = 0; pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK) << DEV_ENTRY_MODE_SHIFT; pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV; - amd_iommu_dev_table[devid].data[2] = domain->id; - amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root); - amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); + if (ats) + flags |= DTE_FLAG_IOTLB; + + amd_iommu_dev_table[devid].data[3] |= flags; + amd_iommu_dev_table[devid].data[2] = domain->id; + amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root); + amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); } static void clear_dte_entry(u16 devid) @@ -1437,34 +1509,42 @@ static void do_attach(struct device *dev, struct protection_domain *domain) { struct iommu_dev_data *dev_data; struct amd_iommu *iommu; + struct pci_dev *pdev; + bool ats = false; u16 devid; devid = get_device_id(dev); iommu = amd_iommu_rlookup_table[devid]; dev_data = get_dev_data(dev); + pdev = to_pci_dev(dev); + + if (amd_iommu_iotlb_sup) + ats = pci_ats_enabled(pdev); /* Update data structures */ dev_data->domain = domain; list_add(&dev_data->list, &domain->dev_list); - set_dte_entry(devid, domain); + set_dte_entry(devid, domain, ats); /* Do reference counting */ domain->dev_iommu[iommu->index] += 1; domain->dev_cnt += 1; /* Flush the DTE entry */ - iommu_flush_device(dev); + device_flush_dte(dev); } static void do_detach(struct device *dev) { struct iommu_dev_data *dev_data; struct amd_iommu *iommu; + struct pci_dev *pdev; u16 devid; devid = get_device_id(dev); iommu = amd_iommu_rlookup_table[devid]; dev_data = get_dev_data(dev); + pdev = to_pci_dev(dev); /* decrease reference counters */ dev_data->domain->dev_iommu[iommu->index] -= 1; @@ -1476,7 +1556,7 @@ static void do_detach(struct device *dev) clear_dte_entry(devid); /* Flush the DTE entry */ - iommu_flush_device(dev); + device_flush_dte(dev); } /* @@ -1539,9 +1619,13 @@ static int __attach_device(struct device *dev, static int attach_device(struct device *dev, struct protection_domain *domain) { + struct pci_dev *pdev = to_pci_dev(dev); unsigned long flags; int ret; + if (amd_iommu_iotlb_sup) + pci_enable_ats(pdev, PAGE_SHIFT); + write_lock_irqsave(&amd_iommu_devtable_lock, flags); ret = __attach_device(dev, domain); write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); @@ -1551,7 +1635,7 @@ static int attach_device(struct device *dev, * left the caches in the IOMMU dirty. So we have to flush * here to evict all dirty stuff. */ - iommu_flush_tlb_pde(domain); + domain_flush_tlb_pde(domain); return ret; } @@ -1598,12 +1682,16 @@ static void __detach_device(struct device *dev) */ static void detach_device(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); unsigned long flags; /* lock device table */ write_lock_irqsave(&amd_iommu_devtable_lock, flags); __detach_device(dev); write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); + + if (amd_iommu_iotlb_sup && pci_ats_enabled(pdev)) + pci_disable_ats(pdev); } /* @@ -1692,7 +1780,7 @@ static int device_change_notifier(struct notifier_block *nb, goto out; } - iommu_flush_device(dev); + device_flush_dte(dev); iommu_completion_wait(iommu); out: @@ -1753,8 +1841,9 @@ static void update_device_table(struct protection_domain *domain) struct iommu_dev_data *dev_data; list_for_each_entry(dev_data, &domain->dev_list, list) { + struct pci_dev *pdev = to_pci_dev(dev_data->dev); u16 devid = get_device_id(dev_data->dev); - set_dte_entry(devid, domain); + set_dte_entry(devid, domain, pci_ats_enabled(pdev)); } } @@ -1764,8 +1853,9 @@ static void update_domain(struct protection_domain *domain) return; update_device_table(domain); - iommu_flush_domain_devices(domain); - iommu_flush_tlb_pde(domain); + + domain_flush_devices(domain); + domain_flush_tlb_pde(domain); domain->updated = false; } @@ -1924,10 +2014,10 @@ static dma_addr_t __map_single(struct device *dev, ADD_STATS_COUNTER(alloced_io_mem, size); if (unlikely(dma_dom->need_flush && !amd_iommu_unmap_flush)) { - iommu_flush_tlb(&dma_dom->domain); + domain_flush_tlb(&dma_dom->domain); dma_dom->need_flush = false; } else if (unlikely(amd_iommu_np_cache)) - iommu_flush_pages(&dma_dom->domain, address, size); + domain_flush_pages(&dma_dom->domain, address, size); out: return address; @@ -1976,7 +2066,7 @@ static void __unmap_single(struct dma_ops_domain *dma_dom, dma_ops_free_addresses(dma_dom, dma_addr, pages); if (amd_iommu_unmap_flush || dma_dom->need_flush) { - iommu_flush_pages(&dma_dom->domain, flush_addr, size); + domain_flush_pages(&dma_dom->domain, flush_addr, size); dma_dom->need_flush = false; } } @@ -2012,7 +2102,7 @@ static dma_addr_t map_page(struct device *dev, struct page *page, if (addr == DMA_ERROR_CODE) goto out; - iommu_flush_complete(domain); + domain_flush_complete(domain); out: spin_unlock_irqrestore(&domain->lock, flags); @@ -2039,7 +2129,7 @@ static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, __unmap_single(domain->priv, dma_addr, size, dir); - iommu_flush_complete(domain); + domain_flush_complete(domain); spin_unlock_irqrestore(&domain->lock, flags); } @@ -2104,7 +2194,7 @@ static int map_sg(struct device *dev, struct scatterlist *sglist, goto unmap; } - iommu_flush_complete(domain); + domain_flush_complete(domain); out: spin_unlock_irqrestore(&domain->lock, flags); @@ -2150,7 +2240,7 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist, s->dma_address = s->dma_length = 0; } - iommu_flush_complete(domain); + domain_flush_complete(domain); spin_unlock_irqrestore(&domain->lock, flags); } @@ -2200,7 +2290,7 @@ static void *alloc_coherent(struct device *dev, size_t size, goto out_free; } - iommu_flush_complete(domain); + domain_flush_complete(domain); spin_unlock_irqrestore(&domain->lock, flags); @@ -2232,7 +2322,7 @@ static void free_coherent(struct device *dev, size_t size, __unmap_single(domain->priv, dma_addr, size, DMA_BIDIRECTIONAL); - iommu_flush_complete(domain); + domain_flush_complete(domain); spin_unlock_irqrestore(&domain->lock, flags); @@ -2476,7 +2566,7 @@ static void amd_iommu_detach_device(struct iommu_domain *dom, if (!iommu) return; - iommu_flush_device(dev); + device_flush_dte(dev); iommu_completion_wait(iommu); } @@ -2542,7 +2632,7 @@ static int amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova, unmap_size = iommu_unmap_page(domain, iova, page_size); mutex_unlock(&domain->api_lock); - iommu_flush_tlb_pde(domain); + domain_flush_tlb_pde(domain); return get_order(unmap_size); } diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 246d727b65b7..9179c21120a8 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -137,6 +137,7 @@ int amd_iommus_present; /* IOMMUs have a non-present cache? */ bool amd_iommu_np_cache __read_mostly; +bool amd_iommu_iotlb_sup __read_mostly = true; /* * The ACPI table parsing functions set this variable on an error @@ -180,6 +181,12 @@ static u32 dev_table_size; /* size of the device table */ static u32 alias_table_size; /* size of the alias table */ static u32 rlookup_table_size; /* size if the rlookup table */ +/* + * This function flushes all internal caches of + * the IOMMU used by this driver. + */ +extern void iommu_flush_all_caches(struct amd_iommu *iommu); + static inline void update_last_devid(u16 devid) { if (devid > amd_iommu_last_bdf) @@ -293,9 +300,23 @@ static void iommu_feature_disable(struct amd_iommu *iommu, u8 bit) /* Function to enable the hardware */ static void iommu_enable(struct amd_iommu *iommu) { - printk(KERN_INFO "AMD-Vi: Enabling IOMMU at %s cap 0x%hx\n", + static const char * const feat_str[] = { + "PreF", "PPR", "X2APIC", "NX", "GT", "[5]", + "IA", "GA", "HE", "PC", NULL + }; + int i; + + printk(KERN_INFO "AMD-Vi: Enabling IOMMU at %s cap 0x%hx", dev_name(&iommu->dev->dev), iommu->cap_ptr); + if (iommu->cap & (1 << IOMMU_CAP_EFR)) { + printk(KERN_CONT " extended features: "); + for (i = 0; feat_str[i]; ++i) + if (iommu_feature(iommu, (1ULL << i))) + printk(KERN_CONT " %s", feat_str[i]); + } + printk(KERN_CONT "\n"); + iommu_feature_enable(iommu, CONTROL_IOMMU_EN); } @@ -651,7 +672,7 @@ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m) static void __init init_iommu_from_pci(struct amd_iommu *iommu) { int cap_ptr = iommu->cap_ptr; - u32 range, misc; + u32 range, misc, low, high; int i, j; pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET, @@ -667,6 +688,15 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu) MMIO_GET_LD(range)); iommu->evt_msi_num = MMIO_MSI_NUM(misc); + if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB))) + amd_iommu_iotlb_sup = false; + + /* read extended feature bits */ + low = readl(iommu->mmio_base + MMIO_EXT_FEATURES); + high = readl(iommu->mmio_base + MMIO_EXT_FEATURES + 4); + + iommu->features = ((u64)high << 32) | low; + if (!is_rd890_iommu(iommu->dev)) return; @@ -1004,10 +1034,11 @@ static int iommu_setup_msi(struct amd_iommu *iommu) if (pci_enable_msi(iommu->dev)) return 1; - r = request_irq(iommu->dev->irq, amd_iommu_int_handler, - IRQF_SAMPLE_RANDOM, - "AMD-Vi", - NULL); + r = request_threaded_irq(iommu->dev->irq, + amd_iommu_int_handler, + amd_iommu_int_thread, + 0, "AMD-Vi", + iommu->dev); if (r) { pci_disable_msi(iommu->dev); @@ -1244,6 +1275,7 @@ static void enable_iommus(void) iommu_set_exclusion_range(iommu); iommu_init_msi(iommu); iommu_enable(iommu); + iommu_flush_all_caches(iommu); } } @@ -1274,8 +1306,8 @@ static void amd_iommu_resume(void) * we have to flush after the IOMMUs are enabled because a * disabled IOMMU will never execute the commands we send */ - amd_iommu_flush_all_devices(); - amd_iommu_flush_all_domains(); + for_each_iommu(iommu) + iommu_flush_all_caches(iommu); } static int amd_iommu_suspend(void) diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index cd1ffed4ee22..289e92862fd9 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c @@ -177,7 +177,6 @@ static struct clocksource clocksource_apbt = { .rating = APBT_CLOCKSOURCE_RATING, .read = apbt_read_clocksource, .mask = APBT_MASK, - .shift = APBT_SHIFT, .flags = CLOCK_SOURCE_IS_CONTINUOUS, .resume = apbt_restart_clocksource, }; @@ -543,14 +542,7 @@ static int apbt_clocksource_register(void) if (t1 == apbt_read_clocksource(&clocksource_apbt)) panic("APBT counter not counting. APBT disabled\n"); - /* - * initialize and register APBT clocksource - * convert that to ns/clock cycle - * mult = (ns/c) * 2^APBT_SHIFT - */ - clocksource_apbt.mult = div_sc(MSEC_PER_SEC, - (unsigned long) apbt_freq, APBT_SHIFT); - clocksource_register(&clocksource_apbt); + clocksource_register_khz(&clocksource_apbt, (u32)apbt_freq*1000); return 0; } diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 86d1ad4962a7..3d2661ca6542 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -30,6 +30,22 @@ #include #include +/* + * Using 512M as goal, in case kexec will load kernel_big + * that will do the on-position decompress, and could overlap with + * with the gart aperture that is used. + * Sequence: + * kernel_small + * ==> kexec (with kdump trigger path or gart still enabled) + * ==> kernel_small (gart area become e820_reserved) + * ==> kexec (with kdump trigger path or gart still enabled) + * ==> kerne_big (uncompressed size will be big than 64M or 128M) + * So don't use 512M below as gart iommu, leave the space for kernel + * code for safe. + */ +#define GART_MIN_ADDR (512ULL << 20) +#define GART_MAX_ADDR (1ULL << 32) + int gart_iommu_aperture; int gart_iommu_aperture_disabled __initdata; int gart_iommu_aperture_allowed __initdata; @@ -70,21 +86,9 @@ static u32 __init allocate_aperture(void) * memory. Unfortunately we cannot move it up because that would * make the IOMMU useless. */ - /* - * using 512M as goal, in case kexec will load kernel_big - * that will do the on position decompress, and could overlap with - * that position with gart that is used. - * sequende: - * kernel_small - * ==> kexec (with kdump trigger path or previous doesn't shutdown gart) - * ==> kernel_small(gart area become e820_reserved) - * ==> kexec (with kdump trigger path or previous doesn't shutdown gart) - * ==> kerne_big (uncompressed size will be big than 64M or 128M) - * so don't use 512M below as gart iommu, leave the space for kernel - * code for safe - */ - addr = memblock_find_in_range(0, 1ULL<<32, aper_size, 512ULL<<20); - if (addr == MEMBLOCK_ERROR || addr + aper_size > 0xffffffff) { + addr = memblock_find_in_range(GART_MIN_ADDR, GART_MAX_ADDR, + aper_size, aper_size); + if (addr == MEMBLOCK_ERROR || addr + aper_size > GART_MAX_ADDR) { printk(KERN_ERR "Cannot allocate aperture memory hole (%lx,%uK)\n", addr, aper_size>>10); @@ -499,7 +503,7 @@ int __init gart_iommu_hole_init(void) * Don't enable translation yet but enable GART IO and CPU * accesses and set DISTLBWALKPRB since GART table memory is UC. */ - u32 ctl = DISTLBWALKPRB | aper_order << 1; + u32 ctl = aper_order << 1; bus = amd_nb_bus_dev_ranges[i].bus; dev_base = amd_nb_bus_dev_ranges[i].dev_base; diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index fabf01eff771..f92a8e5d1e21 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -505,7 +505,7 @@ static void __cpuinit setup_APIC_timer(void) { struct clock_event_device *levt = &__get_cpu_var(lapic_events); - if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_ARAT)) { + if (this_cpu_has(X86_FEATURE_ARAT)) { lapic_clockevent.features &= ~CLOCK_EVT_FEAT_C3STOP; /* Make LAPIC timer preferrable over percpu HPET */ lapic_clockevent.rating = 150; @@ -1237,6 +1237,17 @@ void __cpuinit setup_local_APIC(void) /* always use the value from LDR */ early_per_cpu(x86_cpu_to_logical_apicid, cpu) = logical_smp_processor_id(); + + /* + * Some NUMA implementations (NUMAQ) don't initialize apicid to + * node mapping during NUMA init. Now that logical apicid is + * guaranteed to be known, give it another chance. This is already + * a bit too late - percpu allocation has already happened without + * proper NUMA affinity. + */ + if (apic->x86_32_numa_cpu_node) + set_apicid_to_node(early_per_cpu(x86_cpu_to_apicid, cpu), + apic->x86_32_numa_cpu_node(cpu)); #endif /* @@ -1812,30 +1823,41 @@ void smp_spurious_interrupt(struct pt_regs *regs) */ void smp_error_interrupt(struct pt_regs *regs) { - u32 v, v1; + u32 v0, v1; + u32 i = 0; + static const char * const error_interrupt_reason[] = { + "Send CS error", /* APIC Error Bit 0 */ + "Receive CS error", /* APIC Error Bit 1 */ + "Send accept error", /* APIC Error Bit 2 */ + "Receive accept error", /* APIC Error Bit 3 */ + "Redirectable IPI", /* APIC Error Bit 4 */ + "Send illegal vector", /* APIC Error Bit 5 */ + "Received illegal vector", /* APIC Error Bit 6 */ + "Illegal register address", /* APIC Error Bit 7 */ + }; exit_idle(); irq_enter(); /* First tickle the hardware, only then report what went on. -- REW */ - v = apic_read(APIC_ESR); + v0 = apic_read(APIC_ESR); apic_write(APIC_ESR, 0); v1 = apic_read(APIC_ESR); ack_APIC_irq(); atomic_inc(&irq_err_count); - /* - * Here is what the APIC error bits mean: - * 0: Send CS error - * 1: Receive CS error - * 2: Send accept error - * 3: Receive accept error - * 4: Reserved - * 5: Send illegal vector - * 6: Received illegal vector - * 7: Illegal register address - */ - pr_debug("APIC error on CPU%d: %02x(%02x)\n", - smp_processor_id(), v , v1); + apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x(%02x)", + smp_processor_id(), v0 , v1); + + v1 = v1 & 0xff; + while (v1) { + if (v1 & 0x1) + apic_printk(APIC_DEBUG, KERN_CONT " : %s", error_interrupt_reason[i]); + i++; + v1 >>= 1; + }; + + apic_printk(APIC_DEBUG, KERN_CONT "\n"); + irq_exit(); } @@ -2003,21 +2025,6 @@ void default_init_apic_ldr(void) apic_write(APIC_LDR, val); } -#ifdef CONFIG_X86_32 -int default_x86_32_numa_cpu_node(int cpu) -{ -#ifdef CONFIG_NUMA - int apicid = early_per_cpu(x86_cpu_to_apicid, cpu); - - if (apicid != BAD_APICID) - return __apicid_to_node[apicid]; - return NUMA_NO_NODE; -#else - return 0; -#endif -} -#endif - /* * Power management */ diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c index f1baa2dc087a..775b82bc655c 100644 --- a/arch/x86/kernel/apic/apic_noop.c +++ b/arch/x86/kernel/apic/apic_noop.c @@ -119,14 +119,6 @@ static void noop_apic_write(u32 reg, u32 v) WARN_ON_ONCE(cpu_has_apic && !disable_apic); } -#ifdef CONFIG_X86_32 -static int noop_x86_32_numa_cpu_node(int cpu) -{ - /* we're always on node 0 */ - return 0; -} -#endif - struct apic apic_noop = { .name = "noop", .probe = noop_probe, @@ -195,6 +187,5 @@ struct apic apic_noop = { #ifdef CONFIG_X86_32 .x86_32_early_logical_apicid = noop_x86_32_early_logical_apicid, - .x86_32_numa_cpu_node = noop_x86_32_numa_cpu_node, #endif }; diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c index 541a2e431659..d84ac5a584b5 100644 --- a/arch/x86/kernel/apic/bigsmp_32.c +++ b/arch/x86/kernel/apic/bigsmp_32.c @@ -253,5 +253,4 @@ struct apic apic_bigsmp = { .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, .x86_32_early_logical_apicid = bigsmp_early_logical_apicid, - .x86_32_numa_cpu_node = default_x86_32_numa_cpu_node, }; diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c index 3e9de4854c5b..70533de5bd29 100644 --- a/arch/x86/kernel/apic/es7000_32.c +++ b/arch/x86/kernel/apic/es7000_32.c @@ -510,11 +510,6 @@ static void es7000_setup_apic_routing(void) nr_ioapics, cpumask_bits(es7000_target_cpus())[0]); } -static int es7000_numa_cpu_node(int cpu) -{ - return 0; -} - static int es7000_cpu_present_to_apicid(int mps_cpu) { if (!mps_cpu) @@ -688,7 +683,6 @@ struct apic __refdata apic_es7000_cluster = { .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, .x86_32_early_logical_apicid = es7000_early_logical_apicid, - .x86_32_numa_cpu_node = es7000_numa_cpu_node, }; struct apic __refdata apic_es7000 = { @@ -752,5 +746,4 @@ struct apic __refdata apic_es7000 = { .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, .x86_32_early_logical_apicid = es7000_early_logical_apicid, - .x86_32_numa_cpu_node = es7000_numa_cpu_node, }; diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 68df09bba92e..45fd33d1fd3a 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -128,8 +128,8 @@ static int __init parse_noapic(char *str) } early_param("noapic", parse_noapic); -static int io_apic_setup_irq_pin_once(unsigned int irq, int node, - struct io_apic_irq_attr *attr); +static int io_apic_setup_irq_pin(unsigned int irq, int node, + struct io_apic_irq_attr *attr); /* Will be called in mpparse/acpi/sfi codes for saving IRQ info */ void mp_save_irq(struct mpc_intsrc *m) @@ -3570,7 +3570,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) } #endif /* CONFIG_HT_IRQ */ -int +static int io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr) { struct irq_cfg *cfg = alloc_irq_and_cfg_at(irq, node); @@ -3585,8 +3585,8 @@ io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr) return ret; } -static int io_apic_setup_irq_pin_once(unsigned int irq, int node, - struct io_apic_irq_attr *attr) +int io_apic_setup_irq_pin_once(unsigned int irq, int node, + struct io_apic_irq_attr *attr) { unsigned int id = attr->ioapic, pin = attr->ioapic_pin; int ret; diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c index 6273eee5134b..30f13319e24b 100644 --- a/arch/x86/kernel/apic/numaq_32.c +++ b/arch/x86/kernel/apic/numaq_32.c @@ -48,8 +48,6 @@ #include #include -#define MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT)) - int found_numaq; /* @@ -79,31 +77,20 @@ int quad_local_to_mp_bus_id[NR_CPUS/4][4]; static inline void numaq_register_node(int node, struct sys_cfg_data *scd) { struct eachquadmem *eq = scd->eq + node; + u64 start = (u64)(eq->hi_shrd_mem_start - eq->priv_mem_size) << 20; + u64 end = (u64)(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size) << 20; + int ret; - node_set_online(node); - - /* Convert to pages */ - node_start_pfn[node] = - MB_TO_PAGES(eq->hi_shrd_mem_start - eq->priv_mem_size); - - node_end_pfn[node] = - MB_TO_PAGES(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size); - - memblock_x86_register_active_regions(node, node_start_pfn[node], - node_end_pfn[node]); - - memory_present(node, node_start_pfn[node], node_end_pfn[node]); - - node_remap_size[node] = node_memmap_size_bytes(node, - node_start_pfn[node], - node_end_pfn[node]); + node_set(node, numa_nodes_parsed); + ret = numa_add_memblk(node, start, end); + BUG_ON(ret < 0); } /* * Function: smp_dump_qct() * * Description: gets memory layout from the quad config table. This - * function also updates node_online_map with the nodes (quads) present. + * function also updates numa_nodes_parsed with the nodes (quads) present. */ static void __init smp_dump_qct(void) { @@ -112,7 +99,6 @@ static void __init smp_dump_qct(void) scd = (void *)__va(SYS_CFG_DATA_PRIV_ADDR); - nodes_clear(node_online_map); for_each_node(node) { if (scd->quads_present31_0 & (1 << node)) numaq_register_node(node, scd); @@ -282,14 +268,14 @@ static __init void early_check_numaq(void) } } -int __init get_memcfg_numaq(void) +int __init numaq_numa_init(void) { early_check_numaq(); if (!found_numaq) - return 0; + return -ENOENT; smp_dump_qct(); - return 1; + return 0; } #define NUMAQ_APIC_DFR_VALUE (APIC_DFR_CLUSTER) diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c index fc84c7b61108..6541e471fd91 100644 --- a/arch/x86/kernel/apic/probe_32.c +++ b/arch/x86/kernel/apic/probe_32.c @@ -172,7 +172,6 @@ struct apic apic_default = { .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, .x86_32_early_logical_apicid = default_x86_32_early_logical_apicid, - .x86_32_numa_cpu_node = default_x86_32_numa_cpu_node, }; extern struct apic apic_numaq; diff --git a/arch/x86/kernel/apic/summit_32.c b/arch/x86/kernel/apic/summit_32.c index e4b8059b414a..35bcd7d995a1 100644 --- a/arch/x86/kernel/apic/summit_32.c +++ b/arch/x86/kernel/apic/summit_32.c @@ -551,5 +551,4 @@ struct apic apic_summit = { .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, .x86_32_early_logical_apicid = summit_early_logical_apicid, - .x86_32_numa_cpu_node = default_x86_32_numa_cpu_node, }; diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 33b10a0fc095..7acd2d2ac965 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -37,6 +37,13 @@ #include #include #include +#include + +/* BMC sets a bit this MMR non-zero before sending an NMI */ +#define UVH_NMI_MMR UVH_SCRATCH5 +#define UVH_NMI_MMR_CLEAR (UVH_NMI_MMR + 8) +#define UV_NMI_PENDING_MASK (1UL << 63) +DEFINE_PER_CPU(unsigned long, cpu_last_nmi_count); DEFINE_PER_CPU(int, x2apic_extra_bits); @@ -642,18 +649,46 @@ void __cpuinit uv_cpu_init(void) */ int uv_handle_nmi(struct notifier_block *self, unsigned long reason, void *data) { + unsigned long real_uv_nmi; + int bid; + if (reason != DIE_NMIUNKNOWN) return NOTIFY_OK; if (in_crash_kexec) /* do nothing if entering the crash kernel */ return NOTIFY_OK; + /* - * Use a lock so only one cpu prints at a time - * to prevent intermixed output. + * Each blade has an MMR that indicates when an NMI has been sent + * to cpus on the blade. If an NMI is detected, atomically + * clear the MMR and update a per-blade NMI count used to + * cause each cpu on the blade to notice a new NMI. + */ + bid = uv_numa_blade_id(); + real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK); + + if (unlikely(real_uv_nmi)) { + spin_lock(&uv_blade_info[bid].nmi_lock); + real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK); + if (real_uv_nmi) { + uv_blade_info[bid].nmi_count++; + uv_write_local_mmr(UVH_NMI_MMR_CLEAR, UV_NMI_PENDING_MASK); + } + spin_unlock(&uv_blade_info[bid].nmi_lock); + } + + if (likely(__get_cpu_var(cpu_last_nmi_count) == uv_blade_info[bid].nmi_count)) + return NOTIFY_DONE; + + __get_cpu_var(cpu_last_nmi_count) = uv_blade_info[bid].nmi_count; + + /* + * Use a lock so only one cpu prints at a time. + * This prevents intermixed output. */ spin_lock(&uv_nmi_lock); - pr_info("NMI stack dump cpu %u:\n", smp_processor_id()); + pr_info("UV NMI stack dump cpu %u:\n", smp_processor_id()); dump_stack(); spin_unlock(&uv_nmi_lock); @@ -661,7 +696,8 @@ int uv_handle_nmi(struct notifier_block *self, unsigned long reason, void *data) } static struct notifier_block uv_dump_stack_nmi_nb = { - .notifier_call = uv_handle_nmi + .notifier_call = uv_handle_nmi, + .priority = NMI_LOCAL_LOW_PRIOR - 1, }; void uv_register_nmi_notifier(void) @@ -720,8 +756,9 @@ void __init uv_system_init(void) printk(KERN_DEBUG "UV: Found %d blades\n", uv_num_possible_blades()); bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades(); - uv_blade_info = kmalloc(bytes, GFP_KERNEL); + uv_blade_info = kzalloc(bytes, GFP_KERNEL); BUG_ON(!uv_blade_info); + for (blade = 0; blade < uv_num_possible_blades(); blade++) uv_blade_info[blade].memory_nid = -1; @@ -747,6 +784,7 @@ void __init uv_system_init(void) uv_blade_info[blade].pnode = pnode; uv_blade_info[blade].nr_possible_cpus = 0; uv_blade_info[blade].nr_online_cpus = 0; + spin_lock_init(&uv_blade_info[blade].nmi_lock); max_pnode = max(pnode, max_pnode); blade++; } diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 0b4be431c620..3bfa02235965 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -228,6 +228,7 @@ #include #include #include +#include #include #include @@ -1237,7 +1238,7 @@ static int suspend(int vetoable) dpm_suspend_noirq(PMSG_SUSPEND); local_irq_disable(); - sysdev_suspend(PMSG_SUSPEND); + syscore_suspend(); local_irq_enable(); @@ -1255,7 +1256,7 @@ static int suspend(int vetoable) apm_error("suspend", err); err = (err == APM_SUCCESS) ? 0 : -EIO; - sysdev_resume(); + syscore_resume(); local_irq_enable(); dpm_resume_noirq(PMSG_RESUME); @@ -1279,7 +1280,7 @@ static void standby(void) dpm_suspend_noirq(PMSG_SUSPEND); local_irq_disable(); - sysdev_suspend(PMSG_SUSPEND); + syscore_suspend(); local_irq_enable(); err = set_system_power_state(APM_STATE_STANDBY); @@ -1287,7 +1288,7 @@ static void standby(void) apm_error("standby", err); local_irq_disable(); - sysdev_resume(); + syscore_resume(); local_irq_enable(); dpm_resume_noirq(PMSG_RESUME); diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 3f0ebe429a01..6042981d0309 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -30,7 +30,6 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o obj-$(CONFIG_X86_MCE) += mcheck/ obj-$(CONFIG_MTRR) += mtrr/ -obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 3532d3bf8105..6f9d1f6063e9 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -613,7 +613,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) #endif /* As a rule processors have APIC timer running in deep C states */ - if (c->x86 >= 0xf && !cpu_has_amd_erratum(amd_erratum_400)) + if (c->x86 > 0xf && !cpu_has_amd_erratum(amd_erratum_400)) set_cpu_cap(c, X86_FEATURE_ARAT); /* diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index e2ced0074a45..cbc70a27430c 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -254,6 +254,25 @@ static inline void squash_the_stupid_serial_number(struct cpuinfo_x86 *c) } #endif +static int disable_smep __initdata; +static __init int setup_disable_smep(char *arg) +{ + disable_smep = 1; + return 1; +} +__setup("nosmep", setup_disable_smep); + +static __init void setup_smep(struct cpuinfo_x86 *c) +{ + if (cpu_has(c, X86_FEATURE_SMEP)) { + if (unlikely(disable_smep)) { + setup_clear_cpu_cap(X86_FEATURE_SMEP); + clear_in_cr4(X86_CR4_SMEP); + } else + set_in_cr4(X86_CR4_SMEP); + } +} + /* * Some CPU features depend on higher CPUID levels, which may not always * be available due to CPUID level capping or broken virtualization @@ -565,8 +584,7 @@ void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c) cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx); - if (eax > 0) - c->x86_capability[9] = ebx; + c->x86_capability[9] = ebx; } /* AMD-defined flags: level 0x80000001 */ @@ -668,6 +686,8 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) c->cpu_index = 0; #endif filter_cpuid_features(c, false); + + setup_smep(c); } void __init early_cpu_init(void) @@ -753,6 +773,8 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 *c) #endif } + setup_smep(c); + get_model_name(c); /* Default name */ detect_nopl(c); diff --git a/arch/x86/kernel/cpu/cpufreq/Makefile b/arch/x86/kernel/cpu/cpufreq/Makefile deleted file mode 100644 index bd54bf67e6fb..000000000000 --- a/arch/x86/kernel/cpu/cpufreq/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Link order matters. K8 is preferred to ACPI because of firmware bugs in early -# K8 systems. ACPI is preferred to all other hardware-specific drivers. -# speedstep-* is preferred over p4-clockmod. - -obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o mperf.o -obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o mperf.o -obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o -obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o -obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o -obj-$(CONFIG_X86_LONGHAUL) += longhaul.o -obj-$(CONFIG_X86_E_POWERSAVER) += e_powersaver.o -obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o -obj-$(CONFIG_SC520_CPUFREQ) += sc520_freq.o -obj-$(CONFIG_X86_LONGRUN) += longrun.o -obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o -obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o -obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o -obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o -obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o -obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o -obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index df86bc8c859d..1edf5ba4fb2b 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -29,10 +29,10 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) { + u64 misc_enable; + /* Unmask CPUID levels if masked: */ if (c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xd)) { - u64 misc_enable; - rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable); if (misc_enable & MSR_IA32_MISC_ENABLE_LIMIT_CPUID) { @@ -118,8 +118,6 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) * (model 2) with the same problem. */ if (c->x86 == 15) { - u64 misc_enable; - rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable); if (misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING) { @@ -130,6 +128,19 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) } } #endif + + /* + * If fast string is not enabled in IA32_MISC_ENABLE for any reason, + * clear the fast string and enhanced fast string CPU capabilities. + */ + if (c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xd)) { + rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable); + if (!(misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING)) { + printk(KERN_INFO "Disabled fast string operations\n"); + setup_clear_cpu_cap(X86_FEATURE_REP_GOOD); + setup_clear_cpu_cap(X86_FEATURE_ERMS); + } + } } #ifdef CONFIG_X86_32 @@ -400,12 +411,10 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) switch (c->x86_model) { case 5: - if (c->x86_mask == 0) { - if (l2 == 0) - p = "Celeron (Covington)"; - else if (l2 == 256) - p = "Mobile Pentium II (Dixon)"; - } + if (l2 == 0) + p = "Celeron (Covington)"; + else if (l2 == 256) + p = "Mobile Pentium II (Dixon)"; break; case 6: diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 1ce1af2899df..c105c533ed94 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -327,7 +327,6 @@ static void __cpuinit amd_calc_l3_indices(struct amd_l3_cache *l3) l3->subcaches[2] = sc2 = !(val & BIT(8)) + !(val & BIT(9)); l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13)); - l3->indices = (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1; l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1; } @@ -454,27 +453,16 @@ int amd_set_l3_disable_slot(struct amd_l3_cache *l3, int cpu, unsigned slot, { int ret = 0; -#define SUBCACHE_MASK (3UL << 20) -#define SUBCACHE_INDEX 0xfff - - /* - * check whether this slot is already used or - * the index is already disabled - */ + /* check if @slot is already used or the index is already disabled */ ret = amd_get_l3_disable_slot(l3, slot); if (ret >= 0) return -EINVAL; - /* - * check whether the other slot has disabled the - * same index already - */ - if (index == amd_get_l3_disable_slot(l3, !slot)) + if (index > l3->indices) return -EINVAL; - /* do not allow writes outside of allowed bits */ - if ((index & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) || - ((index & SUBCACHE_INDEX) > l3->indices)) + /* check whether the other slot has disabled the same index already */ + if (index == amd_get_l3_disable_slot(l3, !slot)) return -EINVAL; amd_l3_disable_index(l3, cpu, slot, index); diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 3385ea26f684..ff1ae9b6464d 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -105,20 +105,6 @@ static int cpu_missing; ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain); EXPORT_SYMBOL_GPL(x86_mce_decoder_chain); -static int default_decode_mce(struct notifier_block *nb, unsigned long val, - void *data) -{ - pr_emerg(HW_ERR "No human readable MCE decoding support on this CPU type.\n"); - pr_emerg(HW_ERR "Run the message through 'mcelog --ascii' to decode.\n"); - - return NOTIFY_STOP; -} - -static struct notifier_block mce_dec_nb = { - .notifier_call = default_decode_mce, - .priority = -1, -}; - /* MCA banks polled by the period polling timer for corrected events */ DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL @@ -212,6 +198,8 @@ void mce_log(struct mce *mce) static void print_mce(struct mce *m) { + int ret = 0; + pr_emerg(HW_ERR "CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n", m->extcpu, m->mcgstatus, m->bank, m->status); @@ -239,7 +227,11 @@ static void print_mce(struct mce *m) * Print out human-readable details about the MCE error, * (if the CPU has an implementation for that) */ - atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m); + ret = atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m); + if (ret == NOTIFY_STOP) + return; + + pr_emerg_ratelimited(HW_ERR "Run the above through 'mcelog --ascii'\n"); } #define PANIC_TIMEOUT 5 /* 5 seconds */ @@ -590,7 +582,6 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) if (!(flags & MCP_DONTLOG) && !mce_dont_log_ce) { mce_log(&m); atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, &m); - add_taint(TAINT_MACHINE_CHECK); } /* @@ -1722,8 +1713,6 @@ __setup("mce", mcheck_enable); int __init mcheck_init(void) { - atomic_notifier_chain_register(&x86_mce_decoder_chain, &mce_dec_nb); - mcheck_intel_therm_init(); return 0; diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 167f97b5596e..bb0adad35143 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -509,6 +509,7 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu, out_free: if (b) { kobject_put(&b->kobj); + list_del(&b->miscj); kfree(b); } return err; diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index 6f8c5e9da97f..27c625178bf1 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -187,8 +187,6 @@ static int therm_throt_process(bool new_event, int event, int level) this_cpu, level == CORE_LEVEL ? "Core" : "Package", state->count); - - add_taint(TAINT_MACHINE_CHECK); return 1; } if (old_event) { @@ -355,7 +353,6 @@ static void notify_thresholds(__u64 msr_val) static void intel_thermal_interrupt(void) { __u64 msr_val; - struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); rdmsrl(MSR_IA32_THERM_STATUS, msr_val); @@ -367,19 +364,19 @@ static void intel_thermal_interrupt(void) CORE_LEVEL) != 0) mce_log_therm_throt_event(CORE_THROTTLED | msr_val); - if (cpu_has(c, X86_FEATURE_PLN)) + if (this_cpu_has(X86_FEATURE_PLN)) if (therm_throt_process(msr_val & THERM_STATUS_POWER_LIMIT, POWER_LIMIT_EVENT, CORE_LEVEL) != 0) mce_log_therm_throt_event(CORE_POWER_LIMIT | msr_val); - if (cpu_has(c, X86_FEATURE_PTS)) { + if (this_cpu_has(X86_FEATURE_PTS)) { rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val); if (therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT, THERMAL_THROTTLING_EVENT, PACKAGE_LEVEL) != 0) mce_log_therm_throt_event(PACKAGE_THROTTLED | msr_val); - if (cpu_has(c, X86_FEATURE_PLN)) + if (this_cpu_has(X86_FEATURE_PLN)) if (therm_throt_process(msr_val & PACKAGE_THERM_STATUS_POWER_LIMIT, POWER_LIMIT_EVENT, @@ -393,7 +390,6 @@ static void unexpected_thermal_interrupt(void) { printk(KERN_ERR "CPU%d: Unexpected LVT thermal interrupt!\n", smp_processor_id()); - add_taint(TAINT_MACHINE_CHECK); } static void (*smp_thermal_vector)(void) = unexpected_thermal_interrupt; @@ -446,18 +442,20 @@ void intel_init_thermal(struct cpuinfo_x86 *c) */ rdmsr(MSR_IA32_MISC_ENABLE, l, h); + h = lvtthmr_init; /* * The initial value of thermal LVT entries on all APs always reads * 0x10000 because APs are woken up by BSP issuing INIT-SIPI-SIPI * sequence to them and LVT registers are reset to 0s except for * the mask bits which are set to 1s when APs receive INIT IPI. - * Always restore the value that BIOS has programmed on AP based on - * BSP's info we saved since BIOS is always setting the same value - * for all threads/cores + * If BIOS takes over the thermal interrupt and sets its interrupt + * delivery mode to SMI (not fixed), it restores the value that the + * BIOS has programmed on AP based on BSP's info we saved since BIOS + * is always setting the same value for all threads/cores. */ - apic_write(APIC_LVTTHMR, lvtthmr_init); + if ((h & APIC_DM_FIXED_MASK) != APIC_DM_FIXED) + apic_write(APIC_LVTTHMR, lvtthmr_init); - h = lvtthmr_init; if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) { printk(KERN_DEBUG diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index eed3673a8656..3a0338b4b179 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -31,6 +31,7 @@ #include #include #include +#include #if 0 #undef wrmsrl @@ -363,12 +364,18 @@ x86_perf_event_update(struct perf_event *event) return new_raw_count; } -/* using X86_FEATURE_PERFCTR_CORE to later implement ALTERNATIVE() here */ static inline int x86_pmu_addr_offset(int index) { - if (boot_cpu_has(X86_FEATURE_PERFCTR_CORE)) - return index << 1; - return index; + int offset; + + /* offset = X86_FEATURE_PERFCTR_CORE ? index << 1 : index */ + alternative_io(ASM_NOP2, + "shll $1, %%eax", + X86_FEATURE_PERFCTR_CORE, + "=a" (offset), + "a" (index)); + + return offset; } static inline unsigned int x86_pmu_config_addr(int index) @@ -586,8 +593,12 @@ static int x86_setup_perfctr(struct perf_event *event) return -EOPNOTSUPP; } + /* + * Do not allow config1 (extended registers) to propagate, + * there's no sane user-space generalization yet: + */ if (attr->type == PERF_TYPE_RAW) - return x86_pmu_extra_regs(event->attr.config, event); + return 0; if (attr->type == PERF_TYPE_HW_CACHE) return set_ext_hw_attr(hwc, event); @@ -609,8 +620,8 @@ static int x86_setup_perfctr(struct perf_event *event) /* * Branch tracing: */ - if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) && - (hwc->sample_period == 1)) { + if (attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS && + !attr->freq && hwc->sample_period == 1) { /* BTS is not supported by this architecture. */ if (!x86_pmu.bts_active) return -EOPNOTSUPP; @@ -1284,6 +1295,16 @@ static int x86_pmu_handle_irq(struct pt_regs *regs) cpuc = &__get_cpu_var(cpu_hw_events); + /* + * Some chipsets need to unmask the LVTPC in a particular spot + * inside the nmi handler. As a result, the unmasking was pushed + * into all the nmi handlers. + * + * This generic handler doesn't seem to have any issues where the + * unmasking occurs so it was left at the top. + */ + apic_write(APIC_LVTPC, APIC_DM_NMI); + for (idx = 0; idx < x86_pmu.num_counters; idx++) { if (!test_bit(idx, cpuc->active_mask)) { /* @@ -1370,8 +1391,6 @@ perf_event_nmi_handler(struct notifier_block *self, return NOTIFY_DONE; } - apic_write(APIC_LVTPC, APIC_DM_NMI); - handled = x86_pmu.handle_irq(args->regs); if (!handled) return NOTIFY_DONE; @@ -1754,17 +1773,6 @@ static struct pmu pmu = { * callchain support */ -static void -backtrace_warning_symbol(void *data, char *msg, unsigned long symbol) -{ - /* Ignore warnings */ -} - -static void backtrace_warning(void *data, char *msg) -{ - /* Ignore warnings */ -} - static int backtrace_stack(void *data, char *name) { return 0; @@ -1778,8 +1786,6 @@ static void backtrace_address(void *data, unsigned long addr, int reliable) } static const struct stacktrace_ops backtrace_ops = { - .warning = backtrace_warning, - .warning_symbol = backtrace_warning_symbol, .stack = backtrace_stack, .address = backtrace_address, .walk_stack = print_context_stack_bp, diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index 461f62bbd774..fe29c1d2219e 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c @@ -8,7 +8,7 @@ static __initconst const u64 amd_hw_cache_event_ids [ C(L1D) ] = { [ C(OP_READ) ] = { [ C(RESULT_ACCESS) ] = 0x0040, /* Data Cache Accesses */ - [ C(RESULT_MISS) ] = 0x0041, /* Data Cache Misses */ + [ C(RESULT_MISS) ] = 0x0141, /* Data Cache Misses */ }, [ C(OP_WRITE) ] = { [ C(RESULT_ACCESS) ] = 0x0142, /* Data Cache Refills :system */ @@ -96,12 +96,14 @@ static __initconst const u64 amd_hw_cache_event_ids */ static const u64 amd_perfmon_event_map[] = { - [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, - [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, - [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0080, - [PERF_COUNT_HW_CACHE_MISSES] = 0x0081, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2, - [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3, + [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, + [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, + [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0080, + [PERF_COUNT_HW_CACHE_MISSES] = 0x0081, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2, + [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3, + [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00d0, /* "Decoder empty" event */ + [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x00d1, /* "Dispatch stalls" event */ }; static u64 amd_pmu_event_map(int hw_event) @@ -427,7 +429,9 @@ static __initconst const struct x86_pmu amd_pmu = { * * Exceptions: * + * 0x000 FP PERF_CTL[3], PERF_CTL[5:3] (*) * 0x003 FP PERF_CTL[3] + * 0x004 FP PERF_CTL[3], PERF_CTL[5:3] (*) * 0x00B FP PERF_CTL[3] * 0x00D FP PERF_CTL[3] * 0x023 DE PERF_CTL[2:0] @@ -448,6 +452,8 @@ static __initconst const struct x86_pmu amd_pmu = { * 0x0DF LS PERF_CTL[5:0] * 0x1D6 EX PERF_CTL[5:0] * 0x1D8 EX PERF_CTL[5:0] + * + * (*) depending on the umask all FPU counters may be used */ static struct event_constraint amd_f15_PMC0 = EVENT_CONSTRAINT(0, 0x01, 0); @@ -460,18 +466,28 @@ static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0); static struct event_constraint * amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *event) { - unsigned int event_code = amd_get_event_code(&event->hw); + struct hw_perf_event *hwc = &event->hw; + unsigned int event_code = amd_get_event_code(hwc); switch (event_code & AMD_EVENT_TYPE_MASK) { case AMD_EVENT_FP: switch (event_code) { + case 0x000: + if (!(hwc->config & 0x0000F000ULL)) + break; + if (!(hwc->config & 0x00000F00ULL)) + break; + return &amd_f15_PMC3; + case 0x004: + if (hweight_long(hwc->config & ARCH_PERFMON_EVENTSEL_UMASK) <= 1) + break; + return &amd_f15_PMC3; case 0x003: case 0x00B: case 0x00D: return &amd_f15_PMC3; - default: - return &amd_f15_PMC53; } + return &amd_f15_PMC53; case AMD_EVENT_LS: case AMD_EVENT_DC: case AMD_EVENT_EX_LS: diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 8fc2b2cee1da..41178c826c48 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -25,7 +25,7 @@ struct intel_percore { /* * Intel PerfMon, used on Core and later. */ -static const u64 intel_perfmon_event_map[] = +static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly = { [PERF_COUNT_HW_CPU_CYCLES] = 0x003c, [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, @@ -36,7 +36,7 @@ static const u64 intel_perfmon_event_map[] = [PERF_COUNT_HW_BUS_CYCLES] = 0x013c, }; -static struct event_constraint intel_core_event_constraints[] = +static struct event_constraint intel_core_event_constraints[] __read_mostly = { INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */ INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */ @@ -47,7 +47,7 @@ static struct event_constraint intel_core_event_constraints[] = EVENT_CONSTRAINT_END }; -static struct event_constraint intel_core2_event_constraints[] = +static struct event_constraint intel_core2_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ @@ -70,7 +70,7 @@ static struct event_constraint intel_core2_event_constraints[] = EVENT_CONSTRAINT_END }; -static struct event_constraint intel_nehalem_event_constraints[] = +static struct event_constraint intel_nehalem_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ @@ -86,19 +86,19 @@ static struct event_constraint intel_nehalem_event_constraints[] = EVENT_CONSTRAINT_END }; -static struct extra_reg intel_nehalem_extra_regs[] = +static struct extra_reg intel_nehalem_extra_regs[] __read_mostly = { INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff), EVENT_EXTRA_END }; -static struct event_constraint intel_nehalem_percore_constraints[] = +static struct event_constraint intel_nehalem_percore_constraints[] __read_mostly = { INTEL_EVENT_CONSTRAINT(0xb7, 0), EVENT_CONSTRAINT_END }; -static struct event_constraint intel_westmere_event_constraints[] = +static struct event_constraint intel_westmere_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ @@ -110,7 +110,7 @@ static struct event_constraint intel_westmere_event_constraints[] = EVENT_CONSTRAINT_END }; -static struct event_constraint intel_snb_event_constraints[] = +static struct event_constraint intel_snb_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ @@ -123,21 +123,21 @@ static struct event_constraint intel_snb_event_constraints[] = EVENT_CONSTRAINT_END }; -static struct extra_reg intel_westmere_extra_regs[] = +static struct extra_reg intel_westmere_extra_regs[] __read_mostly = { INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff), INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0xffff), EVENT_EXTRA_END }; -static struct event_constraint intel_westmere_percore_constraints[] = +static struct event_constraint intel_westmere_percore_constraints[] __read_mostly = { INTEL_EVENT_CONSTRAINT(0xb7, 0), INTEL_EVENT_CONSTRAINT(0xbb, 0), EVENT_CONSTRAINT_END }; -static struct event_constraint intel_gen_event_constraints[] = +static struct event_constraint intel_gen_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ @@ -184,26 +184,23 @@ static __initconst const u64 snb_hw_cache_event_ids }, }, [ C(LL ) ] = { - /* - * TBD: Need Off-core Response Performance Monitoring support - */ [ C(OP_READ) ] = { - /* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */ + /* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */ [ C(RESULT_ACCESS) ] = 0x01b7, - /* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */ - [ C(RESULT_MISS) ] = 0x01bb, + /* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01b7, }, [ C(OP_WRITE) ] = { - /* OFFCORE_RESPONSE_0.ANY_RFO.LOCAL_CACHE */ + /* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */ [ C(RESULT_ACCESS) ] = 0x01b7, - /* OFFCORE_RESPONSE_1.ANY_RFO.ANY_LLC_MISS */ - [ C(RESULT_MISS) ] = 0x01bb, + /* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01b7, }, [ C(OP_PREFETCH) ] = { - /* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */ + /* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */ [ C(RESULT_ACCESS) ] = 0x01b7, - /* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */ - [ C(RESULT_MISS) ] = 0x01bb, + /* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01b7, }, }, [ C(DTLB) ] = { @@ -285,26 +282,26 @@ static __initconst const u64 westmere_hw_cache_event_ids }, [ C(LL ) ] = { [ C(OP_READ) ] = { - /* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */ + /* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */ [ C(RESULT_ACCESS) ] = 0x01b7, - /* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */ - [ C(RESULT_MISS) ] = 0x01bb, + /* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01b7, }, /* * Use RFO, not WRITEBACK, because a write miss would typically occur * on RFO. */ [ C(OP_WRITE) ] = { - /* OFFCORE_RESPONSE_1.ANY_RFO.LOCAL_CACHE */ - [ C(RESULT_ACCESS) ] = 0x01bb, - /* OFFCORE_RESPONSE_0.ANY_RFO.ANY_LLC_MISS */ + /* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */ + [ C(RESULT_ACCESS) ] = 0x01b7, + /* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */ [ C(RESULT_MISS) ] = 0x01b7, }, [ C(OP_PREFETCH) ] = { - /* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */ + /* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */ [ C(RESULT_ACCESS) ] = 0x01b7, - /* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */ - [ C(RESULT_MISS) ] = 0x01bb, + /* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01b7, }, }, [ C(DTLB) ] = { @@ -352,16 +349,36 @@ static __initconst const u64 westmere_hw_cache_event_ids }; /* - * OFFCORE_RESPONSE MSR bits (subset), See IA32 SDM Vol 3 30.6.1.3 + * Nehalem/Westmere MSR_OFFCORE_RESPONSE bits; + * See IA32 SDM Vol 3B 30.6.1.3 */ -#define DMND_DATA_RD (1 << 0) -#define DMND_RFO (1 << 1) -#define DMND_WB (1 << 3) -#define PF_DATA_RD (1 << 4) -#define PF_DATA_RFO (1 << 5) -#define RESP_UNCORE_HIT (1 << 8) -#define RESP_MISS (0xf600) /* non uncore hit */ +#define NHM_DMND_DATA_RD (1 << 0) +#define NHM_DMND_RFO (1 << 1) +#define NHM_DMND_IFETCH (1 << 2) +#define NHM_DMND_WB (1 << 3) +#define NHM_PF_DATA_RD (1 << 4) +#define NHM_PF_DATA_RFO (1 << 5) +#define NHM_PF_IFETCH (1 << 6) +#define NHM_OFFCORE_OTHER (1 << 7) +#define NHM_UNCORE_HIT (1 << 8) +#define NHM_OTHER_CORE_HIT_SNP (1 << 9) +#define NHM_OTHER_CORE_HITM (1 << 10) + /* reserved */ +#define NHM_REMOTE_CACHE_FWD (1 << 12) +#define NHM_REMOTE_DRAM (1 << 13) +#define NHM_LOCAL_DRAM (1 << 14) +#define NHM_NON_DRAM (1 << 15) + +#define NHM_ALL_DRAM (NHM_REMOTE_DRAM|NHM_LOCAL_DRAM) + +#define NHM_DMND_READ (NHM_DMND_DATA_RD) +#define NHM_DMND_WRITE (NHM_DMND_RFO|NHM_DMND_WB) +#define NHM_DMND_PREFETCH (NHM_PF_DATA_RD|NHM_PF_DATA_RFO) + +#define NHM_L3_HIT (NHM_UNCORE_HIT|NHM_OTHER_CORE_HIT_SNP|NHM_OTHER_CORE_HITM) +#define NHM_L3_MISS (NHM_NON_DRAM|NHM_ALL_DRAM|NHM_REMOTE_CACHE_FWD) +#define NHM_L3_ACCESS (NHM_L3_HIT|NHM_L3_MISS) static __initconst const u64 nehalem_hw_cache_extra_regs [PERF_COUNT_HW_CACHE_MAX] @@ -370,16 +387,16 @@ static __initconst const u64 nehalem_hw_cache_extra_regs { [ C(LL ) ] = { [ C(OP_READ) ] = { - [ C(RESULT_ACCESS) ] = DMND_DATA_RD|RESP_UNCORE_HIT, - [ C(RESULT_MISS) ] = DMND_DATA_RD|RESP_MISS, + [ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_L3_ACCESS, + [ C(RESULT_MISS) ] = NHM_DMND_READ|NHM_L3_MISS, }, [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = DMND_RFO|DMND_WB|RESP_UNCORE_HIT, - [ C(RESULT_MISS) ] = DMND_RFO|DMND_WB|RESP_MISS, + [ C(RESULT_ACCESS) ] = NHM_DMND_WRITE|NHM_L3_ACCESS, + [ C(RESULT_MISS) ] = NHM_DMND_WRITE|NHM_L3_MISS, }, [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = PF_DATA_RD|PF_DATA_RFO|RESP_UNCORE_HIT, - [ C(RESULT_MISS) ] = PF_DATA_RD|PF_DATA_RFO|RESP_MISS, + [ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_L3_ACCESS, + [ C(RESULT_MISS) ] = NHM_DMND_PREFETCH|NHM_L3_MISS, }, } }; @@ -391,12 +408,12 @@ static __initconst const u64 nehalem_hw_cache_event_ids { [ C(L1D) ] = { [ C(OP_READ) ] = { - [ C(RESULT_ACCESS) ] = 0x0f40, /* L1D_CACHE_LD.MESI */ - [ C(RESULT_MISS) ] = 0x0140, /* L1D_CACHE_LD.I_STATE */ + [ C(RESULT_ACCESS) ] = 0x010b, /* MEM_INST_RETIRED.LOADS */ + [ C(RESULT_MISS) ] = 0x0151, /* L1D.REPL */ }, [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = 0x0f41, /* L1D_CACHE_ST.MESI */ - [ C(RESULT_MISS) ] = 0x0141, /* L1D_CACHE_ST.I_STATE */ + [ C(RESULT_ACCESS) ] = 0x020b, /* MEM_INST_RETURED.STORES */ + [ C(RESULT_MISS) ] = 0x0251, /* L1D.M_REPL */ }, [ C(OP_PREFETCH) ] = { [ C(RESULT_ACCESS) ] = 0x014e, /* L1D_PREFETCH.REQUESTS */ @@ -933,6 +950,16 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) cpuc = &__get_cpu_var(cpu_hw_events); + /* + * Some chipsets need to unmask the LVTPC in a particular spot + * inside the nmi handler. As a result, the unmasking was pushed + * into all the nmi handlers. + * + * This handler doesn't seem to have any issues with the unmasking + * so it was left at the top. + */ + apic_write(APIC_LVTPC, APIC_DM_NMI); + intel_pmu_disable_all(); handled = intel_pmu_drain_bts_buffer(); status = intel_pmu_get_status(); @@ -998,6 +1025,9 @@ intel_bts_constraints(struct perf_event *event) struct hw_perf_event *hwc = &event->hw; unsigned int hw_event, bts_event; + if (event->attr.freq) + return NULL; + hw_event = hwc->config & INTEL_ARCH_EVENT_MASK; bts_event = x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS); @@ -1305,7 +1335,7 @@ static void intel_clovertown_quirks(void) * AJ106 could possibly be worked around by not allowing LBR * usage from PEBS, including the fixup. * AJ68 could possibly be worked around by always programming - * a pebs_event_reset[0] value and coping with the lost events. + * a pebs_event_reset[0] value and coping with the lost events. * * But taken together it might just make sense to not enable PEBS on * these chips. @@ -1409,6 +1439,23 @@ static __init int intel_pmu_init(void) x86_pmu.percore_constraints = intel_nehalem_percore_constraints; x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.extra_regs = intel_nehalem_extra_regs; + + /* UOPS_ISSUED.STALLED_CYCLES */ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e; + /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1; + + if (ebx & 0x40) { + /* + * Erratum AAJ80 detected, we work it around by using + * the BR_MISP_EXEC.ANY event. This will over-count + * branch-misses, but it's still much better than the + * architectural event which is often completely bogus: + */ + intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89; + + pr_cont("erratum AAJ80 worked around, "); + } pr_cont("Nehalem events, "); break; @@ -1425,6 +1472,7 @@ static __init int intel_pmu_init(void) case 37: /* 32 nm nehalem, "Clarkdale" */ case 44: /* 32 nm nehalem, "Gulftown" */ + case 47: /* 32 nm Xeon E7 */ memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, @@ -1437,6 +1485,12 @@ static __init int intel_pmu_init(void) x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.pebs_constraints = intel_westmere_pebs_event_constraints; x86_pmu.extra_regs = intel_westmere_extra_regs; + + /* UOPS_ISSUED.STALLED_CYCLES */ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e; + /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1; + pr_cont("Westmere events, "); break; @@ -1448,6 +1502,12 @@ static __init int intel_pmu_init(void) x86_pmu.event_constraints = intel_snb_event_constraints; x86_pmu.pebs_constraints = intel_snb_pebs_events; + + /* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e; + /* UOPS_DISPATCHED.THREAD,c=1,i=1 to count stall cycles*/ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x18001b1; + pr_cont("SandyBridge events, "); break; diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index c2520e178d32..ead584fb6a7d 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c @@ -468,7 +468,7 @@ static struct p4_event_bind p4_event_bind_map[] = { .opcode = P4_OPCODE(P4_EVENT_MISPRED_BRANCH_RETIRED), .escr_msr = { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 }, .escr_emask = - P4_ESCR_EMASK_BIT(P4_EVENT_MISPRED_BRANCH_RETIRED, NBOGUS), + P4_ESCR_EMASK_BIT(P4_EVENT_MISPRED_BRANCH_RETIRED, NBOGUS), .cntr = { {12, 13, 16}, {14, 15, 17} }, }, [P4_EVENT_X87_ASSIST] = { @@ -912,8 +912,7 @@ static int p4_pmu_handle_irq(struct pt_regs *regs) int idx, handled = 0; u64 val; - data.addr = 0; - data.raw = NULL; + perf_sample_data_init(&data, 0); cpuc = &__get_cpu_var(cpu_hw_events); @@ -947,14 +946,23 @@ static int p4_pmu_handle_irq(struct pt_regs *regs) if (!x86_perf_event_set_period(event)) continue; if (perf_event_overflow(event, 1, &data, regs)) - p4_pmu_disable_event(event); + x86_pmu_stop(event, 0); } - if (handled) { - /* p4 quirk: unmask it again */ - apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); + if (handled) inc_irq_stat(apic_perf_irqs); - } + + /* + * When dealing with the unmasking of the LVTPC on P4 perf hw, it has + * been observed that the OVF bit flag has to be cleared first _before_ + * the LVTPC can be unmasked. + * + * The reason is the NMI line will continue to be asserted while the OVF + * bit is set. This causes a second NMI to generate if the LVTPC is + * unmasked before the OVF bit is cleared, leading to unknown NMI + * messages. + */ + apic_write(APIC_LVTPC, APIC_DM_NMI); return handled; } @@ -1188,7 +1196,7 @@ static __init int p4_pmu_init(void) { unsigned int low, high; - /* If we get stripped -- indexig fails */ + /* If we get stripped -- indexing fails */ BUILD_BUG_ON(ARCH_P4_MAX_CCCR > X86_PMC_MAX_GENERIC); rdmsr(MSR_IA32_MISC_ENABLE, low, high); diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index 706a9fb46a58..e90f08458e6b 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -391,7 +391,7 @@ static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize, set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity); - return io_apic_setup_irq_pin(*out_hwirq, cpu_to_node(0), &attr); + return io_apic_setup_irq_pin_once(*out_hwirq, cpu_to_node(0), &attr); } static void __init ioapic_add_ofnode(struct device_node *np) diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index e2a3f0606da4..1aae78f775fc 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -135,20 +135,6 @@ print_context_stack_bp(struct thread_info *tinfo, } EXPORT_SYMBOL_GPL(print_context_stack_bp); - -static void -print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) -{ - printk(data); - print_symbol(msg, symbol); - printk("\n"); -} - -static void print_trace_warning(void *data, char *msg) -{ - printk("%s%s\n", (char *)data, msg); -} - static int print_trace_stack(void *data, char *name) { printk("%s <%s> ", (char *)data, name); @@ -166,8 +152,6 @@ static void print_trace_address(void *data, unsigned long addr, int reliable) } static const struct stacktrace_ops print_trace_ops = { - .warning = print_trace_warning, - .warning_symbol = print_trace_warning_symbol, .stack = print_trace_stack, .address = print_trace_address, .walk_stack = print_context_stack, @@ -279,7 +263,6 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err) printk("DEBUG_PAGEALLOC"); #endif printk("\n"); - sysfs_printk_last_file(); if (notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) return 1; diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index a93742a57468..0ba15a6cc57e 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -260,9 +260,9 @@ do_ftrace_mod_code(unsigned long ip, void *new_code) return mod_code_status; } -static unsigned char *ftrace_nop_replace(void) +static const unsigned char *ftrace_nop_replace(void) { - return ideal_nop5; + return ideal_nops[NOP_ATOMIC5]; } static int diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index d6d6bb361931..3bb08509a7a1 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c @@ -23,7 +23,6 @@ static void __init i386_default_early_setup(void) { /* Initialize 32bit specific setup functions */ - x86_init.resources.probe_roms = probe_roms; x86_init.resources.reserve_resources = i386_reserve_resources; x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc; diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index bfe8f729e086..6781765b3a0d 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -217,7 +217,7 @@ static void hpet_reserve_platform_timers(unsigned int id) { } /* * Common hpet info */ -static unsigned long hpet_period; +static unsigned long hpet_freq; static void hpet_legacy_set_mode(enum clock_event_mode mode, struct clock_event_device *evt); @@ -232,7 +232,6 @@ static struct clock_event_device hpet_clockevent = { .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_mode = hpet_legacy_set_mode, .set_next_event = hpet_legacy_next_event, - .shift = 32, .irq = 0, .rating = 50, }; @@ -289,29 +288,13 @@ static void hpet_legacy_clockevent_register(void) /* Start HPET legacy interrupts */ hpet_enable_legacy_int(); - /* - * The mult factor is defined as (include/linux/clockchips.h) - * mult/2^shift = cyc/ns (in contrast to ns/cyc in clocksource.h) - * hpet_period is in units of femtoseconds (per cycle), so - * mult/2^shift = cyc/ns = 10^6/hpet_period - * mult = (10^6 * 2^shift)/hpet_period - * mult = (FSEC_PER_NSEC << hpet_clockevent.shift)/hpet_period - */ - hpet_clockevent.mult = div_sc((unsigned long) FSEC_PER_NSEC, - hpet_period, hpet_clockevent.shift); - /* Calculate the min / max delta */ - hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, - &hpet_clockevent); - /* Setup minimum reprogramming delta. */ - hpet_clockevent.min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA, - &hpet_clockevent); - /* * Start hpet with the boot cpu mask and make it * global after the IO_APIC has been initialized. */ hpet_clockevent.cpumask = cpumask_of(smp_processor_id()); - clockevents_register_device(&hpet_clockevent); + clockevents_config_and_register(&hpet_clockevent, hpet_freq, + HPET_MIN_PROG_DELTA, 0x7FFFFFFF); global_clock_event = &hpet_clockevent; printk(KERN_DEBUG "hpet clockevent registered\n"); } @@ -549,7 +532,6 @@ static int hpet_setup_irq(struct hpet_dev *dev) static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu) { struct clock_event_device *evt = &hdev->evt; - uint64_t hpet_freq; WARN_ON(cpu != smp_processor_id()); if (!(hdev->flags & HPET_DEV_VALID)) @@ -571,24 +553,10 @@ static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu) evt->set_mode = hpet_msi_set_mode; evt->set_next_event = hpet_msi_next_event; - evt->shift = 32; - - /* - * The period is a femto seconds value. We need to calculate the - * scaled math multiplication factor for nanosecond to hpet tick - * conversion. - */ - hpet_freq = FSEC_PER_SEC; - do_div(hpet_freq, hpet_period); - evt->mult = div_sc((unsigned long) hpet_freq, - NSEC_PER_SEC, evt->shift); - /* Calculate the max delta */ - evt->max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, evt); - /* 5 usec minimum reprogramming delta. */ - evt->min_delta_ns = 5000; - evt->cpumask = cpumask_of(hdev->cpu); - clockevents_register_device(evt); + + clockevents_config_and_register(evt, hpet_freq, HPET_MIN_PROG_DELTA, + 0x7FFFFFFF); } #ifdef CONFIG_HPET @@ -792,7 +760,6 @@ static struct clocksource clocksource_hpet = { static int hpet_clocksource_register(void) { u64 start, now; - u64 hpet_freq; cycle_t t1; /* Start the counter */ @@ -819,24 +786,7 @@ static int hpet_clocksource_register(void) return -ENODEV; } - /* - * The definition of mult is (include/linux/clocksource.h) - * mult/2^shift = ns/cyc and hpet_period is in units of fsec/cyc - * so we first need to convert hpet_period to ns/cyc units: - * mult/2^shift = ns/cyc = hpet_period/10^6 - * mult = (hpet_period * 2^shift)/10^6 - * mult = (hpet_period << shift)/FSEC_PER_NSEC - */ - - /* Need to convert hpet_period (fsec/cyc) to cyc/sec: - * - * cyc/sec = FSEC_PER_SEC/hpet_period(fsec/cyc) - * cyc/sec = (FSEC_PER_NSEC * NSEC_PER_SEC)/hpet_period - */ - hpet_freq = FSEC_PER_SEC; - do_div(hpet_freq, hpet_period); clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq); - return 0; } @@ -845,7 +795,9 @@ static int hpet_clocksource_register(void) */ int __init hpet_enable(void) { + unsigned long hpet_period; unsigned int id; + u64 freq; int i; if (!is_hpet_capable()) @@ -883,6 +835,14 @@ int __init hpet_enable(void) if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD) goto out_nohpet; + /* + * The period is a femto seconds value. Convert it to a + * frequency. + */ + freq = FSEC_PER_SEC; + do_div(freq, hpet_period); + hpet_freq = freq; + /* * Read the HPET ID register to retrieve the IRQ routing * information and the number of channels diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c index 2dfd31597443..fb66dc9e36cb 100644 --- a/arch/x86/kernel/i8253.c +++ b/arch/x86/kernel/i8253.c @@ -93,7 +93,6 @@ static struct clock_event_device pit_ce = { .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_mode = init_pit_timer, .set_next_event = pit_next_event, - .shift = 32, .irq = 0, }; @@ -108,90 +107,12 @@ void __init setup_pit_timer(void) * IO_APIC has been initialized. */ pit_ce.cpumask = cpumask_of(smp_processor_id()); - pit_ce.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, pit_ce.shift); - pit_ce.max_delta_ns = clockevent_delta2ns(0x7FFF, &pit_ce); - pit_ce.min_delta_ns = clockevent_delta2ns(0xF, &pit_ce); - clockevents_register_device(&pit_ce); + clockevents_config_and_register(&pit_ce, CLOCK_TICK_RATE, 0xF, 0x7FFF); global_clock_event = &pit_ce; } #ifndef CONFIG_X86_64 -/* - * Since the PIT overflows every tick, its not very useful - * to just read by itself. So use jiffies to emulate a free - * running counter: - */ -static cycle_t pit_read(struct clocksource *cs) -{ - static int old_count; - static u32 old_jifs; - unsigned long flags; - int count; - u32 jifs; - - raw_spin_lock_irqsave(&i8253_lock, flags); - /* - * Although our caller may have the read side of xtime_lock, - * this is now a seqlock, and we are cheating in this routine - * by having side effects on state that we cannot undo if - * there is a collision on the seqlock and our caller has to - * retry. (Namely, old_jifs and old_count.) So we must treat - * jiffies as volatile despite the lock. We read jiffies - * before latching the timer count to guarantee that although - * the jiffies value might be older than the count (that is, - * the counter may underflow between the last point where - * jiffies was incremented and the point where we latch the - * count), it cannot be newer. - */ - jifs = jiffies; - outb_pit(0x00, PIT_MODE); /* latch the count ASAP */ - count = inb_pit(PIT_CH0); /* read the latched count */ - count |= inb_pit(PIT_CH0) << 8; - - /* VIA686a test code... reset the latch if count > max + 1 */ - if (count > LATCH) { - outb_pit(0x34, PIT_MODE); - outb_pit(LATCH & 0xff, PIT_CH0); - outb_pit(LATCH >> 8, PIT_CH0); - count = LATCH - 1; - } - - /* - * It's possible for count to appear to go the wrong way for a - * couple of reasons: - * - * 1. The timer counter underflows, but we haven't handled the - * resulting interrupt and incremented jiffies yet. - * 2. Hardware problem with the timer, not giving us continuous time, - * the counter does small "jumps" upwards on some Pentium systems, - * (see c't 95/10 page 335 for Neptun bug.) - * - * Previous attempts to handle these cases intelligently were - * buggy, so we just do the simple thing now. - */ - if (count > old_count && jifs == old_jifs) - count = old_count; - - old_count = count; - old_jifs = jifs; - - raw_spin_unlock_irqrestore(&i8253_lock, flags); - - count = (LATCH - 1) - count; - - return (cycle_t)(jifs * LATCH) + count; -} - -static struct clocksource pit_cs = { - .name = "pit", - .rating = 110, - .read = pit_read, - .mask = CLOCKSOURCE_MASK(32), - .mult = 0, - .shift = 20, -}; - static int __init init_pit_clocksource(void) { /* @@ -205,10 +126,7 @@ static int __init init_pit_clocksource(void) pit_ce.mode != CLOCK_EVT_MODE_PERIODIC) return 0; - pit_cs.mult = clocksource_hz2mult(CLOCK_TICK_RATE, pit_cs.shift); - - return clocksource_register(&pit_cs); + return clocksource_i8253_init(); } arch_initcall(init_pit_clocksource); - #endif /* !CONFIG_X86_64 */ diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 1cb0b9fc78dc..6c0802eb2f7f 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -249,7 +249,7 @@ void fixup_irqs(void) data = irq_desc_get_irq_data(desc); affinity = data->affinity; - if (!irq_has_action(irq) || + if (!irq_has_action(irq) || irqd_is_per_cpu(data) || cpumask_subset(affinity, cpu_online_mask)) { raw_spin_unlock(&desc->lock); continue; @@ -276,7 +276,8 @@ void fixup_irqs(void) else if (!(warned++)) set_affinity = 0; - if (!irqd_can_move_in_process_context(data) && chip->irq_unmask) + if (!irqd_can_move_in_process_context(data) && + !irqd_irq_disabled(data) && chip->irq_unmask) chip->irq_unmask(data); raw_spin_unlock(&desc->lock); diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c index 961b6b30ba90..3fee346ef545 100644 --- a/arch/x86/kernel/jump_label.c +++ b/arch/x86/kernel/jump_label.c @@ -34,7 +34,7 @@ void arch_jump_label_transform(struct jump_entry *entry, code.offset = entry->target - (entry->code + JUMP_LABEL_NOP_SIZE); } else - memcpy(&code, ideal_nop5, JUMP_LABEL_NOP_SIZE); + memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE); get_online_cpus(); mutex_lock(&text_mutex); text_poke_smp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE); @@ -44,7 +44,8 @@ void arch_jump_label_transform(struct jump_entry *entry, void arch_jump_label_text_poke_early(jump_label_t addr) { - text_poke_early((void *)addr, ideal_nop5, JUMP_LABEL_NOP_SIZE); + text_poke_early((void *)addr, ideal_nops[NOP_ATOMIC5], + JUMP_LABEL_NOP_SIZE); } #endif diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index c969fd9d1566..f1a6244d7d93 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c @@ -1183,12 +1183,13 @@ static void __kprobes optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs) { struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + unsigned long flags; /* This is possible if op is under delayed unoptimizing */ if (kprobe_disabled(&op->kp)) return; - preempt_disable(); + local_irq_save(flags); if (kprobe_running()) { kprobes_inc_nmissed_count(&op->kp); } else { @@ -1207,7 +1208,7 @@ static void __kprobes optimized_callback(struct optimized_kprobe *op, opt_pre_handler(&op->kp, regs); __this_cpu_write(current_kprobe, NULL); } - preempt_enable_no_resched(); + local_irq_restore(flags); } static int __kprobes copy_optimized_instructions(u8 *dest, u8 *src) diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index f98d3eafe07a..6389a6bca11b 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -26,8 +26,6 @@ #include #include -#define KVM_SCALE 22 - static int kvmclock = 1; static int msr_kvm_system_time = MSR_KVM_SYSTEM_TIME; static int msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK; @@ -120,8 +118,6 @@ static struct clocksource kvm_clock = { .read = kvm_clock_get_cycles, .rating = 400, .mask = CLOCKSOURCE_MASK(64), - .mult = 1 << KVM_SCALE, - .shift = KVM_SCALE, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -203,7 +199,7 @@ void __init kvmclock_init(void) machine_ops.crash_shutdown = kvm_crash_shutdown; #endif kvm_get_preset_lpj(); - clocksource_register(&kvm_clock); + clocksource_register_hz(&kvm_clock, NSEC_PER_SEC); pv_info.paravirt_enabled = 1; pv_info.name = "KVM"; diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index ab23f1ad4bf1..52f256f2cc81 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 5a532ce646bf..6f9bfffb2720 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -715,17 +715,15 @@ static void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) } } -static int +static int __init check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count) { - int ret = 0; - if (!mpc_new_phys || count <= mpc_new_length) { WARN(1, "update_mptable: No spare slots (length: %x)\n", count); return -1; } - return ret; + return 0; } #else /* CONFIG_X86_IO_APIC */ static diff --git a/arch/x86/kernel/pci-iommu_table.c b/arch/x86/kernel/pci-iommu_table.c index 55d745ec1181..35ccf75696eb 100644 --- a/arch/x86/kernel/pci-iommu_table.c +++ b/arch/x86/kernel/pci-iommu_table.c @@ -50,20 +50,14 @@ void __init check_iommu_entries(struct iommu_table_entry *start, struct iommu_table_entry *finish) { struct iommu_table_entry *p, *q, *x; - char sym_p[KSYM_SYMBOL_LEN]; - char sym_q[KSYM_SYMBOL_LEN]; /* Simple cyclic dependency checker. */ for (p = start; p < finish; p++) { q = find_dependents_of(start, finish, p); x = find_dependents_of(start, finish, q); if (p == x) { - sprint_symbol(sym_p, (unsigned long)p->detect); - sprint_symbol(sym_q, (unsigned long)q->detect); - - printk(KERN_ERR "CYCLIC DEPENDENCY FOUND! %s depends" \ - " on %s and vice-versa. BREAKING IT.\n", - sym_p, sym_q); + printk(KERN_ERR "CYCLIC DEPENDENCY FOUND! %pS depends on %pS and vice-versa. BREAKING IT.\n", + p->detect, q->detect); /* Heavy handed way..*/ x->depend = 0; } @@ -72,12 +66,8 @@ void __init check_iommu_entries(struct iommu_table_entry *start, for (p = start; p < finish; p++) { q = find_dependents_of(p, finish, p); if (q && q > p) { - sprint_symbol(sym_p, (unsigned long)p->detect); - sprint_symbol(sym_q, (unsigned long)q->detect); - - printk(KERN_ERR "EXECUTION ORDER INVALID! %s "\ - "should be called before %s!\n", - sym_p, sym_q); + printk(KERN_ERR "EXECUTION ORDER INVALID! %pS should be called before %pS!\n", + p->detect, q->detect); } } } diff --git a/arch/x86/kernel/probe_roms_32.c b/arch/x86/kernel/probe_roms.c similarity index 65% rename from arch/x86/kernel/probe_roms_32.c rename to arch/x86/kernel/probe_roms.c index 071e7fea42e5..ba0a4cce53be 100644 --- a/arch/x86/kernel/probe_roms_32.c +++ b/arch/x86/kernel/probe_roms.c @@ -73,6 +73,107 @@ static struct resource video_rom_resource = { .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM }; +/* does this oprom support the given pci device, or any of the devices + * that the driver supports? + */ +static bool match_id(struct pci_dev *pdev, unsigned short vendor, unsigned short device) +{ + struct pci_driver *drv = pdev->driver; + const struct pci_device_id *id; + + if (pdev->vendor == vendor && pdev->device == device) + return true; + + for (id = drv ? drv->id_table : NULL; id && id->vendor; id++) + if (id->vendor == vendor && id->device == device) + break; + + return id && id->vendor; +} + +static bool probe_list(struct pci_dev *pdev, unsigned short vendor, + const unsigned char *rom_list) +{ + unsigned short device; + + do { + if (probe_kernel_address(rom_list, device) != 0) + device = 0; + + if (device && match_id(pdev, vendor, device)) + break; + + rom_list += 2; + } while (device); + + return !!device; +} + +static struct resource *find_oprom(struct pci_dev *pdev) +{ + struct resource *oprom = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(adapter_rom_resources); i++) { + struct resource *res = &adapter_rom_resources[i]; + unsigned short offset, vendor, device, list, rev; + const unsigned char *rom; + + if (res->end == 0) + break; + + rom = isa_bus_to_virt(res->start); + if (probe_kernel_address(rom + 0x18, offset) != 0) + continue; + + if (probe_kernel_address(rom + offset + 0x4, vendor) != 0) + continue; + + if (probe_kernel_address(rom + offset + 0x6, device) != 0) + continue; + + if (match_id(pdev, vendor, device)) { + oprom = res; + break; + } + + if (probe_kernel_address(rom + offset + 0x8, list) == 0 && + probe_kernel_address(rom + offset + 0xc, rev) == 0 && + rev >= 3 && list && + probe_list(pdev, vendor, rom + offset + list)) { + oprom = res; + break; + } + } + + return oprom; +} + +void *pci_map_biosrom(struct pci_dev *pdev) +{ + struct resource *oprom = find_oprom(pdev); + + if (!oprom) + return NULL; + + return ioremap(oprom->start, resource_size(oprom)); +} +EXPORT_SYMBOL(pci_map_biosrom); + +void pci_unmap_biosrom(void __iomem *image) +{ + iounmap(image); +} +EXPORT_SYMBOL(pci_unmap_biosrom); + +size_t pci_biosrom_size(struct pci_dev *pdev) +{ + struct resource *oprom = find_oprom(pdev); + + return oprom ? resource_size(oprom) : 0; +} +EXPORT_SYMBOL(pci_biosrom_size); + #define ROMSIGNATURE 0xaa55 static int __init romsignature(const unsigned char *rom) diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index d46cbe46b7ab..88a90a977f8e 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -449,7 +449,7 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); void mwait_idle_with_hints(unsigned long ax, unsigned long cx) { if (!need_resched()) { - if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR)) + if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR)) clflush((void *)¤t_thread_info()->flags); __monitor((void *)¤t_thread_info()->flags, 0, 0); @@ -465,7 +465,7 @@ static void mwait_idle(void) if (!need_resched()) { trace_power_start(POWER_CSTATE, 1, smp_processor_id()); trace_cpu_idle(1, smp_processor_id()); - if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR)) + if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR)) clflush((void *)¤t_thread_info()->flags); __monitor((void *)¤t_thread_info()->flags, 0, 0); diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 45892dc4b72a..f65e5b521dbd 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -608,6 +608,9 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data) unsigned len, type; struct perf_event *bp; + if (ptrace_get_breakpoints(tsk) < 0) + return -ESRCH; + data &= ~DR_CONTROL_RESERVED; old_dr7 = ptrace_get_dr7(thread->ptrace_bps); restore: @@ -655,6 +658,9 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data) } goto restore; } + + ptrace_put_breakpoints(tsk); + return ((orig_ret < 0) ? orig_ret : rc); } @@ -668,10 +674,17 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n) if (n < HBP_NUM) { struct perf_event *bp; + + if (ptrace_get_breakpoints(tsk) < 0) + return -ESRCH; + bp = thread->ptrace_bps[n]; if (!bp) - return 0; - val = bp->hw.info.address; + val = 0; + else + val = bp->hw.info.address; + + ptrace_put_breakpoints(tsk); } else if (n == 6) { val = thread->debugreg6; } else if (n == 7) { @@ -686,6 +699,10 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, struct perf_event *bp; struct thread_struct *t = &tsk->thread; struct perf_event_attr attr; + int err = 0; + + if (ptrace_get_breakpoints(tsk) < 0) + return -ESRCH; if (!t->ptrace_bps[nr]) { ptrace_breakpoint_init(&attr); @@ -709,24 +726,23 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, * writing for the user. And anyway this is the previous * behaviour. */ - if (IS_ERR(bp)) - return PTR_ERR(bp); + if (IS_ERR(bp)) { + err = PTR_ERR(bp); + goto put; + } t->ptrace_bps[nr] = bp; } else { - int err; - bp = t->ptrace_bps[nr]; attr = bp->attr; attr.bp_addr = addr; err = modify_user_hw_breakpoint(bp, &attr); - if (err) - return err; } - - return 0; +put: + ptrace_put_breakpoints(tsk); + return err; } /* diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 08c44b08bf5b..0c016f727695 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -36,7 +36,7 @@ EXPORT_SYMBOL(pm_power_off); static const struct desc_ptr no_idt = {}; static int reboot_mode; -enum reboot_type reboot_type = BOOT_KBD; +enum reboot_type reboot_type = BOOT_ACPI; int reboot_force; #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) @@ -478,9 +478,24 @@ void __attribute__((weak)) mach_reboot_fixups(void) { } +/* + * Windows compatible x86 hardware expects the following on reboot: + * + * 1) If the FADT has the ACPI reboot register flag set, try it + * 2) If still alive, write to the keyboard controller + * 3) If still alive, write to the ACPI reboot register again + * 4) If still alive, write to the keyboard controller again + * + * If the machine is still alive at this stage, it gives up. We default to + * following the same pattern, except that if we're still alive after (4) we'll + * try to force a triple fault and then cycle between hitting the keyboard + * controller and doing that + */ static void native_machine_emergency_restart(void) { int i; + int attempt = 0; + int orig_reboot_type = reboot_type; if (reboot_emergency) emergency_vmx_disable_all(); @@ -502,6 +517,13 @@ static void native_machine_emergency_restart(void) outb(0xfe, 0x64); /* pulse reset low */ udelay(50); } + if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { + attempt = 1; + reboot_type = BOOT_ACPI; + } else { + reboot_type = BOOT_TRIPLE; + } + break; case BOOT_TRIPLE: load_idt(&no_idt); diff --git a/arch/x86/kernel/reboot_32.S b/arch/x86/kernel/reboot_32.S index 29092b38d816..1d5c46df0d78 100644 --- a/arch/x86/kernel/reboot_32.S +++ b/arch/x86/kernel/reboot_32.S @@ -21,26 +21,26 @@ r_base = . /* Get our own relocated address */ call 1f 1: popl %ebx - subl $1b, %ebx + subl $(1b - r_base), %ebx /* Compute the equivalent real-mode segment */ movl %ebx, %ecx shrl $4, %ecx /* Patch post-real-mode segment jump */ - movw dispatch_table(%ebx,%eax,2),%ax - movw %ax, 101f(%ebx) - movw %cx, 102f(%ebx) + movw (dispatch_table - r_base)(%ebx,%eax,2),%ax + movw %ax, (101f - r_base)(%ebx) + movw %cx, (102f - r_base)(%ebx) /* Set up the IDT for real mode. */ - lidtl machine_real_restart_idt(%ebx) + lidtl (machine_real_restart_idt - r_base)(%ebx) /* * Set up a GDT from which we can load segment descriptors for real * mode. The GDT is not used in real mode; it is just needed here to * prepare the descriptors. */ - lgdtl machine_real_restart_gdt(%ebx) + lgdtl (machine_real_restart_gdt - r_base)(%ebx) /* * Load the data segment registers with 16-bit compatible values diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 4be9b398470e..c3050af9306d 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -691,8 +691,6 @@ early_param("reservelow", parse_reservelow); void __init setup_arch(char **cmdline_p) { - unsigned long flags; - #ifdef CONFIG_X86_32 memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); visws_early_detect(); @@ -1041,9 +1039,7 @@ void __init setup_arch(char **cmdline_p) mcheck_init(); - local_irq_save(flags); - arch_init_ideal_nop5(); - local_irq_restore(flags); + arch_init_ideal_nops(); } #ifdef CONFIG_X86_32 diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 4fd173cd8e57..40a24932a8a1 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -601,10 +601,7 @@ long sys_rt_sigreturn(struct pt_regs *regs) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) goto badframe; @@ -682,6 +679,7 @@ static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) { + sigset_t blocked; int ret; /* Are we from a system call? */ @@ -741,12 +739,10 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, */ regs->flags &= ~X86_EFLAGS_TF; - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); + sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + sigaddset(&blocked, sig); + set_current_blocked(&blocked); tracehook_signal_handler(sig, info, ka, regs, test_thread_flag(TIF_SINGLESTEP)); diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 513deac7228d..013e7eba83bb 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -194,14 +194,13 @@ static void native_stop_other_cpus(int wait) } /* - * Reschedule call back. Nothing to do, - * all the work is done automatically when - * we return from the interrupt. + * Reschedule call back. */ void smp_reschedule_interrupt(struct pt_regs *regs) { ack_APIC_irq(); inc_irq_stat(irq_resched_count); + scheduler_ipi(); /* * KVM uses this interrupt to force a cpu out of guest mode */ diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 8ed8908cc9f7..a3c430bdfb60 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -312,26 +312,6 @@ void __cpuinit smp_store_cpu_info(int id) identify_secondary_cpu(c); } -static void __cpuinit check_cpu_siblings_on_same_node(int cpu1, int cpu2) -{ - int node1 = early_cpu_to_node(cpu1); - int node2 = early_cpu_to_node(cpu2); - - /* - * Our CPU scheduler assumes all logical cpus in the same physical cpu - * share the same node. But, buggy ACPI or NUMA emulation might assign - * them to different node. Fix it. - */ - if (node1 != node2) { - pr_warning("CPU %d in node %d and CPU %d in node %d are in the same physical CPU. forcing same node %d\n", - cpu1, node1, cpu2, node2, node2); - - numa_remove_cpu(cpu1); - numa_set_node(cpu1, node2); - numa_add_cpu(cpu1); - } -} - static void __cpuinit link_thread_siblings(int cpu1, int cpu2) { cpumask_set_cpu(cpu1, cpu_sibling_mask(cpu2)); @@ -340,7 +320,6 @@ static void __cpuinit link_thread_siblings(int cpu1, int cpu2) cpumask_set_cpu(cpu2, cpu_core_mask(cpu1)); cpumask_set_cpu(cpu1, cpu_llc_shared_mask(cpu2)); cpumask_set_cpu(cpu2, cpu_llc_shared_mask(cpu1)); - check_cpu_siblings_on_same_node(cpu1, cpu2); } @@ -382,12 +361,10 @@ void __cpuinit set_cpu_sibling_map(int cpu) per_cpu(cpu_llc_id, cpu) == per_cpu(cpu_llc_id, i)) { cpumask_set_cpu(i, cpu_llc_shared_mask(cpu)); cpumask_set_cpu(cpu, cpu_llc_shared_mask(i)); - check_cpu_siblings_on_same_node(cpu, i); } if (c->phys_proc_id == cpu_data(i).phys_proc_id) { cpumask_set_cpu(i, cpu_core_mask(cpu)); cpumask_set_cpu(cpu, cpu_core_mask(i)); - check_cpu_siblings_on_same_node(cpu, i); /* * Does this new cpu bringup a new core? */ @@ -1355,9 +1332,9 @@ static inline void mwait_play_dead(void) void *mwait_ptr; struct cpuinfo_x86 *c = __this_cpu_ptr(&cpu_info); - if (!(cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c))) + if (!this_cpu_has(X86_FEATURE_MWAIT) && mwait_usable(c)) return; - if (!cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLSH)) + if (!this_cpu_has(X86_FEATURE_CLFLSH)) return; if (__this_cpu_read(cpu_info.cpuid_level) < CPUID_MWAIT_LEAF) return; diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index 6515733a289d..55d9bc03f696 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c @@ -9,15 +9,6 @@ #include #include -static void save_stack_warning(void *data, char *msg) -{ -} - -static void -save_stack_warning_symbol(void *data, char *msg, unsigned long symbol) -{ -} - static int save_stack_stack(void *data, char *name) { return 0; @@ -53,16 +44,12 @@ save_stack_address_nosched(void *data, unsigned long addr, int reliable) } static const struct stacktrace_ops save_stack_ops = { - .warning = save_stack_warning, - .warning_symbol = save_stack_warning_symbol, .stack = save_stack_stack, .address = save_stack_address, .walk_stack = print_context_stack, }; static const struct stacktrace_ops save_stack_ops_nosched = { - .warning = save_stack_warning, - .warning_symbol = save_stack_warning_symbol, .stack = save_stack_stack, .address = save_stack_address_nosched, .walk_stack = print_context_stack, diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S index abce34d5c79d..32cbffb0c494 100644 --- a/arch/x86/kernel/syscall_table_32.S +++ b/arch/x86/kernel/syscall_table_32.S @@ -344,3 +344,4 @@ ENTRY(sys_call_table) .long sys_open_by_handle_at .long sys_clock_adjtime .long sys_syncfs + .long sys_sendmmsg /* 345 */ diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index c11514e9128b..6f164bd5e14d 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -35,7 +35,7 @@ void iommu_shutdown_noop(void) { } struct x86_init_ops x86_init __initdata = { .resources = { - .probe_roms = x86_init_noop, + .probe_roms = probe_roms, .reserve_resources = reserve_standard_io_resources, .memory_setup = default_machine_specific_memory_setup, }, @@ -61,6 +61,10 @@ struct x86_init_ops x86_init __initdata = { .banner = default_banner, }, + .mapping = { + .pagetable_reserve = native_pagetable_reserve, + }, + .paging = { .pagetable_setup_start = native_pagetable_setup_start, .pagetable_setup_done = native_pagetable_setup_done, diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 1cd608973ce5..e191c096ab90 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -7,7 +7,7 @@ * kernel and insert a module (lg.ko) which allows us to run other Linux * kernels the same way we'd run processes. We call the first kernel the Host, * and the others the Guests. The program which sets up and configures Guests - * (such as the example in Documentation/lguest/lguest.c) is called the + * (such as the example in Documentation/virtual/lguest/lguest.c) is called the * Launcher. * * Secondly, we only run specially modified Guests, not normal kernels: setting @@ -913,8 +913,6 @@ static struct clocksource lguest_clock = { .rating = 200, .read = lguest_clock_read, .mask = CLOCKSOURCE_MASK(64), - .mult = 1 << 22, - .shift = 22, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -997,7 +995,7 @@ static void lguest_time_init(void) /* Set up the timer interrupt (0) to go to our simple timer routine */ irq_set_handler(0, lguest_time_irq); - clocksource_register(&lguest_clock); + clocksource_register_hz(&lguest_clock, NSEC_PER_SEC); /* We can't set cpumask in the initializer: damn C limitations! Set it * here and register our timer device. */ diff --git a/arch/x86/lib/clear_page_64.S b/arch/x86/lib/clear_page_64.S index aa4326bfb24a..f2145cfa12a6 100644 --- a/arch/x86/lib/clear_page_64.S +++ b/arch/x86/lib/clear_page_64.S @@ -1,5 +1,6 @@ #include #include +#include /* * Zero a page. @@ -14,6 +15,15 @@ ENTRY(clear_page_c) CFI_ENDPROC ENDPROC(clear_page_c) +ENTRY(clear_page_c_e) + CFI_STARTPROC + movl $4096,%ecx + xorl %eax,%eax + rep stosb + ret + CFI_ENDPROC +ENDPROC(clear_page_c_e) + ENTRY(clear_page) CFI_STARTPROC xorl %eax,%eax @@ -38,21 +48,26 @@ ENTRY(clear_page) .Lclear_page_end: ENDPROC(clear_page) - /* Some CPUs run faster using the string instructions. - It is also a lot simpler. Use this when possible */ + /* + * Some CPUs support enhanced REP MOVSB/STOSB instructions. + * It is recommended to use this when possible. + * If enhanced REP MOVSB/STOSB is not available, try to use fast string. + * Otherwise, use original function. + * + */ #include .section .altinstr_replacement,"ax" 1: .byte 0xeb /* jmp */ .byte (clear_page_c - clear_page) - (2f - 1b) /* offset */ -2: +2: .byte 0xeb /* jmp */ + .byte (clear_page_c_e - clear_page) - (3f - 2b) /* offset */ +3: .previous .section .altinstructions,"a" - .align 8 - .quad clear_page - .quad 1b - .word X86_FEATURE_REP_GOOD - .byte .Lclear_page_end - clear_page - .byte 2b - 1b + altinstruction_entry clear_page,1b,X86_FEATURE_REP_GOOD,\ + .Lclear_page_end-clear_page, 2b-1b + altinstruction_entry clear_page,2b,X86_FEATURE_ERMS, \ + .Lclear_page_end-clear_page,3b-2b .previous diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index 99e482615195..024840266ba0 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -15,23 +15,30 @@ #include #include #include +#include - .macro ALTERNATIVE_JUMP feature,orig,alt +/* + * By placing feature2 after feature1 in altinstructions section, we logically + * implement: + * If CPU has feature2, jmp to alt2 is used + * else if CPU has feature1, jmp to alt1 is used + * else jmp to orig is used. + */ + .macro ALTERNATIVE_JUMP feature1,feature2,orig,alt1,alt2 0: .byte 0xe9 /* 32bit jump */ .long \orig-1f /* by default jump to orig */ 1: .section .altinstr_replacement,"ax" 2: .byte 0xe9 /* near jump with 32bit immediate */ - .long \alt-1b /* offset */ /* or alternatively to alt */ + .long \alt1-1b /* offset */ /* or alternatively to alt1 */ +3: .byte 0xe9 /* near jump with 32bit immediate */ + .long \alt2-1b /* offset */ /* or alternatively to alt2 */ .previous + .section .altinstructions,"a" - .align 8 - .quad 0b - .quad 2b - .word \feature /* when feature is set */ - .byte 5 - .byte 5 + altinstruction_entry 0b,2b,\feature1,5,5 + altinstruction_entry 0b,3b,\feature2,5,5 .previous .endm @@ -72,8 +79,10 @@ ENTRY(_copy_to_user) addq %rdx,%rcx jc bad_to_user cmpq TI_addr_limit(%rax),%rcx - jae bad_to_user - ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string + ja bad_to_user + ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS, \ + copy_user_generic_unrolled,copy_user_generic_string, \ + copy_user_enhanced_fast_string CFI_ENDPROC ENDPROC(_copy_to_user) @@ -85,8 +94,10 @@ ENTRY(_copy_from_user) addq %rdx,%rcx jc bad_from_user cmpq TI_addr_limit(%rax),%rcx - jae bad_from_user - ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string + ja bad_from_user + ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS, \ + copy_user_generic_unrolled,copy_user_generic_string, \ + copy_user_enhanced_fast_string CFI_ENDPROC ENDPROC(_copy_from_user) @@ -255,3 +266,37 @@ ENTRY(copy_user_generic_string) .previous CFI_ENDPROC ENDPROC(copy_user_generic_string) + +/* + * Some CPUs are adding enhanced REP MOVSB/STOSB instructions. + * It's recommended to use enhanced REP MOVSB/STOSB if it's enabled. + * + * Input: + * rdi destination + * rsi source + * rdx count + * + * Output: + * eax uncopied bytes or 0 if successful. + */ +ENTRY(copy_user_enhanced_fast_string) + CFI_STARTPROC + andl %edx,%edx + jz 2f + movl %edx,%ecx +1: rep + movsb +2: xorl %eax,%eax + ret + + .section .fixup,"ax" +12: movl %ecx,%edx /* ecx is zerorest also */ + jmp copy_user_handle_tail + .previous + + .section __ex_table,"a" + .align 8 + .quad 1b,12b + .previous + CFI_ENDPROC +ENDPROC(copy_user_enhanced_fast_string) diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S index 75ef61e35e38..efbf2a0ecdea 100644 --- a/arch/x86/lib/memcpy_64.S +++ b/arch/x86/lib/memcpy_64.S @@ -4,6 +4,7 @@ #include #include +#include /* * memcpy - Copy a memory block. @@ -37,6 +38,23 @@ .Lmemcpy_e: .previous +/* + * memcpy_c_e() - enhanced fast string memcpy. This is faster and simpler than + * memcpy_c. Use memcpy_c_e when possible. + * + * This gets patched over the unrolled variant (below) via the + * alternative instructions framework: + */ + .section .altinstr_replacement, "ax", @progbits +.Lmemcpy_c_e: + movq %rdi, %rax + + movl %edx, %ecx + rep movsb + ret +.Lmemcpy_e_e: + .previous + ENTRY(__memcpy) ENTRY(memcpy) CFI_STARTPROC @@ -49,7 +67,7 @@ ENTRY(memcpy) jb .Lhandle_tail /* - * We check whether memory false dependece could occur, + * We check whether memory false dependence could occur, * then jump to corresponding copy mode. */ cmp %dil, %sil @@ -171,21 +189,22 @@ ENDPROC(memcpy) ENDPROC(__memcpy) /* - * Some CPUs run faster using the string copy instructions. - * It is also a lot simpler. Use this when possible: - */ - - .section .altinstructions, "a" - .align 8 - .quad memcpy - .quad .Lmemcpy_c - .word X86_FEATURE_REP_GOOD - - /* + * Some CPUs are adding enhanced REP MOVSB/STOSB feature + * If the feature is supported, memcpy_c_e() is the first choice. + * If enhanced rep movsb copy is not available, use fast string copy + * memcpy_c() when possible. This is faster and code is simpler than + * original memcpy(). + * Otherwise, original memcpy() is used. + * In .altinstructions section, ERMS feature is placed after REG_GOOD + * feature to implement the right patch order. + * * Replace only beginning, memcpy is used to apply alternatives, * so it is silly to overwrite itself with nops - reboot is the * only outcome... */ - .byte .Lmemcpy_e - .Lmemcpy_c - .byte .Lmemcpy_e - .Lmemcpy_c + .section .altinstructions, "a" + altinstruction_entry memcpy,.Lmemcpy_c,X86_FEATURE_REP_GOOD,\ + .Lmemcpy_e-.Lmemcpy_c,.Lmemcpy_e-.Lmemcpy_c + altinstruction_entry memcpy,.Lmemcpy_c_e,X86_FEATURE_ERMS, \ + .Lmemcpy_e_e-.Lmemcpy_c_e,.Lmemcpy_e_e-.Lmemcpy_c_e .previous diff --git a/arch/x86/lib/memmove_64.S b/arch/x86/lib/memmove_64.S index 0ecb8433e5a8..d0ec9c2936d7 100644 --- a/arch/x86/lib/memmove_64.S +++ b/arch/x86/lib/memmove_64.S @@ -8,6 +8,7 @@ #define _STRING_C #include #include +#include #undef memmove @@ -24,6 +25,7 @@ */ ENTRY(memmove) CFI_STARTPROC + /* Handle more 32bytes in loop */ mov %rdi, %rax cmp $0x20, %rdx @@ -31,8 +33,13 @@ ENTRY(memmove) /* Decide forward/backward copy mode */ cmp %rdi, %rsi - jb 2f + jge .Lmemmove_begin_forward + mov %rsi, %r8 + add %rdx, %r8 + cmp %rdi, %r8 + jg 2f +.Lmemmove_begin_forward: /* * movsq instruction have many startup latency * so we handle small size by general register. @@ -78,6 +85,8 @@ ENTRY(memmove) rep movsq movq %r11, (%r10) jmp 13f +.Lmemmove_end_forward: + /* * Handle data backward by movsq. */ @@ -194,4 +203,22 @@ ENTRY(memmove) 13: retq CFI_ENDPROC + + .section .altinstr_replacement,"ax" +.Lmemmove_begin_forward_efs: + /* Forward moving data. */ + movq %rdx, %rcx + rep movsb + retq +.Lmemmove_end_forward_efs: + .previous + + .section .altinstructions,"a" + .align 8 + .quad .Lmemmove_begin_forward + .quad .Lmemmove_begin_forward_efs + .word X86_FEATURE_ERMS + .byte .Lmemmove_end_forward-.Lmemmove_begin_forward + .byte .Lmemmove_end_forward_efs-.Lmemmove_begin_forward_efs + .previous ENDPROC(memmove) diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S index 09d344269652..79bd454b78a3 100644 --- a/arch/x86/lib/memset_64.S +++ b/arch/x86/lib/memset_64.S @@ -2,9 +2,13 @@ #include #include +#include +#include /* - * ISO C memset - set a memory block to a byte value. + * ISO C memset - set a memory block to a byte value. This function uses fast + * string to get better performance than the original function. The code is + * simpler and shorter than the orignal function as well. * * rdi destination * rsi value (char) @@ -31,6 +35,28 @@ .Lmemset_e: .previous +/* + * ISO C memset - set a memory block to a byte value. This function uses + * enhanced rep stosb to override the fast string function. + * The code is simpler and shorter than the fast string function as well. + * + * rdi destination + * rsi value (char) + * rdx count (bytes) + * + * rax original destination + */ + .section .altinstr_replacement, "ax", @progbits +.Lmemset_c_e: + movq %rdi,%r9 + movb %sil,%al + movl %edx,%ecx + rep stosb + movq %r9,%rax + ret +.Lmemset_e_e: + .previous + ENTRY(memset) ENTRY(__memset) CFI_STARTPROC @@ -112,16 +138,20 @@ ENTRY(__memset) ENDPROC(memset) ENDPROC(__memset) - /* Some CPUs run faster using the string instructions. - It is also a lot simpler. Use this when possible */ - -#include - + /* Some CPUs support enhanced REP MOVSB/STOSB feature. + * It is recommended to use this when possible. + * + * If enhanced REP MOVSB/STOSB feature is not available, use fast string + * instructions. + * + * Otherwise, use original memset function. + * + * In .altinstructions section, ERMS feature is placed after REG_GOOD + * feature to implement the right patch order. + */ .section .altinstructions,"a" - .align 8 - .quad memset - .quad .Lmemset_c - .word X86_FEATURE_REP_GOOD - .byte .Lfinal - memset - .byte .Lmemset_e - .Lmemset_c + altinstruction_entry memset,.Lmemset_c,X86_FEATURE_REP_GOOD,\ + .Lfinal-memset,.Lmemset_e-.Lmemset_c + altinstruction_entry memset,.Lmemset_c_e,X86_FEATURE_ERMS, \ + .Lfinal-memset,.Lmemset_e_e-.Lmemset_c_e .previous diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 3e608edf9958..3d11327c9ab4 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -23,8 +23,8 @@ mmiotrace-y := kmmio.o pf_in.o mmio-mod.o obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o obj-$(CONFIG_NUMA) += numa.o numa_$(BITS).o -obj-$(CONFIG_AMD_NUMA) += amdtopology_64.o -obj-$(CONFIG_ACPI_NUMA) += srat_$(BITS).o +obj-$(CONFIG_AMD_NUMA) += amdtopology.o +obj-$(CONFIG_ACPI_NUMA) += srat.o obj-$(CONFIG_NUMA_EMU) += numa_emulation.o obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o diff --git a/arch/x86/mm/amdtopology_64.c b/arch/x86/mm/amdtopology.c similarity index 90% rename from arch/x86/mm/amdtopology_64.c rename to arch/x86/mm/amdtopology.c index 0919c26820d4..5247d01329ca 100644 --- a/arch/x86/mm/amdtopology_64.c +++ b/arch/x86/mm/amdtopology.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -69,10 +70,10 @@ static __init void early_get_boot_cpu_id(void) int __init amd_numa_init(void) { - unsigned long start = PFN_PHYS(0); - unsigned long end = PFN_PHYS(max_pfn); + u64 start = PFN_PHYS(0); + u64 end = PFN_PHYS(max_pfn); unsigned numnodes; - unsigned long prevbase; + u64 prevbase; int i, j, nb; u32 nodeid, reg; unsigned int bits, cores, apicid_base; @@ -95,7 +96,7 @@ int __init amd_numa_init(void) prevbase = 0; for (i = 0; i < 8; i++) { - unsigned long base, limit; + u64 base, limit; base = read_pci_config(0, nb, 1, 0x40 + i*8); limit = read_pci_config(0, nb, 1, 0x44 + i*8); @@ -107,18 +108,18 @@ int __init amd_numa_init(void) continue; } if (nodeid >= numnodes) { - pr_info("Ignoring excess node %d (%lx:%lx)\n", nodeid, + pr_info("Ignoring excess node %d (%Lx:%Lx)\n", nodeid, base, limit); continue; } if (!limit) { - pr_info("Skipping node entry %d (base %lx)\n", + pr_info("Skipping node entry %d (base %Lx)\n", i, base); continue; } if ((base >> 8) & 3 || (limit >> 8) & 3) { - pr_err("Node %d using interleaving mode %lx/%lx\n", + pr_err("Node %d using interleaving mode %Lx/%Lx\n", nodeid, (base >> 8) & 3, (limit >> 8) & 3); return -EINVAL; } @@ -150,19 +151,19 @@ int __init amd_numa_init(void) continue; } if (limit < base) { - pr_err("Node %d bogus settings %lx-%lx.\n", + pr_err("Node %d bogus settings %Lx-%Lx.\n", nodeid, base, limit); continue; } /* Could sort here, but pun for now. Should not happen anyroads. */ if (prevbase > base) { - pr_err("Node map not sorted %lx,%lx\n", + pr_err("Node map not sorted %Lx,%Lx\n", prevbase, base); return -EINVAL; } - pr_info("Node %d MemBase %016lx Limit %016lx\n", + pr_info("Node %d MemBase %016Lx Limit %016Lx\n", nodeid, base, limit); prevbase = base; diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 20e3f8702d1e..bcb394dfbb35 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -12,6 +12,7 @@ #include /* kmmio_handler, ... */ #include /* perf_sw_event */ #include /* hstate_index_to_shift */ +#include /* prefetchw */ #include /* dotraplinkage, ... */ #include /* pgd_*(), ... */ diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 286d289b039b..37b8b0fe8320 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -81,6 +81,11 @@ static void __init find_early_table_space(unsigned long end, int use_pse, end, pgt_buf_start << PAGE_SHIFT, pgt_buf_top << PAGE_SHIFT); } +void __init native_pagetable_reserve(u64 start, u64 end) +{ + memblock_x86_reserve_range(start, end, "PGTABLE"); +} + struct map_range { unsigned long start; unsigned long end; @@ -272,9 +277,24 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, __flush_tlb_all(); + /* + * Reserve the kernel pagetable pages we used (pgt_buf_start - + * pgt_buf_end) and free the other ones (pgt_buf_end - pgt_buf_top) + * so that they can be reused for other purposes. + * + * On native it just means calling memblock_x86_reserve_range, on Xen it + * also means marking RW the pagetable pages that we allocated before + * but that haven't been used. + * + * In fact on xen we mark RO the whole range pgt_buf_start - + * pgt_buf_top, because we have to make sure that when + * init_memory_mapping reaches the pagetable pages area, it maps + * RO all the pagetable pages, including the ones that are beyond + * pgt_buf_end at that time. + */ if (!after_bootmem && pgt_buf_end > pgt_buf_start) - memblock_x86_reserve_range(pgt_buf_start << PAGE_SHIFT, - pgt_buf_end << PAGE_SHIFT, "PGTABLE"); + x86_init.mapping.pagetable_reserve(PFN_PHYS(pgt_buf_start), + PFN_PHYS(pgt_buf_end)); if (!after_bootmem) early_memtest(start, end); diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 80088f994193..29f7c6d98179 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -678,8 +678,10 @@ static void __init zone_sizes_init(void) { unsigned long max_zone_pfns[MAX_NR_ZONES]; memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); +#ifdef CONFIG_ZONE_DMA max_zone_pfns[ZONE_DMA] = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; +#endif max_zone_pfns[ZONE_NORMAL] = max_low_pfn; #ifdef CONFIG_HIGHMEM max_zone_pfns[ZONE_HIGHMEM] = highend_pfn; @@ -716,6 +718,7 @@ void __init paging_init(void) * NOTE: at this point the bootmem allocator is fully available. */ olpc_dt_build_devicetree(); + sparse_memory_present_with_active_regions(MAX_NUMNODES); sparse_init(); zone_sizes_init(); } diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 794233587287..d865c4aeec55 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -616,7 +616,9 @@ void __init paging_init(void) unsigned long max_zone_pfns[MAX_NR_ZONES]; memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); +#ifdef CONFIG_ZONE_DMA max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; +#endif max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; max_zone_pfns[ZONE_NORMAL] = max_pfn; @@ -679,14 +681,6 @@ int arch_add_memory(int nid, u64 start, u64 size) } EXPORT_SYMBOL_GPL(arch_add_memory); -#if !defined(CONFIG_ACPI_NUMA) && defined(CONFIG_NUMA) -int memory_add_physaddr_to_nid(u64 start) -{ - return 0; -} -EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); -#endif - #endif /* CONFIG_MEMORY_HOTPLUG */ static struct kcore_list kcore_vsyscall; diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 0369843511dc..be1ef574ce9a 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -90,13 +90,6 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, if (is_ISA_range(phys_addr, last_addr)) return (__force void __iomem *)phys_to_virt(phys_addr); - /* - * Check if the request spans more than any BAR in the iomem resource - * tree. - */ - WARN_ONCE(iomem_map_sanity_check(phys_addr, size), - KERN_INFO "Info: mapping multiple BARs. Your kernel is fine."); - /* * Don't allow anybody to remap normal RAM that we're using.. */ @@ -170,6 +163,13 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, ret_addr = (void __iomem *) (vaddr + offset); mmiotrace_ioremap(unaligned_phys_addr, unaligned_size, ret_addr); + /* + * Check if the request spans more than any BAR in the iomem resource + * tree. + */ + WARN_ONCE(iomem_map_sanity_check(unaligned_phys_addr, unaligned_size), + KERN_INFO "Info: mapping multiple BARs. Your kernel is fine."); + return ret_addr; err_free_area: free_vm_area(area); diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 9559d360fde7..f5510d889a22 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -1,11 +1,39 @@ /* Common code for 32 and 64-bit NUMA */ -#include -#include +#include +#include +#include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include #include +#include + +#include "numa_internal.h" int __initdata numa_off; +nodemask_t numa_nodes_parsed __initdata; + +struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; +EXPORT_SYMBOL(node_data); + +static struct numa_meminfo numa_meminfo +#ifndef CONFIG_MEMORY_HOTPLUG +__initdata +#endif +; + +static int numa_distance_cnt; +static u8 *numa_distance; static __init int numa_setup(char *opt) { @@ -32,6 +60,15 @@ s16 __apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = { [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE }; +int __cpuinit numa_cpu_node(int cpu) +{ + int apicid = early_per_cpu(x86_cpu_to_apicid, cpu); + + if (apicid != BAD_APICID) + return __apicid_to_node[apicid]; + return NUMA_NO_NODE; +} + cpumask_var_t node_to_cpumask_map[MAX_NUMNODES]; EXPORT_SYMBOL(node_to_cpumask_map); @@ -95,6 +132,407 @@ void __init setup_node_to_cpumask_map(void) pr_debug("Node to cpumask map for %d nodes\n", nr_node_ids); } +static int __init numa_add_memblk_to(int nid, u64 start, u64 end, + struct numa_meminfo *mi) +{ + /* ignore zero length blks */ + if (start == end) + return 0; + + /* whine about and ignore invalid blks */ + if (start > end || nid < 0 || nid >= MAX_NUMNODES) { + pr_warning("NUMA: Warning: invalid memblk node %d (%Lx-%Lx)\n", + nid, start, end); + return 0; + } + + if (mi->nr_blks >= NR_NODE_MEMBLKS) { + pr_err("NUMA: too many memblk ranges\n"); + return -EINVAL; + } + + mi->blk[mi->nr_blks].start = start; + mi->blk[mi->nr_blks].end = end; + mi->blk[mi->nr_blks].nid = nid; + mi->nr_blks++; + return 0; +} + +/** + * numa_remove_memblk_from - Remove one numa_memblk from a numa_meminfo + * @idx: Index of memblk to remove + * @mi: numa_meminfo to remove memblk from + * + * Remove @idx'th numa_memblk from @mi by shifting @mi->blk[] and + * decrementing @mi->nr_blks. + */ +void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi) +{ + mi->nr_blks--; + memmove(&mi->blk[idx], &mi->blk[idx + 1], + (mi->nr_blks - idx) * sizeof(mi->blk[0])); +} + +/** + * numa_add_memblk - Add one numa_memblk to numa_meminfo + * @nid: NUMA node ID of the new memblk + * @start: Start address of the new memblk + * @end: End address of the new memblk + * + * Add a new memblk to the default numa_meminfo. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int __init numa_add_memblk(int nid, u64 start, u64 end) +{ + return numa_add_memblk_to(nid, start, end, &numa_meminfo); +} + +/* Initialize NODE_DATA for a node on the local memory */ +static void __init setup_node_data(int nid, u64 start, u64 end) +{ + const u64 nd_low = PFN_PHYS(MAX_DMA_PFN); + const u64 nd_high = PFN_PHYS(max_pfn_mapped); + const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE); + bool remapped = false; + u64 nd_pa; + void *nd; + int tnid; + + /* + * Don't confuse VM with a node that doesn't have the + * minimum amount of memory: + */ + if (end && (end - start) < NODE_MIN_SIZE) + return; + + /* initialize remap allocator before aligning to ZONE_ALIGN */ + init_alloc_remap(nid, start, end); + + start = roundup(start, ZONE_ALIGN); + + printk(KERN_INFO "Initmem setup node %d %016Lx-%016Lx\n", + nid, start, end); + + /* + * Allocate node data. Try remap allocator first, node-local + * memory and then any node. Never allocate in DMA zone. + */ + nd = alloc_remap(nid, nd_size); + if (nd) { + nd_pa = __pa(nd); + remapped = true; + } else { + nd_pa = memblock_x86_find_in_range_node(nid, nd_low, nd_high, + nd_size, SMP_CACHE_BYTES); + if (nd_pa == MEMBLOCK_ERROR) + nd_pa = memblock_find_in_range(nd_low, nd_high, + nd_size, SMP_CACHE_BYTES); + if (nd_pa == MEMBLOCK_ERROR) { + pr_err("Cannot find %zu bytes in node %d\n", + nd_size, nid); + return; + } + memblock_x86_reserve_range(nd_pa, nd_pa + nd_size, "NODE_DATA"); + nd = __va(nd_pa); + } + + /* report and initialize */ + printk(KERN_INFO " NODE_DATA [%016Lx - %016Lx]%s\n", + nd_pa, nd_pa + nd_size - 1, remapped ? " (remapped)" : ""); + tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT); + if (!remapped && tnid != nid) + printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nid, tnid); + + node_data[nid] = nd; + memset(NODE_DATA(nid), 0, sizeof(pg_data_t)); + NODE_DATA(nid)->node_id = nid; + NODE_DATA(nid)->node_start_pfn = start >> PAGE_SHIFT; + NODE_DATA(nid)->node_spanned_pages = (end - start) >> PAGE_SHIFT; + + node_set_online(nid); +} + +/** + * numa_cleanup_meminfo - Cleanup a numa_meminfo + * @mi: numa_meminfo to clean up + * + * Sanitize @mi by merging and removing unncessary memblks. Also check for + * conflicts and clear unused memblks. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int __init numa_cleanup_meminfo(struct numa_meminfo *mi) +{ + const u64 low = 0; + const u64 high = PFN_PHYS(max_pfn); + int i, j, k; + + /* first, trim all entries */ + for (i = 0; i < mi->nr_blks; i++) { + struct numa_memblk *bi = &mi->blk[i]; + + /* make sure all blocks are inside the limits */ + bi->start = max(bi->start, low); + bi->end = min(bi->end, high); + + /* and there's no empty block */ + if (bi->start >= bi->end) + numa_remove_memblk_from(i--, mi); + } + + /* merge neighboring / overlapping entries */ + for (i = 0; i < mi->nr_blks; i++) { + struct numa_memblk *bi = &mi->blk[i]; + + for (j = i + 1; j < mi->nr_blks; j++) { + struct numa_memblk *bj = &mi->blk[j]; + u64 start, end; + + /* + * See whether there are overlapping blocks. Whine + * about but allow overlaps of the same nid. They + * will be merged below. + */ + if (bi->end > bj->start && bi->start < bj->end) { + if (bi->nid != bj->nid) { + pr_err("NUMA: node %d (%Lx-%Lx) overlaps with node %d (%Lx-%Lx)\n", + bi->nid, bi->start, bi->end, + bj->nid, bj->start, bj->end); + return -EINVAL; + } + pr_warning("NUMA: Warning: node %d (%Lx-%Lx) overlaps with itself (%Lx-%Lx)\n", + bi->nid, bi->start, bi->end, + bj->start, bj->end); + } + + /* + * Join together blocks on the same node, holes + * between which don't overlap with memory on other + * nodes. + */ + if (bi->nid != bj->nid) + continue; + start = min(bi->start, bj->start); + end = max(bi->end, bj->end); + for (k = 0; k < mi->nr_blks; k++) { + struct numa_memblk *bk = &mi->blk[k]; + + if (bi->nid == bk->nid) + continue; + if (start < bk->end && end > bk->start) + break; + } + if (k < mi->nr_blks) + continue; + printk(KERN_INFO "NUMA: Node %d [%Lx,%Lx) + [%Lx,%Lx) -> [%Lx,%Lx)\n", + bi->nid, bi->start, bi->end, bj->start, bj->end, + start, end); + bi->start = start; + bi->end = end; + numa_remove_memblk_from(j--, mi); + } + } + + /* clear unused ones */ + for (i = mi->nr_blks; i < ARRAY_SIZE(mi->blk); i++) { + mi->blk[i].start = mi->blk[i].end = 0; + mi->blk[i].nid = NUMA_NO_NODE; + } + + return 0; +} + +/* + * Set nodes, which have memory in @mi, in *@nodemask. + */ +static void __init numa_nodemask_from_meminfo(nodemask_t *nodemask, + const struct numa_meminfo *mi) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mi->blk); i++) + if (mi->blk[i].start != mi->blk[i].end && + mi->blk[i].nid != NUMA_NO_NODE) + node_set(mi->blk[i].nid, *nodemask); +} + +/** + * numa_reset_distance - Reset NUMA distance table + * + * The current table is freed. The next numa_set_distance() call will + * create a new one. + */ +void __init numa_reset_distance(void) +{ + size_t size = numa_distance_cnt * numa_distance_cnt * sizeof(numa_distance[0]); + + /* numa_distance could be 1LU marking allocation failure, test cnt */ + if (numa_distance_cnt) + memblock_x86_free_range(__pa(numa_distance), + __pa(numa_distance) + size); + numa_distance_cnt = 0; + numa_distance = NULL; /* enable table creation */ +} + +static int __init numa_alloc_distance(void) +{ + nodemask_t nodes_parsed; + size_t size; + int i, j, cnt = 0; + u64 phys; + + /* size the new table and allocate it */ + nodes_parsed = numa_nodes_parsed; + numa_nodemask_from_meminfo(&nodes_parsed, &numa_meminfo); + + for_each_node_mask(i, nodes_parsed) + cnt = i; + cnt++; + size = cnt * cnt * sizeof(numa_distance[0]); + + phys = memblock_find_in_range(0, PFN_PHYS(max_pfn_mapped), + size, PAGE_SIZE); + if (phys == MEMBLOCK_ERROR) { + pr_warning("NUMA: Warning: can't allocate distance table!\n"); + /* don't retry until explicitly reset */ + numa_distance = (void *)1LU; + return -ENOMEM; + } + memblock_x86_reserve_range(phys, phys + size, "NUMA DIST"); + + numa_distance = __va(phys); + numa_distance_cnt = cnt; + + /* fill with the default distances */ + for (i = 0; i < cnt; i++) + for (j = 0; j < cnt; j++) + numa_distance[i * cnt + j] = i == j ? + LOCAL_DISTANCE : REMOTE_DISTANCE; + printk(KERN_DEBUG "NUMA: Initialized distance table, cnt=%d\n", cnt); + + return 0; +} + +/** + * numa_set_distance - Set NUMA distance from one NUMA to another + * @from: the 'from' node to set distance + * @to: the 'to' node to set distance + * @distance: NUMA distance + * + * Set the distance from node @from to @to to @distance. If distance table + * doesn't exist, one which is large enough to accommodate all the currently + * known nodes will be created. + * + * If such table cannot be allocated, a warning is printed and further + * calls are ignored until the distance table is reset with + * numa_reset_distance(). + * + * If @from or @to is higher than the highest known node at the time of + * table creation or @distance doesn't make sense, the call is ignored. + * This is to allow simplification of specific NUMA config implementations. + */ +void __init numa_set_distance(int from, int to, int distance) +{ + if (!numa_distance && numa_alloc_distance() < 0) + return; + + if (from >= numa_distance_cnt || to >= numa_distance_cnt) { + printk_once(KERN_DEBUG "NUMA: Debug: distance out of bound, from=%d to=%d distance=%d\n", + from, to, distance); + return; + } + + if ((u8)distance != distance || + (from == to && distance != LOCAL_DISTANCE)) { + pr_warn_once("NUMA: Warning: invalid distance parameter, from=%d to=%d distance=%d\n", + from, to, distance); + return; + } + + numa_distance[from * numa_distance_cnt + to] = distance; +} + +int __node_distance(int from, int to) +{ + if (from >= numa_distance_cnt || to >= numa_distance_cnt) + return from == to ? LOCAL_DISTANCE : REMOTE_DISTANCE; + return numa_distance[from * numa_distance_cnt + to]; +} +EXPORT_SYMBOL(__node_distance); + +/* + * Sanity check to catch more bad NUMA configurations (they are amazingly + * common). Make sure the nodes cover all memory. + */ +static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi) +{ + u64 numaram, e820ram; + int i; + + numaram = 0; + for (i = 0; i < mi->nr_blks; i++) { + u64 s = mi->blk[i].start >> PAGE_SHIFT; + u64 e = mi->blk[i].end >> PAGE_SHIFT; + numaram += e - s; + numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e); + if ((s64)numaram < 0) + numaram = 0; + } + + e820ram = max_pfn - (memblock_x86_hole_size(0, + PFN_PHYS(max_pfn)) >> PAGE_SHIFT); + /* We seem to lose 3 pages somewhere. Allow 1M of slack. */ + if ((s64)(e820ram - numaram) >= (1 << (20 - PAGE_SHIFT))) { + printk(KERN_ERR "NUMA: nodes only cover %LuMB of your %LuMB e820 RAM. Not used.\n", + (numaram << PAGE_SHIFT) >> 20, + (e820ram << PAGE_SHIFT) >> 20); + return false; + } + return true; +} + +static int __init numa_register_memblks(struct numa_meminfo *mi) +{ + int i, nid; + + /* Account for nodes with cpus and no memory */ + node_possible_map = numa_nodes_parsed; + numa_nodemask_from_meminfo(&node_possible_map, mi); + if (WARN_ON(nodes_empty(node_possible_map))) + return -EINVAL; + + for (i = 0; i < mi->nr_blks; i++) + memblock_x86_register_active_regions(mi->blk[i].nid, + mi->blk[i].start >> PAGE_SHIFT, + mi->blk[i].end >> PAGE_SHIFT); + + /* for out of order entries */ + sort_node_map(); + if (!numa_meminfo_cover_memory(mi)) + return -EINVAL; + + /* Finally register nodes. */ + for_each_node_mask(nid, node_possible_map) { + u64 start = PFN_PHYS(max_pfn); + u64 end = 0; + + for (i = 0; i < mi->nr_blks; i++) { + if (nid != mi->blk[i].nid) + continue; + start = min(mi->blk[i].start, start); + end = max(mi->blk[i].end, end); + } + + if (start < end) + setup_node_data(nid, start, end); + } + + return 0; +} + /* * There are unfortunately some poorly designed mainboards around that * only connect memory to a single CPU. This breaks the 1:1 cpu->node @@ -102,7 +540,7 @@ void __init setup_node_to_cpumask_map(void) * as the number of CPUs is not known yet. We round robin the existing * nodes. */ -void __init numa_init_array(void) +static void __init numa_init_array(void) { int rr, i; @@ -117,6 +555,95 @@ void __init numa_init_array(void) } } +static int __init numa_init(int (*init_func)(void)) +{ + int i; + int ret; + + for (i = 0; i < MAX_LOCAL_APIC; i++) + set_apicid_to_node(i, NUMA_NO_NODE); + + nodes_clear(numa_nodes_parsed); + nodes_clear(node_possible_map); + nodes_clear(node_online_map); + memset(&numa_meminfo, 0, sizeof(numa_meminfo)); + remove_all_active_ranges(); + numa_reset_distance(); + + ret = init_func(); + if (ret < 0) + return ret; + ret = numa_cleanup_meminfo(&numa_meminfo); + if (ret < 0) + return ret; + + numa_emulation(&numa_meminfo, numa_distance_cnt); + + ret = numa_register_memblks(&numa_meminfo); + if (ret < 0) + return ret; + + for (i = 0; i < nr_cpu_ids; i++) { + int nid = early_cpu_to_node(i); + + if (nid == NUMA_NO_NODE) + continue; + if (!node_online(nid)) + numa_clear_node(i); + } + numa_init_array(); + return 0; +} + +/** + * dummy_numa_init - Fallback dummy NUMA init + * + * Used if there's no underlying NUMA architecture, NUMA initialization + * fails, or NUMA is disabled on the command line. + * + * Must online at least one node and add memory blocks that cover all + * allowed memory. This function must not fail. + */ +static int __init dummy_numa_init(void) +{ + printk(KERN_INFO "%s\n", + numa_off ? "NUMA turned off" : "No NUMA configuration found"); + printk(KERN_INFO "Faking a node at %016Lx-%016Lx\n", + 0LLU, PFN_PHYS(max_pfn)); + + node_set(0, numa_nodes_parsed); + numa_add_memblk(0, 0, PFN_PHYS(max_pfn)); + + return 0; +} + +/** + * x86_numa_init - Initialize NUMA + * + * Try each configured NUMA initialization method until one succeeds. The + * last fallback is dummy single node config encomapssing whole memory and + * never fails. + */ +void __init x86_numa_init(void) +{ + if (!numa_off) { +#ifdef CONFIG_X86_NUMAQ + if (!numa_init(numaq_numa_init)) + return; +#endif +#ifdef CONFIG_ACPI_NUMA + if (!numa_init(x86_acpi_numa_init)) + return; +#endif +#ifdef CONFIG_AMD_NUMA + if (!numa_init(amd_numa_init)) + return; +#endif + } + + numa_init(dummy_numa_init); +} + static __init int find_near_online_node(int node) { int n, val; @@ -213,53 +740,48 @@ int early_cpu_to_node(int cpu) return per_cpu(x86_cpu_to_node_map, cpu); } -struct cpumask __cpuinit *debug_cpumask_set_cpu(int cpu, int enable) +void debug_cpumask_set_cpu(int cpu, int node, bool enable) { - int node = early_cpu_to_node(cpu); struct cpumask *mask; char buf[64]; if (node == NUMA_NO_NODE) { /* early_cpu_to_node() already emits a warning and trace */ - return NULL; + return; } mask = node_to_cpumask_map[node]; if (!mask) { pr_err("node_to_cpumask_map[%i] NULL\n", node); dump_stack(); - return NULL; - } - - cpulist_scnprintf(buf, sizeof(buf), mask); - printk(KERN_DEBUG "%s cpu %d node %d: mask now %s\n", - enable ? "numa_add_cpu" : "numa_remove_cpu", - cpu, node, buf); - return mask; -} - -# ifndef CONFIG_NUMA_EMU -static void __cpuinit numa_set_cpumask(int cpu, int enable) -{ - struct cpumask *mask; - - mask = debug_cpumask_set_cpu(cpu, enable); - if (!mask) return; + } if (enable) cpumask_set_cpu(cpu, mask); else cpumask_clear_cpu(cpu, mask); + + cpulist_scnprintf(buf, sizeof(buf), mask); + printk(KERN_DEBUG "%s cpu %d node %d: mask now %s\n", + enable ? "numa_add_cpu" : "numa_remove_cpu", + cpu, node, buf); + return; +} + +# ifndef CONFIG_NUMA_EMU +static void __cpuinit numa_set_cpumask(int cpu, bool enable) +{ + debug_cpumask_set_cpu(cpu, early_cpu_to_node(cpu), enable); } void __cpuinit numa_add_cpu(int cpu) { - numa_set_cpumask(cpu, 1); + numa_set_cpumask(cpu, true); } void __cpuinit numa_remove_cpu(int cpu) { - numa_set_cpumask(cpu, 0); + numa_set_cpumask(cpu, false); } # endif /* !CONFIG_NUMA_EMU */ @@ -287,3 +809,18 @@ const struct cpumask *cpumask_of_node(int node) EXPORT_SYMBOL(cpumask_of_node); #endif /* !CONFIG_DEBUG_PER_CPU_MAPS */ + +#ifdef CONFIG_MEMORY_HOTPLUG +int memory_add_physaddr_to_nid(u64 start) +{ + struct numa_meminfo *mi = &numa_meminfo; + int nid = mi->blk[0].nid; + int i; + + for (i = 0; i < mi->nr_blks; i++) + if (mi->blk[i].start <= start && mi->blk[i].end > start) + nid = mi->blk[i].nid; + return nid; +} +EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); +#endif diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index bde3906420df..849a975d3fa0 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -22,39 +22,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include -#include -#include -#include -#include #include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; -EXPORT_SYMBOL(node_data); - -/* - * numa interface - we expect the numa architecture specific code to have - * populated the following initialisation. - * - * 1) node_online_map - the map of all nodes configured (online) in the system - * 2) node_start_pfn - the starting page frame number for a node - * 3) node_end_pfn - the ending page fram number for a node - */ -unsigned long node_start_pfn[MAX_NUMNODES] __read_mostly; -unsigned long node_end_pfn[MAX_NUMNODES] __read_mostly; +#include "numa_internal.h" #ifdef CONFIG_DISCONTIGMEM /* @@ -99,108 +71,46 @@ unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn, } #endif -extern unsigned long find_max_low_pfn(void); extern unsigned long highend_pfn, highstart_pfn; #define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE) -unsigned long node_remap_size[MAX_NUMNODES]; static void *node_remap_start_vaddr[MAX_NUMNODES]; void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); -static unsigned long kva_start_pfn; -static unsigned long kva_pages; - -int __cpuinit numa_cpu_node(int cpu) -{ - return apic->x86_32_numa_cpu_node(cpu); -} - /* - * FLAT - support for basic PC memory model with discontig enabled, essentially - * a single node with all available processors in it with a flat - * memory map. - */ -int __init get_memcfg_numa_flat(void) -{ - printk(KERN_DEBUG "NUMA - single node, flat memory mode\n"); - - node_start_pfn[0] = 0; - node_end_pfn[0] = max_pfn; - memblock_x86_register_active_regions(0, 0, max_pfn); - memory_present(0, 0, max_pfn); - node_remap_size[0] = node_memmap_size_bytes(0, 0, max_pfn); - - /* Indicate there is one node available. */ - nodes_clear(node_online_map); - node_set_online(0); - return 1; -} - -/* - * Find the highest page frame number we have available for the node - */ -static void __init propagate_e820_map_node(int nid) -{ - if (node_end_pfn[nid] > max_pfn) - node_end_pfn[nid] = max_pfn; - /* - * if a user has given mem=XXXX, then we need to make sure - * that the node _starts_ before that, too, not just ends - */ - if (node_start_pfn[nid] > max_pfn) - node_start_pfn[nid] = max_pfn; - BUG_ON(node_start_pfn[nid] > node_end_pfn[nid]); -} - -/* - * Allocate memory for the pg_data_t for this node via a crude pre-bootmem - * method. For node zero take this from the bottom of memory, for - * subsequent nodes place them at node_remap_start_vaddr which contains - * node local data in physically node local memory. See setup_memory() - * for details. - */ -static void __init allocate_pgdat(int nid) -{ - char buf[16]; - - if (node_has_online_mem(nid) && node_remap_start_vaddr[nid]) - NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid]; - else { - unsigned long pgdat_phys; - pgdat_phys = memblock_find_in_range(min_low_pfn<>PAGE_SHIFT)); - memset(buf, 0, sizeof(buf)); - sprintf(buf, "NODE_DATA %d", nid); - memblock_x86_reserve_range(pgdat_phys, pgdat_phys + sizeof(pg_data_t), buf); - } - printk(KERN_DEBUG "allocate_pgdat: node %d NODE_DATA %08lx\n", - nid, (unsigned long)NODE_DATA(nid)); -} - -/* - * In the DISCONTIGMEM and SPARSEMEM memory model, a portion of the kernel - * virtual address space (KVA) is reserved and portions of nodes are mapped - * using it. This is to allow node-local memory to be allocated for - * structures that would normally require ZONE_NORMAL. The memory is - * allocated with alloc_remap() and callers should be prepared to allocate - * from the bootmem allocator instead. + * Remap memory allocator */ static unsigned long node_remap_start_pfn[MAX_NUMNODES]; static void *node_remap_end_vaddr[MAX_NUMNODES]; static void *node_remap_alloc_vaddr[MAX_NUMNODES]; -static unsigned long node_remap_offset[MAX_NUMNODES]; +/** + * alloc_remap - Allocate remapped memory + * @nid: NUMA node to allocate memory from + * @size: The size of allocation + * + * Allocate @size bytes from the remap area of NUMA node @nid. The + * size of the remap area is predetermined by init_alloc_remap() and + * only the callers considered there should call this function. For + * more info, please read the comment on top of init_alloc_remap(). + * + * The caller must be ready to handle allocation failure from this + * function and fall back to regular memory allocator in such cases. + * + * CONTEXT: + * Single CPU early boot context. + * + * RETURNS: + * Pointer to the allocated memory on success, %NULL on failure. + */ void *alloc_remap(int nid, unsigned long size) { void *allocation = node_remap_alloc_vaddr[nid]; size = ALIGN(size, L1_CACHE_BYTES); - if (!allocation || (allocation + size) >= node_remap_end_vaddr[nid]) + if (!allocation || (allocation + size) > node_remap_end_vaddr[nid]) return NULL; node_remap_alloc_vaddr[nid] += size; @@ -209,26 +119,6 @@ void *alloc_remap(int nid, unsigned long size) return allocation; } -static void __init remap_numa_kva(void) -{ - void *vaddr; - unsigned long pfn; - int node; - - for_each_online_node(node) { - printk(KERN_DEBUG "remap_numa_kva: node %d\n", node); - for (pfn=0; pfn < node_remap_size[node]; pfn += PTRS_PER_PTE) { - vaddr = node_remap_start_vaddr[node]+(pfn<> PAGE_SHIFT; printk(KERN_DEBUG "%s: node %d\n", __func__, node); - for (pfn = 0; pfn < size; pfn += PTRS_PER_PTE) { + for (pfn = 0; pfn < nr_pages; pfn += PTRS_PER_PTE) { unsigned long vaddr = start_va + (pfn << PAGE_SHIFT); pgd_t *pgd = pgd_base + pgd_index(vaddr); pud_t *pud = pud_offset(pgd, vaddr); @@ -264,132 +155,89 @@ void resume_map_numa_kva(pgd_t *pgd_base) } #endif -static __init unsigned long calculate_numa_remap_pages(void) +/** + * init_alloc_remap - Initialize remap allocator for a NUMA node + * @nid: NUMA node to initizlie remap allocator for + * + * NUMA nodes may end up without any lowmem. As allocating pgdat and + * memmap on a different node with lowmem is inefficient, a special + * remap allocator is implemented which can be used by alloc_remap(). + * + * For each node, the amount of memory which will be necessary for + * pgdat and memmap is calculated and two memory areas of the size are + * allocated - one in the node and the other in lowmem; then, the area + * in the node is remapped to the lowmem area. + * + * As pgdat and memmap must be allocated in lowmem anyway, this + * doesn't waste lowmem address space; however, the actual lowmem + * which gets remapped over is wasted. The amount shouldn't be + * problematic on machines this feature will be used. + * + * Initialization failure isn't fatal. alloc_remap() is used + * opportunistically and the callers will fall back to other memory + * allocation mechanisms on failure. + */ +void __init init_alloc_remap(int nid, u64 start, u64 end) { - int nid; - unsigned long size, reserve_pages = 0; + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long end_pfn = end >> PAGE_SHIFT; + unsigned long size, pfn; + u64 node_pa, remap_pa; + void *remap_va; - for_each_online_node(nid) { - u64 node_kva_target; - u64 node_kva_final; + /* + * The acpi/srat node info can show hot-add memroy zones where + * memory could be added but not currently present. + */ + printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n", + nid, start_pfn, end_pfn); - /* - * The acpi/srat node info can show hot-add memroy zones - * where memory could be added but not currently present. - */ - printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n", - nid, node_start_pfn[nid], node_end_pfn[nid]); - if (node_start_pfn[nid] > max_pfn) - continue; - if (!node_end_pfn[nid]) - continue; - if (node_end_pfn[nid] > max_pfn) - node_end_pfn[nid] = max_pfn; + /* calculate the necessary space aligned to large page size */ + size = node_memmap_size_bytes(nid, start_pfn, end_pfn); + size += ALIGN(sizeof(pg_data_t), PAGE_SIZE); + size = ALIGN(size, LARGE_PAGE_BYTES); - /* ensure the remap includes space for the pgdat. */ - size = node_remap_size[nid] + sizeof(pg_data_t); - - /* convert size to large (pmd size) pages, rounding up */ - size = (size + LARGE_PAGE_BYTES - 1) / LARGE_PAGE_BYTES; - /* now the roundup is correct, convert to PAGE_SIZE pages */ - size = size * PTRS_PER_PTE; - - node_kva_target = round_down(node_end_pfn[nid] - size, - PTRS_PER_PTE); - node_kva_target <<= PAGE_SHIFT; - do { - node_kva_final = memblock_find_in_range(node_kva_target, - ((u64)node_end_pfn[nid])<>PAGE_SHIFT) > (node_start_pfn[nid])); - - if (node_kva_final == MEMBLOCK_ERROR) - panic("Can not get kva ram\n"); - - node_remap_size[nid] = size; - node_remap_offset[nid] = reserve_pages; - reserve_pages += size; - printk(KERN_DEBUG "Reserving %ld pages of KVA for lmem_map of" - " node %d at %llx\n", - size, nid, node_kva_final>>PAGE_SHIFT); - - /* - * prevent kva address below max_low_pfn want it on system - * with less memory later. - * layout will be: KVA address , KVA RAM - * - * we are supposed to only record the one less then max_low_pfn - * but we could have some hole in high memory, and it will only - * check page_is_ram(pfn) && !page_is_reserved_early(pfn) to decide - * to use it as free. - * So memblock_x86_reserve_range here, hope we don't run out of that array - */ - memblock_x86_reserve_range(node_kva_final, - node_kva_final+(((u64)size)<>PAGE_SHIFT; + /* allocate node memory and the lowmem remap area */ + node_pa = memblock_find_in_range(start, end, size, LARGE_PAGE_BYTES); + if (node_pa == MEMBLOCK_ERROR) { + pr_warning("remap_alloc: failed to allocate %lu bytes for node %d\n", + size, nid); + return; } - printk(KERN_INFO "Reserving total of %lx pages for numa KVA remap\n", - reserve_pages); - return reserve_pages; -} + memblock_x86_reserve_range(node_pa, node_pa + size, "KVA RAM"); -static void init_remap_allocator(int nid) -{ - node_remap_start_vaddr[nid] = pfn_to_kaddr( - kva_start_pfn + node_remap_offset[nid]); - node_remap_end_vaddr[nid] = node_remap_start_vaddr[nid] + - (node_remap_size[nid] * PAGE_SIZE); - node_remap_alloc_vaddr[nid] = node_remap_start_vaddr[nid] + - ALIGN(sizeof(pg_data_t), PAGE_SIZE); + remap_pa = memblock_find_in_range(min_low_pfn << PAGE_SHIFT, + max_low_pfn << PAGE_SHIFT, + size, LARGE_PAGE_BYTES); + if (remap_pa == MEMBLOCK_ERROR) { + pr_warning("remap_alloc: failed to allocate %lu bytes remap area for node %d\n", + size, nid); + memblock_x86_free_range(node_pa, node_pa + size); + return; + } + memblock_x86_reserve_range(remap_pa, remap_pa + size, "KVA PG"); + remap_va = phys_to_virt(remap_pa); - printk(KERN_DEBUG "node %d will remap to vaddr %08lx - %08lx\n", nid, - (ulong) node_remap_start_vaddr[nid], - (ulong) node_remap_end_vaddr[nid]); + /* perform actual remap */ + for (pfn = 0; pfn < size >> PAGE_SHIFT; pfn += PTRS_PER_PTE) + set_pmd_pfn((unsigned long)remap_va + (pfn << PAGE_SHIFT), + (node_pa >> PAGE_SHIFT) + pfn, + PAGE_KERNEL_LARGE); + + /* initialize remap allocator parameters */ + node_remap_start_pfn[nid] = node_pa >> PAGE_SHIFT; + node_remap_start_vaddr[nid] = remap_va; + node_remap_end_vaddr[nid] = remap_va + size; + node_remap_alloc_vaddr[nid] = remap_va; + + printk(KERN_DEBUG "remap_alloc: node %d [%08llx-%08llx) -> [%p-%p)\n", + nid, node_pa, node_pa + size, remap_va, remap_va + size); } void __init initmem_init(void) { - int nid; - long kva_target_pfn; + x86_numa_init(); - /* - * When mapping a NUMA machine we allocate the node_mem_map arrays - * from node local memory. They are then mapped directly into KVA - * between zone normal and vmalloc space. Calculate the size of - * this space and use it to adjust the boundary between ZONE_NORMAL - * and ZONE_HIGHMEM. - */ - - get_memcfg_numa(); - numa_init_array(); - - kva_pages = roundup(calculate_numa_remap_pages(), PTRS_PER_PTE); - - kva_target_pfn = round_down(max_low_pfn - kva_pages, PTRS_PER_PTE); - do { - kva_start_pfn = memblock_find_in_range(kva_target_pfn<> PAGE_SHIFT; - kva_target_pfn -= PTRS_PER_PTE; - } while (kva_start_pfn == MEMBLOCK_ERROR && kva_target_pfn > min_low_pfn); - - if (kva_start_pfn == MEMBLOCK_ERROR) - panic("Can not get kva space\n"); - - printk(KERN_INFO "kva_start_pfn ~ %lx max_low_pfn ~ %lx\n", - kva_start_pfn, max_low_pfn); - printk(KERN_INFO "max_pfn = %lx\n", max_pfn); - - /* avoid clash with initrd */ - memblock_x86_reserve_range(kva_start_pfn< max_low_pfn) @@ -409,51 +257,9 @@ void __init initmem_init(void) printk(KERN_DEBUG "Low memory ends at vaddr %08lx\n", (ulong) pfn_to_kaddr(max_low_pfn)); - for_each_online_node(nid) { - init_remap_allocator(nid); - - allocate_pgdat(nid); - } - remap_numa_kva(); printk(KERN_DEBUG "High memory starts at vaddr %08lx\n", (ulong) pfn_to_kaddr(highstart_pfn)); - for_each_online_node(nid) - propagate_e820_map_node(nid); - - for_each_online_node(nid) { - memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); - NODE_DATA(nid)->node_id = nid; - } setup_bootmem_allocator(); } - -#ifdef CONFIG_MEMORY_HOTPLUG -static int paddr_to_nid(u64 addr) -{ - int nid; - unsigned long pfn = PFN_DOWN(addr); - - for_each_node(nid) - if (node_start_pfn[nid] <= pfn && - pfn < node_end_pfn[nid]) - return nid; - - return -1; -} - -/* - * This function is used to ask node id BEFORE memmap and mem_section's - * initialization (pfn_to_nid() can't be used yet). - * If _PXM is not defined on ACPI's DSDT, node id must be found by this. - */ -int memory_add_physaddr_to_nid(u64 addr) -{ - int nid = paddr_to_nid(addr); - return (nid >= 0) ? nid : 0; -} - -EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); -#endif - diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index e8c00cc72033..dd27f401f0a0 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -2,646 +2,13 @@ * Generic VM initialization for x86-64 NUMA setups. * Copyright 2002,2003 Andi Kleen, SuSE Labs. */ -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include #include "numa_internal.h" -struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; -EXPORT_SYMBOL(node_data); - -nodemask_t numa_nodes_parsed __initdata; - -struct memnode memnode; - -static unsigned long __initdata nodemap_addr; -static unsigned long __initdata nodemap_size; - -static struct numa_meminfo numa_meminfo __initdata; - -static int numa_distance_cnt; -static u8 *numa_distance; - -/* - * Given a shift value, try to populate memnodemap[] - * Returns : - * 1 if OK - * 0 if memnodmap[] too small (of shift too small) - * -1 if node overlap or lost ram (shift too big) - */ -static int __init populate_memnodemap(const struct numa_meminfo *mi, int shift) -{ - unsigned long addr, end; - int i, res = -1; - - memset(memnodemap, 0xff, sizeof(s16)*memnodemapsize); - for (i = 0; i < mi->nr_blks; i++) { - addr = mi->blk[i].start; - end = mi->blk[i].end; - if (addr >= end) - continue; - if ((end >> shift) >= memnodemapsize) - return 0; - do { - if (memnodemap[addr >> shift] != NUMA_NO_NODE) - return -1; - memnodemap[addr >> shift] = mi->blk[i].nid; - addr += (1UL << shift); - } while (addr < end); - res = 1; - } - return res; -} - -static int __init allocate_cachealigned_memnodemap(void) -{ - unsigned long addr; - - memnodemap = memnode.embedded_map; - if (memnodemapsize <= ARRAY_SIZE(memnode.embedded_map)) - return 0; - - addr = 0x8000; - nodemap_size = roundup(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES); - nodemap_addr = memblock_find_in_range(addr, get_max_mapped(), - nodemap_size, L1_CACHE_BYTES); - if (nodemap_addr == MEMBLOCK_ERROR) { - printk(KERN_ERR - "NUMA: Unable to allocate Memory to Node hash map\n"); - nodemap_addr = nodemap_size = 0; - return -1; - } - memnodemap = phys_to_virt(nodemap_addr); - memblock_x86_reserve_range(nodemap_addr, nodemap_addr + nodemap_size, "MEMNODEMAP"); - - printk(KERN_DEBUG "NUMA: Allocated memnodemap from %lx - %lx\n", - nodemap_addr, nodemap_addr + nodemap_size); - return 0; -} - -/* - * The LSB of all start and end addresses in the node map is the value of the - * maximum possible shift. - */ -static int __init extract_lsb_from_nodes(const struct numa_meminfo *mi) -{ - int i, nodes_used = 0; - unsigned long start, end; - unsigned long bitfield = 0, memtop = 0; - - for (i = 0; i < mi->nr_blks; i++) { - start = mi->blk[i].start; - end = mi->blk[i].end; - if (start >= end) - continue; - bitfield |= start; - nodes_used++; - if (end > memtop) - memtop = end; - } - if (nodes_used <= 1) - i = 63; - else - i = find_first_bit(&bitfield, sizeof(unsigned long)*8); - memnodemapsize = (memtop >> i)+1; - return i; -} - -static int __init compute_hash_shift(const struct numa_meminfo *mi) -{ - int shift; - - shift = extract_lsb_from_nodes(mi); - if (allocate_cachealigned_memnodemap()) - return -1; - printk(KERN_DEBUG "NUMA: Using %d for the hash shift.\n", - shift); - - if (populate_memnodemap(mi, shift) != 1) { - printk(KERN_INFO "Your memory is not aligned you need to " - "rebuild your kernel with a bigger NODEMAPSIZE " - "shift=%d\n", shift); - return -1; - } - return shift; -} - -int __meminit __early_pfn_to_nid(unsigned long pfn) -{ - return phys_to_nid(pfn << PAGE_SHIFT); -} - -static void * __init early_node_mem(int nodeid, unsigned long start, - unsigned long end, unsigned long size, - unsigned long align) -{ - unsigned long mem; - - /* - * put it on high as possible - * something will go with NODE_DATA - */ - if (start < (MAX_DMA_PFN< (MAX_DMA32_PFN< end || nid < 0 || nid >= MAX_NUMNODES) { - pr_warning("NUMA: Warning: invalid memblk node %d (%Lx-%Lx)\n", - nid, start, end); - return 0; - } - - if (mi->nr_blks >= NR_NODE_MEMBLKS) { - pr_err("NUMA: too many memblk ranges\n"); - return -EINVAL; - } - - mi->blk[mi->nr_blks].start = start; - mi->blk[mi->nr_blks].end = end; - mi->blk[mi->nr_blks].nid = nid; - mi->nr_blks++; - return 0; -} - -/** - * numa_remove_memblk_from - Remove one numa_memblk from a numa_meminfo - * @idx: Index of memblk to remove - * @mi: numa_meminfo to remove memblk from - * - * Remove @idx'th numa_memblk from @mi by shifting @mi->blk[] and - * decrementing @mi->nr_blks. - */ -void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi) -{ - mi->nr_blks--; - memmove(&mi->blk[idx], &mi->blk[idx + 1], - (mi->nr_blks - idx) * sizeof(mi->blk[0])); -} - -/** - * numa_add_memblk - Add one numa_memblk to numa_meminfo - * @nid: NUMA node ID of the new memblk - * @start: Start address of the new memblk - * @end: End address of the new memblk - * - * Add a new memblk to the default numa_meminfo. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int __init numa_add_memblk(int nid, u64 start, u64 end) -{ - return numa_add_memblk_to(nid, start, end, &numa_meminfo); -} - -/* Initialize bootmem allocator for a node */ -void __init -setup_node_bootmem(int nodeid, unsigned long start, unsigned long end) -{ - unsigned long start_pfn, last_pfn, nodedata_phys; - const int pgdat_size = roundup(sizeof(pg_data_t), PAGE_SIZE); - int nid; - - if (!end) - return; - - /* - * Don't confuse VM with a node that doesn't have the - * minimum amount of memory: - */ - if (end && (end - start) < NODE_MIN_SIZE) - return; - - start = roundup(start, ZONE_ALIGN); - - printk(KERN_INFO "Initmem setup node %d %016lx-%016lx\n", nodeid, - start, end); - - start_pfn = start >> PAGE_SHIFT; - last_pfn = end >> PAGE_SHIFT; - - node_data[nodeid] = early_node_mem(nodeid, start, end, pgdat_size, - SMP_CACHE_BYTES); - if (node_data[nodeid] == NULL) - return; - nodedata_phys = __pa(node_data[nodeid]); - memblock_x86_reserve_range(nodedata_phys, nodedata_phys + pgdat_size, "NODE_DATA"); - printk(KERN_INFO " NODE_DATA [%016lx - %016lx]\n", nodedata_phys, - nodedata_phys + pgdat_size - 1); - nid = phys_to_nid(nodedata_phys); - if (nid != nodeid) - printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nodeid, nid); - - memset(NODE_DATA(nodeid), 0, sizeof(pg_data_t)); - NODE_DATA(nodeid)->node_id = nodeid; - NODE_DATA(nodeid)->node_start_pfn = start_pfn; - NODE_DATA(nodeid)->node_spanned_pages = last_pfn - start_pfn; - - node_set_online(nodeid); -} - -/** - * numa_cleanup_meminfo - Cleanup a numa_meminfo - * @mi: numa_meminfo to clean up - * - * Sanitize @mi by merging and removing unncessary memblks. Also check for - * conflicts and clear unused memblks. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int __init numa_cleanup_meminfo(struct numa_meminfo *mi) -{ - const u64 low = 0; - const u64 high = (u64)max_pfn << PAGE_SHIFT; - int i, j, k; - - for (i = 0; i < mi->nr_blks; i++) { - struct numa_memblk *bi = &mi->blk[i]; - - /* make sure all blocks are inside the limits */ - bi->start = max(bi->start, low); - bi->end = min(bi->end, high); - - /* and there's no empty block */ - if (bi->start == bi->end) { - numa_remove_memblk_from(i--, mi); - continue; - } - - for (j = i + 1; j < mi->nr_blks; j++) { - struct numa_memblk *bj = &mi->blk[j]; - unsigned long start, end; - - /* - * See whether there are overlapping blocks. Whine - * about but allow overlaps of the same nid. They - * will be merged below. - */ - if (bi->end > bj->start && bi->start < bj->end) { - if (bi->nid != bj->nid) { - pr_err("NUMA: node %d (%Lx-%Lx) overlaps with node %d (%Lx-%Lx)\n", - bi->nid, bi->start, bi->end, - bj->nid, bj->start, bj->end); - return -EINVAL; - } - pr_warning("NUMA: Warning: node %d (%Lx-%Lx) overlaps with itself (%Lx-%Lx)\n", - bi->nid, bi->start, bi->end, - bj->start, bj->end); - } - - /* - * Join together blocks on the same node, holes - * between which don't overlap with memory on other - * nodes. - */ - if (bi->nid != bj->nid) - continue; - start = max(min(bi->start, bj->start), low); - end = min(max(bi->end, bj->end), high); - for (k = 0; k < mi->nr_blks; k++) { - struct numa_memblk *bk = &mi->blk[k]; - - if (bi->nid == bk->nid) - continue; - if (start < bk->end && end > bk->start) - break; - } - if (k < mi->nr_blks) - continue; - printk(KERN_INFO "NUMA: Node %d [%Lx,%Lx) + [%Lx,%Lx) -> [%lx,%lx)\n", - bi->nid, bi->start, bi->end, bj->start, bj->end, - start, end); - bi->start = start; - bi->end = end; - numa_remove_memblk_from(j--, mi); - } - } - - for (i = mi->nr_blks; i < ARRAY_SIZE(mi->blk); i++) { - mi->blk[i].start = mi->blk[i].end = 0; - mi->blk[i].nid = NUMA_NO_NODE; - } - - return 0; -} - -/* - * Set nodes, which have memory in @mi, in *@nodemask. - */ -static void __init numa_nodemask_from_meminfo(nodemask_t *nodemask, - const struct numa_meminfo *mi) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mi->blk); i++) - if (mi->blk[i].start != mi->blk[i].end && - mi->blk[i].nid != NUMA_NO_NODE) - node_set(mi->blk[i].nid, *nodemask); -} - -/** - * numa_reset_distance - Reset NUMA distance table - * - * The current table is freed. The next numa_set_distance() call will - * create a new one. - */ -void __init numa_reset_distance(void) -{ - size_t size = numa_distance_cnt * numa_distance_cnt * sizeof(numa_distance[0]); - - /* numa_distance could be 1LU marking allocation failure, test cnt */ - if (numa_distance_cnt) - memblock_x86_free_range(__pa(numa_distance), - __pa(numa_distance) + size); - numa_distance_cnt = 0; - numa_distance = NULL; /* enable table creation */ -} - -static int __init numa_alloc_distance(void) -{ - nodemask_t nodes_parsed; - size_t size; - int i, j, cnt = 0; - u64 phys; - - /* size the new table and allocate it */ - nodes_parsed = numa_nodes_parsed; - numa_nodemask_from_meminfo(&nodes_parsed, &numa_meminfo); - - for_each_node_mask(i, nodes_parsed) - cnt = i; - cnt++; - size = cnt * cnt * sizeof(numa_distance[0]); - - phys = memblock_find_in_range(0, (u64)max_pfn_mapped << PAGE_SHIFT, - size, PAGE_SIZE); - if (phys == MEMBLOCK_ERROR) { - pr_warning("NUMA: Warning: can't allocate distance table!\n"); - /* don't retry until explicitly reset */ - numa_distance = (void *)1LU; - return -ENOMEM; - } - memblock_x86_reserve_range(phys, phys + size, "NUMA DIST"); - - numa_distance = __va(phys); - numa_distance_cnt = cnt; - - /* fill with the default distances */ - for (i = 0; i < cnt; i++) - for (j = 0; j < cnt; j++) - numa_distance[i * cnt + j] = i == j ? - LOCAL_DISTANCE : REMOTE_DISTANCE; - printk(KERN_DEBUG "NUMA: Initialized distance table, cnt=%d\n", cnt); - - return 0; -} - -/** - * numa_set_distance - Set NUMA distance from one NUMA to another - * @from: the 'from' node to set distance - * @to: the 'to' node to set distance - * @distance: NUMA distance - * - * Set the distance from node @from to @to to @distance. If distance table - * doesn't exist, one which is large enough to accommodate all the currently - * known nodes will be created. - * - * If such table cannot be allocated, a warning is printed and further - * calls are ignored until the distance table is reset with - * numa_reset_distance(). - * - * If @from or @to is higher than the highest known node at the time of - * table creation or @distance doesn't make sense, the call is ignored. - * This is to allow simplification of specific NUMA config implementations. - */ -void __init numa_set_distance(int from, int to, int distance) -{ - if (!numa_distance && numa_alloc_distance() < 0) - return; - - if (from >= numa_distance_cnt || to >= numa_distance_cnt) { - printk_once(KERN_DEBUG "NUMA: Debug: distance out of bound, from=%d to=%d distance=%d\n", - from, to, distance); - return; - } - - if ((u8)distance != distance || - (from == to && distance != LOCAL_DISTANCE)) { - pr_warn_once("NUMA: Warning: invalid distance parameter, from=%d to=%d distance=%d\n", - from, to, distance); - return; - } - - numa_distance[from * numa_distance_cnt + to] = distance; -} - -int __node_distance(int from, int to) -{ - if (from >= numa_distance_cnt || to >= numa_distance_cnt) - return from == to ? LOCAL_DISTANCE : REMOTE_DISTANCE; - return numa_distance[from * numa_distance_cnt + to]; -} -EXPORT_SYMBOL(__node_distance); - -/* - * Sanity check to catch more bad NUMA configurations (they are amazingly - * common). Make sure the nodes cover all memory. - */ -static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi) -{ - unsigned long numaram, e820ram; - int i; - - numaram = 0; - for (i = 0; i < mi->nr_blks; i++) { - unsigned long s = mi->blk[i].start >> PAGE_SHIFT; - unsigned long e = mi->blk[i].end >> PAGE_SHIFT; - numaram += e - s; - numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e); - if ((long)numaram < 0) - numaram = 0; - } - - e820ram = max_pfn - (memblock_x86_hole_size(0, - max_pfn << PAGE_SHIFT) >> PAGE_SHIFT); - /* We seem to lose 3 pages somewhere. Allow 1M of slack. */ - if ((long)(e820ram - numaram) >= (1 << (20 - PAGE_SHIFT))) { - printk(KERN_ERR "NUMA: nodes only cover %luMB of your %luMB e820 RAM. Not used.\n", - (numaram << PAGE_SHIFT) >> 20, - (e820ram << PAGE_SHIFT) >> 20); - return false; - } - return true; -} - -static int __init numa_register_memblks(struct numa_meminfo *mi) -{ - int i, nid; - - /* Account for nodes with cpus and no memory */ - node_possible_map = numa_nodes_parsed; - numa_nodemask_from_meminfo(&node_possible_map, mi); - if (WARN_ON(nodes_empty(node_possible_map))) - return -EINVAL; - - memnode_shift = compute_hash_shift(mi); - if (memnode_shift < 0) { - printk(KERN_ERR "NUMA: No NUMA node hash function found. Contact maintainer\n"); - return -EINVAL; - } - - for (i = 0; i < mi->nr_blks; i++) - memblock_x86_register_active_regions(mi->blk[i].nid, - mi->blk[i].start >> PAGE_SHIFT, - mi->blk[i].end >> PAGE_SHIFT); - - /* for out of order entries */ - sort_node_map(); - if (!numa_meminfo_cover_memory(mi)) - return -EINVAL; - - /* Finally register nodes. */ - for_each_node_mask(nid, node_possible_map) { - u64 start = (u64)max_pfn << PAGE_SHIFT; - u64 end = 0; - - for (i = 0; i < mi->nr_blks; i++) { - if (nid != mi->blk[i].nid) - continue; - start = min(mi->blk[i].start, start); - end = max(mi->blk[i].end, end); - } - - if (start < end) - setup_node_bootmem(nid, start, end); - } - - return 0; -} - -/** - * dummy_numma_init - Fallback dummy NUMA init - * - * Used if there's no underlying NUMA architecture, NUMA initialization - * fails, or NUMA is disabled on the command line. - * - * Must online at least one node and add memory blocks that cover all - * allowed memory. This function must not fail. - */ -static int __init dummy_numa_init(void) -{ - printk(KERN_INFO "%s\n", - numa_off ? "NUMA turned off" : "No NUMA configuration found"); - printk(KERN_INFO "Faking a node at %016lx-%016lx\n", - 0LU, max_pfn << PAGE_SHIFT); - - node_set(0, numa_nodes_parsed); - numa_add_memblk(0, 0, (u64)max_pfn << PAGE_SHIFT); - - return 0; -} - -static int __init numa_init(int (*init_func)(void)) -{ - int i; - int ret; - - for (i = 0; i < MAX_LOCAL_APIC; i++) - set_apicid_to_node(i, NUMA_NO_NODE); - - nodes_clear(numa_nodes_parsed); - nodes_clear(node_possible_map); - nodes_clear(node_online_map); - memset(&numa_meminfo, 0, sizeof(numa_meminfo)); - remove_all_active_ranges(); - numa_reset_distance(); - - ret = init_func(); - if (ret < 0) - return ret; - ret = numa_cleanup_meminfo(&numa_meminfo); - if (ret < 0) - return ret; - - numa_emulation(&numa_meminfo, numa_distance_cnt); - - ret = numa_register_memblks(&numa_meminfo); - if (ret < 0) - return ret; - - for (i = 0; i < nr_cpu_ids; i++) { - int nid = early_cpu_to_node(i); - - if (nid == NUMA_NO_NODE) - continue; - if (!node_online(nid)) - numa_clear_node(i); - } - numa_init_array(); - return 0; -} - void __init initmem_init(void) { - int ret; - - if (!numa_off) { -#ifdef CONFIG_ACPI_NUMA - ret = numa_init(x86_acpi_numa_init); - if (!ret) - return; -#endif -#ifdef CONFIG_AMD_NUMA - ret = numa_init(amd_numa_init); - if (!ret) - return; -#endif - } - - numa_init(dummy_numa_init); + x86_numa_init(); } unsigned long __init numa_free_all_bootmem(void) @@ -656,12 +23,3 @@ unsigned long __init numa_free_all_bootmem(void) return pages; } - -int __cpuinit numa_cpu_node(int cpu) -{ - int apicid = early_per_cpu(x86_cpu_to_apicid, cpu); - - if (apicid != BAD_APICID) - return __apicid_to_node[apicid]; - return NUMA_NO_NODE; -} diff --git a/arch/x86/mm/numa_emulation.c b/arch/x86/mm/numa_emulation.c index ad091e4cff17..d0ed086b6247 100644 --- a/arch/x86/mm/numa_emulation.c +++ b/arch/x86/mm/numa_emulation.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "numa_internal.h" @@ -84,7 +85,13 @@ static int __init split_nodes_interleave(struct numa_meminfo *ei, nr_nodes = MAX_NUMNODES; } - size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) / nr_nodes; + /* + * Calculate target node size. x86_32 freaks on __udivdi3() so do + * the division in ulong number of pages and convert back. + */ + size = max_addr - addr - memblock_x86_hole_size(addr, max_addr); + size = PFN_PHYS((unsigned long)(size >> PAGE_SHIFT) / nr_nodes); + /* * Calculate the number of big nodes that can be allocated as a result * of consolidating the remainder. @@ -226,7 +233,7 @@ static int __init split_nodes_size_interleave(struct numa_meminfo *ei, */ while (nodes_weight(physnode_mask)) { for_each_node_mask(i, physnode_mask) { - u64 dma32_end = MAX_DMA32_PFN << PAGE_SHIFT; + u64 dma32_end = PFN_PHYS(MAX_DMA32_PFN); u64 start, limit, end; int phys_blk; @@ -298,7 +305,7 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt) { static struct numa_meminfo ei __initdata; static struct numa_meminfo pi __initdata; - const u64 max_addr = max_pfn << PAGE_SHIFT; + const u64 max_addr = PFN_PHYS(max_pfn); u8 *phys_dist = NULL; size_t phys_size = numa_dist_cnt * numa_dist_cnt * sizeof(phys_dist[0]); int max_emu_nid, dfl_phys_nid; @@ -342,8 +349,7 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt) if (numa_dist_cnt) { u64 phys; - phys = memblock_find_in_range(0, - (u64)max_pfn_mapped << PAGE_SHIFT, + phys = memblock_find_in_range(0, PFN_PHYS(max_pfn_mapped), phys_size, PAGE_SIZE); if (phys == MEMBLOCK_ERROR) { pr_warning("NUMA: Warning: can't allocate copy of distance table, disabling emulation\n"); @@ -454,10 +460,9 @@ void __cpuinit numa_remove_cpu(int cpu) cpumask_clear_cpu(cpu, node_to_cpumask_map[i]); } #else /* !CONFIG_DEBUG_PER_CPU_MAPS */ -static void __cpuinit numa_set_cpumask(int cpu, int enable) +static void __cpuinit numa_set_cpumask(int cpu, bool enable) { - struct cpumask *mask; - int nid, physnid, i; + int nid, physnid; nid = early_cpu_to_node(cpu); if (nid == NUMA_NO_NODE) { @@ -467,28 +472,21 @@ static void __cpuinit numa_set_cpumask(int cpu, int enable) physnid = emu_nid_to_phys[nid]; - for_each_online_node(i) { + for_each_online_node(nid) { if (emu_nid_to_phys[nid] != physnid) continue; - mask = debug_cpumask_set_cpu(cpu, enable); - if (!mask) - return; - - if (enable) - cpumask_set_cpu(cpu, mask); - else - cpumask_clear_cpu(cpu, mask); + debug_cpumask_set_cpu(cpu, nid, enable); } } void __cpuinit numa_add_cpu(int cpu) { - numa_set_cpumask(cpu, 1); + numa_set_cpumask(cpu, true); } void __cpuinit numa_remove_cpu(int cpu) { - numa_set_cpumask(cpu, 0); + numa_set_cpumask(cpu, false); } #endif /* !CONFIG_DEBUG_PER_CPU_MAPS */ diff --git a/arch/x86/mm/numa_internal.h b/arch/x86/mm/numa_internal.h index ef2d97377d7c..7178c3afe05e 100644 --- a/arch/x86/mm/numa_internal.h +++ b/arch/x86/mm/numa_internal.h @@ -19,6 +19,14 @@ void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi); int __init numa_cleanup_meminfo(struct numa_meminfo *mi); void __init numa_reset_distance(void); +void __init x86_numa_init(void); + +#ifdef CONFIG_X86_64 +static inline void init_alloc_remap(int nid, u64 start, u64 end) { } +#else +void __init init_alloc_remap(int nid, u64 start, u64 end); +#endif + #ifdef CONFIG_NUMA_EMU void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt); diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat.c similarity index 67% rename from arch/x86/mm/srat_64.c rename to arch/x86/mm/srat.c index 8e9d3394f6d4..81dbfdeb080d 100644 --- a/arch/x86/mm/srat_64.c +++ b/arch/x86/mm/srat.c @@ -26,8 +26,6 @@ int acpi_numa __initdata; -static struct bootnode nodes_add[MAX_NUMNODES]; - static __init int setup_node(int pxm) { return acpi_map_pxm_to_node(pxm); @@ -37,7 +35,6 @@ static __init void bad_srat(void) { printk(KERN_ERR "SRAT: SRAT not used.\n"); acpi_numa = -1; - memset(nodes_add, 0, sizeof(nodes_add)); } static __init inline int srat_disabled(void) @@ -131,73 +128,17 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) pxm, apic_id, node); } -#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE +#ifdef CONFIG_MEMORY_HOTPLUG static inline int save_add_info(void) {return 1;} #else static inline int save_add_info(void) {return 0;} #endif -/* - * Update nodes_add[] - * This code supports one contiguous hot add area per node - */ -static void __init -update_nodes_add(int node, unsigned long start, unsigned long end) -{ - unsigned long s_pfn = start >> PAGE_SHIFT; - unsigned long e_pfn = end >> PAGE_SHIFT; - int changed = 0; - struct bootnode *nd = &nodes_add[node]; - - /* I had some trouble with strange memory hotadd regions breaking - the boot. Be very strict here and reject anything unexpected. - If you want working memory hotadd write correct SRATs. - - The node size check is a basic sanity check to guard against - mistakes */ - if ((signed long)(end - start) < NODE_MIN_SIZE) { - printk(KERN_ERR "SRAT: Hotplug area too small\n"); - return; - } - - /* This check might be a bit too strict, but I'm keeping it for now. */ - if (absent_pages_in_range(s_pfn, e_pfn) != e_pfn - s_pfn) { - printk(KERN_ERR - "SRAT: Hotplug area %lu -> %lu has existing memory\n", - s_pfn, e_pfn); - return; - } - - /* Looks good */ - - if (nd->start == nd->end) { - nd->start = start; - nd->end = end; - changed = 1; - } else { - if (nd->start == end) { - nd->start = start; - changed = 1; - } - if (nd->end == start) { - nd->end = end; - changed = 1; - } - if (!changed) - printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n"); - } - - if (changed) { - node_set(node, numa_nodes_parsed); - printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n", - nd->start, nd->end); - } -} /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ void __init acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) { - unsigned long start, end; + u64 start, end; int node, pxm; if (srat_disabled()) @@ -226,11 +167,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) return; } - printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm, + printk(KERN_INFO "SRAT: Node %u PXM %u %Lx-%Lx\n", node, pxm, start, end); - - if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) - update_nodes_add(node, start, end); } void __init acpi_numa_arch_fixup(void) {} @@ -244,17 +182,3 @@ int __init x86_acpi_numa_init(void) return ret; return srat_disabled() ? -EINVAL : 0; } - -#if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || defined(CONFIG_ACPI_HOTPLUG_MEMORY) -int memory_add_physaddr_to_nid(u64 start) -{ - int i, ret = 0; - - for_each_node(i) - if (nodes_add[i].start <= start && nodes_add[i].end > start) - ret = i; - - return ret; -} -EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); -#endif diff --git a/arch/x86/mm/srat_32.c b/arch/x86/mm/srat_32.c deleted file mode 100644 index 364f36bdfad8..000000000000 --- a/arch/x86/mm/srat_32.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Some of the code in this file has been gleaned from the 64 bit - * discontigmem support code base. - * - * Copyright (C) 2002, IBM 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 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU 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. - * - * Send feedback to Pat Gaughen - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * proximity macros and definitions - */ -#define NODE_ARRAY_INDEX(x) ((x) / 8) /* 8 bits/char */ -#define NODE_ARRAY_OFFSET(x) ((x) % 8) /* 8 bits/char */ -#define BMAP_SET(bmap, bit) ((bmap)[NODE_ARRAY_INDEX(bit)] |= 1 << NODE_ARRAY_OFFSET(bit)) -#define BMAP_TEST(bmap, bit) ((bmap)[NODE_ARRAY_INDEX(bit)] & (1 << NODE_ARRAY_OFFSET(bit))) -/* bitmap length; _PXM is at most 255 */ -#define PXM_BITMAP_LEN (MAX_PXM_DOMAINS / 8) -static u8 __initdata pxm_bitmap[PXM_BITMAP_LEN]; /* bitmap of proximity domains */ - -#define MAX_CHUNKS_PER_NODE 3 -#define MAXCHUNKS (MAX_CHUNKS_PER_NODE * MAX_NUMNODES) -struct node_memory_chunk_s { - unsigned long start_pfn; - unsigned long end_pfn; - u8 pxm; // proximity domain of node - u8 nid; // which cnode contains this chunk? - u8 bank; // which mem bank on this node -}; -static struct node_memory_chunk_s __initdata node_memory_chunk[MAXCHUNKS]; - -static int __initdata num_memory_chunks; /* total number of memory chunks */ -static u8 __initdata apicid_to_pxm[MAX_LOCAL_APIC]; - -int acpi_numa __initdata; - -static __init void bad_srat(void) -{ - printk(KERN_ERR "SRAT: SRAT not used.\n"); - acpi_numa = -1; - num_memory_chunks = 0; -} - -static __init inline int srat_disabled(void) -{ - return numa_off || acpi_numa < 0; -} - -/* Identify CPU proximity domains */ -void __init -acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *cpu_affinity) -{ - if (srat_disabled()) - return; - if (cpu_affinity->header.length != - sizeof(struct acpi_srat_cpu_affinity)) { - bad_srat(); - return; - } - - if ((cpu_affinity->flags & ACPI_SRAT_CPU_ENABLED) == 0) - return; /* empty entry */ - - /* mark this node as "seen" in node bitmap */ - BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain_lo); - - /* don't need to check apic_id here, because it is always 8 bits */ - apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain_lo; - - printk(KERN_DEBUG "CPU %02x in proximity domain %02x\n", - cpu_affinity->apic_id, cpu_affinity->proximity_domain_lo); -} - -/* - * Identify memory proximity domains and hot-remove capabilities. - * Fill node memory chunk list structure. - */ -void __init -acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *memory_affinity) -{ - unsigned long long paddr, size; - unsigned long start_pfn, end_pfn; - u8 pxm; - struct node_memory_chunk_s *p, *q, *pend; - - if (srat_disabled()) - return; - if (memory_affinity->header.length != - sizeof(struct acpi_srat_mem_affinity)) { - bad_srat(); - return; - } - - if ((memory_affinity->flags & ACPI_SRAT_MEM_ENABLED) == 0) - return; /* empty entry */ - - pxm = memory_affinity->proximity_domain & 0xff; - - /* mark this node as "seen" in node bitmap */ - BMAP_SET(pxm_bitmap, pxm); - - /* calculate info for memory chunk structure */ - paddr = memory_affinity->base_address; - size = memory_affinity->length; - - start_pfn = paddr >> PAGE_SHIFT; - end_pfn = (paddr + size) >> PAGE_SHIFT; - - - if (num_memory_chunks >= MAXCHUNKS) { - printk(KERN_WARNING "Too many mem chunks in SRAT." - " Ignoring %lld MBytes at %llx\n", - size/(1024*1024), paddr); - return; - } - - /* Insertion sort based on base address */ - pend = &node_memory_chunk[num_memory_chunks]; - for (p = &node_memory_chunk[0]; p < pend; p++) { - if (start_pfn < p->start_pfn) - break; - } - if (p < pend) { - for (q = pend; q >= p; q--) - *(q + 1) = *q; - } - p->start_pfn = start_pfn; - p->end_pfn = end_pfn; - p->pxm = pxm; - - num_memory_chunks++; - - printk(KERN_DEBUG "Memory range %08lx to %08lx" - " in proximity domain %02x %s\n", - start_pfn, end_pfn, - pxm, - ((memory_affinity->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ? - "enabled and removable" : "enabled" ) ); -} - -/* Callback for SLIT parsing */ -void __init acpi_numa_slit_init(struct acpi_table_slit *slit) -{ -} - -void acpi_numa_arch_fixup(void) -{ -} -/* - * The SRAT table always lists ascending addresses, so can always - * assume that the first "start" address that you see is the real - * start of the node, and that the current "end" address is after - * the previous one. - */ -static __init int node_read_chunk(int nid, struct node_memory_chunk_s *memory_chunk) -{ - /* - * Only add present memory as told by the e820. - * There is no guarantee from the SRAT that the memory it - * enumerates is present at boot time because it represents - * *possible* memory hotplug areas the same as normal RAM. - */ - if (memory_chunk->start_pfn >= max_pfn) { - printk(KERN_INFO "Ignoring SRAT pfns: %08lx - %08lx\n", - memory_chunk->start_pfn, memory_chunk->end_pfn); - return -1; - } - if (memory_chunk->nid != nid) - return -1; - - if (!node_has_online_mem(nid)) - node_start_pfn[nid] = memory_chunk->start_pfn; - - if (node_start_pfn[nid] > memory_chunk->start_pfn) - node_start_pfn[nid] = memory_chunk->start_pfn; - - if (node_end_pfn[nid] < memory_chunk->end_pfn) - node_end_pfn[nid] = memory_chunk->end_pfn; - - return 0; -} - -int __init get_memcfg_from_srat(void) -{ - int i, j, nid; - - if (srat_disabled()) - goto out_fail; - - if (acpi_numa_init() < 0) - goto out_fail; - - if (num_memory_chunks == 0) { - printk(KERN_DEBUG - "could not find any ACPI SRAT memory areas.\n"); - goto out_fail; - } - - /* Calculate total number of nodes in system from PXM bitmap and create - * a set of sequential node IDs starting at zero. (ACPI doesn't seem - * to specify the range of _PXM values.) - */ - /* - * MCD - we no longer HAVE to number nodes sequentially. PXM domain - * numbers could go as high as 256, and MAX_NUMNODES for i386 is typically - * 32, so we will continue numbering them in this manner until MAX_NUMNODES - * approaches MAX_PXM_DOMAINS for i386. - */ - nodes_clear(node_online_map); - for (i = 0; i < MAX_PXM_DOMAINS; i++) { - if (BMAP_TEST(pxm_bitmap, i)) { - int nid = acpi_map_pxm_to_node(i); - node_set_online(nid); - } - } - BUG_ON(num_online_nodes() == 0); - - /* set cnode id in memory chunk structure */ - for (i = 0; i < num_memory_chunks; i++) - node_memory_chunk[i].nid = pxm_to_node(node_memory_chunk[i].pxm); - - printk(KERN_DEBUG "pxm bitmap: "); - for (i = 0; i < sizeof(pxm_bitmap); i++) { - printk(KERN_CONT "%02x ", pxm_bitmap[i]); - } - printk(KERN_CONT "\n"); - printk(KERN_DEBUG "Number of logical nodes in system = %d\n", - num_online_nodes()); - printk(KERN_DEBUG "Number of memory chunks in system = %d\n", - num_memory_chunks); - - for (i = 0; i < MAX_LOCAL_APIC; i++) - set_apicid_to_node(i, pxm_to_node(apicid_to_pxm[i])); - - for (j = 0; j < num_memory_chunks; j++){ - struct node_memory_chunk_s * chunk = &node_memory_chunk[j]; - printk(KERN_DEBUG - "chunk %d nid %d start_pfn %08lx end_pfn %08lx\n", - j, chunk->nid, chunk->start_pfn, chunk->end_pfn); - if (node_read_chunk(chunk->nid, chunk)) - continue; - - memblock_x86_register_active_regions(chunk->nid, chunk->start_pfn, - min(chunk->end_pfn, max_pfn)); - } - /* for out of order entries in SRAT */ - sort_node_map(); - - for_each_online_node(nid) { - unsigned long start = node_start_pfn[nid]; - unsigned long end = min(node_end_pfn[nid], max_pfn); - - memory_present(nid, start, end); - node_remap_size[nid] = node_memmap_size_bytes(nid, start, end); - } - return 1; -out_fail: - printk(KERN_DEBUG "failed to get NUMA memory information from SRAT" - " table\n"); - return 0; -} diff --git a/arch/x86/net/Makefile b/arch/x86/net/Makefile new file mode 100644 index 000000000000..90568c33ddb0 --- /dev/null +++ b/arch/x86/net/Makefile @@ -0,0 +1,4 @@ +# +# Arch-specific network modules +# +obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o diff --git a/arch/x86/net/bpf_jit.S b/arch/x86/net/bpf_jit.S new file mode 100644 index 000000000000..66870223f8c5 --- /dev/null +++ b/arch/x86/net/bpf_jit.S @@ -0,0 +1,140 @@ +/* bpf_jit.S : BPF JIT helper functions + * + * Copyright (C) 2011 Eric Dumazet (eric.dumazet@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ +#include +#include + +/* + * Calling convention : + * rdi : skb pointer + * esi : offset of byte(s) to fetch in skb (can be scratched) + * r8 : copy of skb->data + * r9d : hlen = skb->len - skb->data_len + */ +#define SKBDATA %r8 + +sk_load_word_ind: + .globl sk_load_word_ind + + add %ebx,%esi /* offset += X */ +# test %esi,%esi /* if (offset < 0) goto bpf_error; */ + js bpf_error + +sk_load_word: + .globl sk_load_word + + mov %r9d,%eax # hlen + sub %esi,%eax # hlen - offset + cmp $3,%eax + jle bpf_slow_path_word + mov (SKBDATA,%rsi),%eax + bswap %eax /* ntohl() */ + ret + + +sk_load_half_ind: + .globl sk_load_half_ind + + add %ebx,%esi /* offset += X */ + js bpf_error + +sk_load_half: + .globl sk_load_half + + mov %r9d,%eax + sub %esi,%eax # hlen - offset + cmp $1,%eax + jle bpf_slow_path_half + movzwl (SKBDATA,%rsi),%eax + rol $8,%ax # ntohs() + ret + +sk_load_byte_ind: + .globl sk_load_byte_ind + add %ebx,%esi /* offset += X */ + js bpf_error + +sk_load_byte: + .globl sk_load_byte + + cmp %esi,%r9d /* if (offset >= hlen) goto bpf_slow_path_byte */ + jle bpf_slow_path_byte + movzbl (SKBDATA,%rsi),%eax + ret + +/** + * sk_load_byte_msh - BPF_S_LDX_B_MSH helper + * + * Implements BPF_S_LDX_B_MSH : ldxb 4*([offset]&0xf) + * Must preserve A accumulator (%eax) + * Inputs : %esi is the offset value, already known positive + */ +ENTRY(sk_load_byte_msh) + CFI_STARTPROC + cmp %esi,%r9d /* if (offset >= hlen) goto bpf_slow_path_byte_msh */ + jle bpf_slow_path_byte_msh + movzbl (SKBDATA,%rsi),%ebx + and $15,%bl + shl $2,%bl + ret + CFI_ENDPROC +ENDPROC(sk_load_byte_msh) + +bpf_error: +# force a return 0 from jit handler + xor %eax,%eax + mov -8(%rbp),%rbx + leaveq + ret + +/* rsi contains offset and can be scratched */ +#define bpf_slow_path_common(LEN) \ + push %rdi; /* save skb */ \ + push %r9; \ + push SKBDATA; \ +/* rsi already has offset */ \ + mov $LEN,%ecx; /* len */ \ + lea -12(%rbp),%rdx; \ + call skb_copy_bits; \ + test %eax,%eax; \ + pop SKBDATA; \ + pop %r9; \ + pop %rdi + + +bpf_slow_path_word: + bpf_slow_path_common(4) + js bpf_error + mov -12(%rbp),%eax + bswap %eax + ret + +bpf_slow_path_half: + bpf_slow_path_common(2) + js bpf_error + mov -12(%rbp),%ax + rol $8,%ax + movzwl %ax,%eax + ret + +bpf_slow_path_byte: + bpf_slow_path_common(1) + js bpf_error + movzbl -12(%rbp),%eax + ret + +bpf_slow_path_byte_msh: + xchg %eax,%ebx /* dont lose A , X is about to be scratched */ + bpf_slow_path_common(1) + js bpf_error + movzbl -12(%rbp),%eax + and $15,%al + shl $2,%al + xchg %eax,%ebx + ret diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c new file mode 100644 index 000000000000..bfab3fa10edc --- /dev/null +++ b/arch/x86/net/bpf_jit_comp.c @@ -0,0 +1,654 @@ +/* bpf_jit_comp.c : BPF JIT compiler + * + * Copyright (C) 2011 Eric Dumazet (eric.dumazet@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ +#include +#include +#include +#include + +/* + * Conventions : + * EAX : BPF A accumulator + * EBX : BPF X accumulator + * RDI : pointer to skb (first argument given to JIT function) + * RBP : frame pointer (even if CONFIG_FRAME_POINTER=n) + * ECX,EDX,ESI : scratch registers + * r9d : skb->len - skb->data_len (headlen) + * r8 : skb->data + * -8(RBP) : saved RBX value + * -16(RBP)..-80(RBP) : BPF_MEMWORDS values + */ +int bpf_jit_enable __read_mostly; + +/* + * assembly code in arch/x86/net/bpf_jit.S + */ +extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[]; +extern u8 sk_load_word_ind[], sk_load_half_ind[], sk_load_byte_ind[]; + +static inline u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len) +{ + if (len == 1) + *ptr = bytes; + else if (len == 2) + *(u16 *)ptr = bytes; + else { + *(u32 *)ptr = bytes; + barrier(); + } + return ptr + len; +} + +#define EMIT(bytes, len) do { prog = emit_code(prog, bytes, len); } while (0) + +#define EMIT1(b1) EMIT(b1, 1) +#define EMIT2(b1, b2) EMIT((b1) + ((b2) << 8), 2) +#define EMIT3(b1, b2, b3) EMIT((b1) + ((b2) << 8) + ((b3) << 16), 3) +#define EMIT4(b1, b2, b3, b4) EMIT((b1) + ((b2) << 8) + ((b3) << 16) + ((b4) << 24), 4) +#define EMIT1_off32(b1, off) do { EMIT1(b1); EMIT(off, 4);} while (0) + +#define CLEAR_A() EMIT2(0x31, 0xc0) /* xor %eax,%eax */ +#define CLEAR_X() EMIT2(0x31, 0xdb) /* xor %ebx,%ebx */ + +static inline bool is_imm8(int value) +{ + return value <= 127 && value >= -128; +} + +static inline bool is_near(int offset) +{ + return offset <= 127 && offset >= -128; +} + +#define EMIT_JMP(offset) \ +do { \ + if (offset) { \ + if (is_near(offset)) \ + EMIT2(0xeb, offset); /* jmp .+off8 */ \ + else \ + EMIT1_off32(0xe9, offset); /* jmp .+off32 */ \ + } \ +} while (0) + +/* list of x86 cond jumps opcodes (. + s8) + * Add 0x10 (and an extra 0x0f) to generate far jumps (. + s32) + */ +#define X86_JB 0x72 +#define X86_JAE 0x73 +#define X86_JE 0x74 +#define X86_JNE 0x75 +#define X86_JBE 0x76 +#define X86_JA 0x77 + +#define EMIT_COND_JMP(op, offset) \ +do { \ + if (is_near(offset)) \ + EMIT2(op, offset); /* jxx .+off8 */ \ + else { \ + EMIT2(0x0f, op + 0x10); \ + EMIT(offset, 4); /* jxx .+off32 */ \ + } \ +} while (0) + +#define COND_SEL(CODE, TOP, FOP) \ + case CODE: \ + t_op = TOP; \ + f_op = FOP; \ + goto cond_branch + + +#define SEEN_DATAREF 1 /* might call external helpers */ +#define SEEN_XREG 2 /* ebx is used */ +#define SEEN_MEM 4 /* use mem[] for temporary storage */ + +static inline void bpf_flush_icache(void *start, void *end) +{ + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + smp_wmb(); + flush_icache_range((unsigned long)start, (unsigned long)end); + set_fs(old_fs); +} + + +void bpf_jit_compile(struct sk_filter *fp) +{ + u8 temp[64]; + u8 *prog; + unsigned int proglen, oldproglen = 0; + int ilen, i; + int t_offset, f_offset; + u8 t_op, f_op, seen = 0, pass; + u8 *image = NULL; + u8 *func; + int pc_ret0 = -1; /* bpf index of first RET #0 instruction (if any) */ + unsigned int cleanup_addr; /* epilogue code offset */ + unsigned int *addrs; + const struct sock_filter *filter = fp->insns; + int flen = fp->len; + + if (!bpf_jit_enable) + return; + + addrs = kmalloc(flen * sizeof(*addrs), GFP_KERNEL); + if (addrs == NULL) + return; + + /* Before first pass, make a rough estimation of addrs[] + * each bpf instruction is translated to less than 64 bytes + */ + for (proglen = 0, i = 0; i < flen; i++) { + proglen += 64; + addrs[i] = proglen; + } + cleanup_addr = proglen; /* epilogue address */ + + for (pass = 0; pass < 10; pass++) { + /* no prologue/epilogue for trivial filters (RET something) */ + proglen = 0; + prog = temp; + + if (seen) { + EMIT4(0x55, 0x48, 0x89, 0xe5); /* push %rbp; mov %rsp,%rbp */ + EMIT4(0x48, 0x83, 0xec, 96); /* subq $96,%rsp */ + /* note : must save %rbx in case bpf_error is hit */ + if (seen & (SEEN_XREG | SEEN_DATAREF)) + EMIT4(0x48, 0x89, 0x5d, 0xf8); /* mov %rbx, -8(%rbp) */ + if (seen & SEEN_XREG) + CLEAR_X(); /* make sure we dont leek kernel memory */ + + /* + * If this filter needs to access skb data, + * loads r9 and r8 with : + * r9 = skb->len - skb->data_len + * r8 = skb->data + */ + if (seen & SEEN_DATAREF) { + if (offsetof(struct sk_buff, len) <= 127) + /* mov off8(%rdi),%r9d */ + EMIT4(0x44, 0x8b, 0x4f, offsetof(struct sk_buff, len)); + else { + /* mov off32(%rdi),%r9d */ + EMIT3(0x44, 0x8b, 0x8f); + EMIT(offsetof(struct sk_buff, len), 4); + } + if (is_imm8(offsetof(struct sk_buff, data_len))) + /* sub off8(%rdi),%r9d */ + EMIT4(0x44, 0x2b, 0x4f, offsetof(struct sk_buff, data_len)); + else { + EMIT3(0x44, 0x2b, 0x8f); + EMIT(offsetof(struct sk_buff, data_len), 4); + } + + if (is_imm8(offsetof(struct sk_buff, data))) + /* mov off8(%rdi),%r8 */ + EMIT4(0x4c, 0x8b, 0x47, offsetof(struct sk_buff, data)); + else { + /* mov off32(%rdi),%r8 */ + EMIT3(0x4c, 0x8b, 0x87); + EMIT(offsetof(struct sk_buff, data), 4); + } + } + } + + switch (filter[0].code) { + case BPF_S_RET_K: + case BPF_S_LD_W_LEN: + case BPF_S_ANC_PROTOCOL: + case BPF_S_ANC_IFINDEX: + case BPF_S_ANC_MARK: + case BPF_S_ANC_RXHASH: + case BPF_S_ANC_CPU: + case BPF_S_ANC_QUEUE: + case BPF_S_LD_W_ABS: + case BPF_S_LD_H_ABS: + case BPF_S_LD_B_ABS: + /* first instruction sets A register (or is RET 'constant') */ + break; + default: + /* make sure we dont leak kernel information to user */ + CLEAR_A(); /* A = 0 */ + } + + for (i = 0; i < flen; i++) { + unsigned int K = filter[i].k; + + switch (filter[i].code) { + case BPF_S_ALU_ADD_X: /* A += X; */ + seen |= SEEN_XREG; + EMIT2(0x01, 0xd8); /* add %ebx,%eax */ + break; + case BPF_S_ALU_ADD_K: /* A += K; */ + if (!K) + break; + if (is_imm8(K)) + EMIT3(0x83, 0xc0, K); /* add imm8,%eax */ + else + EMIT1_off32(0x05, K); /* add imm32,%eax */ + break; + case BPF_S_ALU_SUB_X: /* A -= X; */ + seen |= SEEN_XREG; + EMIT2(0x29, 0xd8); /* sub %ebx,%eax */ + break; + case BPF_S_ALU_SUB_K: /* A -= K */ + if (!K) + break; + if (is_imm8(K)) + EMIT3(0x83, 0xe8, K); /* sub imm8,%eax */ + else + EMIT1_off32(0x2d, K); /* sub imm32,%eax */ + break; + case BPF_S_ALU_MUL_X: /* A *= X; */ + seen |= SEEN_XREG; + EMIT3(0x0f, 0xaf, 0xc3); /* imul %ebx,%eax */ + break; + case BPF_S_ALU_MUL_K: /* A *= K */ + if (is_imm8(K)) + EMIT3(0x6b, 0xc0, K); /* imul imm8,%eax,%eax */ + else { + EMIT2(0x69, 0xc0); /* imul imm32,%eax */ + EMIT(K, 4); + } + break; + case BPF_S_ALU_DIV_X: /* A /= X; */ + seen |= SEEN_XREG; + EMIT2(0x85, 0xdb); /* test %ebx,%ebx */ + if (pc_ret0 != -1) + EMIT_COND_JMP(X86_JE, addrs[pc_ret0] - (addrs[i] - 4)); + else { + EMIT_COND_JMP(X86_JNE, 2 + 5); + CLEAR_A(); + EMIT1_off32(0xe9, cleanup_addr - (addrs[i] - 4)); /* jmp .+off32 */ + } + EMIT4(0x31, 0xd2, 0xf7, 0xf3); /* xor %edx,%edx; div %ebx */ + break; + case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K); */ + EMIT3(0x48, 0x69, 0xc0); /* imul imm32,%rax,%rax */ + EMIT(K, 4); + EMIT4(0x48, 0xc1, 0xe8, 0x20); /* shr $0x20,%rax */ + break; + case BPF_S_ALU_AND_X: + seen |= SEEN_XREG; + EMIT2(0x21, 0xd8); /* and %ebx,%eax */ + break; + case BPF_S_ALU_AND_K: + if (K >= 0xFFFFFF00) { + EMIT2(0x24, K & 0xFF); /* and imm8,%al */ + } else if (K >= 0xFFFF0000) { + EMIT2(0x66, 0x25); /* and imm16,%ax */ + EMIT2(K, 2); + } else { + EMIT1_off32(0x25, K); /* and imm32,%eax */ + } + break; + case BPF_S_ALU_OR_X: + seen |= SEEN_XREG; + EMIT2(0x09, 0xd8); /* or %ebx,%eax */ + break; + case BPF_S_ALU_OR_K: + if (is_imm8(K)) + EMIT3(0x83, 0xc8, K); /* or imm8,%eax */ + else + EMIT1_off32(0x0d, K); /* or imm32,%eax */ + break; + case BPF_S_ALU_LSH_X: /* A <<= X; */ + seen |= SEEN_XREG; + EMIT4(0x89, 0xd9, 0xd3, 0xe0); /* mov %ebx,%ecx; shl %cl,%eax */ + break; + case BPF_S_ALU_LSH_K: + if (K == 0) + break; + else if (K == 1) + EMIT2(0xd1, 0xe0); /* shl %eax */ + else + EMIT3(0xc1, 0xe0, K); + break; + case BPF_S_ALU_RSH_X: /* A >>= X; */ + seen |= SEEN_XREG; + EMIT4(0x89, 0xd9, 0xd3, 0xe8); /* mov %ebx,%ecx; shr %cl,%eax */ + break; + case BPF_S_ALU_RSH_K: /* A >>= K; */ + if (K == 0) + break; + else if (K == 1) + EMIT2(0xd1, 0xe8); /* shr %eax */ + else + EMIT3(0xc1, 0xe8, K); + break; + case BPF_S_ALU_NEG: + EMIT2(0xf7, 0xd8); /* neg %eax */ + break; + case BPF_S_RET_K: + if (!K) { + if (pc_ret0 == -1) + pc_ret0 = i; + CLEAR_A(); + } else { + EMIT1_off32(0xb8, K); /* mov $imm32,%eax */ + } + /* fallinto */ + case BPF_S_RET_A: + if (seen) { + if (i != flen - 1) { + EMIT_JMP(cleanup_addr - addrs[i]); + break; + } + if (seen & SEEN_XREG) + EMIT4(0x48, 0x8b, 0x5d, 0xf8); /* mov -8(%rbp),%rbx */ + EMIT1(0xc9); /* leaveq */ + } + EMIT1(0xc3); /* ret */ + break; + case BPF_S_MISC_TAX: /* X = A */ + seen |= SEEN_XREG; + EMIT2(0x89, 0xc3); /* mov %eax,%ebx */ + break; + case BPF_S_MISC_TXA: /* A = X */ + seen |= SEEN_XREG; + EMIT2(0x89, 0xd8); /* mov %ebx,%eax */ + break; + case BPF_S_LD_IMM: /* A = K */ + if (!K) + CLEAR_A(); + else + EMIT1_off32(0xb8, K); /* mov $imm32,%eax */ + break; + case BPF_S_LDX_IMM: /* X = K */ + seen |= SEEN_XREG; + if (!K) + CLEAR_X(); + else + EMIT1_off32(0xbb, K); /* mov $imm32,%ebx */ + break; + case BPF_S_LD_MEM: /* A = mem[K] : mov off8(%rbp),%eax */ + seen |= SEEN_MEM; + EMIT3(0x8b, 0x45, 0xf0 - K*4); + break; + case BPF_S_LDX_MEM: /* X = mem[K] : mov off8(%rbp),%ebx */ + seen |= SEEN_XREG | SEEN_MEM; + EMIT3(0x8b, 0x5d, 0xf0 - K*4); + break; + case BPF_S_ST: /* mem[K] = A : mov %eax,off8(%rbp) */ + seen |= SEEN_MEM; + EMIT3(0x89, 0x45, 0xf0 - K*4); + break; + case BPF_S_STX: /* mem[K] = X : mov %ebx,off8(%rbp) */ + seen |= SEEN_XREG | SEEN_MEM; + EMIT3(0x89, 0x5d, 0xf0 - K*4); + break; + case BPF_S_LD_W_LEN: /* A = skb->len; */ + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4); + if (is_imm8(offsetof(struct sk_buff, len))) + /* mov off8(%rdi),%eax */ + EMIT3(0x8b, 0x47, offsetof(struct sk_buff, len)); + else { + EMIT2(0x8b, 0x87); + EMIT(offsetof(struct sk_buff, len), 4); + } + break; + case BPF_S_LDX_W_LEN: /* X = skb->len; */ + seen |= SEEN_XREG; + if (is_imm8(offsetof(struct sk_buff, len))) + /* mov off8(%rdi),%ebx */ + EMIT3(0x8b, 0x5f, offsetof(struct sk_buff, len)); + else { + EMIT2(0x8b, 0x9f); + EMIT(offsetof(struct sk_buff, len), 4); + } + break; + case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */ + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2); + if (is_imm8(offsetof(struct sk_buff, protocol))) { + /* movzwl off8(%rdi),%eax */ + EMIT4(0x0f, 0xb7, 0x47, offsetof(struct sk_buff, protocol)); + } else { + EMIT3(0x0f, 0xb7, 0x87); /* movzwl off32(%rdi),%eax */ + EMIT(offsetof(struct sk_buff, protocol), 4); + } + EMIT2(0x86, 0xc4); /* ntohs() : xchg %al,%ah */ + break; + case BPF_S_ANC_IFINDEX: + if (is_imm8(offsetof(struct sk_buff, dev))) { + /* movq off8(%rdi),%rax */ + EMIT4(0x48, 0x8b, 0x47, offsetof(struct sk_buff, dev)); + } else { + EMIT3(0x48, 0x8b, 0x87); /* movq off32(%rdi),%rax */ + EMIT(offsetof(struct sk_buff, dev), 4); + } + EMIT3(0x48, 0x85, 0xc0); /* test %rax,%rax */ + EMIT_COND_JMP(X86_JE, cleanup_addr - (addrs[i] - 6)); + BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4); + EMIT2(0x8b, 0x80); /* mov off32(%rax),%eax */ + EMIT(offsetof(struct net_device, ifindex), 4); + break; + case BPF_S_ANC_MARK: + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4); + if (is_imm8(offsetof(struct sk_buff, mark))) { + /* mov off8(%rdi),%eax */ + EMIT3(0x8b, 0x47, offsetof(struct sk_buff, mark)); + } else { + EMIT2(0x8b, 0x87); + EMIT(offsetof(struct sk_buff, mark), 4); + } + break; + case BPF_S_ANC_RXHASH: + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4); + if (is_imm8(offsetof(struct sk_buff, rxhash))) { + /* mov off8(%rdi),%eax */ + EMIT3(0x8b, 0x47, offsetof(struct sk_buff, rxhash)); + } else { + EMIT2(0x8b, 0x87); + EMIT(offsetof(struct sk_buff, rxhash), 4); + } + break; + case BPF_S_ANC_QUEUE: + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2); + if (is_imm8(offsetof(struct sk_buff, queue_mapping))) { + /* movzwl off8(%rdi),%eax */ + EMIT4(0x0f, 0xb7, 0x47, offsetof(struct sk_buff, queue_mapping)); + } else { + EMIT3(0x0f, 0xb7, 0x87); /* movzwl off32(%rdi),%eax */ + EMIT(offsetof(struct sk_buff, queue_mapping), 4); + } + break; + case BPF_S_ANC_CPU: +#ifdef CONFIG_SMP + EMIT4(0x65, 0x8b, 0x04, 0x25); /* mov %gs:off32,%eax */ + EMIT((u32)(unsigned long)&cpu_number, 4); /* A = smp_processor_id(); */ +#else + CLEAR_A(); +#endif + break; + case BPF_S_LD_W_ABS: + func = sk_load_word; +common_load: seen |= SEEN_DATAREF; + if ((int)K < 0) + goto out; + t_offset = func - (image + addrs[i]); + EMIT1_off32(0xbe, K); /* mov imm32,%esi */ + EMIT1_off32(0xe8, t_offset); /* call */ + break; + case BPF_S_LD_H_ABS: + func = sk_load_half; + goto common_load; + case BPF_S_LD_B_ABS: + func = sk_load_byte; + goto common_load; + case BPF_S_LDX_B_MSH: + if ((int)K < 0) { + if (pc_ret0 != -1) { + EMIT_JMP(addrs[pc_ret0] - addrs[i]); + break; + } + CLEAR_A(); + EMIT_JMP(cleanup_addr - addrs[i]); + break; + } + seen |= SEEN_DATAREF | SEEN_XREG; + t_offset = sk_load_byte_msh - (image + addrs[i]); + EMIT1_off32(0xbe, K); /* mov imm32,%esi */ + EMIT1_off32(0xe8, t_offset); /* call sk_load_byte_msh */ + break; + case BPF_S_LD_W_IND: + func = sk_load_word_ind; +common_load_ind: seen |= SEEN_DATAREF | SEEN_XREG; + t_offset = func - (image + addrs[i]); + EMIT1_off32(0xbe, K); /* mov imm32,%esi */ + EMIT1_off32(0xe8, t_offset); /* call sk_load_xxx_ind */ + break; + case BPF_S_LD_H_IND: + func = sk_load_half_ind; + goto common_load_ind; + case BPF_S_LD_B_IND: + func = sk_load_byte_ind; + goto common_load_ind; + case BPF_S_JMP_JA: + t_offset = addrs[i + K] - addrs[i]; + EMIT_JMP(t_offset); + break; + COND_SEL(BPF_S_JMP_JGT_K, X86_JA, X86_JBE); + COND_SEL(BPF_S_JMP_JGE_K, X86_JAE, X86_JB); + COND_SEL(BPF_S_JMP_JEQ_K, X86_JE, X86_JNE); + COND_SEL(BPF_S_JMP_JSET_K,X86_JNE, X86_JE); + COND_SEL(BPF_S_JMP_JGT_X, X86_JA, X86_JBE); + COND_SEL(BPF_S_JMP_JGE_X, X86_JAE, X86_JB); + COND_SEL(BPF_S_JMP_JEQ_X, X86_JE, X86_JNE); + COND_SEL(BPF_S_JMP_JSET_X,X86_JNE, X86_JE); + +cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i]; + t_offset = addrs[i + filter[i].jt] - addrs[i]; + + /* same targets, can avoid doing the test :) */ + if (filter[i].jt == filter[i].jf) { + EMIT_JMP(t_offset); + break; + } + + switch (filter[i].code) { + case BPF_S_JMP_JGT_X: + case BPF_S_JMP_JGE_X: + case BPF_S_JMP_JEQ_X: + seen |= SEEN_XREG; + EMIT2(0x39, 0xd8); /* cmp %ebx,%eax */ + break; + case BPF_S_JMP_JSET_X: + seen |= SEEN_XREG; + EMIT2(0x85, 0xd8); /* test %ebx,%eax */ + break; + case BPF_S_JMP_JEQ_K: + if (K == 0) { + EMIT2(0x85, 0xc0); /* test %eax,%eax */ + break; + } + case BPF_S_JMP_JGT_K: + case BPF_S_JMP_JGE_K: + if (K <= 127) + EMIT3(0x83, 0xf8, K); /* cmp imm8,%eax */ + else + EMIT1_off32(0x3d, K); /* cmp imm32,%eax */ + break; + case BPF_S_JMP_JSET_K: + if (K <= 0xFF) + EMIT2(0xa8, K); /* test imm8,%al */ + else if (!(K & 0xFFFF00FF)) + EMIT3(0xf6, 0xc4, K >> 8); /* test imm8,%ah */ + else if (K <= 0xFFFF) { + EMIT2(0x66, 0xa9); /* test imm16,%ax */ + EMIT(K, 2); + } else { + EMIT1_off32(0xa9, K); /* test imm32,%eax */ + } + break; + } + if (filter[i].jt != 0) { + if (filter[i].jf) + t_offset += is_near(f_offset) ? 2 : 6; + EMIT_COND_JMP(t_op, t_offset); + if (filter[i].jf) + EMIT_JMP(f_offset); + break; + } + EMIT_COND_JMP(f_op, f_offset); + break; + default: + /* hmm, too complex filter, give up with jit compiler */ + goto out; + } + ilen = prog - temp; + if (image) { + if (unlikely(proglen + ilen > oldproglen)) { + pr_err("bpb_jit_compile fatal error\n"); + kfree(addrs); + module_free(NULL, image); + return; + } + memcpy(image + proglen, temp, ilen); + } + proglen += ilen; + addrs[i] = proglen; + prog = temp; + } + /* last bpf instruction is always a RET : + * use it to give the cleanup instruction(s) addr + */ + cleanup_addr = proglen - 1; /* ret */ + if (seen) + cleanup_addr -= 1; /* leaveq */ + if (seen & SEEN_XREG) + cleanup_addr -= 4; /* mov -8(%rbp),%rbx */ + + if (image) { + WARN_ON(proglen != oldproglen); + break; + } + if (proglen == oldproglen) { + image = module_alloc(max_t(unsigned int, + proglen, + sizeof(struct work_struct))); + if (!image) + goto out; + } + oldproglen = proglen; + } + if (bpf_jit_enable > 1) + pr_err("flen=%d proglen=%u pass=%d image=%p\n", + flen, proglen, pass, image); + + if (image) { + if (bpf_jit_enable > 1) + print_hex_dump(KERN_ERR, "JIT code: ", DUMP_PREFIX_ADDRESS, + 16, 1, image, proglen, false); + + bpf_flush_icache(image, image + proglen); + + fp->bpf_func = (void *)image; + } +out: + kfree(addrs); + return; +} + +static void jit_free_defer(struct work_struct *arg) +{ + module_free(NULL, arg); +} + +/* run from softirq, we must use a work_struct to call + * module_free() from process context + */ +void bpf_jit_free(struct sk_filter *fp) +{ + if (fp->bpf_func != sk_run_filter) { + struct work_struct *work = (struct work_struct *)fp->bpf_func; + + INIT_WORK(work, jit_free_defer); + schedule_work(work); + } +} diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c index 2d49d4e19a36..a5b64ab4cd6e 100644 --- a/arch/x86/oprofile/backtrace.c +++ b/arch/x86/oprofile/backtrace.c @@ -16,17 +16,6 @@ #include #include -static void backtrace_warning_symbol(void *data, char *msg, - unsigned long symbol) -{ - /* Ignore warnings */ -} - -static void backtrace_warning(void *data, char *msg) -{ - /* Ignore warnings */ -} - static int backtrace_stack(void *data, char *name) { /* Yes, we want all stacks */ @@ -42,8 +31,6 @@ static void backtrace_address(void *data, unsigned long addr, int reliable) } static struct stacktrace_ops backtrace_ops = { - .warning = backtrace_warning, - .warning_symbol = backtrace_warning_symbol, .stack = backtrace_stack, .address = backtrace_address, .walk_stack = print_context_stack, diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index e37b407a0ee8..8214724ce54d 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -108,7 +108,8 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) } irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0, (type == PCI_CAP_ID_MSIX) ? - "msi-x" : "msi"); + "msi-x" : "msi", + DOMID_SELF); if (irq < 0) goto error; dev_dbg(&dev->dev, @@ -148,7 +149,8 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0, (type == PCI_CAP_ID_MSIX) ? "pcifront-msi-x" : - "pcifront-msi"); + "pcifront-msi", + DOMID_SELF); if (irq < 0) goto free; i++; @@ -190,9 +192,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) list_for_each_entry(msidesc, &dev->msi_list, list) { struct physdev_map_pirq map_irq; + domid_t domid; + + domid = ret = xen_find_device_domain_owner(dev); + /* N.B. Casting int's -ENODEV to uint16_t results in 0xFFED, + * hence check ret value for < 0. */ + if (ret < 0) + domid = DOMID_SELF; memset(&map_irq, 0, sizeof(map_irq)); - map_irq.domid = DOMID_SELF; + map_irq.domid = domid; map_irq.type = MAP_PIRQ_TYPE_MSI; map_irq.index = -1; map_irq.pirq = -1; @@ -215,14 +224,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); if (ret) { - dev_warn(&dev->dev, "xen map irq failed %d\n", ret); + dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n", + ret, domid); goto out; } ret = xen_bind_pirq_msi_to_irq(dev, msidesc, map_irq.pirq, map_irq.index, (type == PCI_CAP_ID_MSIX) ? - "msi-x" : "msi"); + "msi-x" : "msi", + domid); if (ret < 0) goto out; } @@ -461,3 +472,78 @@ void __init xen_setup_pirqs(void) } } #endif + +#ifdef CONFIG_XEN_DOM0 +struct xen_device_domain_owner { + domid_t domain; + struct pci_dev *dev; + struct list_head list; +}; + +static DEFINE_SPINLOCK(dev_domain_list_spinlock); +static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list); + +static struct xen_device_domain_owner *find_device(struct pci_dev *dev) +{ + struct xen_device_domain_owner *owner; + + list_for_each_entry(owner, &dev_domain_list, list) { + if (owner->dev == dev) + return owner; + } + return NULL; +} + +int xen_find_device_domain_owner(struct pci_dev *dev) +{ + struct xen_device_domain_owner *owner; + int domain = -ENODEV; + + spin_lock(&dev_domain_list_spinlock); + owner = find_device(dev); + if (owner) + domain = owner->domain; + spin_unlock(&dev_domain_list_spinlock); + return domain; +} +EXPORT_SYMBOL_GPL(xen_find_device_domain_owner); + +int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain) +{ + struct xen_device_domain_owner *owner; + + owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL); + if (!owner) + return -ENODEV; + + spin_lock(&dev_domain_list_spinlock); + if (find_device(dev)) { + spin_unlock(&dev_domain_list_spinlock); + kfree(owner); + return -EEXIST; + } + owner->domain = domain; + owner->dev = dev; + list_add_tail(&owner->list, &dev_domain_list); + spin_unlock(&dev_domain_list_spinlock); + return 0; +} +EXPORT_SYMBOL_GPL(xen_register_device_domain_owner); + +int xen_unregister_device_domain_owner(struct pci_dev *dev) +{ + struct xen_device_domain_owner *owner; + + spin_lock(&dev_domain_list_spinlock); + owner = find_device(dev); + if (!owner) { + spin_unlock(&dev_domain_list_spinlock); + return -ENODEV; + } + list_del(&owner->list); + spin_unlock(&dev_domain_list_spinlock); + kfree(owner); + return 0; +} +EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner); +#endif diff --git a/arch/x86/platform/ce4100/falconfalls.dts b/arch/x86/platform/ce4100/falconfalls.dts index 2d6d226f2b10..e70be38ce039 100644 --- a/arch/x86/platform/ce4100/falconfalls.dts +++ b/arch/x86/platform/ce4100/falconfalls.dts @@ -347,7 +347,7 @@ usb@d,0 { "pciclass0c03"; reg = <0x16800 0x0 0x0 0x0 0x0>; - interrupts = <22 3>; + interrupts = <22 1>; }; usb@d,1 { @@ -357,7 +357,7 @@ usb@d,1 { "pciclass0c03"; reg = <0x16900 0x0 0x0 0x0 0x0>; - interrupts = <22 3>; + interrupts = <22 1>; }; sata@e,0 { @@ -367,7 +367,7 @@ sata@e,0 { "pciclass0106"; reg = <0x17000 0x0 0x0 0x0 0x0>; - interrupts = <23 3>; + interrupts = <23 1>; }; flash@f,0 { diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 0fe27d7c6258..b30aa26a8df2 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -145,17 +145,6 @@ static void virt_efi_reset_system(int reset_type, data_size, data); } -static efi_status_t virt_efi_set_virtual_address_map( - unsigned long memory_map_size, - unsigned long descriptor_size, - u32 descriptor_version, - efi_memory_desc_t *virtual_map) -{ - return efi_call_virt4(set_virtual_address_map, - memory_map_size, descriptor_size, - descriptor_version, virtual_map); -} - static efi_status_t __init phys_efi_set_virtual_address_map( unsigned long memory_map_size, unsigned long descriptor_size, @@ -468,11 +457,25 @@ void __init efi_init(void) #endif } +void __init efi_set_executable(efi_memory_desc_t *md, bool executable) +{ + u64 addr, npages; + + addr = md->virt_addr; + npages = md->num_pages; + + memrange_efi_to_native(&addr, &npages); + + if (executable) + set_memory_x(addr, npages); + else + set_memory_nx(addr, npages); +} + static void __init runtime_code_page_mkexec(void) { efi_memory_desc_t *md; void *p; - u64 addr, npages; /* Make EFI runtime service code area executable */ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { @@ -481,10 +484,7 @@ static void __init runtime_code_page_mkexec(void) if (md->type != EFI_RUNTIME_SERVICES_CODE) continue; - addr = md->virt_addr; - npages = md->num_pages; - memrange_efi_to_native(&addr, &npages); - set_memory_x(addr, npages); + efi_set_executable(md, true); } } @@ -498,13 +498,42 @@ static void __init runtime_code_page_mkexec(void) */ void __init efi_enter_virtual_mode(void) { - efi_memory_desc_t *md; + efi_memory_desc_t *md, *prev_md = NULL; efi_status_t status; unsigned long size; u64 end, systab, addr, npages, end_pfn; - void *p, *va; + void *p, *va, *new_memmap = NULL; + int count = 0; efi.systab = NULL; + + /* Merge contiguous regions of the same type and attribute */ + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { + u64 prev_size; + md = p; + + if (!prev_md) { + prev_md = md; + continue; + } + + if (prev_md->type != md->type || + prev_md->attribute != md->attribute) { + prev_md = md; + continue; + } + + prev_size = prev_md->num_pages << EFI_PAGE_SHIFT; + + if (md->phys_addr == (prev_md->phys_addr + prev_size)) { + prev_md->num_pages += md->num_pages; + md->type = EFI_RESERVED_TYPE; + md->attribute = 0; + continue; + } + prev_md = md; + } + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { md = p; if (!(md->attribute & EFI_MEMORY_RUNTIME)) @@ -541,15 +570,21 @@ void __init efi_enter_virtual_mode(void) systab += md->virt_addr - md->phys_addr; efi.systab = (efi_system_table_t *) (unsigned long) systab; } + new_memmap = krealloc(new_memmap, + (count + 1) * memmap.desc_size, + GFP_KERNEL); + memcpy(new_memmap + (count * memmap.desc_size), md, + memmap.desc_size); + count++; } BUG_ON(!efi.systab); status = phys_efi_set_virtual_address_map( - memmap.desc_size * memmap.nr_map, + memmap.desc_size * count, memmap.desc_size, memmap.desc_version, - memmap.phys_map); + (efi_memory_desc_t *)__pa(new_memmap)); if (status != EFI_SUCCESS) { printk(KERN_ALERT "Unable to switch EFI into virtual mode " @@ -572,11 +607,12 @@ void __init efi_enter_virtual_mode(void) efi.set_variable = virt_efi_set_variable; efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; efi.reset_system = virt_efi_reset_system; - efi.set_virtual_address_map = virt_efi_set_virtual_address_map; + efi.set_virtual_address_map = NULL; if (__supported_pte_mask & _PAGE_NX) runtime_code_page_mkexec(); early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); memmap.map = NULL; + kfree(new_memmap); } /* diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index ac0621a7ac3d..2649426a7905 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -41,22 +41,7 @@ static pgd_t save_pgd __initdata; static unsigned long efi_flags __initdata; -static void __init early_mapping_set_exec(unsigned long start, - unsigned long end, - int executable) -{ - unsigned long num_pages; - - start &= PMD_MASK; - end = (end + PMD_SIZE - 1) & PMD_MASK; - num_pages = (end - start) >> PAGE_SHIFT; - if (executable) - set_memory_x((unsigned long)__va(start), num_pages); - else - set_memory_nx((unsigned long)__va(start), num_pages); -} - -static void __init early_runtime_code_mapping_set_exec(int executable) +static void __init early_code_mapping_set_exec(int executable) { efi_memory_desc_t *md; void *p; @@ -67,11 +52,8 @@ static void __init early_runtime_code_mapping_set_exec(int executable) /* Make EFI runtime service code area executable */ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { md = p; - if (md->type == EFI_RUNTIME_SERVICES_CODE) { - unsigned long end; - end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); - early_mapping_set_exec(md->phys_addr, end, executable); - } + if (md->type == EFI_RUNTIME_SERVICES_CODE) + efi_set_executable(md, executable); } } @@ -79,7 +61,7 @@ void __init efi_call_phys_prelog(void) { unsigned long vaddress; - early_runtime_code_mapping_set_exec(1); + early_code_mapping_set_exec(1); local_irq_save(efi_flags); vaddress = (unsigned long)__va(0x0UL); save_pgd = *pgd_offset_k(0x0UL); @@ -95,7 +77,7 @@ void __init efi_call_phys_epilog(void) set_pgd(pgd_offset_k(0x0UL), save_pgd); __flush_tlb_all(); local_irq_restore(efi_flags); - early_runtime_code_mapping_set_exec(0); + early_code_mapping_set_exec(0); } void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size, @@ -107,8 +89,10 @@ void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size, return ioremap(phys_addr, size); last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size); - if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size) - return NULL; + if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size) { + unsigned long top = last_map_pfn << PAGE_SHIFT; + efi_ioremap(top, size - (top - phys_addr), type); + } return (void __iomem *)__va(phys_addr); } diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c index 275dbc19e2cf..7000e74b3087 100644 --- a/arch/x86/platform/mrst/mrst.c +++ b/arch/x86/platform/mrst/mrst.c @@ -194,7 +194,7 @@ static unsigned long __init mrst_calibrate_tsc(void) return 0; } -void __init mrst_time_init(void) +static void __init mrst_time_init(void) { sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); switch (mrst_timer_options) { @@ -216,7 +216,7 @@ void __init mrst_time_init(void) apbt_time_init(); } -void __cpuinit mrst_arch_setup(void) +static void __cpuinit mrst_arch_setup(void) { if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27) __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; diff --git a/arch/x86/platform/olpc/Makefile b/arch/x86/platform/olpc/Makefile index c2a8cab65e5d..81c5e2165c24 100644 --- a/arch/x86/platform/olpc/Makefile +++ b/arch/x86/platform/olpc/Makefile @@ -1,4 +1,2 @@ -obj-$(CONFIG_OLPC) += olpc.o +obj-$(CONFIG_OLPC) += olpc.o olpc_ofw.o olpc_dt.o obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o -obj-$(CONFIG_OLPC) += olpc_ofw.o -obj-$(CONFIG_OF_PROMTREE) += olpc_dt.o diff --git a/arch/x86/platform/olpc/olpc.c b/arch/x86/platform/olpc/olpc.c index edaf3fe8dc5e..0060fd59ea00 100644 --- a/arch/x86/platform/olpc/olpc.c +++ b/arch/x86/platform/olpc/olpc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -187,41 +188,43 @@ int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen, } EXPORT_SYMBOL_GPL(olpc_ec_cmd); -static bool __init check_ofw_architecture(void) +static bool __init check_ofw_architecture(struct device_node *root) { - size_t propsize; - char olpc_arch[5]; - const void *args[] = { NULL, "architecture", olpc_arch, (void *)5 }; - void *res[] = { &propsize }; + const char *olpc_arch; + int propsize; - if (olpc_ofw("getprop", args, res)) { - printk(KERN_ERR "ofw: getprop call failed!\n"); - return false; - } + olpc_arch = of_get_property(root, "architecture", &propsize); return propsize == 5 && strncmp("OLPC", olpc_arch, 5) == 0; } -static u32 __init get_board_revision(void) +static u32 __init get_board_revision(struct device_node *root) { - size_t propsize; - __be32 rev; - const void *args[] = { NULL, "board-revision-int", &rev, (void *)4 }; - void *res[] = { &propsize }; + int propsize; + const __be32 *rev; - if (olpc_ofw("getprop", args, res) || propsize != 4) { - printk(KERN_ERR "ofw: getprop call failed!\n"); - return cpu_to_be32(0); - } - return be32_to_cpu(rev); + rev = of_get_property(root, "board-revision-int", &propsize); + if (propsize != 4) + return 0; + + return be32_to_cpu(*rev); } static bool __init platform_detect(void) { - if (!check_ofw_architecture()) + struct device_node *root = of_find_node_by_path("/"); + bool success; + + if (!root) return false; - olpc_platform_info.flags |= OLPC_F_PRESENT; - olpc_platform_info.boardrev = get_board_revision(); - return true; + + success = check_ofw_architecture(root); + if (success) { + olpc_platform_info.boardrev = get_board_revision(root); + olpc_platform_info.flags |= OLPC_F_PRESENT; + } + + of_node_put(root); + return success; } static int __init add_xo1_platform_devices(void) diff --git a/arch/x86/platform/olpc/olpc_dt.c b/arch/x86/platform/olpc/olpc_dt.c index 044bda5b3174..d39f63d017d2 100644 --- a/arch/x86/platform/olpc/olpc_dt.c +++ b/arch/x86/platform/olpc/olpc_dt.c @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include static phandle __init olpc_dt_getsibling(phandle node) @@ -180,3 +182,20 @@ void __init olpc_dt_build_devicetree(void) pr_info("PROM DT: Built device tree with %u bytes of memory.\n", prom_early_allocated); } + +/* A list of DT node/bus matches that we want to expose as platform devices */ +static struct of_device_id __initdata of_ids[] = { + { .compatible = "olpc,xo1-battery" }, + { .compatible = "olpc,xo1-dcon" }, + { .compatible = "olpc,xo1-rtc" }, + {}, +}; + +static int __init olpc_create_platform_devices(void) +{ + if (machine_is_olpc()) + return of_platform_bus_probe(NULL, of_ids, NULL); + else + return 0; +} +device_initcall(olpc_create_platform_devices); diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index 7cb6424317f6..c58e0ea39ef5 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c @@ -699,16 +699,17 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, struct mm_struct *mm, unsigned long va, unsigned int cpu) { - int tcpu; - int uvhub; int locals = 0; int remotes = 0; int hubs = 0; + int tcpu; + int tpnode; struct bau_desc *bau_desc; struct cpumask *flush_mask; struct ptc_stats *stat; struct bau_control *bcp; struct bau_control *tbcp; + struct hub_and_pnode *hpp; /* kernel was booted 'nobau' */ if (nobau) @@ -750,11 +751,18 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, bau_desc += UV_ITEMS_PER_DESCRIPTOR * bcp->uvhub_cpu; bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE); - /* cpu statistics */ for_each_cpu(tcpu, flush_mask) { - uvhub = uv_cpu_to_blade_id(tcpu); - bau_uvhub_set(uvhub, &bau_desc->distribution); - if (uvhub == bcp->uvhub) + /* + * The distribution vector is a bit map of pnodes, relative + * to the partition base pnode (and the partition base nasid + * in the header). + * Translate cpu to pnode and hub using an array stored + * in local memory. + */ + hpp = &bcp->socket_master->target_hub_and_pnode[tcpu]; + tpnode = hpp->pnode - bcp->partition_base_pnode; + bau_uvhub_set(tpnode, &bau_desc->distribution); + if (hpp->uvhub == bcp->uvhub) locals++; else remotes++; @@ -855,7 +863,7 @@ void uv_bau_message_interrupt(struct pt_regs *regs) * an interrupt, but causes an error message to be returned to * the sender. */ -static void uv_enable_timeouts(void) +static void __init uv_enable_timeouts(void) { int uvhub; int nuvhubs; @@ -1326,10 +1334,10 @@ static int __init uv_ptc_init(void) } /* - * initialize the sending side's sending buffers + * Initialize the sending side's sending buffers. */ static void -uv_activation_descriptor_init(int node, int pnode) +uv_activation_descriptor_init(int node, int pnode, int base_pnode) { int i; int cpu; @@ -1352,11 +1360,11 @@ uv_activation_descriptor_init(int node, int pnode) n = pa >> uv_nshift; m = pa & uv_mmask; + /* the 14-bit pnode */ uv_write_global_mmr64(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE, (n << UV_DESC_BASE_PNODE_SHIFT | m)); - /* - * initializing all 8 (UV_ITEMS_PER_DESCRIPTOR) descriptors for each + * Initializing all 8 (UV_ITEMS_PER_DESCRIPTOR) descriptors for each * cpu even though we only use the first one; one descriptor can * describe a broadcast to 256 uv hubs. */ @@ -1365,12 +1373,13 @@ uv_activation_descriptor_init(int node, int pnode) memset(bd2, 0, sizeof(struct bau_desc)); bd2->header.sw_ack_flag = 1; /* - * base_dest_nodeid is the nasid of the first uvhub - * in the partition. The bit map will indicate uvhub numbers, - * which are 0-N in a partition. Pnodes are unique system-wide. + * The base_dest_nasid set in the message header is the nasid + * of the first uvhub in the partition. The bit map will + * indicate destination pnode numbers relative to that base. + * They may not be consecutive if nasid striding is being used. */ - bd2->header.base_dest_nodeid = UV_PNODE_TO_NASID(uv_partition_base_pnode); - bd2->header.dest_subnodeid = 0x10; /* the LB */ + bd2->header.base_dest_nasid = UV_PNODE_TO_NASID(base_pnode); + bd2->header.dest_subnodeid = UV_LB_SUBNODEID; bd2->header.command = UV_NET_ENDPOINT_INTD; bd2->header.int_both = 1; /* @@ -1442,7 +1451,7 @@ uv_payload_queue_init(int node, int pnode) /* * Initialization of each UV hub's structures */ -static void __init uv_init_uvhub(int uvhub, int vector) +static void __init uv_init_uvhub(int uvhub, int vector, int base_pnode) { int node; int pnode; @@ -1450,11 +1459,11 @@ static void __init uv_init_uvhub(int uvhub, int vector) node = uvhub_to_first_node(uvhub); pnode = uv_blade_to_pnode(uvhub); - uv_activation_descriptor_init(node, pnode); + uv_activation_descriptor_init(node, pnode, base_pnode); uv_payload_queue_init(node, pnode); /* - * the below initialization can't be in firmware because the - * messaging IRQ will be determined by the OS + * The below initialization can't be in firmware because the + * messaging IRQ will be determined by the OS. */ apicid = uvhub_to_first_apicid(uvhub) | uv_apicid_hibits; uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG, @@ -1491,10 +1500,11 @@ calculate_destination_timeout(void) /* * initialize the bau_control structure for each cpu */ -static int __init uv_init_per_cpu(int nuvhubs) +static int __init uv_init_per_cpu(int nuvhubs, int base_part_pnode) { int i; int cpu; + int tcpu; int pnode; int uvhub; int have_hmaster; @@ -1528,6 +1538,15 @@ static int __init uv_init_per_cpu(int nuvhubs) bcp = &per_cpu(bau_control, cpu); memset(bcp, 0, sizeof(struct bau_control)); pnode = uv_cpu_hub_info(cpu)->pnode; + if ((pnode - base_part_pnode) >= UV_DISTRIBUTION_SIZE) { + printk(KERN_EMERG + "cpu %d pnode %d-%d beyond %d; BAU disabled\n", + cpu, pnode, base_part_pnode, + UV_DISTRIBUTION_SIZE); + return 1; + } + bcp->osnode = cpu_to_node(cpu); + bcp->partition_base_pnode = uv_partition_base_pnode; uvhub = uv_cpu_hub_info(cpu)->numa_blade_id; *(uvhub_mask + (uvhub/8)) |= (1 << (uvhub%8)); bdp = &uvhub_descs[uvhub]; @@ -1536,7 +1555,7 @@ static int __init uv_init_per_cpu(int nuvhubs) bdp->pnode = pnode; /* kludge: 'assuming' one node per socket, and assuming that disabling a socket just leaves a gap in node numbers */ - socket = (cpu_to_node(cpu) & 1); + socket = bcp->osnode & 1; bdp->socket_mask |= (1 << socket); sdp = &bdp->socket[socket]; sdp->cpu_number[sdp->num_cpus] = cpu; @@ -1585,6 +1604,20 @@ static int __init uv_init_per_cpu(int nuvhubs) nextsocket: socket++; socket_mask = (socket_mask >> 1); + /* each socket gets a local array of pnodes/hubs */ + bcp = smaster; + bcp->target_hub_and_pnode = kmalloc_node( + sizeof(struct hub_and_pnode) * + num_possible_cpus(), GFP_KERNEL, bcp->osnode); + memset(bcp->target_hub_and_pnode, 0, + sizeof(struct hub_and_pnode) * + num_possible_cpus()); + for_each_present_cpu(tcpu) { + bcp->target_hub_and_pnode[tcpu].pnode = + uv_cpu_hub_info(tcpu)->pnode; + bcp->target_hub_and_pnode[tcpu].uvhub = + uv_cpu_hub_info(tcpu)->numa_blade_id; + } } } kfree(uvhub_descs); @@ -1637,21 +1670,22 @@ static int __init uv_bau_init(void) spin_lock_init(&disable_lock); congested_cycles = microsec_2_cycles(congested_response_us); - if (uv_init_per_cpu(nuvhubs)) { + uv_partition_base_pnode = 0x7fffffff; + for (uvhub = 0; uvhub < nuvhubs; uvhub++) { + if (uv_blade_nr_possible_cpus(uvhub) && + (uv_blade_to_pnode(uvhub) < uv_partition_base_pnode)) + uv_partition_base_pnode = uv_blade_to_pnode(uvhub); + } + + if (uv_init_per_cpu(nuvhubs, uv_partition_base_pnode)) { nobau = 1; return 0; } - uv_partition_base_pnode = 0x7fffffff; - for (uvhub = 0; uvhub < nuvhubs; uvhub++) - if (uv_blade_nr_possible_cpus(uvhub) && - (uv_blade_to_pnode(uvhub) < uv_partition_base_pnode)) - uv_partition_base_pnode = uv_blade_to_pnode(uvhub); - vector = UV_BAU_MESSAGE; for_each_possible_blade(uvhub) if (uv_blade_nr_possible_cpus(uvhub)) - uv_init_uvhub(uvhub, vector); + uv_init_uvhub(uvhub, vector, uv_partition_base_pnode); uv_enable_timeouts(); alloc_intr_gate(vector, uv_bau_message_intr1); diff --git a/arch/x86/platform/uv/uv_time.c b/arch/x86/platform/uv/uv_time.c index 9daf5d1af9f1..0eb90184515f 100644 --- a/arch/x86/platform/uv/uv_time.c +++ b/arch/x86/platform/uv/uv_time.c @@ -40,7 +40,6 @@ static struct clocksource clocksource_uv = { .rating = 400, .read = uv_read_rtc, .mask = (cycle_t)UVH_RTC_REAL_TIME_CLOCK_MASK, - .shift = 10, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -372,14 +371,11 @@ static __init int uv_rtc_setup_clock(void) if (!is_uv_system()) return -ENODEV; - clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second, - clocksource_uv.shift); - /* If single blade, prefer tsc */ if (uv_num_possible_blades() == 1) clocksource_uv.rating = 250; - rc = clocksource_register(&clocksource_uv); + rc = clocksource_register_hz(&clocksource_uv, sn_rtc_cycles_per_second); if (rc) printk(KERN_INFO "UV RTC clocksource failed rc %d\n", rc); else diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index e3c6a06cf725..dd7b88f2ec7a 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -235,7 +235,7 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx, *dx &= maskedx; } -static __init void xen_init_cpuid_mask(void) +static void __init xen_init_cpuid_mask(void) { unsigned int ax, bx, cx, dx; unsigned int xsave_mask; @@ -400,7 +400,7 @@ static void xen_load_gdt(const struct desc_ptr *dtr) /* * load_gdt for early boot, when the gdt is only mapped once */ -static __init void xen_load_gdt_boot(const struct desc_ptr *dtr) +static void __init xen_load_gdt_boot(const struct desc_ptr *dtr) { unsigned long va = dtr->address; unsigned int size = dtr->size + 1; @@ -662,7 +662,7 @@ static void xen_write_gdt_entry(struct desc_struct *dt, int entry, * Version of write_gdt_entry for use at early boot-time needed to * update an entry as simply as possible. */ -static __init void xen_write_gdt_entry_boot(struct desc_struct *dt, int entry, +static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry, const void *desc, int type) { switch (type) { @@ -933,18 +933,18 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf, return ret; } -static const struct pv_info xen_info __initdata = { +static const struct pv_info xen_info __initconst = { .paravirt_enabled = 1, .shared_kernel_pmd = 0, .name = "Xen", }; -static const struct pv_init_ops xen_init_ops __initdata = { +static const struct pv_init_ops xen_init_ops __initconst = { .patch = xen_patch, }; -static const struct pv_cpu_ops xen_cpu_ops __initdata = { +static const struct pv_cpu_ops xen_cpu_ops __initconst = { .cpuid = xen_cpuid, .set_debugreg = xen_set_debugreg, @@ -1004,7 +1004,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { .end_context_switch = xen_end_context_switch, }; -static const struct pv_apic_ops xen_apic_ops __initdata = { +static const struct pv_apic_ops xen_apic_ops __initconst = { #ifdef CONFIG_X86_LOCAL_APIC .startup_ipi_hook = paravirt_nop, #endif @@ -1055,7 +1055,7 @@ int xen_panic_handler_init(void) return 0; } -static const struct machine_ops __initdata xen_machine_ops = { +static const struct machine_ops xen_machine_ops __initconst = { .restart = xen_restart, .halt = xen_machine_halt, .power_off = xen_machine_halt, @@ -1332,7 +1332,7 @@ static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self, return NOTIFY_OK; } -static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = { +static struct notifier_block xen_hvm_cpu_notifier __cpuinitdata = { .notifier_call = xen_hvm_cpu_notify, }; @@ -1381,7 +1381,7 @@ bool xen_hvm_need_lapic(void) } EXPORT_SYMBOL_GPL(xen_hvm_need_lapic); -const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = { +const struct hypervisor_x86 x86_hyper_xen_hvm __refconst = { .name = "Xen HVM", .detect = xen_hvm_platform, .init_platform = xen_hvm_guest_init, diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c index 6a6fe8939645..8bbb465b6f0a 100644 --- a/arch/x86/xen/irq.c +++ b/arch/x86/xen/irq.c @@ -113,7 +113,7 @@ static void xen_halt(void) xen_safe_halt(); } -static const struct pv_irq_ops xen_irq_ops __initdata = { +static const struct pv_irq_ops xen_irq_ops __initconst = { .save_fl = PV_CALLEE_SAVE(xen_save_fl), .restore_fl = PV_CALLEE_SAVE(xen_restore_fl), .irq_disable = PV_CALLEE_SAVE(xen_irq_disable), diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index a991b57f91fe..02d752460371 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1054,7 +1054,7 @@ void xen_mm_pin_all(void) * that's before we have page structures to store the bits. So do all * the book-keeping now. */ -static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page, +static int __init xen_mark_pinned(struct mm_struct *mm, struct page *page, enum pt_level level) { SetPagePinned(page); @@ -1187,7 +1187,7 @@ static void drop_other_mm_ref(void *info) active_mm = percpu_read(cpu_tlbstate.active_mm); - if (active_mm == mm) + if (active_mm == mm && percpu_read(cpu_tlbstate.state) != TLBSTATE_OK) leave_mm(smp_processor_id()); /* If this cpu still has a stale cr3 reference, then make sure @@ -1271,13 +1271,27 @@ void xen_exit_mmap(struct mm_struct *mm) spin_unlock(&mm->page_table_lock); } -static __init void xen_pagetable_setup_start(pgd_t *base) +static void __init xen_pagetable_setup_start(pgd_t *base) { } +static __init void xen_mapping_pagetable_reserve(u64 start, u64 end) +{ + /* reserve the range used */ + native_pagetable_reserve(start, end); + + /* set as RW the rest */ + printk(KERN_DEBUG "xen: setting RW the range %llx - %llx\n", end, + PFN_PHYS(pgt_buf_top)); + while (end < PFN_PHYS(pgt_buf_top)) { + make_lowmem_page_readwrite(__va(end)); + end += PAGE_SIZE; + } +} + static void xen_post_allocator_init(void); -static __init void xen_pagetable_setup_done(pgd_t *base) +static void __init xen_pagetable_setup_done(pgd_t *base) { xen_setup_shared_info(); xen_post_allocator_init(); @@ -1473,16 +1487,20 @@ static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd) #endif } -static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) -{ - unsigned long pfn = pte_pfn(pte); - #ifdef CONFIG_X86_32 +static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte) +{ /* If there's an existing pte, then don't allow _PAGE_RW to be set */ if (pte_val_ma(*ptep) & _PAGE_PRESENT) pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) & pte_val_ma(pte)); -#endif + + return pte; +} +#else /* CONFIG_X86_64 */ +static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte) +{ + unsigned long pfn = pte_pfn(pte); /* * If the new pfn is within the range of the newly allocated @@ -1491,16 +1509,17 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) * it is RO. */ if (((!is_early_ioremap_ptep(ptep) && - pfn >= pgt_buf_start && pfn < pgt_buf_end)) || + pfn >= pgt_buf_start && pfn < pgt_buf_top)) || (is_early_ioremap_ptep(ptep) && pfn != (pgt_buf_end - 1))) pte = pte_wrprotect(pte); return pte; } +#endif /* CONFIG_X86_64 */ /* Init-time set_pte while constructing initial pagetables, which doesn't allow RO pagetable pages to be remapped RW */ -static __init void xen_set_pte_init(pte_t *ptep, pte_t pte) +static void __init xen_set_pte_init(pte_t *ptep, pte_t pte) { pte = mask_rw_pte(ptep, pte); @@ -1518,7 +1537,7 @@ static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn) /* Early in boot, while setting up the initial pagetable, assume everything is pinned. */ -static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn) +static void __init xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn) { #ifdef CONFIG_FLATMEM BUG_ON(mem_map); /* should only be used early */ @@ -1528,7 +1547,7 @@ static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn) } /* Used for pmd and pud */ -static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn) +static void __init xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn) { #ifdef CONFIG_FLATMEM BUG_ON(mem_map); /* should only be used early */ @@ -1538,13 +1557,13 @@ static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn) /* Early release_pte assumes that all pts are pinned, since there's only init_mm and anything attached to that is pinned. */ -static __init void xen_release_pte_init(unsigned long pfn) +static void __init xen_release_pte_init(unsigned long pfn) { pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn); make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); } -static __init void xen_release_pmd_init(unsigned long pfn) +static void __init xen_release_pmd_init(unsigned long pfn) { make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); } @@ -1670,7 +1689,7 @@ static void set_page_prot(void *addr, pgprot_t prot) BUG(); } -static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) +static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) { unsigned pmdidx, pteidx; unsigned ident_pte; @@ -1753,7 +1772,7 @@ static void convert_pfn_mfn(void *v) * of the physical mapping once some sort of allocator has been set * up. */ -__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, +pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) { pud_t *l3; @@ -1824,7 +1843,7 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, static RESERVE_BRK_ARRAY(pmd_t, initial_kernel_pmd, PTRS_PER_PMD); static RESERVE_BRK_ARRAY(pmd_t, swapper_kernel_pmd, PTRS_PER_PMD); -static __init void xen_write_cr3_init(unsigned long cr3) +static void __init xen_write_cr3_init(unsigned long cr3) { unsigned long pfn = PFN_DOWN(__pa(swapper_pg_dir)); @@ -1861,7 +1880,7 @@ static __init void xen_write_cr3_init(unsigned long cr3) pv_mmu_ops.write_cr3 = &xen_write_cr3; } -__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, +pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) { pmd_t *kernel_pmd; @@ -1967,7 +1986,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) #endif } -__init void xen_ident_map_ISA(void) +void __init xen_ident_map_ISA(void) { unsigned long pa; @@ -1990,7 +2009,7 @@ __init void xen_ident_map_ISA(void) xen_flush_tlb(); } -static __init void xen_post_allocator_init(void) +static void __init xen_post_allocator_init(void) { #ifdef CONFIG_XEN_DEBUG pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug); @@ -2027,7 +2046,7 @@ static void xen_leave_lazy_mmu(void) preempt_enable(); } -static const struct pv_mmu_ops xen_mmu_ops __initdata = { +static const struct pv_mmu_ops xen_mmu_ops __initconst = { .read_cr2 = xen_read_cr2, .write_cr2 = xen_write_cr2, @@ -2100,6 +2119,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = { void __init xen_init_mmu_ops(void) { + x86_init.mapping.pagetable_reserve = xen_mapping_pagetable_reserve; x86_init.paging.pagetable_setup_start = xen_pagetable_setup_start; x86_init.paging.pagetable_setup_done = xen_pagetable_setup_done; pv_mmu_ops = xen_mmu_ops; diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 141eb0de8b06..58efeb9d5440 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -522,11 +522,20 @@ static bool __init __early_alloc_p2m(unsigned long pfn) /* Boundary cross-over for the edges: */ if (idx) { unsigned long *p2m = extend_brk(PAGE_SIZE, PAGE_SIZE); + unsigned long *mid_mfn_p; p2m_init(p2m); p2m_top[topidx][mididx] = p2m; + /* For save/restore we need to MFN of the P2M saved */ + + mid_mfn_p = p2m_top_mfn_p[topidx]; + WARN(mid_mfn_p[mididx] != virt_to_mfn(p2m_missing), + "P2M_TOP_P[%d][%d] != MFN of p2m_missing!\n", + topidx, mididx); + mid_mfn_p[mididx] = virt_to_mfn(p2m); + } return idx != 0; } @@ -549,12 +558,29 @@ unsigned long __init set_phys_range_identity(unsigned long pfn_s, pfn += P2M_MID_PER_PAGE * P2M_PER_PAGE) { unsigned topidx = p2m_top_index(pfn); - if (p2m_top[topidx] == p2m_mid_missing) { - unsigned long **mid = extend_brk(PAGE_SIZE, PAGE_SIZE); + unsigned long *mid_mfn_p; + unsigned long **mid; + + mid = p2m_top[topidx]; + mid_mfn_p = p2m_top_mfn_p[topidx]; + if (mid == p2m_mid_missing) { + mid = extend_brk(PAGE_SIZE, PAGE_SIZE); p2m_mid_init(mid); p2m_top[topidx] = mid; + + BUG_ON(mid_mfn_p != p2m_mid_missing_mfn); + } + /* And the save/restore P2M tables.. */ + if (mid_mfn_p == p2m_mid_missing_mfn) { + mid_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE); + p2m_mid_mfn_init(mid_mfn_p); + + p2m_top_mfn_p[topidx] = mid_mfn_p; + p2m_top_mfn[topidx] = virt_to_mfn(mid_mfn_p); + /* Note: we don't set mid_mfn_p[midix] here, + * look in __early_alloc_p2m */ } } @@ -650,7 +676,7 @@ static unsigned long mfn_hash(unsigned long mfn) } /* Add an MFN override for a particular page */ -int m2p_add_override(unsigned long mfn, struct page *page) +int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte) { unsigned long flags; unsigned long pfn; @@ -662,7 +688,6 @@ int m2p_add_override(unsigned long mfn, struct page *page) if (!PageHighMem(page)) { address = (unsigned long)__va(pfn << PAGE_SHIFT); ptep = lookup_address(address, &level); - if (WARN(ptep == NULL || level != PG_LEVEL_4K, "m2p_add_override: pfn %lx not mapped", pfn)) return -EINVAL; @@ -674,18 +699,17 @@ int m2p_add_override(unsigned long mfn, struct page *page) if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) return -ENOMEM; - if (!PageHighMem(page)) + if (clear_pte && !PageHighMem(page)) /* Just zap old mapping for now */ pte_clear(&init_mm, address, ptep); - spin_lock_irqsave(&m2p_override_lock, flags); list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); spin_unlock_irqrestore(&m2p_override_lock, flags); return 0; } - -int m2p_remove_override(struct page *page) +EXPORT_SYMBOL_GPL(m2p_add_override); +int m2p_remove_override(struct page *page, bool clear_pte) { unsigned long flags; unsigned long mfn; @@ -713,7 +737,7 @@ int m2p_remove_override(struct page *page) spin_unlock_irqrestore(&m2p_override_lock, flags); set_phys_to_machine(pfn, page->index); - if (!PageHighMem(page)) + if (clear_pte && !PageHighMem(page)) set_pte_at(&init_mm, address, ptep, pfn_pte(pfn, PAGE_KERNEL)); /* No tlb flush necessary because the caller already @@ -721,6 +745,7 @@ int m2p_remove_override(struct page *page) return 0; } +EXPORT_SYMBOL_GPL(m2p_remove_override); struct page *m2p_find_override(unsigned long mfn) { diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index fa0269a99377..be1a464f6d66 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -50,7 +50,7 @@ phys_addr_t xen_extra_mem_start, xen_extra_mem_size; */ #define EXTRA_MEM_RATIO (10) -static __init void xen_add_extra_mem(unsigned long pages) +static void __init xen_add_extra_mem(unsigned long pages) { unsigned long pfn; @@ -166,7 +166,7 @@ static unsigned long __init xen_set_identity(const struct e820entry *list, if (last > end) continue; - if (entry->type == E820_RAM) { + if ((entry->type == E820_RAM) || (entry->type == E820_UNUSABLE)) { if (start > start_pci) identity += set_phys_range_identity( PFN_UP(start_pci), PFN_DOWN(start)); @@ -227,7 +227,11 @@ char * __init xen_memory_setup(void) memcpy(map_raw, map, sizeof(map)); e820.nr_map = 0; +#ifdef CONFIG_X86_32 xen_extra_mem_start = mem_end; +#else + xen_extra_mem_start = max((1ULL << 32), mem_end); +#endif for (i = 0; i < memmap.nr_entries; i++) { unsigned long long end; @@ -336,7 +340,7 @@ static void __init fiddle_vdso(void) #endif } -static __cpuinit int register_callback(unsigned type, const void *func) +static int __cpuinit register_callback(unsigned type, const void *func) { struct callback_register callback = { .type = type, diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 30612441ed99..41038c01de40 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -46,18 +46,17 @@ static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id); static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id); /* - * Reschedule call back. Nothing to do, - * all the work is done automatically when - * we return from the interrupt. + * Reschedule call back. */ static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id) { inc_irq_stat(irq_resched_count); + scheduler_ipi(); return IRQ_HANDLED; } -static __cpuinit void cpu_bringup(void) +static void __cpuinit cpu_bringup(void) { int cpu = smp_processor_id(); @@ -85,7 +84,7 @@ static __cpuinit void cpu_bringup(void) wmb(); /* make sure everything is out */ } -static __cpuinit void cpu_bringup_and_idle(void) +static void __cpuinit cpu_bringup_and_idle(void) { cpu_bringup(); cpu_idle(); @@ -242,7 +241,7 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus) } } -static __cpuinit int +static int __cpuinit cpu_initialize_context(unsigned int cpu, struct task_struct *idle) { struct vcpu_guest_context *ctxt; @@ -486,7 +485,7 @@ static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static const struct smp_ops xen_smp_ops __initdata = { +static const struct smp_ops xen_smp_ops __initconst = { .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu, .smp_prepare_cpus = xen_smp_prepare_cpus, .smp_cpus_done = xen_smp_cpus_done, diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 2e2d370a47b1..5158c505bef9 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -26,8 +26,6 @@ #include "xen-ops.h" -#define XEN_SHIFT 22 - /* Xen may fire a timer up to this many ns early */ #define TIMER_SLOP 100000 #define NS_PER_TICK (1000000000LL / HZ) @@ -211,8 +209,6 @@ static struct clocksource xen_clocksource __read_mostly = { .rating = 400, .read = xen_clocksource_get_cycles, .mask = ~0, - .mult = 1< 0 and at this point we don't know how many cpus are diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 3112f55638c4..97dfdc8757b3 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -74,7 +74,7 @@ static inline void xen_hvm_smp_init(void) {} #ifdef CONFIG_PARAVIRT_SPINLOCKS void __init xen_init_spinlocks(void); -__cpuinit void xen_init_lock_cpu(int cpu); +void __cpuinit xen_init_lock_cpu(int cpu); void xen_uninit_lock_cpu(int cpu); #else static inline void xen_init_spinlocks(void) diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c index d77089df412e..4340ee076bd5 100644 --- a/arch/xtensa/kernel/irq.c +++ b/arch/xtensa/kernel/irq.c @@ -64,47 +64,41 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs) int arch_show_interrupts(struct seq_file *p, int prec) { - int j; - - seq_printf(p, "%*s: ", prec, "NMI"); - for_each_online_cpu(j) - seq_printf(p, "%10u ", nmi_count(j)); - seq_putc(p, '\n'); seq_printf(p, "%*s: ", prec, "ERR"); seq_printf(p, "%10u\n", atomic_read(&irq_err_count)); return 0; } -static void xtensa_irq_mask(struct irq_chip *d) +static void xtensa_irq_mask(struct irq_data *d) { cached_irq_mask &= ~(1 << d->irq); set_sr (cached_irq_mask, INTENABLE); } -static void xtensa_irq_unmask(struct irq_chip *d) +static void xtensa_irq_unmask(struct irq_data *d) { cached_irq_mask |= 1 << d->irq; set_sr (cached_irq_mask, INTENABLE); } -static void xtensa_irq_enable(struct irq_chip *d) +static void xtensa_irq_enable(struct irq_data *d) { variant_irq_enable(d->irq); xtensa_irq_unmask(d->irq); } -static void xtensa_irq_disable(struct irq_chip *d) +static void xtensa_irq_disable(struct irq_data *d) { xtensa_irq_mask(d->irq); variant_irq_disable(d->irq); } -static void xtensa_irq_ack(struct irq_chip *d) +static void xtensa_irq_ack(struct irq_data *d) { set_sr(1 << d->irq, INTCLEAR); } -static int xtensa_irq_retrigger(struct irq_chip *d) +static int xtensa_irq_retrigger(struct irq_data *d) { set_sr (1 << d->irq, INTSET); return 1; diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index f0605ab2a761..471fdcc5df85 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -114,6 +114,13 @@ struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup) } EXPORT_SYMBOL_GPL(cgroup_to_blkio_cgroup); +struct blkio_cgroup *task_blkio_cgroup(struct task_struct *tsk) +{ + return container_of(task_subsys_state(tsk, blkio_subsys_id), + struct blkio_cgroup, css); +} +EXPORT_SYMBOL_GPL(task_blkio_cgroup); + static inline void blkio_update_group_weight(struct blkio_group *blkg, unsigned int weight) { diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h index 10919fae2d3a..c774930cc206 100644 --- a/block/blk-cgroup.h +++ b/block/blk-cgroup.h @@ -291,6 +291,7 @@ static inline void blkiocg_set_start_empty_time(struct blkio_group *blkg) {} #if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE) extern struct blkio_cgroup blkio_root_cgroup; extern struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup); +extern struct blkio_cgroup *task_blkio_cgroup(struct task_struct *tsk); extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, struct blkio_group *blkg, void *key, dev_t dev, enum blkio_policy_id plid); @@ -314,6 +315,8 @@ void blkiocg_update_io_remove_stats(struct blkio_group *blkg, struct cgroup; static inline struct blkio_cgroup * cgroup_to_blkio_cgroup(struct cgroup *cgroup) { return NULL; } +static inline struct blkio_cgroup * +task_blkio_cgroup(struct task_struct *tsk) { return NULL; } static inline void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, struct blkio_group *blkg, void *key, dev_t dev, diff --git a/block/blk-core.c b/block/blk-core.c index 78b7b0cb7216..3fe00a14822a 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -204,7 +204,7 @@ static void blk_delay_work(struct work_struct *work) q = container_of(work, struct request_queue, delay_work.work); spin_lock_irq(q->queue_lock); - __blk_run_queue(q, false); + __blk_run_queue(q); spin_unlock_irq(q->queue_lock); } @@ -220,7 +220,8 @@ static void blk_delay_work(struct work_struct *work) */ void blk_delay_queue(struct request_queue *q, unsigned long msecs) { - schedule_delayed_work(&q->delay_work, msecs_to_jiffies(msecs)); + queue_delayed_work(kblockd_workqueue, &q->delay_work, + msecs_to_jiffies(msecs)); } EXPORT_SYMBOL(blk_delay_queue); @@ -238,7 +239,7 @@ void blk_start_queue(struct request_queue *q) WARN_ON(!irqs_disabled()); queue_flag_clear(QUEUE_FLAG_STOPPED, q); - __blk_run_queue(q, false); + __blk_run_queue(q); } EXPORT_SYMBOL(blk_start_queue); @@ -291,30 +292,37 @@ EXPORT_SYMBOL(blk_sync_queue); /** * __blk_run_queue - run a single device queue * @q: The queue to run - * @force_kblockd: Don't run @q->request_fn directly. Use kblockd. * * Description: * See @blk_run_queue. This variant must be called with the queue lock * held and interrupts disabled. - * */ -void __blk_run_queue(struct request_queue *q, bool force_kblockd) +void __blk_run_queue(struct request_queue *q) { if (unlikely(blk_queue_stopped(q))) return; - /* - * Only recurse once to avoid overrunning the stack, let the unplug - * handling reinvoke the handler shortly if we already got there. - */ - if (!force_kblockd && !queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { - q->request_fn(q); - queue_flag_clear(QUEUE_FLAG_REENTER, q); - } else - queue_delayed_work(kblockd_workqueue, &q->delay_work, 0); + q->request_fn(q); } EXPORT_SYMBOL(__blk_run_queue); +/** + * blk_run_queue_async - run a single device queue in workqueue context + * @q: The queue to run + * + * Description: + * Tells kblockd to perform the equivalent of @blk_run_queue on behalf + * of us. + */ +void blk_run_queue_async(struct request_queue *q) +{ + if (likely(!blk_queue_stopped(q))) { + __cancel_delayed_work(&q->delay_work); + queue_delayed_work(kblockd_workqueue, &q->delay_work, 0); + } +} +EXPORT_SYMBOL(blk_run_queue_async); + /** * blk_run_queue - run a single device queue * @q: The queue to run @@ -328,7 +336,7 @@ void blk_run_queue(struct request_queue *q) unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); - __blk_run_queue(q, false); + __blk_run_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); } EXPORT_SYMBOL(blk_run_queue); @@ -977,7 +985,7 @@ void blk_insert_request(struct request_queue *q, struct request *rq, blk_queue_end_tag(q, rq); add_acct_request(q, rq, where); - __blk_run_queue(q, false); + __blk_run_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); } EXPORT_SYMBOL(blk_insert_request); @@ -1321,7 +1329,7 @@ static int __make_request(struct request_queue *q, struct bio *bio) } else { spin_lock_irq(q->queue_lock); add_acct_request(q, req, where); - __blk_run_queue(q, false); + __blk_run_queue(q); out_unlock: spin_unlock_irq(q->queue_lock); } @@ -2638,6 +2646,7 @@ void blk_start_plug(struct blk_plug *plug) plug->magic = PLUG_MAGIC; INIT_LIST_HEAD(&plug->list); + INIT_LIST_HEAD(&plug->cb_list); plug->should_sort = 0; /* @@ -2670,12 +2679,41 @@ static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b) */ static void queue_unplugged(struct request_queue *q, unsigned int depth, bool from_schedule) + __releases(q->queue_lock) { trace_block_unplug(q, depth, !from_schedule); - __blk_run_queue(q, from_schedule); - if (q->unplugged_fn) - q->unplugged_fn(q); + /* + * If we are punting this to kblockd, then we can safely drop + * the queue_lock before waking kblockd (which needs to take + * this lock). + */ + if (from_schedule) { + spin_unlock(q->queue_lock); + blk_run_queue_async(q); + } else { + __blk_run_queue(q); + spin_unlock(q->queue_lock); + } + +} + +static void flush_plug_callbacks(struct blk_plug *plug) +{ + LIST_HEAD(callbacks); + + if (list_empty(&plug->cb_list)) + return; + + list_splice_init(&plug->cb_list, &callbacks); + + while (!list_empty(&callbacks)) { + struct blk_plug_cb *cb = list_first_entry(&callbacks, + struct blk_plug_cb, + list); + list_del(&cb->list); + cb->callback(cb); + } } void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) @@ -2688,6 +2726,7 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) BUG_ON(plug->magic != PLUG_MAGIC); + flush_plug_callbacks(plug); if (list_empty(&plug->list)) return; @@ -2712,10 +2751,11 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) BUG_ON(!(rq->cmd_flags & REQ_ON_PLUG)); BUG_ON(!rq->q); if (rq->q != q) { - if (q) { + /* + * This drops the queue lock + */ + if (q) queue_unplugged(q, depth, from_schedule); - spin_unlock(q->queue_lock); - } q = rq->q; depth = 0; spin_lock(q->queue_lock); @@ -2733,14 +2773,14 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) depth++; } - if (q) { + /* + * This drops the queue lock + */ + if (q) queue_unplugged(q, depth, from_schedule); - spin_unlock(q->queue_lock); - } local_irq_restore(flags); } -EXPORT_SYMBOL(blk_flush_plug_list); void blk_finish_plug(struct blk_plug *plug) { diff --git a/block/blk-exec.c b/block/blk-exec.c index 7482b7fa863b..81e31819a597 100644 --- a/block/blk-exec.c +++ b/block/blk-exec.c @@ -55,7 +55,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, WARN_ON(irqs_disabled()); spin_lock_irq(q->queue_lock); __elv_add_request(q, rq, where); - __blk_run_queue(q, false); + __blk_run_queue(q); /* the queue is stopped so it won't be plugged+unplugged */ if (rq->cmd_type == REQ_TYPE_PM_RESUME) q->request_fn(q); diff --git a/block/blk-flush.c b/block/blk-flush.c index eba4a2790c6c..6c9b5e189e62 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -218,7 +218,7 @@ static void flush_end_io(struct request *flush_rq, int error) * request_fn may confuse the driver. Always use kblockd. */ if (queued) - __blk_run_queue(q, true); + blk_run_queue_async(q); } /** @@ -274,7 +274,7 @@ static void flush_data_end_io(struct request *rq, int error) * the comment in flush_end_io(). */ if (blk_flush_complete_seq(rq, REQ_FSEQ_DATA, error)) - __blk_run_queue(q, true); + blk_run_queue_async(q); } /** diff --git a/block/blk-settings.c b/block/blk-settings.c index eb949045bb12..1fa769293597 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -790,22 +790,6 @@ void blk_queue_flush(struct request_queue *q, unsigned int flush) } EXPORT_SYMBOL_GPL(blk_queue_flush); -/** - * blk_queue_unplugged - register a callback for an unplug event - * @q: the request queue for the device - * @fn: the function to call - * - * Some stacked drivers may need to know when IO is dispatched on an - * unplug event. By registrering a callback here, they will be notified - * when someone flushes their on-stack queue plug. The function will be - * called with the queue lock held. - */ -void blk_queue_unplugged(struct request_queue *q, unplugged_fn *fn) -{ - q->unplugged_fn = fn; -} -EXPORT_SYMBOL(blk_queue_unplugged); - static int __init blk_settings_init(void) { blk_max_low_pfn = max_low_pfn - 1; diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 6d735122bc59..bd236313f35d 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -66,14 +66,14 @@ queue_requests_store(struct request_queue *q, const char *page, size_t count) if (rl->count[BLK_RW_SYNC] >= q->nr_requests) { blk_set_queue_full(q, BLK_RW_SYNC); - } else if (rl->count[BLK_RW_SYNC]+1 <= q->nr_requests) { + } else { blk_clear_queue_full(q, BLK_RW_SYNC); wake_up(&rl->wait[BLK_RW_SYNC]); } if (rl->count[BLK_RW_ASYNC] >= q->nr_requests) { blk_set_queue_full(q, BLK_RW_ASYNC); - } else if (rl->count[BLK_RW_ASYNC]+1 <= q->nr_requests) { + } else { blk_clear_queue_full(q, BLK_RW_ASYNC); wake_up(&rl->wait[BLK_RW_ASYNC]); } @@ -508,8 +508,10 @@ int blk_register_queue(struct gendisk *disk) return ret; ret = kobject_add(&q->kobj, kobject_get(&dev->kobj), "%s", "queue"); - if (ret < 0) + if (ret < 0) { + blk_trace_remove_sysfs(dev); return ret; + } kobject_uevent(&q->kobj, KOBJ_ADD); diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 0475a22a420d..252a81a306f7 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -160,9 +160,8 @@ static void throtl_put_tg(struct throtl_grp *tg) } static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td, - struct cgroup *cgroup) + struct blkio_cgroup *blkcg) { - struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup); struct throtl_grp *tg = NULL; void *key = td; struct backing_dev_info *bdi = &td->queue->backing_dev_info; @@ -229,12 +228,12 @@ static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td, static struct throtl_grp * throtl_get_tg(struct throtl_data *td) { - struct cgroup *cgroup; struct throtl_grp *tg = NULL; + struct blkio_cgroup *blkcg; rcu_read_lock(); - cgroup = task_cgroup(current, blkio_subsys_id); - tg = throtl_find_alloc_tg(td, cgroup); + blkcg = task_blkio_cgroup(current); + tg = throtl_find_alloc_tg(td, blkcg); if (!tg) tg = &td->root_tg; rcu_read_unlock(); diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 3be881ec95ad..ab7a9e6a9b1c 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1014,10 +1014,9 @@ void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg, cfqg->needs_update = true; } -static struct cfq_group * -cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create) +static struct cfq_group * cfq_find_alloc_cfqg(struct cfq_data *cfqd, + struct blkio_cgroup *blkcg, int create) { - struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup); struct cfq_group *cfqg = NULL; void *key = cfqd; int i, j; @@ -1079,12 +1078,12 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create) */ static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create) { - struct cgroup *cgroup; + struct blkio_cgroup *blkcg; struct cfq_group *cfqg = NULL; rcu_read_lock(); - cgroup = task_cgroup(current, blkio_subsys_id); - cfqg = cfq_find_alloc_cfqg(cfqd, cgroup, create); + blkcg = task_blkio_cgroup(current); + cfqg = cfq_find_alloc_cfqg(cfqd, blkcg, create); if (!cfqg && create) cfqg = &cfqd->root_group; rcu_read_unlock(); @@ -2581,20 +2580,6 @@ static void cfq_put_queue(struct cfq_queue *cfqq) cfq_put_cfqg(cfqg); } -/* - * Must always be called with the rcu_read_lock() held - */ -static void -__call_for_each_cic(struct io_context *ioc, - void (*func)(struct io_context *, struct cfq_io_context *)) -{ - struct cfq_io_context *cic; - struct hlist_node *n; - - hlist_for_each_entry_rcu(cic, n, &ioc->cic_list, cic_list) - func(ioc, cic); -} - /* * Call func for each cic attached to this ioc. */ @@ -2602,8 +2587,14 @@ static void call_for_each_cic(struct io_context *ioc, void (*func)(struct io_context *, struct cfq_io_context *)) { + struct cfq_io_context *cic; + struct hlist_node *n; + rcu_read_lock(); - __call_for_each_cic(ioc, func); + + hlist_for_each_entry_rcu(cic, n, &ioc->cic_list, cic_list) + func(ioc, cic); + rcu_read_unlock(); } @@ -2664,7 +2655,7 @@ static void cfq_free_io_context(struct io_context *ioc) * should be ok to iterate over the known list, we will see all cic's * since no new ones are added. */ - __call_for_each_cic(ioc, cic_free_func); + call_for_each_cic(ioc, cic_free_func); } static void cfq_put_cooperator(struct cfq_queue *cfqq) @@ -3368,7 +3359,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, cfqd->busy_queues > 1) { cfq_del_timer(cfqd, cfqq); cfq_clear_cfqq_wait_request(cfqq); - __blk_run_queue(cfqd->queue, false); + __blk_run_queue(cfqd->queue); } else { cfq_blkiocg_update_idle_time_stats( &cfqq->cfqg->blkg); @@ -3383,7 +3374,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, * this new queue is RT and the current one is BE */ cfq_preempt_queue(cfqd, cfqq); - __blk_run_queue(cfqd->queue, false); + __blk_run_queue(cfqd->queue); } } @@ -3743,7 +3734,7 @@ static void cfq_kick_queue(struct work_struct *work) struct request_queue *q = cfqd->queue; spin_lock_irq(q->queue_lock); - __blk_run_queue(cfqd->queue, false); + __blk_run_queue(cfqd->queue); spin_unlock_irq(q->queue_lock); } diff --git a/block/elevator.c b/block/elevator.c index 0cdb4e7ebab4..45ca1e34f582 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -642,7 +642,7 @@ void elv_quiesce_start(struct request_queue *q) */ elv_drain_elevator(q); while (q->rq.elvpriv) { - __blk_run_queue(q, false); + __blk_run_queue(q); spin_unlock_irq(q->queue_lock); msleep(10); spin_lock_irq(q->queue_lock); @@ -671,7 +671,8 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where) q->boundary_rq = rq; } } else if (!(rq->cmd_flags & REQ_ELVPRIV) && - where == ELEVATOR_INSERT_SORT) + (where == ELEVATOR_INSERT_SORT || + where == ELEVATOR_INSERT_SORT_MERGE)) where = ELEVATOR_INSERT_BACK; switch (where) { @@ -695,7 +696,7 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where) * with anything. There's no point in delaying queue * processing. */ - __blk_run_queue(q, false); + __blk_run_queue(q); break; case ELEVATOR_INSERT_SORT_MERGE: diff --git a/block/genhd.c b/block/genhd.c index b364bd038a18..2dd988723d73 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1588,9 +1588,13 @@ static void disk_events_workfn(struct work_struct *work) spin_unlock_irq(&ev->lock); - /* tell userland about new events */ + /* + * Tell userland about new events. Only the events listed in + * @disk->events are reported. Unlisted events are processed the + * same internally but never get reported to userland. + */ for (i = 0; i < ARRAY_SIZE(disk_uevents); i++) - if (events & (1 << i)) + if (events & disk->events & (1 << i)) envp[nr_events++] = disk_uevents[i]; if (nr_events) diff --git a/crypto/Kconfig b/crypto/Kconfig index 4b7cb0e691cd..87b22ca9c223 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -264,11 +264,6 @@ config CRYPTO_XTS key size 256, 384 or 512 bits. This implementation currently can't handle a sectorsize which is not a multiple of 16 bytes. -config CRYPTO_FPU - tristate - select CRYPTO_BLKCIPHER - select CRYPTO_MANAGER - comment "Hash modes" config CRYPTO_HMAC @@ -543,7 +538,6 @@ config CRYPTO_AES_NI_INTEL select CRYPTO_AES_586 if !64BIT select CRYPTO_CRYPTD select CRYPTO_ALGAPI - select CRYPTO_FPU help Use Intel AES-NI instructions for AES algorithm. diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index e912ea5def3d..2222617b3bed 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1009,6 +1009,10 @@ static int do_test(int m) speed_template_32_48_64); test_cipher_speed("xts(aes)", DECRYPT, sec, NULL, 0, speed_template_32_48_64); + test_cipher_speed("ctr(aes)", ENCRYPT, sec, NULL, 0, + speed_template_16_24_32); + test_cipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0, + speed_template_16_24_32); break; case 201: diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 2854865f2434..b6b93d416351 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -2218,6 +2218,22 @@ static const struct alg_test_desc alg_test_descs[] = { .count = MICHAEL_MIC_TEST_VECTORS } } + }, { + .alg = "ofb(aes)", + .test = alg_test_skcipher, + .fips_allowed = 1, + .suite = { + .cipher = { + .enc = { + .vecs = aes_ofb_enc_tv_template, + .count = AES_OFB_ENC_TEST_VECTORS + }, + .dec = { + .vecs = aes_ofb_dec_tv_template, + .count = AES_OFB_DEC_TEST_VECTORS + } + } + } }, { .alg = "pcbc(fcrypt)", .test = alg_test_skcipher, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index aa6dac05f843..27e60619538e 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -2980,6 +2980,8 @@ static struct cipher_testvec cast6_dec_tv_template[] = { #define AES_XTS_DEC_TEST_VECTORS 4 #define AES_CTR_ENC_TEST_VECTORS 3 #define AES_CTR_DEC_TEST_VECTORS 3 +#define AES_OFB_ENC_TEST_VECTORS 1 +#define AES_OFB_DEC_TEST_VECTORS 1 #define AES_CTR_3686_ENC_TEST_VECTORS 7 #define AES_CTR_3686_DEC_TEST_VECTORS 6 #define AES_GCM_ENC_TEST_VECTORS 9 @@ -5506,6 +5508,64 @@ static struct cipher_testvec aes_ctr_rfc3686_dec_tv_template[] = { }, }; +static struct cipher_testvec aes_ofb_enc_tv_template[] = { + /* From NIST Special Publication 800-38A, Appendix F.5 */ + { + .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" + "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", + .klen = 16, + .iv = "\x00\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .input = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .ilen = 64, + .result = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20" + "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" + "\x77\x89\x50\x8d\x16\x91\x8f\x03\xf5" + "\x3c\x52\xda\xc5\x4e\xd8\x25" + "\x97\x40\x05\x1e\x9c\x5f\xec\xf6\x43" + "\x44\xf7\xa8\x22\x60\xed\xcc" + "\x30\x4c\x65\x28\xf6\x59\xc7\x78" + "\x66\xa5\x10\xd9\xc1\xd6\xae\x5e", + .rlen = 64, + } +}; + +static struct cipher_testvec aes_ofb_dec_tv_template[] = { + /* From NIST Special Publication 800-38A, Appendix F.5 */ + { + .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" + "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", + .klen = 16, + .iv = "\x00\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .input = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20" + "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" + "\x77\x89\x50\x8d\x16\x91\x8f\x03\xf5" + "\x3c\x52\xda\xc5\x4e\xd8\x25" + "\x97\x40\x05\x1e\x9c\x5f\xec\xf6\x43" + "\x44\xf7\xa8\x22\x60\xed\xcc" + "\x30\x4c\x65\x28\xf6\x59\xc7\x78" + "\x66\xa5\x10\xd9\xc1\xd6\xae\x5e", + .ilen = 64, + .result = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .rlen = 64, + } +}; + static struct aead_testvec aes_gcm_enc_tv_template[] = { { /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */ .key = zeroed_string, diff --git a/drivers/Kconfig b/drivers/Kconfig index 177c7d156933..61631edfecc2 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -68,6 +68,8 @@ source "drivers/watchdog/Kconfig" source "drivers/ssb/Kconfig" +source "drivers/bcma/Kconfig" + source "drivers/mfd/Kconfig" source "drivers/regulator/Kconfig" @@ -119,4 +121,7 @@ source "drivers/platform/Kconfig" source "drivers/clk/Kconfig" source "drivers/hwspinlock/Kconfig" + +source "drivers/clocksource/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 3f135b6fb014..a29527f4ded6 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -110,6 +110,7 @@ obj-$(CONFIG_HID) += hid/ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_OF) += of/ obj-$(CONFIG_SSB) += ssb/ +obj-$(CONFIG_BCMA) += bcma/ obj-$(CONFIG_VHOST_NET) += vhost/ obj-$(CONFIG_VLYNQ) += vlynq/ obj-$(CONFIG_STAGING) += staging/ diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index 66a03caa2ad9..f739a70b1c70 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -1,5 +1,6 @@ config ACPI_APEI bool "ACPI Platform Error Interface (APEI)" + select MISC_FILESYSTEMS select PSTORE depends on X86 help diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index d6cb0ff6988e..e6cef8e1b534 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -929,13 +929,17 @@ static int erst_check_table(struct acpi_table_erst *erst_tab) return 0; } -static size_t erst_reader(u64 *id, enum pstore_type_id *type, +static int erst_open_pstore(struct pstore_info *psi); +static int erst_close_pstore(struct pstore_info *psi); +static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, struct timespec *time); static u64 erst_writer(enum pstore_type_id type, size_t size); static struct pstore_info erst_info = { .owner = THIS_MODULE, .name = "erst", + .open = erst_open_pstore, + .close = erst_close_pstore, .read = erst_reader, .write = erst_writer, .erase = erst_clear @@ -957,12 +961,32 @@ struct cper_pstore_record { char data[]; } __packed; -static size_t erst_reader(u64 *id, enum pstore_type_id *type, +static int reader_pos; + +static int erst_open_pstore(struct pstore_info *psi) +{ + int rc; + + if (erst_disable) + return -ENODEV; + + rc = erst_get_record_id_begin(&reader_pos); + + return rc; +} + +static int erst_close_pstore(struct pstore_info *psi) +{ + erst_get_record_id_end(); + + return 0; +} + +static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, struct timespec *time) { int rc; - ssize_t len; - unsigned long flags; + ssize_t len = 0; u64 record_id; struct cper_pstore_record *rcd = (struct cper_pstore_record *) (erst_info.buf - sizeof(*rcd)); @@ -970,24 +994,28 @@ static size_t erst_reader(u64 *id, enum pstore_type_id *type, if (erst_disable) return -ENODEV; - raw_spin_lock_irqsave(&erst_lock, flags); skip: - rc = __erst_get_next_record_id(&record_id); - if (rc) { - raw_spin_unlock_irqrestore(&erst_lock, flags); - return rc; - } + rc = erst_get_record_id_next(&reader_pos, &record_id); + if (rc) + goto out; + /* no more record */ if (record_id == APEI_ERST_INVALID_RECORD_ID) { - raw_spin_unlock_irqrestore(&erst_lock, flags); - return 0; + rc = -1; + goto out; } - len = __erst_read(record_id, &rcd->hdr, sizeof(*rcd) + - erst_erange.size); + len = erst_read(record_id, &rcd->hdr, sizeof(*rcd) + + erst_info.bufsize); + /* The record may be cleared by others, try read next record */ + if (len == -ENOENT) + goto skip; + else if (len < 0) { + rc = -1; + goto out; + } if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0) goto skip; - raw_spin_unlock_irqrestore(&erst_lock, flags); *id = record_id; if (uuid_le_cmp(rcd->sec_hdr.section_type, @@ -1005,7 +1033,8 @@ static size_t erst_reader(u64 *id, enum pstore_type_id *type, time->tv_sec = 0; time->tv_nsec = 0; - return len - sizeof(*rcd); +out: + return (rc < 0) ? rc : (len - sizeof(*rcd)); } static u64 erst_writer(enum pstore_type_id type, size_t size) diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 3a73a93596e8..85b32376dad7 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -49,10 +49,6 @@ ACPI_MODULE_NAME("processor_perflib"); static DEFINE_MUTEX(performance_mutex); -/* Use cpufreq debug layer for _PPC changes. */ -#define cpufreq_printk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \ - "cpufreq-core", msg) - /* * _PPC support is implemented as a CPUfreq policy notifier: * This means each time a CPUfreq driver registered also with @@ -145,7 +141,7 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) return -ENODEV; } - cpufreq_printk("CPU %d: _PPC is %d - frequency %s limited\n", pr->id, + pr_debug("CPU %d: _PPC is %d - frequency %s limited\n", pr->id, (int)ppc, ppc ? "" : "not"); pr->performance_platform_limit = (int)ppc; diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index ad3501739563..605a2954ef17 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -710,20 +710,14 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr) } #ifdef CONFIG_X86 -static int acpi_throttling_rdmsr(struct acpi_processor *pr, - u64 *value) +static int acpi_throttling_rdmsr(u64 *value) { - struct cpuinfo_x86 *c; u64 msr_high, msr_low; - unsigned int cpu; u64 msr = 0; int ret = -1; - cpu = pr->id; - c = &cpu_data(cpu); - - if ((c->x86_vendor != X86_VENDOR_INTEL) || - !cpu_has(c, X86_FEATURE_ACPI)) { + if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) || + !this_cpu_has(X86_FEATURE_ACPI)) { printk(KERN_ERR PREFIX "HARDWARE addr space,NOT supported yet\n"); } else { @@ -738,18 +732,13 @@ static int acpi_throttling_rdmsr(struct acpi_processor *pr, return ret; } -static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) +static int acpi_throttling_wrmsr(u64 value) { - struct cpuinfo_x86 *c; - unsigned int cpu; int ret = -1; u64 msr; - cpu = pr->id; - c = &cpu_data(cpu); - - if ((c->x86_vendor != X86_VENDOR_INTEL) || - !cpu_has(c, X86_FEATURE_ACPI)) { + if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) || + !this_cpu_has(X86_FEATURE_ACPI)) { printk(KERN_ERR PREFIX "HARDWARE addr space,NOT supported yet\n"); } else { @@ -761,15 +750,14 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) return ret; } #else -static int acpi_throttling_rdmsr(struct acpi_processor *pr, - u64 *value) +static int acpi_throttling_rdmsr(u64 *value) { printk(KERN_ERR PREFIX "HARDWARE addr space,NOT supported yet\n"); return -1; } -static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) +static int acpi_throttling_wrmsr(u64 value) { printk(KERN_ERR PREFIX "HARDWARE addr space,NOT supported yet\n"); @@ -801,7 +789,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr, ret = 0; break; case ACPI_ADR_SPACE_FIXED_HARDWARE: - ret = acpi_throttling_rdmsr(pr, value); + ret = acpi_throttling_rdmsr(value); break; default: printk(KERN_ERR PREFIX "Unknown addr space %d\n", @@ -834,7 +822,7 @@ static int acpi_write_throttling_state(struct acpi_processor *pr, ret = 0; break; case ACPI_ADR_SPACE_FIXED_HARDWARE: - ret = acpi_throttling_wrmsr(pr, value); + ret = acpi_throttling_wrmsr(value); break; default: printk(KERN_ERR PREFIX "Unknown addr space %d\n", diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b136c9c1e531..449c556274c0 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -943,6 +943,10 @@ static int acpi_bus_get_flags(struct acpi_device *device) if (ACPI_SUCCESS(status)) device->flags.lockable = 1; + /* Power resources cannot be power manageable. */ + if (device->device_type == ACPI_BUS_TYPE_POWER) + return 0; + /* Presence of _PS0|_PR0 indicates 'power manageable' */ status = acpi_get_handle(device->handle, "_PS0", &temp); if (ACPI_FAILURE(status)) diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index 339c210f03a6..ae22be4157b5 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -417,7 +417,7 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id VPRINTK("ENTER\n"); - WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); + WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS); if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 39d829cd82dd..71afe0371311 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -150,7 +150,7 @@ static const struct ata_port_info ahci_port_info[] = { { AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ), - .flags = AHCI_FLAG_COMMON, + .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, @@ -261,6 +261,12 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */ { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */ { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */ + { PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */ + { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */ + { PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */ + { PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */ + { PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */ + { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 39865009c251..12c5282e7fca 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -229,6 +229,10 @@ enum { EM_CTL_ALHD = (1 << 26), /* Activity LED */ EM_CTL_XMT = (1 << 25), /* Transmit Only */ EM_CTL_SMB = (1 << 24), /* Single Message Buffer */ + EM_CTL_SGPIO = (1 << 19), /* SGPIO messages supported */ + EM_CTL_SES = (1 << 18), /* SES-2 messages supported */ + EM_CTL_SAFTE = (1 << 17), /* SAF-TE messages supported */ + EM_CTL_LED = (1 << 16), /* LED messages supported */ /* em message type */ EM_MSG_TYPE_LED = (1 << 0), /* LED */ diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 0bc3fd6c3fdb..6f6e7718b05c 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -309,6 +309,14 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* SATA Controller IDE (PBG) */ { 0x8086, 0x1d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Panther Point) */ + { 0x8086, 0x1e00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + /* SATA Controller IDE (Panther Point) */ + { 0x8086, 0x1e01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + /* SATA Controller IDE (Panther Point) */ + { 0x8086, 0x1e08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Panther Point) */ + { 0x8086, 0x1e09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { } /* terminate list */ }; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 26d452339e98..d38c40fe4ddb 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -109,6 +109,8 @@ static ssize_t ahci_read_em_buffer(struct device *dev, static ssize_t ahci_store_em_buffer(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); +static ssize_t ahci_show_em_supported(struct device *dev, + struct device_attribute *attr, char *buf); static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL); static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL); @@ -116,6 +118,7 @@ static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL); static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL); static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO, ahci_read_em_buffer, ahci_store_em_buffer); +static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL); struct device_attribute *ahci_shost_attrs[] = { &dev_attr_link_power_management_policy, @@ -126,6 +129,7 @@ struct device_attribute *ahci_shost_attrs[] = { &dev_attr_ahci_host_version, &dev_attr_ahci_port_cmd, &dev_attr_em_buffer, + &dev_attr_em_message_supported, NULL }; EXPORT_SYMBOL_GPL(ahci_shost_attrs); @@ -343,6 +347,24 @@ static ssize_t ahci_store_em_buffer(struct device *dev, return size; } +static ssize_t ahci_show_em_supported(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *mmio = hpriv->mmio; + u32 em_ctl; + + em_ctl = readl(mmio + HOST_EM_CTL); + + return sprintf(buf, "%s%s%s%s\n", + em_ctl & EM_CTL_LED ? "led " : "", + em_ctl & EM_CTL_SAFTE ? "saf-te " : "", + em_ctl & EM_CTL_SES ? "ses-2 " : "", + em_ctl & EM_CTL_SGPIO ? "sgpio " : ""); +} + /** * ahci_save_initial_config - Save and fixup initial config values * @dev: target AHCI device @@ -1897,7 +1919,17 @@ static void ahci_pmp_attach(struct ata_port *ap) ahci_enable_fbs(ap); pp->intr_mask |= PORT_IRQ_BAD_PMP; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + + /* + * We must not change the port interrupt mask register if the + * port is marked frozen, the value in pp->intr_mask will be + * restored later when the port is thawed. + * + * Note that during initialization, the port is marked as + * frozen since the irq handler is not yet registered. + */ + if (!(ap->pflags & ATA_PFLAG_FROZEN)) + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } static void ahci_pmp_detach(struct ata_port *ap) @@ -1913,7 +1945,10 @@ static void ahci_pmp_detach(struct ata_port *ap) writel(cmd, port_mmio + PORT_CMD); pp->intr_mask &= ~PORT_IRQ_BAD_PMP; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + + /* see comment above in ahci_pmp_attach() */ + if (!(ap->pflags & ATA_PFLAG_FROZEN)) + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } int ahci_port_resume(struct ata_port *ap) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 423c0a6952b2..736bee5dafeb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3619,8 +3619,14 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, scontrol |= (0x2 << 8); break; case ATA_LPM_MIN_POWER: - /* no restrictions on LPM transitions */ - scontrol &= ~(0x3 << 8); + if (ata_link_nr_enabled(link) > 0) + /* no restrictions on LPM transitions */ + scontrol &= ~(0x3 << 8); + else { + /* empty port, power off */ + scontrol &= ~0xf; + scontrol |= (0x1 << 2); + } break; default: WARN_ON(1); @@ -4139,6 +4145,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { */ { "PIONEER DVD-RW DVRTD08", "1.00", ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-212D", "1.28", ATA_HORKAGE_NOSETXFER }, + { "PIONEER DVD-RW DVR-216D", "1.08", ATA_HORKAGE_NOSETXFER }, /* End Marker */ { } @@ -5480,7 +5487,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) if (!ap) return NULL; - ap->pflags |= ATA_PFLAG_INITIALIZING; + ap->pflags |= ATA_PFLAG_INITIALIZING | ATA_PFLAG_FROZEN; ap->lock = &host->lock; ap->print_id = -1; ap->host = host; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 88cd22fa65cd..dfb6e9d3d759 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3316,6 +3316,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL; enum ata_lpm_policy old_policy = link->lpm_policy; + bool no_dipm = link->ap->flags & ATA_FLAG_NO_DIPM; unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM; unsigned int err_mask; int rc; @@ -3332,7 +3333,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, */ ata_for_each_dev(dev, link, ENABLED) { bool hipm = ata_id_has_hipm(dev->id); - bool dipm = ata_id_has_dipm(dev->id); + bool dipm = ata_id_has_dipm(dev->id) && !no_dipm; /* find the first enabled and LPM enabled devices */ if (!link_dev) @@ -3389,7 +3390,8 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, /* host config updated, enable DIPM if transitioning to MIN_POWER */ ata_for_each_dev(dev, link, ENABLED) { - if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) { + if (policy == ATA_LPM_MIN_POWER && !no_dipm && + ata_id_has_dipm(dev->id)) { err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE, SATA_DIPM); if (err_mask && err_mask != AC_ERR_DEV) { @@ -3421,7 +3423,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, return rc; } -static int ata_link_nr_enabled(struct ata_link *link) +int ata_link_nr_enabled(struct ata_link *link) { struct ata_device *dev; int cnt = 0; diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 3120596d4afc..f06b7ea590d3 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -449,6 +449,16 @@ static void sata_pmp_quirks(struct ata_port *ap) * otherwise. Don't try hard to recover it. */ ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY; + } else if (vendor == 0x197b && devid == 0x2352) { + /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */ + ata_for_each_link(link, ap, EDGE) { + /* SRST breaks detection and disks get misclassified + * LPM disabled to avoid potential problems + */ + link->flags |= ATA_LFLAG_NO_LPM | + ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_ATA; + } } } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e2f57e9e12f0..30ea95f43e79 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2138,7 +2138,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) * with the unmap bit set. */ if (ata_id_has_trim(args->id)) { - put_unaligned_be32(65535 * 512 / 8, &rbuf[20]); + put_unaligned_be64(65535 * 512 / 8, &rbuf[36]); put_unaligned_be32(1, &rbuf[28]); } diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index f8380ce0f4d1..b1b926c55a72 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2447,13 +2447,18 @@ int ata_pci_sff_activate_host(struct ata_host *host, return -ENOMEM; if (!legacy_mode && pdev->irq) { + int i; + rc = devm_request_irq(dev, pdev->irq, irq_handler, IRQF_SHARED, drv_name, host); if (rc) goto out; - ata_port_desc(host->ports[0], "irq %d", pdev->irq); - ata_port_desc(host->ports[1], "irq %d", pdev->irq); + for (i = 0; i < 2; i++) { + if (ata_port_is_dummy(host->ports[i])) + continue; + ata_port_desc(host->ports[i], "irq %d", pdev->irq); + } } else if (legacy_mode) { if (!ata_port_is_dummy(host->ports[0])) { rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index 0da0dcc7dd08..960c72571395 100644 --- a/drivers/ata/pata_at91.c +++ b/drivers/ata/pata_at91.c @@ -3,6 +3,7 @@ * with CompactFlash interface in True IDE mode * * Copyright (C) 2009 Matyukevich Sergey + * 2011 Igor Plyatov * * Based on: * * generic platform driver by Paul Mundt: drivers/ata/pata_platform.c @@ -31,26 +32,149 @@ #include #include +#define DRV_NAME "pata_at91" +#define DRV_VERSION "0.3" -#define DRV_NAME "pata_at91" -#define DRV_VERSION "0.1" - -#define CF_IDE_OFFSET 0x00c00000 -#define CF_ALT_IDE_OFFSET 0x00e00000 -#define CF_IDE_RES_SIZE 0x08 +#define CF_IDE_OFFSET 0x00c00000 +#define CF_ALT_IDE_OFFSET 0x00e00000 +#define CF_IDE_RES_SIZE 0x08 +#define CS_PULSE_MAXIMUM 319 +#define ER_SMC_CALC 1 +#define ER_SMC_RECALC 2 struct at91_ide_info { unsigned long mode; unsigned int cs; - struct clk *mck; - void __iomem *ide_addr; void __iomem *alt_addr; }; -static const struct ata_timing initial_timing = - {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0}; +/** + * struct smc_range - range of valid values for SMC register. + */ +struct smc_range { + int min; + int max; +}; + +/** + * adjust_smc_value - adjust value for one of SMC registers. + * @value: adjusted value + * @range: array of SMC ranges with valid values + * @size: SMC ranges array size + * + * This returns the difference between input and output value or negative + * in case of invalid input value. + * If negative returned, then output value = maximal possible from ranges. + */ +static int adjust_smc_value(int *value, struct smc_range *range, int size) +{ + int maximum = (range + size - 1)->max; + int remainder; + + do { + if (*value < range->min) { + remainder = range->min - *value; + *value = range->min; /* nearest valid value */ + return remainder; + } else if ((range->min <= *value) && (*value <= range->max)) + return 0; + + range++; + } while (--size); + *value = maximum; + + return -1; /* invalid value */ +} + +/** + * calc_smc_vals - calculate SMC register values + * @dev: ATA device + * @setup: SMC_SETUP register value + * @pulse: SMC_PULSE register value + * @cycle: SMC_CYCLE register value + * + * This returns negative in case of invalid values for SMC registers: + * -ER_SMC_RECALC - recalculation required for SMC values, + * -ER_SMC_CALC - calculation failed (invalid input values). + * + * SMC use special coding scheme, see "Coding and Range of Timing + * Parameters" table from AT91SAM9 datasheets. + * + * SMC_SETUP = 128*setup[5] + setup[4:0] + * SMC_PULSE = 256*pulse[6] + pulse[5:0] + * SMC_CYCLE = 256*cycle[8:7] + cycle[6:0] + */ +static int calc_smc_vals(struct device *dev, + int *setup, int *pulse, int *cycle, int *cs_pulse) +{ + int ret_val; + int err = 0; + struct smc_range range_setup[] = { /* SMC_SETUP valid values */ + {.min = 0, .max = 31}, /* first range */ + {.min = 128, .max = 159} /* second range */ + }; + struct smc_range range_pulse[] = { /* SMC_PULSE valid values */ + {.min = 0, .max = 63}, /* first range */ + {.min = 256, .max = 319} /* second range */ + }; + struct smc_range range_cycle[] = { /* SMC_CYCLE valid values */ + {.min = 0, .max = 127}, /* first range */ + {.min = 256, .max = 383}, /* second range */ + {.min = 512, .max = 639}, /* third range */ + {.min = 768, .max = 895} /* fourth range */ + }; + + ret_val = adjust_smc_value(setup, range_setup, ARRAY_SIZE(range_setup)); + if (ret_val < 0) + dev_warn(dev, "maximal SMC Setup value\n"); + else + *cycle += ret_val; + + ret_val = adjust_smc_value(pulse, range_pulse, ARRAY_SIZE(range_pulse)); + if (ret_val < 0) + dev_warn(dev, "maximal SMC Pulse value\n"); + else + *cycle += ret_val; + + ret_val = adjust_smc_value(cycle, range_cycle, ARRAY_SIZE(range_cycle)); + if (ret_val < 0) + dev_warn(dev, "maximal SMC Cycle value\n"); + + *cs_pulse = *cycle; + if (*cs_pulse > CS_PULSE_MAXIMUM) { + dev_err(dev, "unable to calculate valid SMC settings\n"); + return -ER_SMC_CALC; + } + + ret_val = adjust_smc_value(cs_pulse, range_pulse, + ARRAY_SIZE(range_pulse)); + if (ret_val < 0) { + dev_warn(dev, "maximal SMC CS Pulse value\n"); + } else if (ret_val != 0) { + *cycle = *cs_pulse; + dev_warn(dev, "SMC Cycle extended\n"); + err = -ER_SMC_RECALC; + } + + return err; +} + +/** + * to_smc_format - convert values into SMC format + * @setup: SETUP value of SMC Setup Register + * @pulse: PULSE value of SMC Pulse Register + * @cycle: CYCLE value of SMC Cycle Register + * @cs_pulse: NCS_PULSE value of SMC Pulse Register + */ +static void to_smc_format(int *setup, int *pulse, int *cycle, int *cs_pulse) +{ + *setup = (*setup & 0x1f) | ((*setup & 0x80) >> 2); + *pulse = (*pulse & 0x3f) | ((*pulse & 0x100) >> 2); + *cycle = (*cycle & 0x7f) | ((*cycle & 0x300) >> 1); + *cs_pulse = (*cs_pulse & 0x3f) | ((*cs_pulse & 0x100) >> 2); +} static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz) { @@ -69,80 +193,77 @@ static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz) return (ns * mul + 65536) >> 16; /* rounding */ } -static void set_smc_mode(struct at91_ide_info *info) -{ - at91_sys_write(AT91_SMC_MODE(info->cs), info->mode); - return; -} - -static void set_smc_timing(struct device *dev, +/** + * set_smc_timing - SMC timings setup. + * @dev: device + * @info: AT91 IDE info + * @ata: ATA timings + * + * Its assumed that write timings are same as read timings, + * cs_setup = 0 and cs_pulse = cycle. + */ +static void set_smc_timing(struct device *dev, struct ata_device *adev, struct at91_ide_info *info, const struct ata_timing *ata) { - unsigned long read_cycle, write_cycle, active, recover; - unsigned long nrd_setup, nrd_pulse, nrd_recover; - unsigned long nwe_setup, nwe_pulse; - - unsigned long ncs_write_setup, ncs_write_pulse; - unsigned long ncs_read_setup, ncs_read_pulse; - - unsigned long mck_hz; - - read_cycle = ata->cyc8b; - nrd_setup = ata->setup; - nrd_pulse = ata->act8b; - nrd_recover = ata->rec8b; + int ret = 0; + int use_iordy; + unsigned int t6z; /* data tristate time in ns */ + unsigned int cycle; /* SMC Cycle width in MCK ticks */ + unsigned int setup; /* SMC Setup width in MCK ticks */ + unsigned int pulse; /* CFIOR and CFIOW pulse width in MCK ticks */ + unsigned int cs_setup = 0;/* CS4 or CS5 setup width in MCK ticks */ + unsigned int cs_pulse; /* CS4 or CS5 pulse width in MCK ticks*/ + unsigned int tdf_cycles; /* SMC TDF MCK ticks */ + unsigned long mck_hz; /* MCK frequency in Hz */ + t6z = (ata->mode < XFER_PIO_5) ? 30 : 20; mck_hz = clk_get_rate(info->mck); + cycle = calc_mck_cycles(ata->cyc8b, mck_hz); + setup = calc_mck_cycles(ata->setup, mck_hz); + pulse = calc_mck_cycles(ata->act8b, mck_hz); + tdf_cycles = calc_mck_cycles(t6z, mck_hz); - read_cycle = calc_mck_cycles(read_cycle, mck_hz); - nrd_setup = calc_mck_cycles(nrd_setup, mck_hz); - nrd_pulse = calc_mck_cycles(nrd_pulse, mck_hz); - nrd_recover = calc_mck_cycles(nrd_recover, mck_hz); + do { + ret = calc_smc_vals(dev, &setup, &pulse, &cycle, &cs_pulse); + } while (ret == -ER_SMC_RECALC); - active = nrd_setup + nrd_pulse; - recover = read_cycle - active; + if (ret == -ER_SMC_CALC) + dev_err(dev, "Interface may not operate correctly\n"); - /* Need at least two cycles recovery */ - if (recover < 2) - read_cycle = active + 2; + dev_dbg(dev, "SMC Setup=%u, Pulse=%u, Cycle=%u, CS Pulse=%u\n", + setup, pulse, cycle, cs_pulse); + to_smc_format(&setup, &pulse, &cycle, &cs_pulse); + /* disable or enable waiting for IORDY signal */ + use_iordy = ata_pio_need_iordy(adev); + if (use_iordy) + info->mode |= AT91_SMC_EXNWMODE_READY; - /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */ - ncs_read_setup = 1; - ncs_read_pulse = read_cycle - 2; + if (tdf_cycles > 15) { + tdf_cycles = 15; + dev_warn(dev, "maximal SMC TDF Cycles value\n"); + } - /* Write timings same as read timings */ - write_cycle = read_cycle; - nwe_setup = nrd_setup; - nwe_pulse = nrd_pulse; - ncs_write_setup = ncs_read_setup; - ncs_write_pulse = ncs_read_pulse; - - dev_dbg(dev, "ATA timings: nrd_setup = %lu nrd_pulse = %lu nrd_cycle = %lu\n", - nrd_setup, nrd_pulse, read_cycle); - dev_dbg(dev, "ATA timings: nwe_setup = %lu nwe_pulse = %lu nwe_cycle = %lu\n", - nwe_setup, nwe_pulse, write_cycle); - dev_dbg(dev, "ATA timings: ncs_read_setup = %lu ncs_read_pulse = %lu\n", - ncs_read_setup, ncs_read_pulse); - dev_dbg(dev, "ATA timings: ncs_write_setup = %lu ncs_write_pulse = %lu\n", - ncs_write_setup, ncs_write_pulse); + dev_dbg(dev, "Use IORDY=%u, TDF Cycles=%u\n", use_iordy, tdf_cycles); + info->mode |= AT91_SMC_TDF_(tdf_cycles); + /* write SMC Setup Register */ at91_sys_write(AT91_SMC_SETUP(info->cs), - AT91_SMC_NWESETUP_(nwe_setup) | - AT91_SMC_NRDSETUP_(nrd_setup) | - AT91_SMC_NCS_WRSETUP_(ncs_write_setup) | - AT91_SMC_NCS_RDSETUP_(ncs_read_setup)); - + AT91_SMC_NWESETUP_(setup) | + AT91_SMC_NRDSETUP_(setup) | + AT91_SMC_NCS_WRSETUP_(cs_setup) | + AT91_SMC_NCS_RDSETUP_(cs_setup)); + /* write SMC Pulse Register */ at91_sys_write(AT91_SMC_PULSE(info->cs), - AT91_SMC_NWEPULSE_(nwe_pulse) | - AT91_SMC_NRDPULSE_(nrd_pulse) | - AT91_SMC_NCS_WRPULSE_(ncs_write_pulse) | - AT91_SMC_NCS_RDPULSE_(ncs_read_pulse)); - + AT91_SMC_NWEPULSE_(pulse) | + AT91_SMC_NRDPULSE_(pulse) | + AT91_SMC_NCS_WRPULSE_(cs_pulse) | + AT91_SMC_NCS_RDPULSE_(cs_pulse)); + /* write SMC Cycle Register */ at91_sys_write(AT91_SMC_CYCLE(info->cs), - AT91_SMC_NWECYCLE_(write_cycle) | - AT91_SMC_NRDCYCLE_(read_cycle)); - - return; + AT91_SMC_NWECYCLE_(cycle) | + AT91_SMC_NRDCYCLE_(cycle)); + /* write SMC Mode Register*/ + at91_sys_write(AT91_SMC_MODE(info->cs), info->mode); } static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev) @@ -156,15 +277,9 @@ static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev) if (ret) { dev_warn(ap->dev, "Failed to compute ATA timing %d, " "set PIO_0 timing\n", ret); - set_smc_timing(ap->dev, info, &initial_timing); - } else { - set_smc_timing(ap->dev, info, &timing); + timing = *ata_timing_find_mode(XFER_PIO_0); } - - /* Setup SMC mode */ - set_smc_mode(info); - - return; + set_smc_timing(ap->dev, adev, info, &timing); } static unsigned int pata_at91_data_xfer_noirq(struct ata_device *dev, @@ -330,7 +445,7 @@ static int __devexit pata_at91_remove(struct platform_device *pdev) static struct platform_driver pata_at91_driver = { .probe = pata_at91_probe, .remove = __devexit_p(pata_at91_remove), - .driver = { + .driver = { .name = DRV_NAME, .owner = THIS_MODULE, }, diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 905ff76d3cbb..7bafc16cf5e0 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -41,6 +41,9 @@ enum { CFR = 0x50, CFR_INTR_CH0 = 0x04, + CNTRL = 0x51, + CNTRL_CH0 = 0x04, + CNTRL_CH1 = 0x08, CMDTIM = 0x52, ARTTIM0 = 0x53, DRWTIM0 = 0x54, @@ -328,9 +331,19 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &cmd648_port_ops } }; - const struct ata_port_info *ppi[] = { &cmd_info[id->driver_data], NULL }; - u8 mrdmode; + const struct ata_port_info *ppi[] = { + &cmd_info[id->driver_data], + &cmd_info[id->driver_data], + NULL + }; + u8 mrdmode, reg; int rc; + struct pci_dev *bridge = pdev->bus->self; + /* mobility split bridges don't report enabled ports correctly */ + int port_ok = !(bridge && bridge->vendor == + PCI_VENDOR_ID_MOBILITY_ELECTRONICS); + /* all (with exceptions below) apart from 643 have CNTRL_CH0 bit */ + int cntrl_ch0_ok = (id->driver_data != 0); rc = pcim_enable_device(pdev); if (rc) @@ -341,11 +354,18 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (pdev->device == PCI_DEVICE_ID_CMD_646) { /* Does UDMA work ? */ - if (pdev->revision > 4) + if (pdev->revision > 4) { ppi[0] = &cmd_info[2]; + ppi[1] = &cmd_info[2]; + } /* Early rev with other problems ? */ - else if (pdev->revision == 1) + else if (pdev->revision == 1) { ppi[0] = &cmd_info[3]; + ppi[1] = &cmd_info[3]; + } + /* revs 1,2 have no CNTRL_CH0 */ + if (pdev->revision < 3) + cntrl_ch0_ok = 0; } pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); @@ -354,6 +374,20 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) mrdmode |= 0x02; /* Memory read line enable */ pci_write_config_byte(pdev, MRDMODE, mrdmode); + /* check for enabled ports */ + pci_read_config_byte(pdev, CNTRL, ®); + if (!port_ok) + dev_printk(KERN_NOTICE, &pdev->dev, "Mobility Bridge detected, ignoring CNTRL port enable/disable\n"); + if (port_ok && cntrl_ch0_ok && !(reg & CNTRL_CH0)) { + dev_printk(KERN_NOTICE, &pdev->dev, "Primary port is disabled\n"); + ppi[0] = &ata_dummy_port_info; + + } + if (port_ok && !(reg & CNTRL_CH1)) { + dev_printk(KERN_NOTICE, &pdev->dev, "Secondary port is disabled\n"); + ppi[1] = &ata_dummy_port_info; + } + /* Force PIO 0 here.. */ /* PPC specific fixup copied from old driver */ diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index 03b6d69d6197..b3e0c9432283 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -210,13 +210,34 @@ static const struct pci_device_id triflex[] = { { }, }; +#ifdef CONFIG_PM +static int triflex_ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + int rc = 0; + + rc = ata_host_suspend(host, mesg); + if (rc) + return rc; + + /* + * We must not disable or powerdown the device. + * APM bios refuses to suspend if IDE is not accessible. + */ + pci_save_state(pdev); + + return 0; +} + +#endif + static struct pci_driver triflex_pci_driver = { .name = DRV_NAME, .id_table = triflex, .probe = triflex_init_one, .remove = ata_pci_remove_one, #ifdef CONFIG_PM - .suspend = ata_pci_device_suspend, + .suspend = triflex_ata_pci_device_suspend, .resume = ata_pci_device_resume, #endif }; diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index c495fae74200..3230ea0df83c 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -1469,10 +1469,7 @@ if (eni_boards) printk(KERN_INFO "loss: %ld\n",ENI_DEV(eni_boards)->lost); static void bug_int(struct atm_dev *dev,unsigned long reason) { - struct eni_dev *eni_dev; - DPRINTK(">bug_int\n"); - eni_dev = ENI_DEV(dev); if (reason & MID_DMA_ERR_ACK) printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA " "error\n",dev->number); @@ -1900,7 +1897,6 @@ static void eni_close(struct atm_vcc *vcc) static int eni_open(struct atm_vcc *vcc) { - struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; int error; short vpi = vcc->vpi; @@ -1910,7 +1906,6 @@ static int eni_open(struct atm_vcc *vcc) EVENT("eni_open\n",0,0); if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) vcc->dev_data = NULL; - eni_dev = ENI_DEV(vcc->dev); if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) set_bit(ATM_VF_ADDR,&vcc->flags); if (vcc->qos.aal != ATM_AAL0 && vcc->qos.aal != ATM_AAL5) diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index bdd2719f3f68..bc9e702186dd 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -2643,16 +2643,19 @@ fore200e_init(struct fore200e* fore200e, struct device *parent) } #ifdef CONFIG_SBUS +static const struct of_device_id fore200e_sba_match[]; static int __devinit fore200e_sba_probe(struct platform_device *op) { + const struct of_device_id *match; const struct fore200e_bus *bus; struct fore200e *fore200e; static int index = 0; int err; - if (!op->dev.of_match) + match = of_match_device(fore200e_sba_match, &op->dev); + if (!match) return -EINVAL; - bus = op->dev.of_match->data; + bus = match->data; fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL); if (!fore200e) diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 6cf59bf281dc..9a51df4f5b74 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -1801,7 +1801,7 @@ he_service_rbrq(struct he_dev *he_dev, int group) next_rbrq_entry: he_dev->rbrq_head = (struct he_rbrq *) ((unsigned long) he_dev->rbrq_base | - RBRQ_MASK(++he_dev->rbrq_head)); + RBRQ_MASK(he_dev->rbrq_head + 1)); } read_unlock(&vcc_sklist_lock); @@ -1884,7 +1884,7 @@ he_service_tbrq(struct he_dev *he_dev, int group) pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); he_dev->tbrq_head = (struct he_tbrq *) ((unsigned long) he_dev->tbrq_base | - TBRQ_MASK(++he_dev->tbrq_head)); + TBRQ_MASK(he_dev->tbrq_head + 1)); } if (updated) { diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index 048f99fe6f83..1f8d724a18bf 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -1261,14 +1261,13 @@ idt77252_rx_raw(struct idt77252_dev *card) PCI_DMA_FROMDEVICE); while (head != tail) { - unsigned int vpi, vci, pti; + unsigned int vpi, vci; u32 header; header = le32_to_cpu(*(u32 *) &queue->data[0]); vpi = (header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT; vci = (header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT; - pti = (header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; #ifdef CONFIG_ATM_IDT77252_DEBUG if (debug & DBG_RAW_CELL) { @@ -2709,53 +2708,10 @@ idt77252_proc_read(struct atm_dev *dev, loff_t * pos, char *page) static void idt77252_collect_stat(struct idt77252_dev *card) { - u32 cdc, vpec, icc; + (void) readl(SAR_REG_CDC); + (void) readl(SAR_REG_VPEC); + (void) readl(SAR_REG_ICC); - cdc = readl(SAR_REG_CDC); - vpec = readl(SAR_REG_VPEC); - icc = readl(SAR_REG_ICC); - -#ifdef NOTDEF - printk("%s:", card->name); - - if (cdc & 0x7f0000) { - char *s = ""; - - printk(" ["); - if (cdc & (1 << 22)) { - printk("%sRM ID", s); - s = " | "; - } - if (cdc & (1 << 21)) { - printk("%sCON TAB", s); - s = " | "; - } - if (cdc & (1 << 20)) { - printk("%sNO FB", s); - s = " | "; - } - if (cdc & (1 << 19)) { - printk("%sOAM CRC", s); - s = " | "; - } - if (cdc & (1 << 18)) { - printk("%sRM CRC", s); - s = " | "; - } - if (cdc & (1 << 17)) { - printk("%sRM FIFO", s); - s = " | "; - } - if (cdc & (1 << 16)) { - printk("%sRX FIFO", s); - s = " | "; - } - printk("]"); - } - - printk(" CDC %04x, VPEC %04x, ICC: %04x\n", - cdc & 0xffff, vpec & 0xffff, icc & 0xffff); -#endif } static irqreturn_t diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 1c674a91f146..dee4f01a64d8 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -613,7 +613,6 @@ static int ia_que_tx (IADEV *iadev) { struct sk_buff *skb; int num_desc; struct atm_vcc *vcc; - struct ia_vcc *iavcc; num_desc = ia_avail_descs(iadev); while (num_desc && (skb = skb_dequeue(&iadev->tx_backlog))) { @@ -627,7 +626,6 @@ static int ia_que_tx (IADEV *iadev) { printk("Free the SKB on closed vci %d \n", vcc->vci); break; } - iavcc = INPH_IA_VCC(vcc); if (ia_pkt_tx (vcc, skb)) { skb_queue_head(&iadev->tx_backlog, skb); } @@ -823,8 +821,6 @@ static void IaFrontEndIntr(IADEV *iadev) { volatile IA_SUNI *suni; volatile ia_mb25_t *mb25; volatile suni_pm7345_t *suni_pm7345; - u32 intr_status; - u_int frmr_intr; if(iadev->phy_type & FE_25MBIT_PHY) { mb25 = (ia_mb25_t*)iadev->phy; @@ -832,18 +828,18 @@ static void IaFrontEndIntr(IADEV *iadev) { } else if (iadev->phy_type & FE_DS3_PHY) { suni_pm7345 = (suni_pm7345_t *)iadev->phy; /* clear FRMR interrupts */ - frmr_intr = suni_pm7345->suni_ds3_frm_intr_stat; + (void) suni_pm7345->suni_ds3_frm_intr_stat; iadev->carrier_detect = Boolean(!(suni_pm7345->suni_ds3_frm_stat & SUNI_DS3_LOSV)); } else if (iadev->phy_type & FE_E3_PHY ) { suni_pm7345 = (suni_pm7345_t *)iadev->phy; - frmr_intr = suni_pm7345->suni_e3_frm_maint_intr_ind; + (void) suni_pm7345->suni_e3_frm_maint_intr_ind; iadev->carrier_detect = Boolean(!(suni_pm7345->suni_e3_frm_fram_intr_ind_stat&SUNI_E3_LOS)); } else { suni = (IA_SUNI *)iadev->phy; - intr_status = suni->suni_rsop_status & 0xff; + (void) suni->suni_rsop_status; iadev->carrier_detect = Boolean(!(suni->suni_rsop_status & SUNI_LOSV)); } if (iadev->carrier_detect) @@ -2660,7 +2656,6 @@ static void ia_close(struct atm_vcc *vcc) static int ia_open(struct atm_vcc *vcc) { - IADEV *iadev; struct ia_vcc *ia_vcc; int error; if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) @@ -2668,7 +2663,6 @@ static int ia_open(struct atm_vcc *vcc) IF_EVENT(printk("ia: not partially allocated resources\n");) vcc->dev_data = NULL; } - iadev = INPH_IA_DEV(vcc->dev); if (vcc->vci != ATM_VPI_UNSPEC && vcc->vpi != ATM_VCI_UNSPEC) { IF_EVENT(printk("iphase open: unspec part\n");) @@ -3052,11 +3046,9 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) { static int ia_send(struct atm_vcc *vcc, struct sk_buff *skb) { IADEV *iadev; - struct ia_vcc *iavcc; unsigned long flags; iadev = INPH_IA_DEV(vcc->dev); - iavcc = INPH_IA_VCC(vcc); if ((!skb)||(skb->len>(iadev->tx_buf_sz-sizeof(struct cpcs_trailer)))) { if (!skb) diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index cd0ff66469b2..5d1d07645132 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -527,7 +527,6 @@ static int flash_upgrade(struct solos_card *card, int chip) { const struct firmware *fw; const char *fw_name; - uint32_t data32 = 0; int blocksize = 0; int numblocks = 0; int offset; @@ -576,7 +575,7 @@ static int flash_upgrade(struct solos_card *card, int chip) dev_info(&card->dev->dev, "Changing FPGA to Update mode\n"); iowrite32(1, card->config_regs + FPGA_MODE); - data32 = ioread32(card->config_regs + FPGA_MODE); + (void) ioread32(card->config_regs + FPGA_MODE); /* Set mode to Chip Erase */ if(chip == 0 || chip == 2) diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index e9e5238f3106..d57e8d0fb823 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -168,11 +168,4 @@ config SYS_HYPERVISOR bool default n -config ARCH_NO_SYSDEV_OPS - bool - ---help--- - To be selected by architectures that don't use sysdev class or - sysdev driver power management (suspend/resume) and shutdown - operations. - endmenu diff --git a/drivers/base/base.h b/drivers/base/base.h index 19f49e41ce5d..a34dca0ad041 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -111,8 +111,6 @@ static inline int driver_match_device(struct device_driver *drv, return drv->bus->match ? drv->bus->match(dev, drv) : 1; } -extern void sysdev_shutdown(void); - extern char *make_class_name(const char *name, struct kobject *kobj); extern int devres_release_all(struct device *dev); diff --git a/drivers/base/core.c b/drivers/base/core.c index 81b78ede37c4..bc8729d603a7 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -400,7 +400,7 @@ static void device_remove_groups(struct device *dev, static int device_add_attrs(struct device *dev) { struct class *class = dev->class; - struct device_type *type = dev->type; + const struct device_type *type = dev->type; int error; if (class) { @@ -440,7 +440,7 @@ static int device_add_attrs(struct device *dev) static void device_remove_attrs(struct device *dev) { struct class *class = dev->class; - struct device_type *type = dev->type; + const struct device_type *type = dev->type; device_remove_groups(dev, dev->groups); @@ -1314,8 +1314,7 @@ EXPORT_SYMBOL_GPL(put_device); EXPORT_SYMBOL_GPL(device_create_file); EXPORT_SYMBOL_GPL(device_remove_file); -struct root_device -{ +struct root_device { struct device dev; struct module *owner; }; diff --git a/drivers/base/dd.c b/drivers/base/dd.c index da57ee9d63fe..6658da743c3a 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -245,6 +245,10 @@ int device_attach(struct device *dev) device_lock(dev); if (dev->driver) { + if (klist_node_attached(&dev->p->knode_driver)) { + ret = 1; + goto out_unlock; + } ret = device_bind_driver(dev); if (ret == 0) ret = 1; @@ -257,6 +261,7 @@ int device_attach(struct device *dev) ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); pm_runtime_put_sync(dev); } +out_unlock: device_unlock(dev); return ret; } @@ -316,8 +321,7 @@ static void __device_release_driver(struct device *dev) drv = dev->driver; if (drv) { - pm_runtime_get_noresume(dev); - pm_runtime_barrier(dev); + pm_runtime_get_sync(dev); driver_sysfs_remove(dev); @@ -326,6 +330,8 @@ static void __device_release_driver(struct device *dev) BUS_NOTIFY_UNBIND_DRIVER, dev); + pm_runtime_put_sync(dev); + if (dev->bus && dev->bus->remove) dev->bus->remove(dev); else if (drv->remove) @@ -338,7 +344,6 @@ static void __device_release_driver(struct device *dev) BUS_NOTIFY_UNBOUND_DRIVER, dev); - pm_runtime_put_sync(dev); } } @@ -408,17 +413,16 @@ void *dev_get_drvdata(const struct device *dev) } EXPORT_SYMBOL(dev_get_drvdata); -void dev_set_drvdata(struct device *dev, void *data) +int dev_set_drvdata(struct device *dev, void *data) { int error; - if (!dev) - return; if (!dev->p) { error = device_private_init(dev); if (error) - return; + return error; } dev->p->driver_data = data; + return 0; } EXPORT_SYMBOL(dev_set_drvdata); diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 8c798ef7f13f..bbb03e6f7255 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -521,6 +521,11 @@ static int _request_firmware(const struct firmware **firmware_p, if (!firmware_p) return -EINVAL; + if (WARN_ON(usermodehelper_is_disabled())) { + dev_err(device, "firmware: %s will not be loaded\n", name); + return -EBUSY; + } + *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); if (!firmware) { dev_err(device, "%s: kmalloc(struct firmware) failed\n", diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 3da6a43b7756..0a134a424a37 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -48,7 +48,8 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) return MEMORY_CLASS_NAME; } -static int memory_uevent(struct kset *kset, struct kobject *obj, struct kobj_uevent_env *env) +static int memory_uevent(struct kset *kset, struct kobject *obj, + struct kobj_uevent_env *env) { int retval = 0; @@ -228,10 +229,11 @@ int memory_isolate_notify(unsigned long val, void *v) * OK to have direct references to sparsemem variables in here. */ static int -memory_section_action(unsigned long phys_index, unsigned long action) +memory_block_action(unsigned long phys_index, unsigned long action) { int i; unsigned long start_pfn, start_paddr; + unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block; struct page *first_page; int ret; @@ -243,7 +245,7 @@ memory_section_action(unsigned long phys_index, unsigned long action) * that way. */ if (action == MEM_ONLINE) { - for (i = 0; i < PAGES_PER_SECTION; i++) { + for (i = 0; i < nr_pages; i++) { if (PageReserved(first_page+i)) continue; @@ -257,12 +259,12 @@ memory_section_action(unsigned long phys_index, unsigned long action) switch (action) { case MEM_ONLINE: start_pfn = page_to_pfn(first_page); - ret = online_pages(start_pfn, PAGES_PER_SECTION); + ret = online_pages(start_pfn, nr_pages); break; case MEM_OFFLINE: start_paddr = page_to_pfn(first_page) << PAGE_SHIFT; ret = remove_memory(start_paddr, - PAGES_PER_SECTION << PAGE_SHIFT); + nr_pages << PAGE_SHIFT); break; default: WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: " @@ -276,7 +278,7 @@ memory_section_action(unsigned long phys_index, unsigned long action) static int memory_block_change_state(struct memory_block *mem, unsigned long to_state, unsigned long from_state_req) { - int i, ret = 0; + int ret = 0; mutex_lock(&mem->state_mutex); @@ -288,20 +290,11 @@ static int memory_block_change_state(struct memory_block *mem, if (to_state == MEM_OFFLINE) mem->state = MEM_GOING_OFFLINE; - for (i = 0; i < sections_per_block; i++) { - ret = memory_section_action(mem->start_section_nr + i, - to_state); - if (ret) - break; - } - - if (ret) { - for (i = 0; i < sections_per_block; i++) - memory_section_action(mem->start_section_nr + i, - from_state_req); + ret = memory_block_action(mem->start_section_nr, to_state); + if (ret) mem->state = from_state_req; - } else + else mem->state = to_state; out: diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 9e0e4fc24c46..1c291af637b3 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -192,18 +192,18 @@ EXPORT_SYMBOL_GPL(platform_device_alloc); int platform_device_add_resources(struct platform_device *pdev, const struct resource *res, unsigned int num) { - struct resource *r; + struct resource *r = NULL; - if (!res) - return 0; - - r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); - if (r) { - pdev->resource = r; - pdev->num_resources = num; - return 0; + if (res) { + r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); + if (!r) + return -ENOMEM; } - return -ENOMEM; + + kfree(pdev->resource); + pdev->resource = r; + pdev->num_resources = num; + return 0; } EXPORT_SYMBOL_GPL(platform_device_add_resources); @@ -220,17 +220,17 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources); int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size) { - void *d; + void *d = NULL; - if (!data) - return 0; - - d = kmemdup(data, size, GFP_KERNEL); - if (d) { - pdev->dev.platform_data = d; - return 0; + if (data) { + d = kmemdup(data, size, GFP_KERNEL); + if (!d) + return -ENOMEM; } - return -ENOMEM; + + kfree(pdev->dev.platform_data); + pdev->dev.platform_data = d; + return 0; } EXPORT_SYMBOL_GPL(platform_device_add_data); @@ -667,7 +667,7 @@ static int platform_legacy_resume(struct device *dev) return ret; } -static int platform_pm_prepare(struct device *dev) +int platform_pm_prepare(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -678,7 +678,7 @@ static int platform_pm_prepare(struct device *dev) return ret; } -static void platform_pm_complete(struct device *dev) +void platform_pm_complete(struct device *dev) { struct device_driver *drv = dev->driver; @@ -686,16 +686,11 @@ static void platform_pm_complete(struct device *dev) drv->pm->complete(dev); } -#else /* !CONFIG_PM_SLEEP */ - -#define platform_pm_prepare NULL -#define platform_pm_complete NULL - -#endif /* !CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_SUSPEND -int __weak platform_pm_suspend(struct device *dev) +int platform_pm_suspend(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -713,7 +708,7 @@ int __weak platform_pm_suspend(struct device *dev) return ret; } -int __weak platform_pm_suspend_noirq(struct device *dev) +int platform_pm_suspend_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -729,7 +724,7 @@ int __weak platform_pm_suspend_noirq(struct device *dev) return ret; } -int __weak platform_pm_resume(struct device *dev) +int platform_pm_resume(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -747,7 +742,7 @@ int __weak platform_pm_resume(struct device *dev) return ret; } -int __weak platform_pm_resume_noirq(struct device *dev) +int platform_pm_resume_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -763,18 +758,11 @@ int __weak platform_pm_resume_noirq(struct device *dev) return ret; } -#else /* !CONFIG_SUSPEND */ - -#define platform_pm_suspend NULL -#define platform_pm_resume NULL -#define platform_pm_suspend_noirq NULL -#define platform_pm_resume_noirq NULL - -#endif /* !CONFIG_SUSPEND */ +#endif /* CONFIG_SUSPEND */ #ifdef CONFIG_HIBERNATE_CALLBACKS -static int platform_pm_freeze(struct device *dev) +int platform_pm_freeze(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -792,7 +780,7 @@ static int platform_pm_freeze(struct device *dev) return ret; } -static int platform_pm_freeze_noirq(struct device *dev) +int platform_pm_freeze_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -808,7 +796,7 @@ static int platform_pm_freeze_noirq(struct device *dev) return ret; } -static int platform_pm_thaw(struct device *dev) +int platform_pm_thaw(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -826,7 +814,7 @@ static int platform_pm_thaw(struct device *dev) return ret; } -static int platform_pm_thaw_noirq(struct device *dev) +int platform_pm_thaw_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -842,7 +830,7 @@ static int platform_pm_thaw_noirq(struct device *dev) return ret; } -static int platform_pm_poweroff(struct device *dev) +int platform_pm_poweroff(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -860,7 +848,7 @@ static int platform_pm_poweroff(struct device *dev) return ret; } -static int platform_pm_poweroff_noirq(struct device *dev) +int platform_pm_poweroff_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -876,7 +864,7 @@ static int platform_pm_poweroff_noirq(struct device *dev) return ret; } -static int platform_pm_restore(struct device *dev) +int platform_pm_restore(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -894,7 +882,7 @@ static int platform_pm_restore(struct device *dev) return ret; } -static int platform_pm_restore_noirq(struct device *dev) +int platform_pm_restore_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -910,62 +898,13 @@ static int platform_pm_restore_noirq(struct device *dev) return ret; } -#else /* !CONFIG_HIBERNATE_CALLBACKS */ - -#define platform_pm_freeze NULL -#define platform_pm_thaw NULL -#define platform_pm_poweroff NULL -#define platform_pm_restore NULL -#define platform_pm_freeze_noirq NULL -#define platform_pm_thaw_noirq NULL -#define platform_pm_poweroff_noirq NULL -#define platform_pm_restore_noirq NULL - -#endif /* !CONFIG_HIBERNATE_CALLBACKS */ - -#ifdef CONFIG_PM_RUNTIME - -int __weak platform_pm_runtime_suspend(struct device *dev) -{ - return pm_generic_runtime_suspend(dev); -}; - -int __weak platform_pm_runtime_resume(struct device *dev) -{ - return pm_generic_runtime_resume(dev); -}; - -int __weak platform_pm_runtime_idle(struct device *dev) -{ - return pm_generic_runtime_idle(dev); -}; - -#else /* !CONFIG_PM_RUNTIME */ - -#define platform_pm_runtime_suspend NULL -#define platform_pm_runtime_resume NULL -#define platform_pm_runtime_idle NULL - -#endif /* !CONFIG_PM_RUNTIME */ +#endif /* CONFIG_HIBERNATE_CALLBACKS */ static const struct dev_pm_ops platform_dev_pm_ops = { - .prepare = platform_pm_prepare, - .complete = platform_pm_complete, - .suspend = platform_pm_suspend, - .resume = platform_pm_resume, - .freeze = platform_pm_freeze, - .thaw = platform_pm_thaw, - .poweroff = platform_pm_poweroff, - .restore = platform_pm_restore, - .suspend_noirq = platform_pm_suspend_noirq, - .resume_noirq = platform_pm_resume_noirq, - .freeze_noirq = platform_pm_freeze_noirq, - .thaw_noirq = platform_pm_thaw_noirq, - .poweroff_noirq = platform_pm_poweroff_noirq, - .restore_noirq = platform_pm_restore_noirq, - .runtime_suspend = platform_pm_runtime_suspend, - .runtime_resume = platform_pm_runtime_resume, - .runtime_idle = platform_pm_runtime_idle, + .runtime_suspend = pm_generic_runtime_suspend, + .runtime_resume = pm_generic_runtime_resume, + .runtime_idle = pm_generic_runtime_idle, + USE_PLATFORM_PM_SLEEP_OPS }; struct bus_type platform_bus_type = { @@ -977,41 +916,6 @@ struct bus_type platform_bus_type = { }; EXPORT_SYMBOL_GPL(platform_bus_type); -/** - * platform_bus_get_pm_ops() - return pointer to busses dev_pm_ops - * - * This function can be used by platform code to get the current - * set of dev_pm_ops functions used by the platform_bus_type. - */ -const struct dev_pm_ops * __init platform_bus_get_pm_ops(void) -{ - return platform_bus_type.pm; -} - -/** - * platform_bus_set_pm_ops() - update dev_pm_ops for the platform_bus_type - * - * @pm: pointer to new dev_pm_ops struct to be used for platform_bus_type - * - * Platform code can override the dev_pm_ops methods of - * platform_bus_type by using this function. It is expected that - * platform code will first do a platform_bus_get_pm_ops(), then - * kmemdup it, then customize selected methods and pass a pointer to - * the new struct dev_pm_ops to this function. - * - * Since platform-specific code is customizing methods for *all* - * devices (not just platform-specific devices) it is expected that - * any custom overrides of these functions will keep existing behavior - * and simply extend it. For example, any customization of the - * runtime PM methods should continue to call the pm_generic_* - * functions as the default ones do in addition to the - * platform-specific behavior. - */ -void __init platform_bus_set_pm_ops(const struct dev_pm_ops *pm) -{ - platform_bus_type.pm = pm; -} - int __init platform_bus_init(void) { int error; diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 118c1b92a511..3647e114d0e7 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -3,6 +3,6 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o obj-$(CONFIG_PM_OPP) += opp.o +obj-$(CONFIG_HAVE_CLK) += clock_ops.o -ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG -ccflags-$(CONFIG_PM_VERBOSE) += -DDEBUG +ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG \ No newline at end of file diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c new file mode 100644 index 000000000000..c0dd09df7be8 --- /dev/null +++ b/drivers/base/power/clock_ops.c @@ -0,0 +1,431 @@ +/* + * drivers/base/power/clock_ops.c - Generic clock manipulation PM callbacks + * + * Copyright (c) 2011 Rafael J. Wysocki , Renesas Electronics Corp. + * + * This file is released under the GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM_RUNTIME + +struct pm_runtime_clk_data { + struct list_head clock_list; + struct mutex lock; +}; + +enum pce_status { + PCE_STATUS_NONE = 0, + PCE_STATUS_ACQUIRED, + PCE_STATUS_ENABLED, + PCE_STATUS_ERROR, +}; + +struct pm_clock_entry { + struct list_head node; + char *con_id; + struct clk *clk; + enum pce_status status; +}; + +static struct pm_runtime_clk_data *__to_prd(struct device *dev) +{ + return dev ? dev->power.subsys_data : NULL; +} + +/** + * pm_runtime_clk_add - Start using a device clock for runtime PM. + * @dev: Device whose clock is going to be used for runtime PM. + * @con_id: Connection ID of the clock. + * + * Add the clock represented by @con_id to the list of clocks used for + * the runtime PM of @dev. + */ +int pm_runtime_clk_add(struct device *dev, const char *con_id) +{ + struct pm_runtime_clk_data *prd = __to_prd(dev); + struct pm_clock_entry *ce; + + if (!prd) + return -EINVAL; + + ce = kzalloc(sizeof(*ce), GFP_KERNEL); + if (!ce) { + dev_err(dev, "Not enough memory for clock entry.\n"); + return -ENOMEM; + } + + if (con_id) { + ce->con_id = kstrdup(con_id, GFP_KERNEL); + if (!ce->con_id) { + dev_err(dev, + "Not enough memory for clock connection ID.\n"); + kfree(ce); + return -ENOMEM; + } + } + + mutex_lock(&prd->lock); + list_add_tail(&ce->node, &prd->clock_list); + mutex_unlock(&prd->lock); + return 0; +} + +/** + * __pm_runtime_clk_remove - Destroy runtime PM clock entry. + * @ce: Runtime PM clock entry to destroy. + * + * This routine must be called under the mutex protecting the runtime PM list + * of clocks corresponding the the @ce's device. + */ +static void __pm_runtime_clk_remove(struct pm_clock_entry *ce) +{ + if (!ce) + return; + + list_del(&ce->node); + + if (ce->status < PCE_STATUS_ERROR) { + if (ce->status == PCE_STATUS_ENABLED) + clk_disable(ce->clk); + + if (ce->status >= PCE_STATUS_ACQUIRED) + clk_put(ce->clk); + } + + if (ce->con_id) + kfree(ce->con_id); + + kfree(ce); +} + +/** + * pm_runtime_clk_remove - Stop using a device clock for runtime PM. + * @dev: Device whose clock should not be used for runtime PM any more. + * @con_id: Connection ID of the clock. + * + * Remove the clock represented by @con_id from the list of clocks used for + * the runtime PM of @dev. + */ +void pm_runtime_clk_remove(struct device *dev, const char *con_id) +{ + struct pm_runtime_clk_data *prd = __to_prd(dev); + struct pm_clock_entry *ce; + + if (!prd) + return; + + mutex_lock(&prd->lock); + + list_for_each_entry(ce, &prd->clock_list, node) { + if (!con_id && !ce->con_id) { + __pm_runtime_clk_remove(ce); + break; + } else if (!con_id || !ce->con_id) { + continue; + } else if (!strcmp(con_id, ce->con_id)) { + __pm_runtime_clk_remove(ce); + break; + } + } + + mutex_unlock(&prd->lock); +} + +/** + * pm_runtime_clk_init - Initialize a device's list of runtime PM clocks. + * @dev: Device to initialize the list of runtime PM clocks for. + * + * Allocate a struct pm_runtime_clk_data object, initialize its lock member and + * make the @dev's power.subsys_data field point to it. + */ +int pm_runtime_clk_init(struct device *dev) +{ + struct pm_runtime_clk_data *prd; + + prd = kzalloc(sizeof(*prd), GFP_KERNEL); + if (!prd) { + dev_err(dev, "Not enough memory fo runtime PM data.\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&prd->clock_list); + mutex_init(&prd->lock); + dev->power.subsys_data = prd; + return 0; +} + +/** + * pm_runtime_clk_destroy - Destroy a device's list of runtime PM clocks. + * @dev: Device to destroy the list of runtime PM clocks for. + * + * Clear the @dev's power.subsys_data field, remove the list of clock entries + * from the struct pm_runtime_clk_data object pointed to by it before and free + * that object. + */ +void pm_runtime_clk_destroy(struct device *dev) +{ + struct pm_runtime_clk_data *prd = __to_prd(dev); + struct pm_clock_entry *ce, *c; + + if (!prd) + return; + + dev->power.subsys_data = NULL; + + mutex_lock(&prd->lock); + + list_for_each_entry_safe_reverse(ce, c, &prd->clock_list, node) + __pm_runtime_clk_remove(ce); + + mutex_unlock(&prd->lock); + + kfree(prd); +} + +/** + * pm_runtime_clk_acquire - Acquire a device clock. + * @dev: Device whose clock is to be acquired. + * @con_id: Connection ID of the clock. + */ +static void pm_runtime_clk_acquire(struct device *dev, + struct pm_clock_entry *ce) +{ + ce->clk = clk_get(dev, ce->con_id); + if (IS_ERR(ce->clk)) { + ce->status = PCE_STATUS_ERROR; + } else { + ce->status = PCE_STATUS_ACQUIRED; + dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id); + } +} + +/** + * pm_runtime_clk_suspend - Disable clocks in a device's runtime PM clock list. + * @dev: Device to disable the clocks for. + */ +int pm_runtime_clk_suspend(struct device *dev) +{ + struct pm_runtime_clk_data *prd = __to_prd(dev); + struct pm_clock_entry *ce; + + dev_dbg(dev, "%s()\n", __func__); + + if (!prd) + return 0; + + mutex_lock(&prd->lock); + + list_for_each_entry_reverse(ce, &prd->clock_list, node) { + if (ce->status == PCE_STATUS_NONE) + pm_runtime_clk_acquire(dev, ce); + + if (ce->status < PCE_STATUS_ERROR) { + clk_disable(ce->clk); + ce->status = PCE_STATUS_ACQUIRED; + } + } + + mutex_unlock(&prd->lock); + + return 0; +} + +/** + * pm_runtime_clk_resume - Enable clocks in a device's runtime PM clock list. + * @dev: Device to enable the clocks for. + */ +int pm_runtime_clk_resume(struct device *dev) +{ + struct pm_runtime_clk_data *prd = __to_prd(dev); + struct pm_clock_entry *ce; + + dev_dbg(dev, "%s()\n", __func__); + + if (!prd) + return 0; + + mutex_lock(&prd->lock); + + list_for_each_entry(ce, &prd->clock_list, node) { + if (ce->status == PCE_STATUS_NONE) + pm_runtime_clk_acquire(dev, ce); + + if (ce->status < PCE_STATUS_ERROR) { + clk_enable(ce->clk); + ce->status = PCE_STATUS_ENABLED; + } + } + + mutex_unlock(&prd->lock); + + return 0; +} + +/** + * pm_runtime_clk_notify - Notify routine for device addition and removal. + * @nb: Notifier block object this function is a member of. + * @action: Operation being carried out by the caller. + * @data: Device the routine is being run for. + * + * For this function to work, @nb must be a member of an object of type + * struct pm_clk_notifier_block containing all of the requisite data. + * Specifically, the pwr_domain member of that object is copied to the device's + * pwr_domain field and its con_ids member is used to populate the device's list + * of runtime PM clocks, depending on @action. + * + * If the device's pwr_domain field is already populated with a value different + * from the one stored in the struct pm_clk_notifier_block object, the function + * does nothing. + */ +static int pm_runtime_clk_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct pm_clk_notifier_block *clknb; + struct device *dev = data; + char *con_id; + int error; + + dev_dbg(dev, "%s() %ld\n", __func__, action); + + clknb = container_of(nb, struct pm_clk_notifier_block, nb); + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + if (dev->pwr_domain) + break; + + error = pm_runtime_clk_init(dev); + if (error) + break; + + dev->pwr_domain = clknb->pwr_domain; + if (clknb->con_ids[0]) { + for (con_id = clknb->con_ids[0]; *con_id; con_id++) + pm_runtime_clk_add(dev, con_id); + } else { + pm_runtime_clk_add(dev, NULL); + } + + break; + case BUS_NOTIFY_DEL_DEVICE: + if (dev->pwr_domain != clknb->pwr_domain) + break; + + dev->pwr_domain = NULL; + pm_runtime_clk_destroy(dev); + break; + } + + return 0; +} + +#else /* !CONFIG_PM_RUNTIME */ + +/** + * enable_clock - Enable a device clock. + * @dev: Device whose clock is to be enabled. + * @con_id: Connection ID of the clock. + */ +static void enable_clock(struct device *dev, const char *con_id) +{ + struct clk *clk; + + clk = clk_get(dev, con_id); + if (!IS_ERR(clk)) { + clk_enable(clk); + clk_put(clk); + dev_info(dev, "Runtime PM disabled, clock forced on.\n"); + } +} + +/** + * disable_clock - Disable a device clock. + * @dev: Device whose clock is to be disabled. + * @con_id: Connection ID of the clock. + */ +static void disable_clock(struct device *dev, const char *con_id) +{ + struct clk *clk; + + clk = clk_get(dev, con_id); + if (!IS_ERR(clk)) { + clk_disable(clk); + clk_put(clk); + dev_info(dev, "Runtime PM disabled, clock forced off.\n"); + } +} + +/** + * pm_runtime_clk_notify - Notify routine for device addition and removal. + * @nb: Notifier block object this function is a member of. + * @action: Operation being carried out by the caller. + * @data: Device the routine is being run for. + * + * For this function to work, @nb must be a member of an object of type + * struct pm_clk_notifier_block containing all of the requisite data. + * Specifically, the con_ids member of that object is used to enable or disable + * the device's clocks, depending on @action. + */ +static int pm_runtime_clk_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct pm_clk_notifier_block *clknb; + struct device *dev = data; + char *con_id; + + dev_dbg(dev, "%s() %ld\n", __func__, action); + + clknb = container_of(nb, struct pm_clk_notifier_block, nb); + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + if (clknb->con_ids[0]) { + for (con_id = clknb->con_ids[0]; *con_id; con_id++) + enable_clock(dev, con_id); + } else { + enable_clock(dev, NULL); + } + break; + case BUS_NOTIFY_DEL_DEVICE: + if (clknb->con_ids[0]) { + for (con_id = clknb->con_ids[0]; *con_id; con_id++) + disable_clock(dev, con_id); + } else { + disable_clock(dev, NULL); + } + break; + } + + return 0; +} + +#endif /* !CONFIG_PM_RUNTIME */ + +/** + * pm_runtime_clk_add_notifier - Add bus type notifier for runtime PM clocks. + * @bus: Bus type to add the notifier to. + * @clknb: Notifier to be added to the given bus type. + * + * The nb member of @clknb is not expected to be initialized and its + * notifier_call member will be replaced with pm_runtime_clk_notify(). However, + * the remaining members of @clknb should be populated prior to calling this + * routine. + */ +void pm_runtime_clk_add_notifier(struct bus_type *bus, + struct pm_clk_notifier_block *clknb) +{ + if (!bus || !clknb) + return; + + clknb->nb.notifier_call = pm_runtime_clk_notify; + bus_register_notifier(bus, &clknb->nb); +} diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index 42f97f925629..cb3bb368681c 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c @@ -73,6 +73,23 @@ EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); #endif /* CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP +/** + * pm_generic_prepare - Generic routine preparing a device for power transition. + * @dev: Device to prepare. + * + * Prepare a device for a system-wide power transition. + */ +int pm_generic_prepare(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (drv && drv->pm && drv->pm->prepare) + ret = drv->pm->prepare(dev); + + return ret; +} + /** * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. * @dev: Device to handle. @@ -213,16 +230,38 @@ int pm_generic_restore(struct device *dev) return __pm_generic_resume(dev, PM_EVENT_RESTORE); } EXPORT_SYMBOL_GPL(pm_generic_restore); + +/** + * pm_generic_complete - Generic routine competing a device power transition. + * @dev: Device to handle. + * + * Complete a device power transition during a system-wide power transition. + */ +void pm_generic_complete(struct device *dev) +{ + struct device_driver *drv = dev->driver; + + if (drv && drv->pm && drv->pm->complete) + drv->pm->complete(dev); + + /* + * Let runtime PM try to suspend devices that haven't been in use before + * going into the system-wide sleep state we're resuming from. + */ + pm_runtime_idle(dev); +} #endif /* CONFIG_PM_SLEEP */ struct dev_pm_ops generic_subsys_pm_ops = { #ifdef CONFIG_PM_SLEEP + .prepare = pm_generic_prepare, .suspend = pm_generic_suspend, .resume = pm_generic_resume, .freeze = pm_generic_freeze, .thaw = pm_generic_thaw, .poweroff = pm_generic_poweroff, .restore = pm_generic_restore, + .complete = pm_generic_complete, #endif #ifdef CONFIG_PM_RUNTIME .runtime_suspend = pm_generic_runtime_suspend, diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index fbc5b6e7c591..aa6320207745 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -63,6 +63,7 @@ void device_pm_init(struct device *dev) dev->power.wakeup = NULL; spin_lock_init(&dev->power.lock); pm_runtime_init(dev); + INIT_LIST_HEAD(&dev->power.entry); } /** @@ -425,10 +426,8 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (dev->pwr_domain) { pm_dev_dbg(dev, state, "EARLY power domain "); - pm_noirq_op(dev, &dev->pwr_domain->ops, state); - } - - if (dev->type && dev->type->pm) { + error = pm_noirq_op(dev, &dev->pwr_domain->ops, state); + } else if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "EARLY type "); error = pm_noirq_op(dev, dev->type->pm, state); } else if (dev->class && dev->class->pm) { @@ -516,7 +515,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) if (dev->pwr_domain) { pm_dev_dbg(dev, state, "power domain "); - pm_op(dev, &dev->pwr_domain->ops, state); + error = pm_op(dev, &dev->pwr_domain->ops, state); + goto End; } if (dev->type && dev->type->pm) { @@ -579,11 +579,13 @@ static bool is_async(struct device *dev) * Execute the appropriate "resume" callback for all devices whose status * indicates that they are suspended. */ -static void dpm_resume(pm_message_t state) +void dpm_resume(pm_message_t state) { struct device *dev; ktime_t starttime = ktime_get(); + might_sleep(); + mutex_lock(&dpm_list_mtx); pm_transition = state; async_error = 0; @@ -628,12 +630,11 @@ static void device_complete(struct device *dev, pm_message_t state) { device_lock(dev); - if (dev->pwr_domain && dev->pwr_domain->ops.complete) { + if (dev->pwr_domain) { pm_dev_dbg(dev, state, "completing power domain "); - dev->pwr_domain->ops.complete(dev); - } - - if (dev->type && dev->type->pm) { + if (dev->pwr_domain->ops.complete) + dev->pwr_domain->ops.complete(dev); + } else if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "completing type "); if (dev->type->pm->complete) dev->type->pm->complete(dev); @@ -657,10 +658,12 @@ static void device_complete(struct device *dev, pm_message_t state) * Execute the ->complete() callbacks for all devices whose PM status is not * DPM_ON (this allows new devices to be registered). */ -static void dpm_complete(pm_message_t state) +void dpm_complete(pm_message_t state) { struct list_head list; + might_sleep(); + INIT_LIST_HEAD(&list); mutex_lock(&dpm_list_mtx); while (!list_empty(&dpm_prepared_list)) { @@ -689,7 +692,6 @@ static void dpm_complete(pm_message_t state) */ void dpm_resume_end(pm_message_t state) { - might_sleep(); dpm_resume(state); dpm_complete(state); } @@ -731,7 +733,12 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) { int error; - if (dev->type && dev->type->pm) { + if (dev->pwr_domain) { + pm_dev_dbg(dev, state, "LATE power domain "); + error = pm_noirq_op(dev, &dev->pwr_domain->ops, state); + if (error) + return error; + } else if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "LATE type "); error = pm_noirq_op(dev, dev->type->pm, state); if (error) @@ -748,11 +755,6 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) return error; } - if (dev->pwr_domain) { - pm_dev_dbg(dev, state, "LATE power domain "); - pm_noirq_op(dev, &dev->pwr_domain->ops, state); - } - return 0; } @@ -840,21 +842,27 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) goto End; } + if (dev->pwr_domain) { + pm_dev_dbg(dev, state, "power domain "); + error = pm_op(dev, &dev->pwr_domain->ops, state); + goto End; + } + if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "type "); error = pm_op(dev, dev->type->pm, state); - goto Domain; + goto End; } if (dev->class) { if (dev->class->pm) { pm_dev_dbg(dev, state, "class "); error = pm_op(dev, dev->class->pm, state); - goto Domain; + goto End; } else if (dev->class->suspend) { pm_dev_dbg(dev, state, "legacy class "); error = legacy_suspend(dev, state, dev->class->suspend); - goto Domain; + goto End; } } @@ -868,12 +876,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) } } - Domain: - if (!error && dev->pwr_domain) { - pm_dev_dbg(dev, state, "power domain "); - pm_op(dev, &dev->pwr_domain->ops, state); - } - End: device_unlock(dev); complete_all(&dev->power.completion); @@ -913,11 +915,13 @@ static int device_suspend(struct device *dev) * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices. * @state: PM transition of the system being carried out. */ -static int dpm_suspend(pm_message_t state) +int dpm_suspend(pm_message_t state) { ktime_t starttime = ktime_get(); int error = 0; + might_sleep(); + mutex_lock(&dpm_list_mtx); pm_transition = state; async_error = 0; @@ -964,7 +968,14 @@ static int device_prepare(struct device *dev, pm_message_t state) device_lock(dev); - if (dev->type && dev->type->pm) { + if (dev->pwr_domain) { + pm_dev_dbg(dev, state, "preparing power domain "); + if (dev->pwr_domain->ops.prepare) + error = dev->pwr_domain->ops.prepare(dev); + suspend_report_result(dev->pwr_domain->ops.prepare, error); + if (error) + goto End; + } else if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "preparing type "); if (dev->type->pm->prepare) error = dev->type->pm->prepare(dev); @@ -983,13 +994,6 @@ static int device_prepare(struct device *dev, pm_message_t state) if (dev->bus->pm->prepare) error = dev->bus->pm->prepare(dev); suspend_report_result(dev->bus->pm->prepare, error); - if (error) - goto End; - } - - if (dev->pwr_domain && dev->pwr_domain->ops.prepare) { - pm_dev_dbg(dev, state, "preparing power domain "); - dev->pwr_domain->ops.prepare(dev); } End: @@ -1004,10 +1008,12 @@ static int device_prepare(struct device *dev, pm_message_t state) * * Execute the ->prepare() callback(s) for all devices. */ -static int dpm_prepare(pm_message_t state) +int dpm_prepare(pm_message_t state) { int error = 0; + might_sleep(); + mutex_lock(&dpm_list_mtx); while (!list_empty(&dpm_list)) { struct device *dev = to_device(dpm_list.next); @@ -1056,7 +1062,6 @@ int dpm_suspend_start(pm_message_t state) { int error; - might_sleep(); error = dpm_prepare(state); if (!error) error = dpm_suspend(state); diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 3172c60d23a9..0d4587b15c55 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -168,7 +168,6 @@ static int rpm_check_suspend_allowed(struct device *dev) static int rpm_idle(struct device *dev, int rpmflags) { int (*callback)(struct device *); - int (*domain_callback)(struct device *); int retval; retval = rpm_check_suspend_allowed(dev); @@ -214,7 +213,9 @@ static int rpm_idle(struct device *dev, int rpmflags) dev->power.idle_notification = true; - if (dev->type && dev->type->pm) + if (dev->pwr_domain) + callback = dev->pwr_domain->ops.runtime_idle; + else if (dev->type && dev->type->pm) callback = dev->type->pm->runtime_idle; else if (dev->class && dev->class->pm) callback = dev->class->pm->runtime_idle; @@ -223,19 +224,10 @@ static int rpm_idle(struct device *dev, int rpmflags) else callback = NULL; - if (dev->pwr_domain) - domain_callback = dev->pwr_domain->ops.runtime_idle; - else - domain_callback = NULL; - - if (callback || domain_callback) { + if (callback) { spin_unlock_irq(&dev->power.lock); - if (domain_callback) - retval = domain_callback(dev); - - if (!retval && callback) - callback(dev); + callback(dev); spin_lock_irq(&dev->power.lock); } @@ -382,7 +374,9 @@ static int rpm_suspend(struct device *dev, int rpmflags) __update_runtime_status(dev, RPM_SUSPENDING); - if (dev->type && dev->type->pm) + if (dev->pwr_domain) + callback = dev->pwr_domain->ops.runtime_suspend; + else if (dev->type && dev->type->pm) callback = dev->type->pm->runtime_suspend; else if (dev->class && dev->class->pm) callback = dev->class->pm->runtime_suspend; @@ -400,8 +394,6 @@ static int rpm_suspend(struct device *dev, int rpmflags) else pm_runtime_cancel_pending(dev); } else { - if (dev->pwr_domain) - rpm_callback(dev->pwr_domain->ops.runtime_suspend, dev); no_callback: __update_runtime_status(dev, RPM_SUSPENDED); pm_runtime_deactivate_timer(dev); @@ -582,9 +574,8 @@ static int rpm_resume(struct device *dev, int rpmflags) __update_runtime_status(dev, RPM_RESUMING); if (dev->pwr_domain) - rpm_callback(dev->pwr_domain->ops.runtime_resume, dev); - - if (dev->type && dev->type->pm) + callback = dev->pwr_domain->ops.runtime_resume; + else if (dev->type && dev->type->pm) callback = dev->type->pm->runtime_resume; else if (dev->class && dev->class->pm) callback = dev->class->pm->runtime_resume; diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index fff49bee781d..a9f5b8979611 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -212,8 +212,9 @@ static ssize_t autosuspend_delay_ms_store(struct device *dev, static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show, autosuspend_delay_ms_store); -#endif +#endif /* CONFIG_PM_RUNTIME */ +#ifdef CONFIG_PM_SLEEP static ssize_t wake_show(struct device * dev, struct device_attribute *attr, char * buf) { @@ -248,7 +249,6 @@ wake_store(struct device * dev, struct device_attribute *attr, static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); -#ifdef CONFIG_PM_SLEEP static ssize_t wakeup_count_show(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 4573c83df6dd..84f7c7d5a098 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -110,7 +110,6 @@ void wakeup_source_add(struct wakeup_source *ws) spin_lock_irq(&events_lock); list_add_rcu(&ws->entry, &wakeup_sources); spin_unlock_irq(&events_lock); - synchronize_rcu(); } EXPORT_SYMBOL_GPL(wakeup_source_add); @@ -258,7 +257,7 @@ void device_set_wakeup_capable(struct device *dev, bool capable) if (!!dev->power.can_wakeup == !!capable) return; - if (device_is_registered(dev)) { + if (device_is_registered(dev) && !list_empty(&dev->power.entry)) { if (capable) { if (wakeup_sysfs_add(dev)) return; diff --git a/drivers/base/sys.c b/drivers/base/sys.c index acde9b5ee131..9dff77bfe1e3 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -328,203 +328,8 @@ void sysdev_unregister(struct sys_device *sysdev) kobject_put(&sysdev->kobj); } - -#ifndef CONFIG_ARCH_NO_SYSDEV_OPS -/** - * sysdev_shutdown - Shut down all system devices. - * - * Loop over each class of system devices, and the devices in each - * of those classes. For each device, we call the shutdown method for - * each driver registered for the device - the auxiliaries, - * and the class driver. - * - * Note: The list is iterated in reverse order, so that we shut down - * child devices before we shut down their parents. The list ordering - * is guaranteed by virtue of the fact that child devices are registered - * after their parents. - */ -void sysdev_shutdown(void) -{ - struct sysdev_class *cls; - - pr_debug("Shutting Down System Devices\n"); - - mutex_lock(&sysdev_drivers_lock); - list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { - struct sys_device *sysdev; - - pr_debug("Shutting down type '%s':\n", - kobject_name(&cls->kset.kobj)); - - list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { - struct sysdev_driver *drv; - pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - - /* Call auxiliary drivers first */ - list_for_each_entry(drv, &cls->drivers, entry) { - if (drv->shutdown) - drv->shutdown(sysdev); - } - - /* Now call the generic one */ - if (cls->shutdown) - cls->shutdown(sysdev); - } - } - mutex_unlock(&sysdev_drivers_lock); -} - -static void __sysdev_resume(struct sys_device *dev) -{ - struct sysdev_class *cls = dev->cls; - struct sysdev_driver *drv; - - /* First, call the class-specific one */ - if (cls->resume) - cls->resume(dev); - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled after %pF\n", cls->resume); - - /* Call auxiliary drivers next. */ - list_for_each_entry(drv, &cls->drivers, entry) { - if (drv->resume) - drv->resume(dev); - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled after %pF\n", drv->resume); - } -} - -/** - * sysdev_suspend - Suspend all system devices. - * @state: Power state to enter. - * - * We perform an almost identical operation as sysdev_shutdown() - * above, though calling ->suspend() instead. Interrupts are disabled - * when this called. Devices are responsible for both saving state and - * quiescing or powering down the device. - * - * This is only called by the device PM core, so we let them handle - * all synchronization. - */ -int sysdev_suspend(pm_message_t state) -{ - struct sysdev_class *cls; - struct sys_device *sysdev, *err_dev; - struct sysdev_driver *drv, *err_drv; - int ret; - - pr_debug("Checking wake-up interrupts\n"); - - /* Return error code if there are any wake-up interrupts pending */ - ret = check_wakeup_irqs(); - if (ret) - return ret; - - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled while suspending system devices\n"); - - pr_debug("Suspending System Devices\n"); - - list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { - pr_debug("Suspending type '%s':\n", - kobject_name(&cls->kset.kobj)); - - list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { - pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - - /* Call auxiliary drivers first */ - list_for_each_entry(drv, &cls->drivers, entry) { - if (drv->suspend) { - ret = drv->suspend(sysdev, state); - if (ret) - goto aux_driver; - } - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled after %pF\n", - drv->suspend); - } - - /* Now call the generic one */ - if (cls->suspend) { - ret = cls->suspend(sysdev, state); - if (ret) - goto cls_driver; - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled after %pF\n", - cls->suspend); - } - } - } - return 0; - /* resume current sysdev */ -cls_driver: - drv = NULL; - printk(KERN_ERR "Class suspend failed for %s: %d\n", - kobject_name(&sysdev->kobj), ret); - -aux_driver: - if (drv) - printk(KERN_ERR "Class driver suspend failed for %s: %d\n", - kobject_name(&sysdev->kobj), ret); - list_for_each_entry(err_drv, &cls->drivers, entry) { - if (err_drv == drv) - break; - if (err_drv->resume) - err_drv->resume(sysdev); - } - - /* resume other sysdevs in current class */ - list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { - if (err_dev == sysdev) - break; - pr_debug(" %s\n", kobject_name(&err_dev->kobj)); - __sysdev_resume(err_dev); - } - - /* resume other classes */ - list_for_each_entry_continue(cls, &system_kset->list, kset.kobj.entry) { - list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { - pr_debug(" %s\n", kobject_name(&err_dev->kobj)); - __sysdev_resume(err_dev); - } - } - return ret; -} -EXPORT_SYMBOL_GPL(sysdev_suspend); - -/** - * sysdev_resume - Bring system devices back to life. - * - * Similar to sysdev_suspend(), but we iterate the list forwards - * to guarantee that parent devices are resumed before their children. - * - * Note: Interrupts are disabled when called. - */ -int sysdev_resume(void) -{ - struct sysdev_class *cls; - - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled while resuming system devices\n"); - - pr_debug("Resuming System Devices\n"); - - list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) { - struct sys_device *sysdev; - - pr_debug("Resuming type '%s':\n", - kobject_name(&cls->kset.kobj)); - - list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { - pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - - __sysdev_resume(sysdev); - } - } - return 0; -} -EXPORT_SYMBOL_GPL(sysdev_resume); -#endif /* CONFIG_ARCH_NO_SYSDEV_OPS */ +EXPORT_SYMBOL_GPL(sysdev_register); +EXPORT_SYMBOL_GPL(sysdev_unregister); int __init system_bus_init(void) { @@ -534,9 +339,6 @@ int __init system_bus_init(void) return 0; } -EXPORT_SYMBOL_GPL(sysdev_register); -EXPORT_SYMBOL_GPL(sysdev_unregister); - #define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr) ssize_t sysdev_store_ulong(struct sys_device *sysdev, diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c index 90af2943f9e4..c126db3cb7d1 100644 --- a/drivers/base/syscore.c +++ b/drivers/base/syscore.c @@ -73,6 +73,7 @@ int syscore_suspend(void) return ret; } +EXPORT_SYMBOL_GPL(syscore_suspend); /** * syscore_resume - Execute all the registered system core resume callbacks. @@ -95,6 +96,7 @@ void syscore_resume(void) "Interrupts enabled after %pF\n", ops->resume); } } +EXPORT_SYMBOL_GPL(syscore_resume); #endif /* CONFIG_PM_SLEEP */ /** diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig new file mode 100644 index 000000000000..353781b5b78b --- /dev/null +++ b/drivers/bcma/Kconfig @@ -0,0 +1,33 @@ +config BCMA_POSSIBLE + bool + depends on HAS_IOMEM && HAS_DMA + default y + +menu "Broadcom specific AMBA" + depends on BCMA_POSSIBLE + +config BCMA + tristate "BCMA support" + depends on BCMA_POSSIBLE + help + Bus driver for Broadcom specific Advanced Microcontroller Bus + Architecture. + +config BCMA_HOST_PCI_POSSIBLE + bool + depends on BCMA && PCI = y + default y + +config BCMA_HOST_PCI + bool "Support for BCMA on PCI-host bus" + depends on BCMA_HOST_PCI_POSSIBLE + +config BCMA_DEBUG + bool "BCMA debugging" + depends on BCMA + help + This turns on additional debugging messages. + + If unsure, say N + +endmenu diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile new file mode 100644 index 000000000000..0d56245bcb79 --- /dev/null +++ b/drivers/bcma/Makefile @@ -0,0 +1,7 @@ +bcma-y += main.o scan.o core.o +bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o +bcma-y += driver_pci.o +bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o +obj-$(CONFIG_BCMA) += bcma.o + +ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG diff --git a/drivers/bcma/README b/drivers/bcma/README new file mode 100644 index 000000000000..f7e7ce46c603 --- /dev/null +++ b/drivers/bcma/README @@ -0,0 +1,19 @@ +Broadcom introduced new bus as replacement for older SSB. It is based on AMBA, +however from programming point of view there is nothing AMBA specific we use. + +Standard AMBA drivers are platform specific, have hardcoded addresses and use +AMBA standard fields like CID and PID. + +In case of Broadcom's cards every device consists of: +1) Broadcom specific AMBA device. It is put on AMBA bus, but can not be treated + as standard AMBA device. Reading it's CID or PID can cause machine lockup. +2) AMBA standard devices called ports or wrappers. They have CIDs (AMBA_CID) + and PIDs (0x103BB369), but we do not use that info for anything. One of that + devices is used for managing Broadcom specific core. + +Addresses of AMBA devices are not hardcoded in driver and have to be read from +EPROM. + +In this situation we decided to introduce separated bus. It can contain up to +16 devices identified by Broadcom specific fields: manufacturer, id, revision +and class. diff --git a/drivers/bcma/TODO b/drivers/bcma/TODO new file mode 100644 index 000000000000..da7aa99fe81c --- /dev/null +++ b/drivers/bcma/TODO @@ -0,0 +1,3 @@ +- Interrupts +- Defines for PCI core driver +- Create kernel Documentation (use info from README) diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h new file mode 100644 index 000000000000..2f72e9c585fd --- /dev/null +++ b/drivers/bcma/bcma_private.h @@ -0,0 +1,28 @@ +#ifndef LINUX_BCMA_PRIVATE_H_ +#define LINUX_BCMA_PRIVATE_H_ + +#ifndef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#endif + +#include +#include + +#define BCMA_CORE_SIZE 0x1000 + +struct bcma_bus; + +/* main.c */ +extern int bcma_bus_register(struct bcma_bus *bus); +extern void bcma_bus_unregister(struct bcma_bus *bus); + +/* scan.c */ +int bcma_bus_scan(struct bcma_bus *bus); + +#ifdef CONFIG_BCMA_HOST_PCI +/* host_pci.c */ +extern int __init bcma_host_pci_init(void); +extern void __exit bcma_host_pci_exit(void); +#endif /* CONFIG_BCMA_HOST_PCI */ + +#endif diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c new file mode 100644 index 000000000000..ced379f7b371 --- /dev/null +++ b/drivers/bcma/core.c @@ -0,0 +1,51 @@ +/* + * Broadcom specific AMBA + * Core ops + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include + +bool bcma_core_is_enabled(struct bcma_device *core) +{ + if ((bcma_aread32(core, BCMA_IOCTL) & (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC)) + != BCMA_IOCTL_CLK) + return false; + if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET) + return false; + return true; +} +EXPORT_SYMBOL_GPL(bcma_core_is_enabled); + +static void bcma_core_disable(struct bcma_device *core, u32 flags) +{ + if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET) + return; + + bcma_awrite32(core, BCMA_IOCTL, flags); + bcma_aread32(core, BCMA_IOCTL); + udelay(10); + + bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET); + udelay(1); +} + +int bcma_core_enable(struct bcma_device *core, u32 flags) +{ + bcma_core_disable(core, flags); + + bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC | flags)); + bcma_aread32(core, BCMA_IOCTL); + + bcma_awrite32(core, BCMA_RESET_CTL, 0); + udelay(1); + + bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags)); + bcma_aread32(core, BCMA_IOCTL); + udelay(1); + + return 0; +} +EXPORT_SYMBOL_GPL(bcma_core_enable); diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c new file mode 100644 index 000000000000..606102256b44 --- /dev/null +++ b/drivers/bcma/driver_chipcommon.c @@ -0,0 +1,89 @@ +/* + * Broadcom specific AMBA + * ChipCommon core driver + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include + +static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset, + u32 mask, u32 value) +{ + value &= mask; + value |= bcma_cc_read32(cc, offset) & ~mask; + bcma_cc_write32(cc, offset, value); + + return value; +} + +void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) +{ + if (cc->core->id.rev >= 11) + cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); + cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); + if (cc->core->id.rev >= 35) + cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT); + + if (cc->core->id.rev >= 20) { + bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0); + bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0); + } + + if (cc->capabilities & BCMA_CC_CAP_PMU) + bcma_pmu_init(cc); + if (cc->capabilities & BCMA_CC_CAP_PCTL) + pr_err("Power control not implemented!\n"); +} + +/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ +void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) +{ + /* instant NMI */ + bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks); +} + +void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value) +{ + bcma_cc_write32_masked(cc, BCMA_CC_IRQMASK, mask, value); +} + +u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask) +{ + return bcma_cc_read32(cc, BCMA_CC_IRQSTAT) & mask; +} + +u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask) +{ + return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask; +} + +u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value) +{ + return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value); +} + +u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value) +{ + return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value); +} + +u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value) +{ + return bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value); +} +EXPORT_SYMBOL_GPL(bcma_chipco_gpio_control); + +u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value) +{ + return bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value); +} + +u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value) +{ + return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value); +} diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c new file mode 100644 index 000000000000..f44177a644c7 --- /dev/null +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -0,0 +1,134 @@ +/* + * Broadcom specific AMBA + * ChipCommon Power Management Unit driver + * + * Copyright 2009, Michael Buesch + * Copyright 2007, Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include + +static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, + u32 offset, u32 mask, u32 set) +{ + u32 value; + + bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); + bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset); + bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); + value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA); + value &= mask; + value |= set; + bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value); + bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA); +} + +static void bcma_pmu_pll_init(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + + switch (bus->chipinfo.id) { + case 0x4313: + case 0x4331: + case 43224: + case 43225: + break; + default: + pr_err("PLL init unknown for device 0x%04X\n", + bus->chipinfo.id); + } +} + +static void bcma_pmu_resources_init(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + u32 min_msk = 0, max_msk = 0; + + switch (bus->chipinfo.id) { + case 0x4313: + min_msk = 0x200D; + max_msk = 0xFFFF; + break; + case 43224: + break; + default: + pr_err("PMU resource config unknown for device 0x%04X\n", + bus->chipinfo.id); + } + + /* Set the resource masks. */ + if (min_msk) + bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk); + if (max_msk) + bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk); +} + +void bcma_pmu_swreg_init(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + + switch (bus->chipinfo.id) { + case 0x4313: + case 0x4331: + case 43224: + break; + default: + pr_err("PMU switch/regulators init unknown for device " + "0x%04X\n", bus->chipinfo.id); + } +} + +void bcma_pmu_workarounds(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + + switch (bus->chipinfo.id) { + case 0x4313: + bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7); + break; + case 0x4331: + pr_err("Enabling Ext PA lines not implemented\n"); + break; + case 43224: + if (bus->chipinfo.rev == 0) { + pr_err("Workarounds for 43224 rev 0 not fully " + "implemented\n"); + bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0); + } else { + bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0); + } + break; + default: + pr_err("Workarounds unknown for device 0x%04X\n", + bus->chipinfo.id); + } +} + +void bcma_pmu_init(struct bcma_drv_cc *cc) +{ + u32 pmucap; + + pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP); + cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION); + + pr_debug("Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev, + pmucap); + + if (cc->pmu.rev == 1) + bcma_cc_mask32(cc, BCMA_CC_PMU_CTL, + ~BCMA_CC_PMU_CTL_NOILPONW); + else + bcma_cc_set32(cc, BCMA_CC_PMU_CTL, + BCMA_CC_PMU_CTL_NOILPONW); + + if (cc->core->id.id == 0x4329 && cc->core->id.rev == 2) + pr_err("Fix for 4329b0 bad LPOM state not implemented!\n"); + + bcma_pmu_pll_init(cc); + bcma_pmu_resources_init(cc); + bcma_pmu_swreg_init(cc); + bcma_pmu_workarounds(cc); +} diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c new file mode 100644 index 000000000000..e757e4e3c7e2 --- /dev/null +++ b/drivers/bcma/driver_pci.c @@ -0,0 +1,163 @@ +/* + * Broadcom specific AMBA + * PCI Core + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include + +/************************************************** + * R/W ops. + **************************************************/ + +static u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address) +{ + pcicore_write32(pc, 0x130, address); + pcicore_read32(pc, 0x130); + return pcicore_read32(pc, 0x134); +} + +#if 0 +static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data) +{ + pcicore_write32(pc, 0x130, address); + pcicore_read32(pc, 0x130); + pcicore_write32(pc, 0x134, data); +} +#endif + +static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy) +{ + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; + u32 v; + int i; + + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 28); /* Write Transaction */ + v |= (1 << 17); /* Turnaround */ + v |= (0x1F << 18); + v |= (phy << 4); + pcicore_write32(pc, mdio_data, v); + + udelay(10); + for (i = 0; i < 200; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) + break; + msleep(1); + } +} + +static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address) +{ + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; + int max_retries = 10; + u16 ret = 0; + u32 v; + int i; + + v = 0x80; /* Enable Preamble Sequence */ + v |= 0x2; /* MDIO Clock Divisor */ + pcicore_write32(pc, mdio_control, v); + + if (pc->core->id.rev >= 10) { + max_retries = 200; + bcma_pcie_mdio_set_phy(pc, device); + } + + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 29); /* Read Transaction */ + v |= (1 << 17); /* Turnaround */ + if (pc->core->id.rev < 10) + v |= (u32)device << 22; + v |= (u32)address << 18; + pcicore_write32(pc, mdio_data, v); + /* Wait for the device to complete the transaction */ + udelay(10); + for (i = 0; i < max_retries; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) { + udelay(10); + ret = pcicore_read32(pc, mdio_data); + break; + } + msleep(1); + } + pcicore_write32(pc, mdio_control, 0); + return ret; +} + +static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device, + u8 address, u16 data) +{ + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; + int max_retries = 10; + u32 v; + int i; + + v = 0x80; /* Enable Preamble Sequence */ + v |= 0x2; /* MDIO Clock Divisor */ + pcicore_write32(pc, mdio_control, v); + + if (pc->core->id.rev >= 10) { + max_retries = 200; + bcma_pcie_mdio_set_phy(pc, device); + } + + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 28); /* Write Transaction */ + v |= (1 << 17); /* Turnaround */ + if (pc->core->id.rev < 10) + v |= (u32)device << 22; + v |= (u32)address << 18; + v |= data; + pcicore_write32(pc, mdio_data, v); + /* Wait for the device to complete the transaction */ + udelay(10); + for (i = 0; i < max_retries; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) + break; + msleep(1); + } + pcicore_write32(pc, mdio_control, 0); +} + +/************************************************** + * Workarounds. + **************************************************/ + +static u8 bcma_pcicore_polarity_workaround(struct bcma_drv_pci *pc) +{ + return (bcma_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80; +} + +static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc) +{ + const u8 serdes_pll_device = 0x1D; + const u8 serdes_rx_device = 0x1F; + u16 tmp; + + bcma_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */, + bcma_pcicore_polarity_workaround(pc)); + tmp = bcma_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */); + if (tmp & 0x4000) + bcma_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000); +} + +/************************************************** + * Init. + **************************************************/ + +void bcma_core_pci_init(struct bcma_drv_pci *pc) +{ + bcma_pcicore_serdes_workaround(pc); +} diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c new file mode 100644 index 000000000000..99dd36e8500b --- /dev/null +++ b/drivers/bcma/host_pci.c @@ -0,0 +1,196 @@ +/* + * Broadcom specific AMBA + * PCI Host + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include +#include + +static void bcma_host_pci_switch_core(struct bcma_device *core) +{ + pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN, + core->addr); + pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2, + core->wrap); + core->bus->mapped_core = core; + pr_debug("Switched to core: 0x%X\n", core->id.id); +} + +static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + return ioread8(core->bus->mmio + offset); +} + +static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + return ioread16(core->bus->mmio + offset); +} + +static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + return ioread32(core->bus->mmio + offset); +} + +static void bcma_host_pci_write8(struct bcma_device *core, u16 offset, + u8 value) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + iowrite8(value, core->bus->mmio + offset); +} + +static void bcma_host_pci_write16(struct bcma_device *core, u16 offset, + u16 value) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + iowrite16(value, core->bus->mmio + offset); +} + +static void bcma_host_pci_write32(struct bcma_device *core, u16 offset, + u32 value) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + iowrite32(value, core->bus->mmio + offset); +} + +static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + return ioread32(core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset); +} + +static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset, + u32 value) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset); +} + +const struct bcma_host_ops bcma_host_pci_ops = { + .read8 = bcma_host_pci_read8, + .read16 = bcma_host_pci_read16, + .read32 = bcma_host_pci_read32, + .write8 = bcma_host_pci_write8, + .write16 = bcma_host_pci_write16, + .write32 = bcma_host_pci_write32, + .aread32 = bcma_host_pci_aread32, + .awrite32 = bcma_host_pci_awrite32, +}; + +static int bcma_host_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct bcma_bus *bus; + int err = -ENOMEM; + const char *name; + u32 val; + + /* Alloc */ + bus = kzalloc(sizeof(*bus), GFP_KERNEL); + if (!bus) + goto out; + + /* Basic PCI configuration */ + err = pci_enable_device(dev); + if (err) + goto err_kfree_bus; + + name = dev_name(&dev->dev); + if (dev->driver && dev->driver->name) + name = dev->driver->name; + err = pci_request_regions(dev, name); + if (err) + goto err_pci_disable; + pci_set_master(dev); + + /* Disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_read_config_dword(dev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(dev, 0x40, val & 0xffff00ff); + + /* SSB needed additional powering up, do we have any AMBA PCI cards? */ + if (!pci_is_pcie(dev)) + pr_err("PCI card detected, report problems.\n"); + + /* Map MMIO */ + err = -ENOMEM; + bus->mmio = pci_iomap(dev, 0, ~0UL); + if (!bus->mmio) + goto err_pci_release_regions; + + /* Host specific */ + bus->host_pci = dev; + bus->hosttype = BCMA_HOSTTYPE_PCI; + bus->ops = &bcma_host_pci_ops; + + /* Register */ + err = bcma_bus_register(bus); + if (err) + goto err_pci_unmap_mmio; + + pci_set_drvdata(dev, bus); + +out: + return err; + +err_pci_unmap_mmio: + pci_iounmap(dev, bus->mmio); +err_pci_release_regions: + pci_release_regions(dev); +err_pci_disable: + pci_disable_device(dev); +err_kfree_bus: + kfree(bus); + return err; +} + +static void bcma_host_pci_remove(struct pci_dev *dev) +{ + struct bcma_bus *bus = pci_get_drvdata(dev); + + bcma_bus_unregister(bus); + pci_iounmap(dev, bus->mmio); + pci_release_regions(dev); + pci_disable_device(dev); + kfree(bus); + pci_set_drvdata(dev, NULL); +} + +static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = { + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl); + +static struct pci_driver bcma_pci_bridge_driver = { + .name = "bcma-pci-bridge", + .id_table = bcma_pci_bridge_tbl, + .probe = bcma_host_pci_probe, + .remove = bcma_host_pci_remove, +}; + +int __init bcma_host_pci_init(void) +{ + return pci_register_driver(&bcma_pci_bridge_driver); +} + +void __exit bcma_host_pci_exit(void) +{ + pci_unregister_driver(&bcma_pci_bridge_driver); +} diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c new file mode 100644 index 000000000000..be52344ed19d --- /dev/null +++ b/drivers/bcma/main.c @@ -0,0 +1,247 @@ +/* + * Broadcom specific AMBA + * Bus subsystem + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include + +MODULE_DESCRIPTION("Broadcom's specific AMBA driver"); +MODULE_LICENSE("GPL"); + +static int bcma_bus_match(struct device *dev, struct device_driver *drv); +static int bcma_device_probe(struct device *dev); +static int bcma_device_remove(struct device *dev); + +static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + return sprintf(buf, "0x%03X\n", core->id.manuf); +} +static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + return sprintf(buf, "0x%03X\n", core->id.id); +} +static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + return sprintf(buf, "0x%02X\n", core->id.rev); +} +static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + return sprintf(buf, "0x%X\n", core->id.class); +} +static struct device_attribute bcma_device_attrs[] = { + __ATTR_RO(manuf), + __ATTR_RO(id), + __ATTR_RO(rev), + __ATTR_RO(class), + __ATTR_NULL, +}; + +static struct bus_type bcma_bus_type = { + .name = "bcma", + .match = bcma_bus_match, + .probe = bcma_device_probe, + .remove = bcma_device_remove, + .dev_attrs = bcma_device_attrs, +}; + +static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid) +{ + struct bcma_device *core; + + list_for_each_entry(core, &bus->cores, list) { + if (core->id.id == coreid) + return core; + } + return NULL; +} + +static void bcma_release_core_dev(struct device *dev) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + kfree(core); +} + +static int bcma_register_cores(struct bcma_bus *bus) +{ + struct bcma_device *core; + int err, dev_id = 0; + + list_for_each_entry(core, &bus->cores, list) { + /* We support that cores ourself */ + switch (core->id.id) { + case BCMA_CORE_CHIPCOMMON: + case BCMA_CORE_PCI: + case BCMA_CORE_PCIE: + continue; + } + + core->dev.release = bcma_release_core_dev; + core->dev.bus = &bcma_bus_type; + dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id); + + switch (bus->hosttype) { + case BCMA_HOSTTYPE_PCI: + core->dev.parent = &bus->host_pci->dev; + break; + case BCMA_HOSTTYPE_NONE: + case BCMA_HOSTTYPE_SDIO: + break; + } + + err = device_register(&core->dev); + if (err) { + pr_err("Could not register dev for core 0x%03X\n", + core->id.id); + continue; + } + core->dev_registered = true; + dev_id++; + } + + return 0; +} + +static void bcma_unregister_cores(struct bcma_bus *bus) +{ + struct bcma_device *core; + + list_for_each_entry(core, &bus->cores, list) { + if (core->dev_registered) + device_unregister(&core->dev); + } +} + +int bcma_bus_register(struct bcma_bus *bus) +{ + int err; + struct bcma_device *core; + + /* Scan for devices (cores) */ + err = bcma_bus_scan(bus); + if (err) { + pr_err("Failed to scan: %d\n", err); + return -1; + } + + /* Init CC core */ + core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON); + if (core) { + bus->drv_cc.core = core; + bcma_core_chipcommon_init(&bus->drv_cc); + } + + /* Init PCIE core */ + core = bcma_find_core(bus, BCMA_CORE_PCIE); + if (core) { + bus->drv_pci.core = core; + bcma_core_pci_init(&bus->drv_pci); + } + + /* Register found cores */ + bcma_register_cores(bus); + + pr_info("Bus registered\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(bcma_bus_register); + +void bcma_bus_unregister(struct bcma_bus *bus) +{ + bcma_unregister_cores(bus); +} +EXPORT_SYMBOL_GPL(bcma_bus_unregister); + +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner) +{ + drv->drv.name = drv->name; + drv->drv.bus = &bcma_bus_type; + drv->drv.owner = owner; + + return driver_register(&drv->drv); +} +EXPORT_SYMBOL_GPL(__bcma_driver_register); + +void bcma_driver_unregister(struct bcma_driver *drv) +{ + driver_unregister(&drv->drv); +} +EXPORT_SYMBOL_GPL(bcma_driver_unregister); + +static int bcma_bus_match(struct device *dev, struct device_driver *drv) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv); + const struct bcma_device_id *cid = &core->id; + const struct bcma_device_id *did; + + for (did = adrv->id_table; did->manuf || did->id || did->rev; did++) { + if ((did->manuf == cid->manuf || did->manuf == BCMA_ANY_MANUF) && + (did->id == cid->id || did->id == BCMA_ANY_ID) && + (did->rev == cid->rev || did->rev == BCMA_ANY_REV) && + (did->class == cid->class || did->class == BCMA_ANY_CLASS)) + return 1; + } + return 0; +} + +static int bcma_device_probe(struct device *dev) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver, + drv); + int err = 0; + + if (adrv->probe) + err = adrv->probe(core); + + return err; +} + +static int bcma_device_remove(struct device *dev) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver, + drv); + + if (adrv->remove) + adrv->remove(core); + + return 0; +} + +static int __init bcma_modinit(void) +{ + int err; + + err = bus_register(&bcma_bus_type); + if (err) + return err; + +#ifdef CONFIG_BCMA_HOST_PCI + err = bcma_host_pci_init(); + if (err) { + pr_err("PCI host initialization failed\n"); + err = 0; + } +#endif + + return err; +} +fs_initcall(bcma_modinit); + +static void __exit bcma_modexit(void) +{ +#ifdef CONFIG_BCMA_HOST_PCI + bcma_host_pci_exit(); +#endif + bus_unregister(&bcma_bus_type); +} +module_exit(bcma_modexit) diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c new file mode 100644 index 000000000000..40d7dcce8933 --- /dev/null +++ b/drivers/bcma/scan.c @@ -0,0 +1,360 @@ +/* + * Broadcom specific AMBA + * Bus scanning + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "scan.h" +#include "bcma_private.h" + +#include +#include +#include +#include +#include +#include + +struct bcma_device_id_name { + u16 id; + const char *name; +}; +struct bcma_device_id_name bcma_device_names[] = { + { BCMA_CORE_OOB_ROUTER, "OOB Router" }, + { BCMA_CORE_INVALID, "Invalid" }, + { BCMA_CORE_CHIPCOMMON, "ChipCommon" }, + { BCMA_CORE_ILINE20, "ILine 20" }, + { BCMA_CORE_SRAM, "SRAM" }, + { BCMA_CORE_SDRAM, "SDRAM" }, + { BCMA_CORE_PCI, "PCI" }, + { BCMA_CORE_MIPS, "MIPS" }, + { BCMA_CORE_ETHERNET, "Fast Ethernet" }, + { BCMA_CORE_V90, "V90" }, + { BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" }, + { BCMA_CORE_ADSL, "ADSL" }, + { BCMA_CORE_ILINE100, "ILine 100" }, + { BCMA_CORE_IPSEC, "IPSEC" }, + { BCMA_CORE_UTOPIA, "UTOPIA" }, + { BCMA_CORE_PCMCIA, "PCMCIA" }, + { BCMA_CORE_INTERNAL_MEM, "Internal Memory" }, + { BCMA_CORE_MEMC_SDRAM, "MEMC SDRAM" }, + { BCMA_CORE_OFDM, "OFDM" }, + { BCMA_CORE_EXTIF, "EXTIF" }, + { BCMA_CORE_80211, "IEEE 802.11" }, + { BCMA_CORE_PHY_A, "PHY A" }, + { BCMA_CORE_PHY_B, "PHY B" }, + { BCMA_CORE_PHY_G, "PHY G" }, + { BCMA_CORE_MIPS_3302, "MIPS 3302" }, + { BCMA_CORE_USB11_HOST, "USB 1.1 Host" }, + { BCMA_CORE_USB11_DEV, "USB 1.1 Device" }, + { BCMA_CORE_USB20_HOST, "USB 2.0 Host" }, + { BCMA_CORE_USB20_DEV, "USB 2.0 Device" }, + { BCMA_CORE_SDIO_HOST, "SDIO Host" }, + { BCMA_CORE_ROBOSWITCH, "Roboswitch" }, + { BCMA_CORE_PARA_ATA, "PATA" }, + { BCMA_CORE_SATA_XORDMA, "SATA XOR-DMA" }, + { BCMA_CORE_ETHERNET_GBIT, "GBit Ethernet" }, + { BCMA_CORE_PCIE, "PCIe" }, + { BCMA_CORE_PHY_N, "PHY N" }, + { BCMA_CORE_SRAM_CTL, "SRAM Controller" }, + { BCMA_CORE_MINI_MACPHY, "Mini MACPHY" }, + { BCMA_CORE_ARM_1176, "ARM 1176" }, + { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" }, + { BCMA_CORE_PHY_LP, "PHY LP" }, + { BCMA_CORE_PMU, "PMU" }, + { BCMA_CORE_PHY_SSN, "PHY SSN" }, + { BCMA_CORE_SDIO_DEV, "SDIO Device" }, + { BCMA_CORE_ARM_CM3, "ARM CM3" }, + { BCMA_CORE_PHY_HT, "PHY HT" }, + { BCMA_CORE_MIPS_74K, "MIPS 74K" }, + { BCMA_CORE_MAC_GBIT, "GBit MAC" }, + { BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" }, + { BCMA_CORE_PCIE_RC, "PCIe Root Complex" }, + { BCMA_CORE_OCP_OCP_BRIDGE, "OCP to OCP Bridge" }, + { BCMA_CORE_SHARED_COMMON, "Common Shared" }, + { BCMA_CORE_OCP_AHB_BRIDGE, "OCP to AHB Bridge" }, + { BCMA_CORE_SPI_HOST, "SPI Host" }, + { BCMA_CORE_I2S, "I2S" }, + { BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" }, + { BCMA_CORE_SHIM, "SHIM" }, + { BCMA_CORE_DEFAULT, "Default" }, +}; +const char *bcma_device_name(struct bcma_device_id *id) +{ + int i; + + if (id->manuf == BCMA_MANUF_BCM) { + for (i = 0; i < ARRAY_SIZE(bcma_device_names); i++) { + if (bcma_device_names[i].id == id->id) + return bcma_device_names[i].name; + } + } + return "UNKNOWN"; +} + +static u32 bcma_scan_read32(struct bcma_bus *bus, u8 current_coreidx, + u16 offset) +{ + return readl(bus->mmio + offset); +} + +static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr) +{ + if (bus->hosttype == BCMA_HOSTTYPE_PCI) + pci_write_config_dword(bus->host_pci, BCMA_PCI_BAR0_WIN, + addr); +} + +static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 **eromptr) +{ + u32 ent = readl(*eromptr); + (*eromptr)++; + return ent; +} + +static void bcma_erom_push_ent(u32 **eromptr) +{ + (*eromptr)--; +} + +static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 **eromptr) +{ + u32 ent = bcma_erom_get_ent(bus, eromptr); + if (!(ent & SCAN_ER_VALID)) + return -ENOENT; + if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_CI) + return -ENOENT; + return ent; +} + +static bool bcma_erom_is_end(struct bcma_bus *bus, u32 **eromptr) +{ + u32 ent = bcma_erom_get_ent(bus, eromptr); + bcma_erom_push_ent(eromptr); + return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID)); +} + +static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 **eromptr) +{ + u32 ent = bcma_erom_get_ent(bus, eromptr); + bcma_erom_push_ent(eromptr); + return (((ent & SCAN_ER_VALID)) && + ((ent & SCAN_ER_TAGX) == SCAN_ER_TAG_ADDR) && + ((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE)); +} + +static void bcma_erom_skip_component(struct bcma_bus *bus, u32 **eromptr) +{ + u32 ent; + while (1) { + ent = bcma_erom_get_ent(bus, eromptr); + if ((ent & SCAN_ER_VALID) && + ((ent & SCAN_ER_TAG) == SCAN_ER_TAG_CI)) + break; + if (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID)) + break; + } + bcma_erom_push_ent(eromptr); +} + +static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 **eromptr) +{ + u32 ent = bcma_erom_get_ent(bus, eromptr); + if (!(ent & SCAN_ER_VALID)) + return -ENOENT; + if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_MP) + return -ENOENT; + return ent; +} + +static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr, + u32 type, u8 port) +{ + u32 addrl, addrh, sizel, sizeh = 0; + u32 size; + + u32 ent = bcma_erom_get_ent(bus, eromptr); + if ((!(ent & SCAN_ER_VALID)) || + ((ent & SCAN_ER_TAGX) != SCAN_ER_TAG_ADDR) || + ((ent & SCAN_ADDR_TYPE) != type) || + (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) { + bcma_erom_push_ent(eromptr); + return -EINVAL; + } + + addrl = ent & SCAN_ADDR_ADDR; + if (ent & SCAN_ADDR_AG32) + addrh = bcma_erom_get_ent(bus, eromptr); + else + addrh = 0; + + if ((ent & SCAN_ADDR_SZ) == SCAN_ADDR_SZ_SZD) { + size = bcma_erom_get_ent(bus, eromptr); + sizel = size & SCAN_SIZE_SZ; + if (size & SCAN_SIZE_SG32) + sizeh = bcma_erom_get_ent(bus, eromptr); + } else + sizel = SCAN_ADDR_SZ_BASE << + ((ent & SCAN_ADDR_SZ) >> SCAN_ADDR_SZ_SHIFT); + + return addrl; +} + +int bcma_bus_scan(struct bcma_bus *bus) +{ + u32 erombase; + u32 __iomem *eromptr, *eromend; + + s32 cia, cib; + u8 ports[2], wrappers[2]; + + s32 tmp; + u8 i, j; + + int err; + + INIT_LIST_HEAD(&bus->cores); + bus->nr_cores = 0; + + bcma_scan_switch_core(bus, BCMA_ADDR_BASE); + + tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID); + bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; + bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; + bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; + + erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); + eromptr = bus->mmio; + eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); + + bcma_scan_switch_core(bus, erombase); + + while (eromptr < eromend) { + struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL); + if (!core) + return -ENOMEM; + INIT_LIST_HEAD(&core->list); + core->bus = bus; + + /* get CIs */ + cia = bcma_erom_get_ci(bus, &eromptr); + if (cia < 0) { + bcma_erom_push_ent(&eromptr); + if (bcma_erom_is_end(bus, &eromptr)) + break; + err= -EILSEQ; + goto out; + } + cib = bcma_erom_get_ci(bus, &eromptr); + if (cib < 0) { + err= -EILSEQ; + goto out; + } + + /* parse CIs */ + core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT; + core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT; + core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT; + ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT; + ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT; + wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT; + wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT; + core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT; + + if (((core->id.manuf == BCMA_MANUF_ARM) && + (core->id.id == 0xFFF)) || + (ports[1] == 0)) { + bcma_erom_skip_component(bus, &eromptr); + continue; + } + + /* check if component is a core at all */ + if (wrappers[0] + wrappers[1] == 0) { + /* we could save addrl of the router + if (cid == BCMA_CORE_OOB_ROUTER) + */ + bcma_erom_skip_component(bus, &eromptr); + continue; + } + + if (bcma_erom_is_bridge(bus, &eromptr)) { + bcma_erom_skip_component(bus, &eromptr); + continue; + } + + /* get & parse master ports */ + for (i = 0; i < ports[0]; i++) { + u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr); + if (mst_port_d < 0) { + err= -EILSEQ; + goto out; + } + } + + /* get & parse slave ports */ + for (i = 0; i < ports[1]; i++) { + for (j = 0; ; j++) { + tmp = bcma_erom_get_addr_desc(bus, &eromptr, + SCAN_ADDR_TYPE_SLAVE, i); + if (tmp < 0) { + /* no more entries for port _i_ */ + /* pr_debug("erom: slave port %d " + * "has %d descriptors\n", i, j); */ + break; + } else { + if (i == 0 && j == 0) + core->addr = tmp; + } + } + } + + /* get & parse master wrappers */ + for (i = 0; i < wrappers[0]; i++) { + for (j = 0; ; j++) { + tmp = bcma_erom_get_addr_desc(bus, &eromptr, + SCAN_ADDR_TYPE_MWRAP, i); + if (tmp < 0) { + /* no more entries for port _i_ */ + /* pr_debug("erom: master wrapper %d " + * "has %d descriptors\n", i, j); */ + break; + } else { + if (i == 0 && j == 0) + core->wrap = tmp; + } + } + } + + /* get & parse slave wrappers */ + for (i = 0; i < wrappers[1]; i++) { + u8 hack = (ports[1] == 1) ? 0 : 1; + for (j = 0; ; j++) { + tmp = bcma_erom_get_addr_desc(bus, &eromptr, + SCAN_ADDR_TYPE_SWRAP, i + hack); + if (tmp < 0) { + /* no more entries for port _i_ */ + /* pr_debug("erom: master wrapper %d " + * has %d descriptors\n", i, j); */ + break; + } else { + if (wrappers[0] == 0 && !i && !j) + core->wrap = tmp; + } + } + } + + pr_info("Core %d found: %s " + "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", + bus->nr_cores, bcma_device_name(&core->id), + core->id.manuf, core->id.id, core->id.rev, + core->id.class); + + core->core_index = bus->nr_cores++; + list_add(&core->list, &bus->cores); + continue; +out: + return err; + } + + return 0; +} diff --git a/drivers/bcma/scan.h b/drivers/bcma/scan.h new file mode 100644 index 000000000000..113e6a66884c --- /dev/null +++ b/drivers/bcma/scan.h @@ -0,0 +1,56 @@ +#ifndef BCMA_SCAN_H_ +#define BCMA_SCAN_H_ + +#define BCMA_ADDR_BASE 0x18000000 +#define BCMA_WRAP_BASE 0x18100000 + +#define SCAN_ER_VALID 0x00000001 +#define SCAN_ER_TAGX 0x00000006 /* we have to ignore 0x8 bit when checking tag for SCAN_ER_TAG_ADDR */ +#define SCAN_ER_TAG 0x0000000E +#define SCAN_ER_TAG_CI 0x00000000 +#define SCAN_ER_TAG_MP 0x00000002 +#define SCAN_ER_TAG_ADDR 0x00000004 +#define SCAN_ER_TAG_END 0x0000000E +#define SCAN_ER_BAD 0xFFFFFFFF + +#define SCAN_CIA_CLASS 0x000000F0 +#define SCAN_CIA_CLASS_SHIFT 4 +#define SCAN_CIA_ID 0x000FFF00 +#define SCAN_CIA_ID_SHIFT 8 +#define SCAN_CIA_MANUF 0xFFF00000 +#define SCAN_CIA_MANUF_SHIFT 20 + +#define SCAN_CIB_NMP 0x000001F0 +#define SCAN_CIB_NMP_SHIFT 4 +#define SCAN_CIB_NSP 0x00003E00 +#define SCAN_CIB_NSP_SHIFT 9 +#define SCAN_CIB_NMW 0x0007C000 +#define SCAN_CIB_NMW_SHIFT 14 +#define SCAN_CIB_NSW 0x00F80000 +#define SCAN_CIB_NSW_SHIFT 17 +#define SCAN_CIB_REV 0xFF000000 +#define SCAN_CIB_REV_SHIFT 24 + +#define SCAN_ADDR_AG32 0x00000008 +#define SCAN_ADDR_SZ 0x00000030 +#define SCAN_ADDR_SZ_SHIFT 4 +#define SCAN_ADDR_SZ_4K 0x00000000 +#define SCAN_ADDR_SZ_8K 0x00000010 +#define SCAN_ADDR_SZ_16K 0x00000020 +#define SCAN_ADDR_SZ_SZD 0x00000030 +#define SCAN_ADDR_TYPE 0x000000C0 +#define SCAN_ADDR_TYPE_SLAVE 0x00000000 +#define SCAN_ADDR_TYPE_BRIDGE 0x00000040 +#define SCAN_ADDR_TYPE_SWRAP 0x00000080 +#define SCAN_ADDR_TYPE_MWRAP 0x000000C0 +#define SCAN_ADDR_PORT 0x00000F00 +#define SCAN_ADDR_PORT_SHIFT 8 +#define SCAN_ADDR_ADDR 0xFFFFF000 + +#define SCAN_ADDR_SZ_BASE 0x00001000 /* 4KB */ + +#define SCAN_SIZE_SZ_ALIGN 0x00000FFF +#define SCAN_SIZE_SZ 0xFFFFF000 +#define SCAN_SIZE_SG32 0x00000008 + +#endif /* BCMA_SCAN_H_ */ diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 8066d086578a..e086fbbbe853 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -2547,7 +2547,6 @@ static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) disk->major = MajorNumber; disk->first_minor = n << DAC960_MaxPartitionsBits; disk->fops = &DAC960_BlockDeviceOperations; - disk->events = DISK_EVENT_MEDIA_CHANGE; } /* Indicate the Block Device Registration completed successfully, diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 456c0cc90dcf..8eba86bba599 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1736,7 +1736,6 @@ static int __init fd_probe_drives(void) disk->major = FLOPPY_MAJOR; disk->first_minor = drive; disk->fops = &floppy_fops; - disk->events = DISK_EVENT_MEDIA_CHANGE; sprintf(disk->disk_name, "fd%d", drive); disk->private_data = &unit[drive]; set_capacity(disk, 880*2); diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index c871eae14120..ede16c64ff07 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1964,7 +1964,6 @@ static int __init atari_floppy_init (void) unit[i].disk->first_minor = i; sprintf(unit[i].disk->disk_name, "fd%d", i); unit[i].disk->fops = &floppy_fops; - unit[i].disk->events = DISK_EVENT_MEDIA_CHANGE; unit[i].disk->private_data = &unit[i]; unit[i].disk->queue = blk_init_queue(do_fd_request, &ataflop_lock); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 301d7a9a41a6..db8f88586c8d 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4205,7 +4205,6 @@ static int __init floppy_init(void) disks[dr]->major = FLOPPY_MAJOR; disks[dr]->first_minor = TOMINOR(dr); disks[dr]->fops = &floppy_fops; - disks[dr]->events = DISK_EVENT_MEDIA_CHANGE; sprintf(disks[dr]->disk_name, "fd%d", dr); init_timer(&motor_off_timer[dr]); diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 2f2ccf686251..8690e31d9932 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -320,7 +320,6 @@ static void pcd_init_units(void) disk->first_minor = unit; strcpy(disk->disk_name, cd->name); /* umm... */ disk->fops = &pcd_bdops; - disk->events = DISK_EVENT_MEDIA_CHANGE; } } diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 21dfdb776869..869e7676d46f 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -837,7 +837,6 @@ static void pd_probe_drive(struct pd_unit *disk) p->fops = &pd_fops; p->major = major; p->first_minor = (disk - pd) << PD_BITS; - p->events = DISK_EVENT_MEDIA_CHANGE; disk->gd = p; p->private_data = disk; p->queue = pd_queue; diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 7adeb1edbf43..f21b520ef419 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -294,7 +294,6 @@ static void __init pf_init_units(void) disk->first_minor = unit; strcpy(disk->disk_name, pf->name); disk->fops = &pf_fops; - disk->events = DISK_EVENT_MEDIA_CHANGE; if (!(*drives[unit])[D_PRT]) pf_drive_count++; } diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 16dc3645291c..9712fad82bc6 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -92,6 +92,8 @@ struct rbd_client { struct list_head node; }; +struct rbd_req_coll; + /* * a single io request */ @@ -100,6 +102,24 @@ struct rbd_request { struct bio *bio; /* cloned bio */ struct page **pages; /* list of used pages */ u64 len; + int coll_index; + struct rbd_req_coll *coll; +}; + +struct rbd_req_status { + int done; + int rc; + u64 bytes; +}; + +/* + * a collection of requests + */ +struct rbd_req_coll { + int total; + int num_done; + struct kref kref; + struct rbd_req_status status[0]; }; struct rbd_snap { @@ -416,6 +436,17 @@ static void rbd_put_client(struct rbd_device *rbd_dev) rbd_dev->client = NULL; } +/* + * Destroy requests collection + */ +static void rbd_coll_release(struct kref *kref) +{ + struct rbd_req_coll *coll = + container_of(kref, struct rbd_req_coll, kref); + + dout("rbd_coll_release %p\n", coll); + kfree(coll); +} /* * Create a new header structure, translate header format from the on-disk @@ -590,6 +621,14 @@ static u64 rbd_get_segment(struct rbd_image_header *header, return len; } +static int rbd_get_num_segments(struct rbd_image_header *header, + u64 ofs, u64 len) +{ + u64 start_seg = ofs >> header->obj_order; + u64 end_seg = (ofs + len - 1) >> header->obj_order; + return end_seg - start_seg + 1; +} + /* * bio helpers */ @@ -735,6 +774,50 @@ static void rbd_destroy_ops(struct ceph_osd_req_op *ops) kfree(ops); } +static void rbd_coll_end_req_index(struct request *rq, + struct rbd_req_coll *coll, + int index, + int ret, u64 len) +{ + struct request_queue *q; + int min, max, i; + + dout("rbd_coll_end_req_index %p index %d ret %d len %lld\n", + coll, index, ret, len); + + if (!rq) + return; + + if (!coll) { + blk_end_request(rq, ret, len); + return; + } + + q = rq->q; + + spin_lock_irq(q->queue_lock); + coll->status[index].done = 1; + coll->status[index].rc = ret; + coll->status[index].bytes = len; + max = min = coll->num_done; + while (max < coll->total && coll->status[max].done) + max++; + + for (i = min; istatus[i].rc, + coll->status[i].bytes); + coll->num_done++; + kref_put(&coll->kref, rbd_coll_release); + } + spin_unlock_irq(q->queue_lock); +} + +static void rbd_coll_end_req(struct rbd_request *req, + int ret, u64 len) +{ + rbd_coll_end_req_index(req->rq, req->coll, req->coll_index, ret, len); +} + /* * Send ceph osd request */ @@ -749,6 +832,8 @@ static int rbd_do_request(struct request *rq, int flags, struct ceph_osd_req_op *ops, int num_reply, + struct rbd_req_coll *coll, + int coll_index, void (*rbd_cb)(struct ceph_osd_request *req, struct ceph_msg *msg), struct ceph_osd_request **linger_req, @@ -763,12 +848,20 @@ static int rbd_do_request(struct request *rq, struct ceph_osd_request_head *reqhead; struct rbd_image_header *header = &dev->header; - ret = -ENOMEM; req_data = kzalloc(sizeof(*req_data), GFP_NOIO); - if (!req_data) - goto done; + if (!req_data) { + if (coll) + rbd_coll_end_req_index(rq, coll, coll_index, + -ENOMEM, len); + return -ENOMEM; + } - dout("rbd_do_request len=%lld ofs=%lld\n", len, ofs); + if (coll) { + req_data->coll = coll; + req_data->coll_index = coll_index; + } + + dout("rbd_do_request obj=%s ofs=%lld len=%lld\n", obj, len, ofs); down_read(&header->snap_rwsem); @@ -777,9 +870,9 @@ static int rbd_do_request(struct request *rq, ops, false, GFP_NOIO, pages, bio); - if (IS_ERR(req)) { + if (!req) { up_read(&header->snap_rwsem); - ret = PTR_ERR(req); + ret = -ENOMEM; goto done_pages; } @@ -828,7 +921,8 @@ static int rbd_do_request(struct request *rq, ret = ceph_osdc_wait_request(&dev->client->osdc, req); if (ver) *ver = le64_to_cpu(req->r_reassert_version.version); - dout("reassert_ver=%lld\n", le64_to_cpu(req->r_reassert_version.version)); + dout("reassert_ver=%lld\n", + le64_to_cpu(req->r_reassert_version.version)); ceph_osdc_put_request(req); } return ret; @@ -837,10 +931,8 @@ static int rbd_do_request(struct request *rq, bio_chain_put(req_data->bio); ceph_osdc_put_request(req); done_pages: + rbd_coll_end_req(req_data, ret, len); kfree(req_data); -done: - if (rq) - blk_end_request(rq, ret, len); return ret; } @@ -874,7 +966,7 @@ static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg) bytes = req_data->len; } - blk_end_request(req_data->rq, rc, bytes); + rbd_coll_end_req(req_data, rc, bytes); if (req_data->bio) bio_chain_put(req_data->bio); @@ -934,6 +1026,7 @@ static int rbd_req_sync_op(struct rbd_device *dev, flags, ops, 2, + NULL, 0, NULL, linger_req, ver); if (ret < 0) @@ -959,7 +1052,9 @@ static int rbd_do_op(struct request *rq, u64 snapid, int opcode, int flags, int num_reply, u64 ofs, u64 len, - struct bio *bio) + struct bio *bio, + struct rbd_req_coll *coll, + int coll_index) { char *seg_name; u64 seg_ofs; @@ -995,7 +1090,10 @@ static int rbd_do_op(struct request *rq, flags, ops, num_reply, + coll, coll_index, rbd_req_cb, 0, NULL); + + rbd_destroy_ops(ops); done: kfree(seg_name); return ret; @@ -1008,13 +1106,15 @@ static int rbd_req_write(struct request *rq, struct rbd_device *rbd_dev, struct ceph_snap_context *snapc, u64 ofs, u64 len, - struct bio *bio) + struct bio *bio, + struct rbd_req_coll *coll, + int coll_index) { return rbd_do_op(rq, rbd_dev, snapc, CEPH_NOSNAP, CEPH_OSD_OP_WRITE, CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, 2, - ofs, len, bio); + ofs, len, bio, coll, coll_index); } /* @@ -1024,14 +1124,16 @@ static int rbd_req_read(struct request *rq, struct rbd_device *rbd_dev, u64 snapid, u64 ofs, u64 len, - struct bio *bio) + struct bio *bio, + struct rbd_req_coll *coll, + int coll_index) { return rbd_do_op(rq, rbd_dev, NULL, (snapid ? snapid : CEPH_NOSNAP), CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ, 2, - ofs, len, bio); + ofs, len, bio, coll, coll_index); } /* @@ -1063,7 +1165,9 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev, { struct ceph_osd_req_op *ops; struct page **pages = NULL; - int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY_ACK, 0); + int ret; + + ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY_ACK, 0); if (ret < 0) return ret; @@ -1077,6 +1181,7 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev, CEPH_OSD_FLAG_READ, ops, 1, + NULL, 0, rbd_simple_req_cb, 0, NULL); rbd_destroy_ops(ops); @@ -1274,6 +1379,20 @@ static int rbd_req_sync_exec(struct rbd_device *dev, return ret; } +static struct rbd_req_coll *rbd_alloc_coll(int num_reqs) +{ + struct rbd_req_coll *coll = + kzalloc(sizeof(struct rbd_req_coll) + + sizeof(struct rbd_req_status) * num_reqs, + GFP_ATOMIC); + + if (!coll) + return NULL; + coll->total = num_reqs; + kref_init(&coll->kref); + return coll; +} + /* * block device queue callback */ @@ -1291,6 +1410,8 @@ static void rbd_rq_fn(struct request_queue *q) bool do_write; int size, op_size = 0; u64 ofs; + int num_segs, cur_seg = 0; + struct rbd_req_coll *coll; /* peek at request from block layer */ if (!rq) @@ -1321,6 +1442,14 @@ static void rbd_rq_fn(struct request_queue *q) do_write ? "write" : "read", size, blk_rq_pos(rq) * 512ULL); + num_segs = rbd_get_num_segments(&rbd_dev->header, ofs, size); + coll = rbd_alloc_coll(num_segs); + if (!coll) { + spin_lock_irq(q->queue_lock); + __blk_end_request_all(rq, -ENOMEM); + goto next; + } + do { /* a bio clone to be passed down to OSD req */ dout("rq->bio->bi_vcnt=%d\n", rq->bio->bi_vcnt); @@ -1328,35 +1457,41 @@ static void rbd_rq_fn(struct request_queue *q) rbd_dev->header.block_name, ofs, size, NULL, NULL); + kref_get(&coll->kref); bio = bio_chain_clone(&rq_bio, &next_bio, &bp, op_size, GFP_ATOMIC); if (!bio) { - spin_lock_irq(q->queue_lock); - __blk_end_request_all(rq, -ENOMEM); - goto next; + rbd_coll_end_req_index(rq, coll, cur_seg, + -ENOMEM, op_size); + goto next_seg; } + /* init OSD command: write or read */ if (do_write) rbd_req_write(rq, rbd_dev, rbd_dev->header.snapc, ofs, - op_size, bio); + op_size, bio, + coll, cur_seg); else rbd_req_read(rq, rbd_dev, cur_snap_id(rbd_dev), ofs, - op_size, bio); + op_size, bio, + coll, cur_seg); +next_seg: size -= op_size; ofs += op_size; + cur_seg++; rq_bio = next_bio; } while (size > 0); + kref_put(&coll->kref, rbd_coll_release); if (bp) bio_pair_release(bp); - spin_lock_irq(q->queue_lock); next: rq = blk_fetch_request(q); diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 24a482f2fbd6..fd5adcd55944 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -858,7 +858,6 @@ static int __devinit swim_floppy_init(struct swim_priv *swd) swd->unit[drive].disk->first_minor = drive; sprintf(swd->unit[drive].disk->disk_name, "fd%d", drive); swd->unit[drive].disk->fops = &floppy_fops; - swd->unit[drive].disk->events = DISK_EVENT_MEDIA_CHANGE; swd->unit[drive].disk->private_data = &swd->unit[drive]; swd->unit[drive].disk->queue = swd->queue; set_capacity(swd->unit[drive].disk, 2880); diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 4c10f56facbf..773bfa792777 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -1163,7 +1163,6 @@ static int __devinit swim3_attach(struct macio_dev *mdev, const struct of_device disk->major = FLOPPY_MAJOR; disk->first_minor = i; disk->fops = &floppy_fops; - disk->events = DISK_EVENT_MEDIA_CHANGE; disk->private_data = &floppy_states[i]; disk->queue = swim3_queue; disk->flags |= GENHD_FL_REMOVABLE; diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 68b9430c7cfe..0e376d46bdd1 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -2334,7 +2334,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum) disk->major = UB_MAJOR; disk->first_minor = lun->id * UB_PARTS_PER_LUN; disk->fops = &ub_bd_fops; - disk->events = DISK_EVENT_MEDIA_CHANGE; disk->private_data = lun; disk->driverfs_dev = &sc->intf->dev; diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 645ff765cd12..6c7fd7db6dff 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1005,7 +1005,6 @@ static int __devinit ace_setup(struct ace_device *ace) ace->gd->major = ace_major; ace->gd->first_minor = ace->id * ACE_NUM_MINORS; ace->gd->fops = &ace_fops; - ace->gd->events = DISK_EVENT_MEDIA_CHANGE; ace->gd->queue = ace->queue; ace->gd->private_data = ace; snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a'); diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 8e0de9a05867..11b41fd40c27 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -188,7 +188,7 @@ config BT_MRVL The core driver to support Marvell Bluetooth devices. This driver is required if you want to support - Marvell Bluetooth devices, such as 8688. + Marvell Bluetooth devices, such as 8688/8787. Say Y here to compile Marvell Bluetooth driver into the kernel or say M to compile it as module. @@ -201,7 +201,7 @@ config BT_MRVL_SDIO The driver for Marvell Bluetooth chipsets with SDIO interface. This driver is required if you want to use Marvell Bluetooth - devices with SDIO interface. Currently only SD8688 chipset is + devices with SDIO interface. Currently SD8688/SD8787 chipsets are supported. Say Y here to compile support for Marvell BT-over-SDIO driver diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 5577ed656e2f..6bacef368fab 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -62,6 +62,7 @@ static struct usb_device_id ath3k_table[] = { /* Atheros AR3011 with sflash firmware*/ { USB_DEVICE(0x0CF3, 0x3002) }, + { USB_DEVICE(0x13d3, 0x3304) }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03F0, 0x311D) }, @@ -138,9 +139,6 @@ static int ath3k_load_firmware(struct usb_device *udev, count -= size; } - kfree(send_buf); - return 0; - error: kfree(send_buf); return err; diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index dcc2a6ec23f0..7f521d4ac657 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -49,15 +49,59 @@ static u8 user_rmmod; static u8 sdio_ireg; +static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = { + .cfg = 0x03, + .host_int_mask = 0x04, + .host_intstatus = 0x05, + .card_status = 0x20, + .sq_read_base_addr_a0 = 0x10, + .sq_read_base_addr_a1 = 0x11, + .card_fw_status0 = 0x40, + .card_fw_status1 = 0x41, + .card_rx_len = 0x42, + .card_rx_unit = 0x43, + .io_port_0 = 0x00, + .io_port_1 = 0x01, + .io_port_2 = 0x02, +}; +static const struct btmrvl_sdio_card_reg btmrvl_reg_8787 = { + .cfg = 0x00, + .host_int_mask = 0x02, + .host_intstatus = 0x03, + .card_status = 0x30, + .sq_read_base_addr_a0 = 0x40, + .sq_read_base_addr_a1 = 0x41, + .card_revision = 0x5c, + .card_fw_status0 = 0x60, + .card_fw_status1 = 0x61, + .card_rx_len = 0x62, + .card_rx_unit = 0x63, + .io_port_0 = 0x78, + .io_port_1 = 0x79, + .io_port_2 = 0x7a, +}; + static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = { .helper = "sd8688_helper.bin", .firmware = "sd8688.bin", + .reg = &btmrvl_reg_8688, + .sd_blksz_fw_dl = 64, +}; + +static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { + .helper = NULL, + .firmware = "mrvl/sd8787_uapsta.bin", + .reg = &btmrvl_reg_8787, + .sd_blksz_fw_dl = 256, }; static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8688 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105), .driver_data = (unsigned long) &btmrvl_sdio_sd6888 }, + /* Marvell SD8787 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A), + .driver_data = (unsigned long) &btmrvl_sdio_sd8787 }, { } /* Terminating entry */ }; @@ -69,7 +113,7 @@ static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card) u8 reg; int ret; - reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret); + reg = sdio_readb(card->func, card->reg->card_rx_unit, &ret); if (!ret) card->rx_unit = reg; @@ -83,11 +127,11 @@ static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat) *dat = 0; - fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret); + fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret); if (ret) return -EIO; - fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret); + fws1 = sdio_readb(card->func, card->reg->card_fw_status1, &ret); if (ret) return -EIO; @@ -101,7 +145,7 @@ static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat) u8 reg; int ret; - reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret); + reg = sdio_readb(card->func, card->reg->card_rx_len, &ret); if (!ret) *dat = (u16) reg << card->rx_unit; @@ -113,7 +157,7 @@ static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card, { int ret; - sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret); + sdio_writeb(card->func, mask, card->reg->host_int_mask, &ret); if (ret) { BT_ERR("Unable to enable the host interrupt!"); ret = -EIO; @@ -128,13 +172,13 @@ static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card, u8 host_int_mask; int ret; - host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret); + host_int_mask = sdio_readb(card->func, card->reg->host_int_mask, &ret); if (ret) return -EIO; host_int_mask &= ~mask; - sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret); + sdio_writeb(card->func, host_int_mask, card->reg->host_int_mask, &ret); if (ret < 0) { BT_ERR("Unable to disable the host interrupt!"); return -EIO; @@ -150,7 +194,7 @@ static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits) int ret; for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) { - status = sdio_readb(card->func, CARD_STATUS_REG, &ret); + status = sdio_readb(card->func, card->reg->card_status, &ret); if (ret) goto failed; if ((status & bits) == bits) @@ -299,7 +343,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) u8 base0, base1; void *tmpfwbuf = NULL; u8 *fwbuf; - u16 len; + u16 len, blksz_dl = card->sd_blksz_fw_dl; int txlen = 0, tx_blocks = 0, count = 0; ret = request_firmware(&fw_firmware, card->firmware, @@ -345,7 +389,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) for (tries = 0; tries < MAX_POLL_TRIES; tries++) { base0 = sdio_readb(card->func, - SQ_READ_BASE_ADDRESS_A0_REG, &ret); + card->reg->sq_read_base_addr_a0, &ret); if (ret) { BT_ERR("BASE0 register read failed:" " base0 = 0x%04X(%d)." @@ -355,7 +399,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) goto done; } base1 = sdio_readb(card->func, - SQ_READ_BASE_ADDRESS_A1_REG, &ret); + card->reg->sq_read_base_addr_a1, &ret); if (ret) { BT_ERR("BASE1 register read failed:" " base1 = 0x%04X(%d)." @@ -403,20 +447,19 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) if (firmwarelen - offset < txlen) txlen = firmwarelen - offset; - tx_blocks = - (txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE; + tx_blocks = (txlen + blksz_dl - 1) / blksz_dl; memcpy(fwbuf, &firmware[offset], txlen); } ret = sdio_writesb(card->func, card->ioport, fwbuf, - tx_blocks * SDIO_BLOCK_SIZE); + tx_blocks * blksz_dl); if (ret < 0) { BT_ERR("FW download, writesb(%d) failed @%d", count, offset); - sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG, - &ret); + sdio_writeb(card->func, HOST_CMD53_FIN, + card->reg->cfg, &ret); if (ret) BT_ERR("writeb failed (CFG)"); } @@ -597,7 +640,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func) priv = card->priv; - ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret); + ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret); if (ret) { BT_ERR("sdio_readb: read int status register failed"); return; @@ -613,7 +656,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func) sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS), - HOST_INTSTATUS_REG, &ret); + card->reg->host_intstatus, &ret); if (ret) { BT_ERR("sdio_writeb: clear int status register failed"); return; @@ -664,7 +707,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) goto release_irq; } - reg = sdio_readb(func, IO_PORT_0_REG, &ret); + reg = sdio_readb(func, card->reg->io_port_0, &ret); if (ret < 0) { ret = -EIO; goto release_irq; @@ -672,7 +715,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) card->ioport = reg; - reg = sdio_readb(func, IO_PORT_1_REG, &ret); + reg = sdio_readb(func, card->reg->io_port_1, &ret); if (ret < 0) { ret = -EIO; goto release_irq; @@ -680,7 +723,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) card->ioport |= (reg << 8); - reg = sdio_readb(func, IO_PORT_2_REG, &ret); + reg = sdio_readb(func, card->reg->io_port_2, &ret); if (ret < 0) { ret = -EIO; goto release_irq; @@ -815,6 +858,8 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) { int ret = 0; + u8 fws0; + int pollnum = MAX_POLL_TRIES; if (!card || !card->func) { BT_ERR("card or function is NULL!"); @@ -827,20 +872,36 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) goto done; } - ret = btmrvl_sdio_download_helper(card); + /* Check if other function driver is downloading the firmware */ + fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret); if (ret) { - BT_ERR("Failed to download helper!"); + BT_ERR("Failed to read FW downloading status!"); ret = -EIO; goto done; } + if (fws0) { + BT_DBG("BT not the winner (%#x). Skip FW downloading", fws0); - if (btmrvl_sdio_download_fw_w_helper(card)) { - BT_ERR("Failed to download firmware!"); - ret = -EIO; - goto done; + /* Give other function more time to download the firmware */ + pollnum *= 10; + } else { + if (card->helper) { + ret = btmrvl_sdio_download_helper(card); + if (ret) { + BT_ERR("Failed to download helper!"); + ret = -EIO; + goto done; + } + } + + if (btmrvl_sdio_download_fw_w_helper(card)) { + BT_ERR("Failed to download firmware!"); + ret = -EIO; + goto done; + } } - if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) { + if (btmrvl_sdio_verify_fw_download(card, pollnum)) { BT_ERR("FW failed to be active in time!"); ret = -ETIMEDOUT; goto done; @@ -864,7 +925,7 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv) sdio_claim_host(card->func); - sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret); + sdio_writeb(card->func, HOST_POWER_UP, card->reg->cfg, &ret); sdio_release_host(card->func); @@ -893,8 +954,10 @@ static int btmrvl_sdio_probe(struct sdio_func *func, if (id->driver_data) { struct btmrvl_sdio_device *data = (void *) id->driver_data; - card->helper = data->helper; + card->helper = data->helper; card->firmware = data->firmware; + card->reg = data->reg; + card->sd_blksz_fw_dl = data->sd_blksz_fw_dl; } if (btmrvl_sdio_register_dev(card) < 0) { @@ -1011,3 +1074,4 @@ MODULE_VERSION(VERSION); MODULE_LICENSE("GPL v2"); MODULE_FIRMWARE("sd8688_helper.bin"); MODULE_FIRMWARE("sd8688.bin"); +MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index 27329f107e5a..43d35a609ca9 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -47,44 +47,46 @@ /* Max retry number of CMD53 write */ #define MAX_WRITE_IOMEM_RETRY 2 -/* Host Control Registers */ -#define IO_PORT_0_REG 0x00 -#define IO_PORT_1_REG 0x01 -#define IO_PORT_2_REG 0x02 +/* register bitmasks */ +#define HOST_POWER_UP BIT(1) +#define HOST_CMD53_FIN BIT(2) -#define CONFIG_REG 0x03 -#define HOST_POWER_UP BIT(1) -#define HOST_CMD53_FIN BIT(2) +#define HIM_DISABLE 0xff +#define HIM_ENABLE (BIT(0) | BIT(1)) -#define HOST_INT_MASK_REG 0x04 -#define HIM_DISABLE 0xff -#define HIM_ENABLE (BIT(0) | BIT(1)) +#define UP_LD_HOST_INT_STATUS BIT(0) +#define DN_LD_HOST_INT_STATUS BIT(1) -#define HOST_INTSTATUS_REG 0x05 -#define UP_LD_HOST_INT_STATUS BIT(0) -#define DN_LD_HOST_INT_STATUS BIT(1) +#define DN_LD_CARD_RDY BIT(0) +#define CARD_IO_READY BIT(3) -/* Card Control Registers */ -#define SQ_READ_BASE_ADDRESS_A0_REG 0x10 -#define SQ_READ_BASE_ADDRESS_A1_REG 0x11 +#define FIRMWARE_READY 0xfedc -#define CARD_STATUS_REG 0x20 -#define DN_LD_CARD_RDY BIT(0) -#define CARD_IO_READY BIT(3) - -#define CARD_FW_STATUS0_REG 0x40 -#define CARD_FW_STATUS1_REG 0x41 -#define FIRMWARE_READY 0xfedc - -#define CARD_RX_LEN_REG 0x42 -#define CARD_RX_UNIT_REG 0x43 +struct btmrvl_sdio_card_reg { + u8 cfg; + u8 host_int_mask; + u8 host_intstatus; + u8 card_status; + u8 sq_read_base_addr_a0; + u8 sq_read_base_addr_a1; + u8 card_revision; + u8 card_fw_status0; + u8 card_fw_status1; + u8 card_rx_len; + u8 card_rx_unit; + u8 io_port_0; + u8 io_port_1; + u8 io_port_2; +}; struct btmrvl_sdio_card { struct sdio_func *func; u32 ioport; const char *helper; const char *firmware; + const struct btmrvl_sdio_card_reg *reg; + u16 sd_blksz_fw_dl; u8 rx_unit; struct btmrvl_private *priv; }; @@ -92,6 +94,8 @@ struct btmrvl_sdio_card { struct btmrvl_sdio_device { const char *helper; const char *firmware; + const struct btmrvl_sdio_card_reg *reg; + u16 sd_blksz_fw_dl; }; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 762a5109c68a..c2de8951e3fb 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -104,6 +104,7 @@ static struct usb_device_id blacklist_table[] = { /* Atheros 3011 with sflash firmware */ { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index bd34406faaae..4093935ddf42 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -201,8 +201,13 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu) /* Recv data */ static int ath_recv(struct hci_uart *hu, void *data, int count) { - if (hci_recv_stream_fragment(hu->hdev, data, count) < 0) + int ret; + + ret = hci_recv_stream_fragment(hu->hdev, data, count); + if (ret < 0) { BT_ERR("Frame Reassembly Failed"); + return ret; + } return count; } diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 7b8ad93e2c36..2fcd8b387d69 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -151,8 +151,13 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len) /* Recv data */ static int h4_recv(struct hci_uart *hu, void *data, int count) { - if (hci_recv_stream_fragment(hu->hdev, data, count) < 0) + int ret; + + ret = hci_recv_stream_fragment(hu->hdev, data, count); + if (ret < 0) { BT_ERR("Frame Reassembly Failed"); + return ret; + } return count; } diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 48ad2a7ab080..320f71803a2b 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -359,6 +359,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) */ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) { + int ret; struct hci_uart *hu = (void *)tty->disc_data; if (!hu || tty != hu->tty) @@ -368,8 +369,9 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f return; spin_lock(&hu->rx_lock); - hu->proto->recv(hu, (void *) data, count); - hu->hdev->stat.byte_rx += count; + ret = hu->proto->recv(hu, (void *) data, count); + if (ret > 0) + hu->hdev->stat.byte_rx += count; spin_unlock(&hu->rx_lock); tty_unthrottle(tty); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 514dd8efaf73..75fb965b8f72 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -986,6 +986,9 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t cdinfo(CD_OPEN, "entering cdrom_open\n"); + /* open is event synchronization point, check events first */ + check_disk_change(bdev); + /* if this was a O_NONBLOCK open and we should honor the flags, * do a quick open without drive/disc integrity checks. */ cdi->use_count++; @@ -1012,9 +1015,6 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", cdi->name, cdi->use_count); - /* Do this on open. Don't wait for mount, because they might - not be mounting, but opening with O_NONBLOCK */ - check_disk_change(bdev); return 0; err_release: if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index b2b034fea34e..3ceaf006e7f0 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -803,7 +803,6 @@ static int __devinit probe_gdrom(struct platform_device *devptr) goto probe_fail_cdrom_register; } gd.disk->fops = &gdrom_bdops; - gd.disk->events = DISK_EVENT_MEDIA_CHANGE; /* latch on to the interrupt */ err = gdrom_set_interrupt_handlers(); if (err) diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 4e874c5fa605..e427fbe45999 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -626,7 +626,6 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) gendisk->queue = q; gendisk->fops = &viocd_fops; gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE; - gendisk->events = DISK_EVENT_MEDIA_CHANGE; set_capacity(gendisk, 0); gendisk->private_data = d; d->viocd_disk = gendisk; diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index ad59b4e0a9b5..49502bc5360a 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -523,7 +523,7 @@ config RAW_DRIVER with the O_DIRECT flag. config MAX_RAW_DEVS - int "Maximum number of RAW devices to support (1-8192)" + int "Maximum number of RAW devices to support (1-65536)" depends on RAW_DRIVER default "256" help diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 012cba0d6d96..b072648dc3f6 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -115,6 +115,9 @@ static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages) struct agp_memory *new; unsigned long alloc_size = num_agp_pages*sizeof(struct page *); + if (INT_MAX/sizeof(struct page *) < num_agp_pages) + return NULL; + new = kzalloc(sizeof(struct agp_memory), GFP_KERNEL); if (new == NULL) return NULL; @@ -234,11 +237,14 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge, int scratch_pages; struct agp_memory *new; size_t i; + int cur_memory; if (!bridge) return NULL; - if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp) + cur_memory = atomic_read(&bridge->current_memory_agp); + if ((cur_memory + page_count > bridge->max_memory_agp) || + (cur_memory + page_count < page_count)) return NULL; if (type >= AGP_USER_TYPES) { @@ -1089,8 +1095,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type) return -EINVAL; } - /* AK: could wrap */ - if ((pg_start + mem->page_count) > num_entries) + if (((pg_start + mem->page_count) > num_entries) || + ((pg_start + mem->page_count) < pg_start)) return -EINVAL; j = pg_start; @@ -1124,7 +1130,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) { size_t i; struct agp_bridge_data *bridge; - int mask_type; + int mask_type, num_entries; bridge = mem->bridge; if (!bridge) @@ -1136,6 +1142,11 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) if (type != mem->type) return -EINVAL; + num_entries = agp_num_entries(); + if (((pg_start + mem->page_count) > num_entries) || + ((pg_start + mem->page_count) < pg_start)) + return -EINVAL; + mask_type = bridge->driver->agp_type_to_mask_type(bridge, type); if (mask_type != 0) { /* The generic routines know nothing of memory types */ diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index a4a6c2f044b5..cf39bc08ce08 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -295,7 +295,7 @@ static int bsr_create_devs(struct device_node *bn) static int __init bsr_init(void) { struct device_node *np; - dev_t bsr_dev = MKDEV(bsr_major, 0); + dev_t bsr_dev; int ret = -ENODEV; int result; diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 7066e801b9d3..051474c65b78 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -84,8 +84,6 @@ static struct clocksource clocksource_hpet = { .rating = 250, .read = read_hpet, .mask = CLOCKSOURCE_MASK(64), - .mult = 0, /* to be calculated */ - .shift = 10, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static struct clocksource *hpet_clocksource; @@ -934,9 +932,7 @@ int hpet_alloc(struct hpet_data *hdp) if (!hpet_clocksource) { hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc; CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr); - clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq, - clocksource_hpet.shift); - clocksource_register(&clocksource_hpet); + clocksource_register_hz(&clocksource_hpet, hpetp->hp_tick_freq); hpetp->hp_clocksource = &clocksource_hpet; hpet_clocksource = &clocksource_hpet; } diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index beecd1cf9b99..a60043b3e409 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -49,7 +49,7 @@ config HW_RANDOM_INTEL config HW_RANDOM_AMD tristate "AMD HW Random Number Generator support" - depends on HW_RANDOM && X86 && PCI + depends on HW_RANDOM && (X86 || PPC_MAPLE) && PCI default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c index 0d8c5788b8e4..c6af038682f1 100644 --- a/drivers/char/hw_random/amd-rng.c +++ b/drivers/char/hw_random/amd-rng.c @@ -133,6 +133,12 @@ static int __init mod_init(void) pmbase &= 0x0000FF00; if (pmbase == 0) goto out; + if (!request_region(pmbase + 0xF0, 8, "AMD HWRNG")) { + dev_err(&pdev->dev, "AMD HWRNG region 0x%x already in use!\n", + pmbase + 0xF0); + err = -EBUSY; + goto out; + } amd_rng.priv = (unsigned long)pmbase; amd_pdev = pdev; @@ -141,6 +147,7 @@ static int __init mod_init(void) if (err) { printk(KERN_ERR PFX "RNG registering failed (%d)\n", err); + release_region(pmbase + 0xF0, 8); goto out; } out: @@ -149,6 +156,8 @@ static int __init mod_init(void) static void __exit mod_exit(void) { + u32 pmbase = (unsigned long)amd_rng.priv; + release_region(pmbase + 0xF0, 8); hwrng_unregister(&amd_rng); } diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index 43ac61978d8b..ac6739e085e3 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -619,15 +619,18 @@ static void __devinit n2rng_driver_version(void) pr_info("%s", version); } +static const struct of_device_id n2rng_match[]; static int __devinit n2rng_probe(struct platform_device *op) { + const struct of_device_id *match; int victoria_falls; int err = -ENOMEM; struct n2rng *np; - if (!op->dev.of_match) + match = of_match_device(n2rng_match, &op->dev); + if (!match) return -EINVAL; - victoria_falls = (op->dev.of_match->data != NULL); + victoria_falls = (match->data != NULL); n2rng_driver_version(); np = kzalloc(sizeof(*np), GFP_KERNEL); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index cc6c9b2546a3..64c6b8530615 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2554,9 +2554,11 @@ static struct pci_driver ipmi_pci_driver = { }; #endif /* CONFIG_PCI */ +static struct of_device_id ipmi_match[]; static int __devinit ipmi_probe(struct platform_device *dev) { #ifdef CONFIG_OF + const struct of_device_id *match; struct smi_info *info; struct resource resource; const __be32 *regsize, *regspacing, *regshift; @@ -2566,7 +2568,8 @@ static int __devinit ipmi_probe(struct platform_device *dev) dev_info(&dev->dev, "probing via device tree\n"); - if (!dev->dev.of_match) + match = of_match_device(ipmi_match, &dev->dev); + if (!match) return -EINVAL; ret = of_address_to_resource(np, 0, &resource); @@ -2601,7 +2604,7 @@ static int __devinit ipmi_probe(struct platform_device *dev) return -ENOMEM; } - info->si_type = (enum si_type) dev->dev.of_match->data; + info->si_type = (enum si_type) match->data; info->addr_source = SI_DEVICETREE; info->irq_setup = std_irq_setup; diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 436a99017998..8fc04b4f311f 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -806,29 +806,41 @@ static const struct file_operations oldmem_fops = { }; #endif -static ssize_t kmsg_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv, + unsigned long count, loff_t pos) { - char *tmp; - ssize_t ret; + char *line, *p; + int i; + ssize_t ret = -EFAULT; + size_t len = iov_length(iv, count); - tmp = kmalloc(count + 1, GFP_KERNEL); - if (tmp == NULL) + line = kmalloc(len + 1, GFP_KERNEL); + if (line == NULL) return -ENOMEM; - ret = -EFAULT; - if (!copy_from_user(tmp, buf, count)) { - tmp[count] = 0; - ret = printk("%s", tmp); - if (ret > count) - /* printk can add a prefix */ - ret = count; + + /* + * copy all vectors into a single string, to ensure we do + * not interleave our log line with other printk calls + */ + p = line; + for (i = 0; i < count; i++) { + if (copy_from_user(p, iv[i].iov_base, iv[i].iov_len)) + goto out; + p += iv[i].iov_len; } - kfree(tmp); + p[0] = '\0'; + + ret = printk("%s", line); + /* printk can add a prefix */ + if (ret > len) + ret = len; +out: + kfree(line); return ret; } static const struct file_operations kmsg_fops = { - .write = kmsg_write, + .aio_write = kmsg_writev, .llseek = noop_llseek, }; diff --git a/drivers/char/raw.c b/drivers/char/raw.c index b4b9d5a47885..b33e8ea314ed 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -30,10 +31,15 @@ struct raw_device_data { }; static struct class *raw_class; -static struct raw_device_data raw_devices[MAX_RAW_MINORS]; +static struct raw_device_data *raw_devices; static DEFINE_MUTEX(raw_mutex); static const struct file_operations raw_ctl_fops; /* forward declaration */ +static int max_raw_minors = MAX_RAW_MINORS; + +module_param(max_raw_minors, int, 0); +MODULE_PARM_DESC(max_raw_minors, "Maximum number of raw devices (1-65536)"); + /* * Open/close code for raw IO. * @@ -125,7 +131,7 @@ static int bind_set(int number, u64 major, u64 minor) struct raw_device_data *rawdev; int err = 0; - if (number <= 0 || number >= MAX_RAW_MINORS) + if (number <= 0 || number >= max_raw_minors) return -EINVAL; if (MAJOR(dev) != major || MINOR(dev) != minor) @@ -312,14 +318,27 @@ static int __init raw_init(void) dev_t dev = MKDEV(RAW_MAJOR, 0); int ret; - ret = register_chrdev_region(dev, MAX_RAW_MINORS, "raw"); + if (max_raw_minors < 1 || max_raw_minors > 65536) { + printk(KERN_WARNING "raw: invalid max_raw_minors (must be" + " between 1 and 65536), using %d\n", MAX_RAW_MINORS); + max_raw_minors = MAX_RAW_MINORS; + } + + raw_devices = vmalloc(sizeof(struct raw_device_data) * max_raw_minors); + if (!raw_devices) { + printk(KERN_ERR "Not enough memory for raw device structures\n"); + ret = -ENOMEM; + goto error; + } + memset(raw_devices, 0, sizeof(struct raw_device_data) * max_raw_minors); + + ret = register_chrdev_region(dev, max_raw_minors, "raw"); if (ret) goto error; cdev_init(&raw_cdev, &raw_fops); - ret = cdev_add(&raw_cdev, dev, MAX_RAW_MINORS); + ret = cdev_add(&raw_cdev, dev, max_raw_minors); if (ret) { - kobject_put(&raw_cdev.kobj); goto error_region; } @@ -336,8 +355,9 @@ static int __init raw_init(void) return 0; error_region: - unregister_chrdev_region(dev, MAX_RAW_MINORS); + unregister_chrdev_region(dev, max_raw_minors); error: + vfree(raw_devices); return ret; } @@ -346,7 +366,7 @@ static void __exit raw_exit(void) device_destroy(raw_class, MKDEV(RAW_MAJOR, 0)); class_destroy(raw_class); cdev_del(&raw_cdev); - unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS); + unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), max_raw_minors); } module_init(raw_init); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 84b164d1eb2b..838568a7dbf5 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1280,18 +1280,7 @@ static void unplug_port(struct port *port) spin_lock_irq(&pdrvdata_lock); list_del(&port->cons.list); spin_unlock_irq(&pdrvdata_lock); -#if 0 - /* - * hvc_remove() not called as removing one hvc port - * results in other hvc ports getting frozen. - * - * Once this is resolved in hvc, this functionality - * will be enabled. Till that is done, the -EPIPE - * return from get_chars() above will help - * hvc_console.c to clean up on ports we remove here. - */ hvc_remove(port->cons.hvc); -#endif } /* Remove unused data this port might have received. */ diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index d6412c16385f..39ccdeada791 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -715,13 +715,13 @@ static int __devexit hwicap_remove(struct device *dev) } #ifdef CONFIG_OF -static int __devinit hwicap_of_probe(struct platform_device *op) +static int __devinit hwicap_of_probe(struct platform_device *op, + const struct hwicap_driver_config *config) { struct resource res; const unsigned int *id; const char *family; int rc; - const struct hwicap_driver_config *config = op->dev.of_match->data; const struct config_registers *regs; @@ -751,20 +751,24 @@ static int __devinit hwicap_of_probe(struct platform_device *op) regs); } #else -static inline int hwicap_of_probe(struct platform_device *op) +static inline int hwicap_of_probe(struct platform_device *op, + const struct hwicap_driver_config *config) { return -EINVAL; } #endif /* CONFIG_OF */ +static const struct of_device_id __devinitconst hwicap_of_match[]; static int __devinit hwicap_drv_probe(struct platform_device *pdev) { + const struct of_device_id *match; struct resource *res; const struct config_registers *regs; const char *family; - if (pdev->dev.of_match) - return hwicap_of_probe(pdev); + match = of_match_device(hwicap_of_match, &pdev->dev); + if (match) + return hwicap_of_probe(pdev, match->data); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 0fc0a79852de..6db161f64ae0 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -32,10 +32,9 @@ static DEFINE_MUTEX(clocks_mutex); * Then we take the most specific entry - with the following * order of precedence: dev+con > dev only > con only. */ -static struct clk *clk_find(const char *dev_id, const char *con_id) +static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) { - struct clk_lookup *p; - struct clk *clk = NULL; + struct clk_lookup *p, *cl = NULL; int match, best = 0; list_for_each_entry(p, &clocks, node) { @@ -52,27 +51,27 @@ static struct clk *clk_find(const char *dev_id, const char *con_id) } if (match > best) { - clk = p->clk; + cl = p; if (match != 3) best = match; else break; } } - return clk; + return cl; } struct clk *clk_get_sys(const char *dev_id, const char *con_id) { - struct clk *clk; + struct clk_lookup *cl; mutex_lock(&clocks_mutex); - clk = clk_find(dev_id, con_id); - if (clk && !__clk_get(clk)) - clk = NULL; + cl = clk_find(dev_id, con_id); + if (cl && !__clk_get(cl->clk)) + cl = NULL; mutex_unlock(&clocks_mutex); - return clk ? clk : ERR_PTR(-ENOENT); + return cl ? cl->clk : ERR_PTR(-ENOENT); } EXPORT_SYMBOL(clk_get_sys); diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig new file mode 100644 index 000000000000..110aeeb52f9a --- /dev/null +++ b/drivers/clocksource/Kconfig @@ -0,0 +1,2 @@ +config CLKSRC_I8253 + bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index be61ece6330b..cfb6383b543a 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o +obj-$(CONFIG_CLKSRC_I8253) += i8253.o diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c index 64e528e8bfa6..72f811f73e9c 100644 --- a/drivers/clocksource/cyclone.c +++ b/drivers/clocksource/cyclone.c @@ -29,8 +29,6 @@ static struct clocksource clocksource_cyclone = { .rating = 250, .read = read_cyclone, .mask = CYCLONE_TIMER_MASK, - .mult = 10, - .shift = 0, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -108,12 +106,8 @@ static int __init init_cyclone_clocksource(void) } cyclone_ptr = cyclone_timer; - /* sort out mult/shift values: */ - clocksource_cyclone.shift = 22; - clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ, - clocksource_cyclone.shift); - - return clocksource_register(&clocksource_cyclone); + return clocksource_register_hz(&clocksource_cyclone, + CYCLONE_TIMER_FREQ); } arch_initcall(init_cyclone_clocksource); diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c new file mode 100644 index 000000000000..225c1761b372 --- /dev/null +++ b/drivers/clocksource/i8253.c @@ -0,0 +1,88 @@ +/* + * i8253 PIT clocksource + */ +#include +#include +#include +#include +#include + +#include + +/* + * Since the PIT overflows every tick, its not very useful + * to just read by itself. So use jiffies to emulate a free + * running counter: + */ +static cycle_t i8253_read(struct clocksource *cs) +{ + static int old_count; + static u32 old_jifs; + unsigned long flags; + int count; + u32 jifs; + + raw_spin_lock_irqsave(&i8253_lock, flags); + /* + * Although our caller may have the read side of xtime_lock, + * this is now a seqlock, and we are cheating in this routine + * by having side effects on state that we cannot undo if + * there is a collision on the seqlock and our caller has to + * retry. (Namely, old_jifs and old_count.) So we must treat + * jiffies as volatile despite the lock. We read jiffies + * before latching the timer count to guarantee that although + * the jiffies value might be older than the count (that is, + * the counter may underflow between the last point where + * jiffies was incremented and the point where we latch the + * count), it cannot be newer. + */ + jifs = jiffies; + outb_pit(0x00, PIT_MODE); /* latch the count ASAP */ + count = inb_pit(PIT_CH0); /* read the latched count */ + count |= inb_pit(PIT_CH0) << 8; + + /* VIA686a test code... reset the latch if count > max + 1 */ + if (count > LATCH) { + outb_pit(0x34, PIT_MODE); + outb_pit(PIT_LATCH & 0xff, PIT_CH0); + outb_pit(PIT_LATCH >> 8, PIT_CH0); + count = PIT_LATCH - 1; + } + + /* + * It's possible for count to appear to go the wrong way for a + * couple of reasons: + * + * 1. The timer counter underflows, but we haven't handled the + * resulting interrupt and incremented jiffies yet. + * 2. Hardware problem with the timer, not giving us continuous time, + * the counter does small "jumps" upwards on some Pentium systems, + * (see c't 95/10 page 335 for Neptun bug.) + * + * Previous attempts to handle these cases intelligently were + * buggy, so we just do the simple thing now. + */ + if (count > old_count && jifs == old_jifs) + count = old_count; + + old_count = count; + old_jifs = jifs; + + raw_spin_unlock_irqrestore(&i8253_lock, flags); + + count = (PIT_LATCH - 1) - count; + + return (cycle_t)(jifs * PIT_LATCH) + count; +} + +static struct clocksource i8253_cs = { + .name = "pit", + .rating = 110, + .read = i8253_read, + .mask = CLOCKSOURCE_MASK(32), +}; + +int __init clocksource_i8253_init(void) +{ + return clocksource_register_hz(&i8253_cs, PIT_TICK_RATE); +} diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index d77005849af8..219d88a0eeae 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -142,6 +142,7 @@ static int cn_call_callback(struct sk_buff *skb) cbq->callback(msg, nsp); kfree_skb(skb); cn_queue_release_callback(cbq); + err = 0; } return err; diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index ca8ee8093d6c..9fb84853d8e3 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -1,3 +1,5 @@ +menu "CPU Frequency scaling" + config CPU_FREQ bool "CPU Frequency scaling" help @@ -18,19 +20,6 @@ if CPU_FREQ config CPU_FREQ_TABLE tristate -config CPU_FREQ_DEBUG - bool "Enable CPUfreq debugging" - help - Say Y here to enable CPUfreq subsystem (including drivers) - debugging. You will need to activate it via the kernel - command line by passing - cpufreq.debug= - - To get , add - 1 to activate CPUfreq core debugging, - 2 to activate CPUfreq drivers debugging, and - 4 to activate CPUfreq governor debugging - config CPU_FREQ_STAT tristate "CPU frequency translation statistics" select CPU_FREQ_TABLE @@ -190,4 +179,10 @@ config CPU_FREQ_GOV_CONSERVATIVE If in doubt, say N. -endif # CPU_FREQ +menu "x86 CPU frequency scaling drivers" +depends on X86 +source "drivers/cpufreq/Kconfig.x86" +endmenu + +endif +endmenu diff --git a/arch/x86/kernel/cpu/cpufreq/Kconfig b/drivers/cpufreq/Kconfig.x86 similarity index 97% rename from arch/x86/kernel/cpu/cpufreq/Kconfig rename to drivers/cpufreq/Kconfig.x86 index 870e6cc6ad28..78ff7ee48951 100644 --- a/arch/x86/kernel/cpu/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig.x86 @@ -1,15 +1,7 @@ # -# CPU Frequency scaling +# x86 CPU Frequency scaling drivers # -menu "CPU Frequency scaling" - -source "drivers/cpufreq/Kconfig" - -if CPU_FREQ - -comment "CPUFreq processor drivers" - config X86_PCC_CPUFREQ tristate "Processor Clocking Control interface driver" depends on ACPI && ACPI_PROCESSOR @@ -43,7 +35,7 @@ config X86_ACPI_CPUFREQ config ELAN_CPUFREQ tristate "AMD Elan SC400 and SC410" select CPU_FREQ_TABLE - depends on X86_ELAN + depends on MELAN ---help--- This adds the CPUFreq driver for AMD Elan SC400 and SC410 processors. @@ -59,7 +51,7 @@ config ELAN_CPUFREQ config SC520_CPUFREQ tristate "AMD Elan SC520" select CPU_FREQ_TABLE - depends on X86_ELAN + depends on MELAN ---help--- This adds the CPUFreq driver for AMD Elan SC520 processor. @@ -261,6 +253,3 @@ config X86_SPEEDSTEP_RELAXED_CAP_CHECK option lets the probing code bypass some of those checks if the parameter "relaxed_check=1" is passed to the module. -endif # CPU_FREQ - -endmenu diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 71fc3b4173f1..c7f1a6f16b6e 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -13,3 +13,29 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o +##################################################################################d +# x86 drivers. +# Link order matters. K8 is preferred to ACPI because of firmware bugs in early +# K8 systems. ACPI is preferred to all other hardware-specific drivers. +# speedstep-* is preferred over p4-clockmod. + +obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o mperf.o +obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o mperf.o +obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o +obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o +obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o +obj-$(CONFIG_X86_LONGHAUL) += longhaul.o +obj-$(CONFIG_X86_E_POWERSAVER) += e_powersaver.o +obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o +obj-$(CONFIG_SC520_CPUFREQ) += sc520_freq.o +obj-$(CONFIG_X86_LONGRUN) += longrun.o +obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o +obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o +obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o +obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o +obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o +obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o +obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o + +##################################################################################d + diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c similarity index 94% rename from arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c rename to drivers/cpufreq/acpi-cpufreq.c index a2baafb2fe6d..4e04e1274388 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -47,9 +47,6 @@ #include #include "mperf.h" -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "acpi-cpufreq", msg) - MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); MODULE_DESCRIPTION("ACPI Processor P-States Driver"); MODULE_LICENSE("GPL"); @@ -233,7 +230,7 @@ static u32 get_cur_val(const struct cpumask *mask) cmd.mask = mask; drv_read(&cmd); - dprintk("get_cur_val = %u\n", cmd.val); + pr_debug("get_cur_val = %u\n", cmd.val); return cmd.val; } @@ -244,7 +241,7 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu) unsigned int freq; unsigned int cached_freq; - dprintk("get_cur_freq_on_cpu (%d)\n", cpu); + pr_debug("get_cur_freq_on_cpu (%d)\n", cpu); if (unlikely(data == NULL || data->acpi_data == NULL || data->freq_table == NULL)) { @@ -261,7 +258,7 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu) data->resume = 1; } - dprintk("cur freq = %u\n", freq); + pr_debug("cur freq = %u\n", freq); return freq; } @@ -293,7 +290,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, unsigned int i; int result = 0; - dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); + pr_debug("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); if (unlikely(data == NULL || data->acpi_data == NULL || data->freq_table == NULL)) { @@ -313,11 +310,11 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, next_perf_state = data->freq_table[next_state].index; if (perf->state == next_perf_state) { if (unlikely(data->resume)) { - dprintk("Called after resume, resetting to P%d\n", + pr_debug("Called after resume, resetting to P%d\n", next_perf_state); data->resume = 0; } else { - dprintk("Already at target state (P%d)\n", + pr_debug("Already at target state (P%d)\n", next_perf_state); goto out; } @@ -357,7 +354,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, if (acpi_pstate_strict) { if (!check_freqs(cmd.mask, freqs.new, data)) { - dprintk("acpi_cpufreq_target failed (%d)\n", + pr_debug("acpi_cpufreq_target failed (%d)\n", policy->cpu); result = -EAGAIN; goto out; @@ -378,7 +375,7 @@ static int acpi_cpufreq_verify(struct cpufreq_policy *policy) { struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); - dprintk("acpi_cpufreq_verify\n"); + pr_debug("acpi_cpufreq_verify\n"); return cpufreq_frequency_table_verify(policy, data->freq_table); } @@ -433,11 +430,11 @@ static void free_acpi_perf_data(void) static int __init acpi_cpufreq_early_init(void) { unsigned int i; - dprintk("acpi_cpufreq_early_init\n"); + pr_debug("acpi_cpufreq_early_init\n"); acpi_perf_data = alloc_percpu(struct acpi_processor_performance); if (!acpi_perf_data) { - dprintk("Memory allocation error for acpi_perf_data.\n"); + pr_debug("Memory allocation error for acpi_perf_data.\n"); return -ENOMEM; } for_each_possible_cpu(i) { @@ -519,7 +516,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) static int blacklisted; #endif - dprintk("acpi_cpufreq_cpu_init\n"); + pr_debug("acpi_cpufreq_cpu_init\n"); #ifdef CONFIG_SMP if (blacklisted) @@ -566,7 +563,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) /* capability check */ if (perf->state_count <= 1) { - dprintk("No P-States\n"); + pr_debug("No P-States\n"); result = -ENODEV; goto err_unreg; } @@ -578,11 +575,11 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) switch (perf->control_register.space_id) { case ACPI_ADR_SPACE_SYSTEM_IO: - dprintk("SYSTEM IO addr space\n"); + pr_debug("SYSTEM IO addr space\n"); data->cpu_feature = SYSTEM_IO_CAPABLE; break; case ACPI_ADR_SPACE_FIXED_HARDWARE: - dprintk("HARDWARE addr space\n"); + pr_debug("HARDWARE addr space\n"); if (!check_est_cpu(cpu)) { result = -ENODEV; goto err_unreg; @@ -590,7 +587,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE; break; default: - dprintk("Unknown addr space %d\n", + pr_debug("Unknown addr space %d\n", (u32) (perf->control_register.space_id)); result = -ENODEV; goto err_unreg; @@ -661,9 +658,9 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) if (cpu_has(c, X86_FEATURE_APERFMPERF)) acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf; - dprintk("CPU%u - ACPI performance management activated.\n", cpu); + pr_debug("CPU%u - ACPI performance management activated.\n", cpu); for (i = 0; i < perf->state_count; i++) - dprintk(" %cP%d: %d MHz, %d mW, %d uS\n", + pr_debug(" %cP%d: %d MHz, %d mW, %d uS\n", (i == perf->state ? '*' : ' '), i, (u32) perf->states[i].core_frequency, (u32) perf->states[i].power, @@ -694,7 +691,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) { struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); - dprintk("acpi_cpufreq_cpu_exit\n"); + pr_debug("acpi_cpufreq_cpu_exit\n"); if (data) { cpufreq_frequency_table_put_attr(policy->cpu); @@ -712,7 +709,7 @@ static int acpi_cpufreq_resume(struct cpufreq_policy *policy) { struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); - dprintk("acpi_cpufreq_resume\n"); + pr_debug("acpi_cpufreq_resume\n"); data->resume = 1; @@ -743,7 +740,7 @@ static int __init acpi_cpufreq_init(void) if (acpi_disabled) return 0; - dprintk("acpi_cpufreq_init\n"); + pr_debug("acpi_cpufreq_init\n"); ret = acpi_cpufreq_early_init(); if (ret) @@ -758,7 +755,7 @@ static int __init acpi_cpufreq_init(void) static void __exit acpi_cpufreq_exit(void) { - dprintk("acpi_cpufreq_exit\n"); + pr_debug("acpi_cpufreq_exit\n"); cpufreq_unregister_driver(&acpi_cpufreq_driver); diff --git a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c similarity index 97% rename from arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c rename to drivers/cpufreq/cpufreq-nforce2.c index 141abebc4516..7bac808804f3 100644 --- a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c +++ b/drivers/cpufreq/cpufreq-nforce2.c @@ -57,8 +57,6 @@ MODULE_PARM_DESC(min_fsb, "Minimum FSB to use, if not defined: current FSB - 50"); #define PFX "cpufreq-nforce2: " -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "cpufreq-nforce2", msg) /** * nforce2_calc_fsb - calculate FSB @@ -270,7 +268,7 @@ static int nforce2_target(struct cpufreq_policy *policy, if (freqs.old == freqs.new) return 0; - dprintk("Old CPU frequency %d kHz, new %d kHz\n", + pr_debug("Old CPU frequency %d kHz, new %d kHz\n", freqs.old, freqs.new); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); @@ -282,7 +280,7 @@ static int nforce2_target(struct cpufreq_policy *policy, printk(KERN_ERR PFX "Changing FSB to %d failed\n", target_fsb); else - dprintk("Changed FSB successfully to %d\n", + pr_debug("Changed FSB successfully to %d\n", target_fsb); /* Enable IRQs */ diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2dafc5c38ae7..0a5bea9e3585 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -32,9 +32,6 @@ #include -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \ - "cpufreq-core", msg) - /** * The "cpufreq driver" - the arch- or hardware-dependent low * level driver of CPUFreq support, and its spinlock. This lock @@ -180,93 +177,6 @@ void cpufreq_cpu_put(struct cpufreq_policy *data) EXPORT_SYMBOL_GPL(cpufreq_cpu_put); -/********************************************************************* - * UNIFIED DEBUG HELPERS * - *********************************************************************/ -#ifdef CONFIG_CPU_FREQ_DEBUG - -/* what part(s) of the CPUfreq subsystem are debugged? */ -static unsigned int debug; - -/* is the debug output ratelimit'ed using printk_ratelimit? User can - * set or modify this value. - */ -static unsigned int debug_ratelimit = 1; - -/* is the printk_ratelimit'ing enabled? It's enabled after a successful - * loading of a cpufreq driver, temporarily disabled when a new policy - * is set, and disabled upon cpufreq driver removal - */ -static unsigned int disable_ratelimit = 1; -static DEFINE_SPINLOCK(disable_ratelimit_lock); - -static void cpufreq_debug_enable_ratelimit(void) -{ - unsigned long flags; - - spin_lock_irqsave(&disable_ratelimit_lock, flags); - if (disable_ratelimit) - disable_ratelimit--; - spin_unlock_irqrestore(&disable_ratelimit_lock, flags); -} - -static void cpufreq_debug_disable_ratelimit(void) -{ - unsigned long flags; - - spin_lock_irqsave(&disable_ratelimit_lock, flags); - disable_ratelimit++; - spin_unlock_irqrestore(&disable_ratelimit_lock, flags); -} - -void cpufreq_debug_printk(unsigned int type, const char *prefix, - const char *fmt, ...) -{ - char s[256]; - va_list args; - unsigned int len; - unsigned long flags; - - WARN_ON(!prefix); - if (type & debug) { - spin_lock_irqsave(&disable_ratelimit_lock, flags); - if (!disable_ratelimit && debug_ratelimit - && !printk_ratelimit()) { - spin_unlock_irqrestore(&disable_ratelimit_lock, flags); - return; - } - spin_unlock_irqrestore(&disable_ratelimit_lock, flags); - - len = snprintf(s, 256, KERN_DEBUG "%s: ", prefix); - - va_start(args, fmt); - len += vsnprintf(&s[len], (256 - len), fmt, args); - va_end(args); - - printk(s); - - WARN_ON(len < 5); - } -} -EXPORT_SYMBOL(cpufreq_debug_printk); - - -module_param(debug, uint, 0644); -MODULE_PARM_DESC(debug, "CPUfreq debugging: add 1 to debug core," - " 2 to debug drivers, and 4 to debug governors."); - -module_param(debug_ratelimit, uint, 0644); -MODULE_PARM_DESC(debug_ratelimit, "CPUfreq debugging:" - " set to 0 to disable ratelimiting."); - -#else /* !CONFIG_CPU_FREQ_DEBUG */ - -static inline void cpufreq_debug_enable_ratelimit(void) { return; } -static inline void cpufreq_debug_disable_ratelimit(void) { return; } - -#endif /* CONFIG_CPU_FREQ_DEBUG */ - - /********************************************************************* * EXTERNALLY AFFECTING FREQUENCY CHANGES * *********************************************************************/ @@ -291,7 +201,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) if (!l_p_j_ref_freq) { l_p_j_ref = loops_per_jiffy; l_p_j_ref_freq = ci->old; - dprintk("saving %lu as reference value for loops_per_jiffy; " + pr_debug("saving %lu as reference value for loops_per_jiffy; " "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq); } if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || @@ -299,7 +209,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); - dprintk("scaling loops_per_jiffy to %lu " + pr_debug("scaling loops_per_jiffy to %lu " "for frequency %u kHz\n", loops_per_jiffy, ci->new); } } @@ -326,7 +236,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) BUG_ON(irqs_disabled()); freqs->flags = cpufreq_driver->flags; - dprintk("notification %u of frequency transition to %u kHz\n", + pr_debug("notification %u of frequency transition to %u kHz\n", state, freqs->new); policy = per_cpu(cpufreq_cpu_data, freqs->cpu); @@ -340,7 +250,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { if ((policy) && (policy->cpu == freqs->cpu) && (policy->cur) && (policy->cur != freqs->old)) { - dprintk("Warning: CPU frequency is" + pr_debug("Warning: CPU frequency is" " %u, cpufreq assumed %u kHz.\n", freqs->old, policy->cur); freqs->old = policy->cur; @@ -353,7 +263,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) case CPUFREQ_POSTCHANGE: adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); - dprintk("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new, + pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new, (unsigned long)freqs->cpu); trace_power_frequency(POWER_PSTATE, freqs->new, freqs->cpu); trace_cpu_frequency(freqs->new, freqs->cpu); @@ -411,21 +321,14 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, t = __find_governor(str_governor); if (t == NULL) { - char *name = kasprintf(GFP_KERNEL, "cpufreq_%s", - str_governor); + int ret; - if (name) { - int ret; + mutex_unlock(&cpufreq_governor_mutex); + ret = request_module("cpufreq_%s", str_governor); + mutex_lock(&cpufreq_governor_mutex); - mutex_unlock(&cpufreq_governor_mutex); - ret = request_module("%s", name); - mutex_lock(&cpufreq_governor_mutex); - - if (ret == 0) - t = __find_governor(str_governor); - } - - kfree(name); + if (ret == 0) + t = __find_governor(str_governor); } if (t != NULL) { @@ -753,7 +656,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, static void cpufreq_sysfs_release(struct kobject *kobj) { struct cpufreq_policy *policy = to_policy(kobj); - dprintk("last reference is dropped\n"); + pr_debug("last reference is dropped\n"); complete(&policy->kobj_unregister); } @@ -788,7 +691,7 @@ static int cpufreq_add_dev_policy(unsigned int cpu, gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu)); if (gov) { policy->governor = gov; - dprintk("Restoring governor %s for cpu %d\n", + pr_debug("Restoring governor %s for cpu %d\n", policy->governor->name, cpu); } #endif @@ -824,7 +727,7 @@ static int cpufreq_add_dev_policy(unsigned int cpu, per_cpu(cpufreq_cpu_data, cpu) = managed_policy; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); - dprintk("CPU already managed, adding link\n"); + pr_debug("CPU already managed, adding link\n"); ret = sysfs_create_link(&sys_dev->kobj, &managed_policy->kobj, "cpufreq"); @@ -865,7 +768,7 @@ static int cpufreq_add_dev_symlink(unsigned int cpu, if (!cpu_online(j)) continue; - dprintk("CPU %u already managed, adding link\n", j); + pr_debug("CPU %u already managed, adding link\n", j); managed_policy = cpufreq_cpu_get(cpu); cpu_sys_dev = get_cpu_sysdev(j); ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj, @@ -941,7 +844,7 @@ static int cpufreq_add_dev_interface(unsigned int cpu, policy->user_policy.governor = policy->governor; if (ret) { - dprintk("setting policy failed\n"); + pr_debug("setting policy failed\n"); if (cpufreq_driver->exit) cpufreq_driver->exit(policy); } @@ -977,8 +880,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) if (cpu_is_offline(cpu)) return 0; - cpufreq_debug_disable_ratelimit(); - dprintk("adding CPU %u\n", cpu); + pr_debug("adding CPU %u\n", cpu); #ifdef CONFIG_SMP /* check whether a different CPU already registered this @@ -986,7 +888,6 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) policy = cpufreq_cpu_get(cpu); if (unlikely(policy)) { cpufreq_cpu_put(policy); - cpufreq_debug_enable_ratelimit(); return 0; } #endif @@ -1037,7 +938,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) */ ret = cpufreq_driver->init(policy); if (ret) { - dprintk("initialization failed\n"); + pr_debug("initialization failed\n"); goto err_unlock_policy; } policy->user_policy.min = policy->min; @@ -1063,8 +964,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) kobject_uevent(&policy->kobj, KOBJ_ADD); module_put(cpufreq_driver->owner); - dprintk("initialization complete\n"); - cpufreq_debug_enable_ratelimit(); + pr_debug("initialization complete\n"); return 0; @@ -1088,7 +988,6 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) nomem_out: module_put(cpufreq_driver->owner); module_out: - cpufreq_debug_enable_ratelimit(); return ret; } @@ -1112,15 +1011,13 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) unsigned int j; #endif - cpufreq_debug_disable_ratelimit(); - dprintk("unregistering CPU %u\n", cpu); + pr_debug("unregistering CPU %u\n", cpu); spin_lock_irqsave(&cpufreq_driver_lock, flags); data = per_cpu(cpufreq_cpu_data, cpu); if (!data) { spin_unlock_irqrestore(&cpufreq_driver_lock, flags); - cpufreq_debug_enable_ratelimit(); unlock_policy_rwsem_write(cpu); return -EINVAL; } @@ -1132,12 +1029,11 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) * only need to unlink, put and exit */ if (unlikely(cpu != data->cpu)) { - dprintk("removing link\n"); + pr_debug("removing link\n"); cpumask_clear_cpu(cpu, data->cpus); spin_unlock_irqrestore(&cpufreq_driver_lock, flags); kobj = &sys_dev->kobj; cpufreq_cpu_put(data); - cpufreq_debug_enable_ratelimit(); unlock_policy_rwsem_write(cpu); sysfs_remove_link(kobj, "cpufreq"); return 0; @@ -1170,7 +1066,7 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) for_each_cpu(j, data->cpus) { if (j == cpu) continue; - dprintk("removing link for cpu %u\n", j); + pr_debug("removing link for cpu %u\n", j); #ifdef CONFIG_HOTPLUG_CPU strncpy(per_cpu(cpufreq_cpu_governor, j), data->governor->name, CPUFREQ_NAME_LEN); @@ -1199,21 +1095,35 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) * not referenced anymore by anybody before we proceed with * unloading. */ - dprintk("waiting for dropping of refcount\n"); + pr_debug("waiting for dropping of refcount\n"); wait_for_completion(cmp); - dprintk("wait complete\n"); + pr_debug("wait complete\n"); lock_policy_rwsem_write(cpu); if (cpufreq_driver->exit) cpufreq_driver->exit(data); unlock_policy_rwsem_write(cpu); +#ifdef CONFIG_HOTPLUG_CPU + /* when the CPU which is the parent of the kobj is hotplugged + * offline, check for siblings, and create cpufreq sysfs interface + * and symlinks + */ + if (unlikely(cpumask_weight(data->cpus) > 1)) { + /* first sibling now owns the new sysfs dir */ + cpumask_clear_cpu(cpu, data->cpus); + cpufreq_add_dev(get_cpu_sysdev(cpumask_first(data->cpus))); + + /* finally remove our own symlink */ + lock_policy_rwsem_write(cpu); + __cpufreq_remove_dev(sys_dev); + } +#endif + free_cpumask_var(data->related_cpus); free_cpumask_var(data->cpus); kfree(data); - per_cpu(cpufreq_cpu_data, cpu) = NULL; - cpufreq_debug_enable_ratelimit(); return 0; } @@ -1239,7 +1149,7 @@ static void handle_update(struct work_struct *work) struct cpufreq_policy *policy = container_of(work, struct cpufreq_policy, update); unsigned int cpu = policy->cpu; - dprintk("handle_update for cpu %u called\n", cpu); + pr_debug("handle_update for cpu %u called\n", cpu); cpufreq_update_policy(cpu); } @@ -1257,7 +1167,7 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, { struct cpufreq_freqs freqs; - dprintk("Warning: CPU frequency out of sync: cpufreq and timing " + pr_debug("Warning: CPU frequency out of sync: cpufreq and timing " "core thinks of %u, is %u kHz.\n", old_freq, new_freq); freqs.cpu = cpu; @@ -1360,7 +1270,7 @@ static int cpufreq_bp_suspend(void) int cpu = smp_processor_id(); struct cpufreq_policy *cpu_policy; - dprintk("suspending cpu %u\n", cpu); + pr_debug("suspending cpu %u\n", cpu); /* If there's no policy for the boot CPU, we have nothing to do. */ cpu_policy = cpufreq_cpu_get(cpu); @@ -1398,7 +1308,7 @@ static void cpufreq_bp_resume(void) int cpu = smp_processor_id(); struct cpufreq_policy *cpu_policy; - dprintk("resuming cpu %u\n", cpu); + pr_debug("resuming cpu %u\n", cpu); /* If there's no policy for the boot CPU, we have nothing to do. */ cpu_policy = cpufreq_cpu_get(cpu); @@ -1510,7 +1420,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, { int retval = -EINVAL; - dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu, + pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu, target_freq, relation); if (cpu_online(policy->cpu) && cpufreq_driver->target) retval = cpufreq_driver->target(policy, target_freq, relation); @@ -1596,7 +1506,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, if (!try_module_get(policy->governor->owner)) return -EINVAL; - dprintk("__cpufreq_governor for CPU %u, event %u\n", + pr_debug("__cpufreq_governor for CPU %u, event %u\n", policy->cpu, event); ret = policy->governor->governor(policy, event); @@ -1697,8 +1607,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, { int ret = 0; - cpufreq_debug_disable_ratelimit(); - dprintk("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, + pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, policy->min, policy->max); memcpy(&policy->cpuinfo, &data->cpuinfo, @@ -1735,19 +1644,19 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, data->min = policy->min; data->max = policy->max; - dprintk("new min and max freqs are %u - %u kHz\n", + pr_debug("new min and max freqs are %u - %u kHz\n", data->min, data->max); if (cpufreq_driver->setpolicy) { data->policy = policy->policy; - dprintk("setting range\n"); + pr_debug("setting range\n"); ret = cpufreq_driver->setpolicy(policy); } else { if (policy->governor != data->governor) { /* save old, working values */ struct cpufreq_governor *old_gov = data->governor; - dprintk("governor switch\n"); + pr_debug("governor switch\n"); /* end old governor */ if (data->governor) @@ -1757,7 +1666,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, data->governor = policy->governor; if (__cpufreq_governor(data, CPUFREQ_GOV_START)) { /* new governor failed, so re-start old one */ - dprintk("starting governor %s failed\n", + pr_debug("starting governor %s failed\n", data->governor->name); if (old_gov) { data->governor = old_gov; @@ -1769,12 +1678,11 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, } /* might be a policy change, too, so fall through */ } - dprintk("governor: change or update limits\n"); + pr_debug("governor: change or update limits\n"); __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); } error_out: - cpufreq_debug_enable_ratelimit(); return ret; } @@ -1801,7 +1709,7 @@ int cpufreq_update_policy(unsigned int cpu) goto fail; } - dprintk("updating policy for CPU %u\n", cpu); + pr_debug("updating policy for CPU %u\n", cpu); memcpy(&policy, data, sizeof(struct cpufreq_policy)); policy.min = data->user_policy.min; policy.max = data->user_policy.max; @@ -1813,7 +1721,7 @@ int cpufreq_update_policy(unsigned int cpu) if (cpufreq_driver->get) { policy.cur = cpufreq_driver->get(cpu); if (!data->cur) { - dprintk("Driver did not initialize current freq"); + pr_debug("Driver did not initialize current freq"); data->cur = policy.cur; } else { if (data->cur != policy.cur) @@ -1889,7 +1797,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) ((!driver_data->setpolicy) && (!driver_data->target))) return -EINVAL; - dprintk("trying to register driver %s\n", driver_data->name); + pr_debug("trying to register driver %s\n", driver_data->name); if (driver_data->setpolicy) driver_data->flags |= CPUFREQ_CONST_LOOPS; @@ -1920,15 +1828,14 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) /* if all ->init() calls failed, unregister */ if (ret) { - dprintk("no CPU initialized for driver %s\n", + pr_debug("no CPU initialized for driver %s\n", driver_data->name); goto err_sysdev_unreg; } } register_hotcpu_notifier(&cpufreq_cpu_notifier); - dprintk("driver %s up and running\n", driver_data->name); - cpufreq_debug_enable_ratelimit(); + pr_debug("driver %s up and running\n", driver_data->name); return 0; err_sysdev_unreg: @@ -1955,14 +1862,10 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) { unsigned long flags; - cpufreq_debug_disable_ratelimit(); - - if (!cpufreq_driver || (driver != cpufreq_driver)) { - cpufreq_debug_enable_ratelimit(); + if (!cpufreq_driver || (driver != cpufreq_driver)) return -EINVAL; - } - dprintk("unregistering driver %s\n", driver->name); + pr_debug("unregistering driver %s\n", driver->name); sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver); unregister_hotcpu_notifier(&cpufreq_cpu_notifier); diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c index 7e2e515087f8..f13a8a9af6a1 100644 --- a/drivers/cpufreq/cpufreq_performance.c +++ b/drivers/cpufreq/cpufreq_performance.c @@ -15,9 +15,6 @@ #include #include -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "performance", msg) - static int cpufreq_governor_performance(struct cpufreq_policy *policy, unsigned int event) @@ -25,7 +22,7 @@ static int cpufreq_governor_performance(struct cpufreq_policy *policy, switch (event) { case CPUFREQ_GOV_START: case CPUFREQ_GOV_LIMITS: - dprintk("setting to %u kHz because of event %u\n", + pr_debug("setting to %u kHz because of event %u\n", policy->max, event); __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c index e6db5faf3eb1..4c2eb512f2bc 100644 --- a/drivers/cpufreq/cpufreq_powersave.c +++ b/drivers/cpufreq/cpufreq_powersave.c @@ -15,16 +15,13 @@ #include #include -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "powersave", msg) - static int cpufreq_governor_powersave(struct cpufreq_policy *policy, unsigned int event) { switch (event) { case CPUFREQ_GOV_START: case CPUFREQ_GOV_LIMITS: - dprintk("setting to %u kHz because of event %u\n", + pr_debug("setting to %u kHz because of event %u\n", policy->min, event); __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 00d73fc8e4e2..b60a4c263686 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -165,17 +165,27 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) return -1; } +/* should be called late in the CPU removal sequence so that the stats + * memory is still available in case someone tries to use it. + */ static void cpufreq_stats_free_table(unsigned int cpu) { struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); - struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); - if (policy && policy->cpu == cpu) - sysfs_remove_group(&policy->kobj, &stats_attr_group); if (stat) { kfree(stat->time_in_state); kfree(stat); } per_cpu(cpufreq_stats_table, cpu) = NULL; +} + +/* must be called early in the CPU removal sequence (before + * cpufreq_remove_dev) so that policy is still valid. + */ +static void cpufreq_stats_free_sysfs(unsigned int cpu) +{ + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + if (policy && policy->cpu == cpu) + sysfs_remove_group(&policy->kobj, &stats_attr_group); if (policy) cpufreq_cpu_put(policy); } @@ -316,6 +326,9 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, case CPU_ONLINE_FROZEN: cpufreq_update_policy(cpu); break; + case CPU_DOWN_PREPARE: + cpufreq_stats_free_sysfs(cpu); + break; case CPU_DEAD: case CPU_DEAD_FROZEN: cpufreq_stats_free_table(cpu); @@ -324,9 +337,10 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block cpufreq_stat_cpu_notifier __refdata = -{ +/* priority=1 so this will get called before cpufreq_remove_dev */ +static struct notifier_block cpufreq_stat_cpu_notifier __refdata = { .notifier_call = cpufreq_stat_cpu_callback, + .priority = 1, }; static struct notifier_block notifier_policy_block = { diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index 66d2d1d6c80f..f231015904c0 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -37,9 +37,6 @@ static DEFINE_PER_CPU(unsigned int, cpu_is_managed); static DEFINE_MUTEX(userspace_mutex); static int cpus_using_userspace_governor; -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "userspace", msg) - /* keep track of frequency transitions */ static int userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val, @@ -50,7 +47,7 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val, if (!per_cpu(cpu_is_managed, freq->cpu)) return 0; - dprintk("saving cpu_cur_freq of cpu %u to be %u kHz\n", + pr_debug("saving cpu_cur_freq of cpu %u to be %u kHz\n", freq->cpu, freq->new); per_cpu(cpu_cur_freq, freq->cpu) = freq->new; @@ -73,7 +70,7 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) { int ret = -EINVAL; - dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); + pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); mutex_lock(&userspace_mutex); if (!per_cpu(cpu_is_managed, policy->cpu)) @@ -134,7 +131,7 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy, per_cpu(cpu_max_freq, cpu) = policy->max; per_cpu(cpu_cur_freq, cpu) = policy->cur; per_cpu(cpu_set_freq, cpu) = policy->cur; - dprintk("managing cpu %u started " + pr_debug("managing cpu %u started " "(%u - %u kHz, currently %u kHz)\n", cpu, per_cpu(cpu_min_freq, cpu), @@ -156,12 +153,12 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy, per_cpu(cpu_min_freq, cpu) = 0; per_cpu(cpu_max_freq, cpu) = 0; per_cpu(cpu_set_freq, cpu) = 0; - dprintk("managing cpu %u stopped\n", cpu); + pr_debug("managing cpu %u stopped\n", cpu); mutex_unlock(&userspace_mutex); break; case CPUFREQ_GOV_LIMITS: mutex_lock(&userspace_mutex); - dprintk("limit event for cpu %u: %u - %u kHz, " + pr_debug("limit event for cpu %u: %u - %u kHz, " "currently %u kHz, last set to %u kHz\n", cpu, policy->min, policy->max, per_cpu(cpu_cur_freq, cpu), diff --git a/arch/x86/kernel/cpu/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c similarity index 100% rename from arch/x86/kernel/cpu/cpufreq/e_powersaver.c rename to drivers/cpufreq/e_powersaver.c diff --git a/arch/x86/kernel/cpu/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c similarity index 100% rename from arch/x86/kernel/cpu/cpufreq/elanfreq.c rename to drivers/cpufreq/elanfreq.c diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 05432216e224..90431cb92804 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -14,9 +14,6 @@ #include #include -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg) - /********************************************************************* * FREQUENCY TABLE HELPERS * *********************************************************************/ @@ -31,11 +28,11 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { unsigned int freq = table[i].frequency; if (freq == CPUFREQ_ENTRY_INVALID) { - dprintk("table entry %u is invalid, skipping\n", i); + pr_debug("table entry %u is invalid, skipping\n", i); continue; } - dprintk("table entry %u: %u kHz, %u index\n", + pr_debug("table entry %u: %u kHz, %u index\n", i, freq, table[i].index); if (freq < min_freq) min_freq = freq; @@ -61,7 +58,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, unsigned int i; unsigned int count = 0; - dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n", + pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu); if (!cpu_online(policy->cpu)) @@ -86,7 +83,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); - dprintk("verification lead to (%u - %u kHz) for cpu %u\n", + pr_debug("verification lead to (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu); return 0; @@ -110,7 +107,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, }; unsigned int i; - dprintk("request for target %u kHz (relation: %u) for cpu %u\n", + pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu); switch (relation) { @@ -167,7 +164,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, } else *index = optimal.index; - dprintk("target is %u (%u kHz, %u)\n", *index, table[*index].frequency, + pr_debug("target is %u (%u kHz, %u)\n", *index, table[*index].frequency, table[*index].index); return 0; @@ -216,14 +213,14 @@ EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, unsigned int cpu) { - dprintk("setting show_table for cpu %u to %p\n", cpu, table); + pr_debug("setting show_table for cpu %u to %p\n", cpu, table); per_cpu(cpufreq_show_table, cpu) = table; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr); void cpufreq_frequency_table_put_attr(unsigned int cpu) { - dprintk("clearing show_table for cpu %u\n", cpu); + pr_debug("clearing show_table for cpu %u\n", cpu); per_cpu(cpufreq_show_table, cpu) = NULL; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); diff --git a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c similarity index 95% rename from arch/x86/kernel/cpu/cpufreq/gx-suspmod.c rename to drivers/cpufreq/gx-suspmod.c index 32974cf84232..ffe1f2c92ed3 100644 --- a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c +++ b/drivers/cpufreq/gx-suspmod.c @@ -142,9 +142,6 @@ module_param(max_duration, int, 0444); #define POLICY_MIN_DIV 20 -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "gx-suspmod", msg) - /** * we can detect a core multipiler from dir0_lsb * from GX1 datasheet p.56, @@ -191,7 +188,7 @@ static __init struct pci_dev *gx_detect_chipset(void) /* check if CPU is a MediaGX or a Geode. */ if ((boot_cpu_data.x86_vendor != X86_VENDOR_NSC) && (boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) { - dprintk("error: no MediaGX/Geode processor found!\n"); + pr_debug("error: no MediaGX/Geode processor found!\n"); return NULL; } @@ -201,7 +198,7 @@ static __init struct pci_dev *gx_detect_chipset(void) return gx_pci; } - dprintk("error: no supported chipset found!\n"); + pr_debug("error: no supported chipset found!\n"); return NULL; } @@ -305,14 +302,14 @@ static void gx_set_cpuspeed(unsigned int khz) break; default: local_irq_restore(flags); - dprintk("fatal: try to set unknown chipset.\n"); + pr_debug("fatal: try to set unknown chipset.\n"); return; } } else { suscfg = gx_params->pci_suscfg & ~(SUSMOD); gx_params->off_duration = 0; gx_params->on_duration = 0; - dprintk("suspend modulation disabled: cpu runs 100%% speed.\n"); + pr_debug("suspend modulation disabled: cpu runs 100%% speed.\n"); } gx_write_byte(PCI_MODOFF, gx_params->off_duration); @@ -327,9 +324,9 @@ static void gx_set_cpuspeed(unsigned int khz) cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - dprintk("suspend modulation w/ duration of ON:%d us, OFF:%d us\n", + pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n", gx_params->on_duration * 32, gx_params->off_duration * 32); - dprintk("suspend modulation w/ clock speed: %d kHz.\n", freqs.new); + pr_debug("suspend modulation w/ clock speed: %d kHz.\n", freqs.new); } /**************************************************************** @@ -428,8 +425,8 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) stock_freq = maxfreq; curfreq = gx_get_cpuspeed(0); - dprintk("cpu max frequency is %d.\n", maxfreq); - dprintk("cpu current frequency is %dkHz.\n", curfreq); + pr_debug("cpu max frequency is %d.\n", maxfreq); + pr_debug("cpu current frequency is %dkHz.\n", curfreq); /* setup basic struct for cpufreq API */ policy->cpu = 0; @@ -475,7 +472,7 @@ static int __init cpufreq_gx_init(void) if (max_duration > 0xff) max_duration = 0xff; - dprintk("geode suspend modulation available.\n"); + pr_debug("geode suspend modulation available.\n"); params = kzalloc(sizeof(struct gxfreq_params), GFP_KERNEL); if (params == NULL) diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c similarity index 98% rename from arch/x86/kernel/cpu/cpufreq/longhaul.c rename to drivers/cpufreq/longhaul.c index cf48cdd6907d..f47d26e2a135 100644 --- a/arch/x86/kernel/cpu/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -77,9 +77,6 @@ static int scale_voltage; static int disable_acpi_c3; static int revid_errata; -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "longhaul", msg) - /* Clock ratios multiplied by 10 */ static int mults[32]; @@ -87,7 +84,6 @@ static int eblcr[32]; static int longhaul_version; static struct cpufreq_frequency_table *longhaul_table; -#ifdef CONFIG_CPU_FREQ_DEBUG static char speedbuffer[8]; static char *print_speed(int speed) @@ -106,7 +102,6 @@ static char *print_speed(int speed) return speedbuffer; } -#endif static unsigned int calc_speed(int mult) @@ -275,7 +270,7 @@ static void longhaul_setstate(unsigned int table_index) cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - dprintk("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", + pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", fsb, mult/10, mult%10, print_speed(speed/1000)); retry_loop: preempt_disable(); @@ -460,12 +455,12 @@ static int __cpuinit longhaul_get_ranges(void) break; } - dprintk("MinMult:%d.%dx MaxMult:%d.%dx\n", + pr_debug("MinMult:%d.%dx MaxMult:%d.%dx\n", minmult/10, minmult%10, maxmult/10, maxmult%10); highest_speed = calc_speed(maxmult); lowest_speed = calc_speed(minmult); - dprintk("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, + pr_debug("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, print_speed(lowest_speed/1000), print_speed(highest_speed/1000)); diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.h b/drivers/cpufreq/longhaul.h similarity index 100% rename from arch/x86/kernel/cpu/cpufreq/longhaul.h rename to drivers/cpufreq/longhaul.h diff --git a/arch/x86/kernel/cpu/cpufreq/longrun.c b/drivers/cpufreq/longrun.c similarity index 94% rename from arch/x86/kernel/cpu/cpufreq/longrun.c rename to drivers/cpufreq/longrun.c index d9f51367666b..34ea359b370e 100644 --- a/arch/x86/kernel/cpu/cpufreq/longrun.c +++ b/drivers/cpufreq/longrun.c @@ -15,9 +15,6 @@ #include #include -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "longrun", msg) - static struct cpufreq_driver longrun_driver; /** @@ -40,14 +37,14 @@ static void __cpuinit longrun_get_policy(struct cpufreq_policy *policy) u32 msr_lo, msr_hi; rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi); - dprintk("longrun flags are %x - %x\n", msr_lo, msr_hi); + pr_debug("longrun flags are %x - %x\n", msr_lo, msr_hi); if (msr_lo & 0x01) policy->policy = CPUFREQ_POLICY_PERFORMANCE; else policy->policy = CPUFREQ_POLICY_POWERSAVE; rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); - dprintk("longrun ctrl is %x - %x\n", msr_lo, msr_hi); + pr_debug("longrun ctrl is %x - %x\n", msr_lo, msr_hi); msr_lo &= 0x0000007F; msr_hi &= 0x0000007F; @@ -150,7 +147,7 @@ static unsigned int longrun_get(unsigned int cpu) return 0; cpuid(0x80860007, &eax, &ebx, &ecx, &edx); - dprintk("cpuid eax is %u\n", eax); + pr_debug("cpuid eax is %u\n", eax); return eax * 1000; } @@ -196,7 +193,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq, rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi); *high_freq = msr_lo * 1000; /* to kHz */ - dprintk("longrun table interface told %u - %u kHz\n", + pr_debug("longrun table interface told %u - %u kHz\n", *low_freq, *high_freq); if (*low_freq > *high_freq) @@ -207,7 +204,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq, /* set the upper border to the value determined during TSC init */ *high_freq = (cpu_khz / 1000); *high_freq = *high_freq * 1000; - dprintk("high frequency is %u kHz\n", *high_freq); + pr_debug("high frequency is %u kHz\n", *high_freq); /* get current borders */ rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); @@ -233,7 +230,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq, /* restore values */ wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi); } - dprintk("percentage is %u %%, freq is %u MHz\n", ecx, eax); + pr_debug("percentage is %u %%, freq is %u MHz\n", ecx, eax); /* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) * eqals @@ -249,7 +246,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq, edx = ((eax - ebx) * 100) / (100 - ecx); *low_freq = edx * 1000; /* back to kHz */ - dprintk("low frequency is %u kHz\n", *low_freq); + pr_debug("low frequency is %u kHz\n", *low_freq); if (*low_freq > *high_freq) *low_freq = *high_freq; diff --git a/arch/x86/kernel/cpu/cpufreq/mperf.c b/drivers/cpufreq/mperf.c similarity index 100% rename from arch/x86/kernel/cpu/cpufreq/mperf.c rename to drivers/cpufreq/mperf.c diff --git a/arch/x86/kernel/cpu/cpufreq/mperf.h b/drivers/cpufreq/mperf.h similarity index 100% rename from arch/x86/kernel/cpu/cpufreq/mperf.h rename to drivers/cpufreq/mperf.h diff --git a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c similarity index 96% rename from arch/x86/kernel/cpu/cpufreq/p4-clockmod.c rename to drivers/cpufreq/p4-clockmod.c index 52c93648e492..6be3e0760c26 100644 --- a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c +++ b/drivers/cpufreq/p4-clockmod.c @@ -35,8 +35,6 @@ #include "speedstep-lib.h" #define PFX "p4-clockmod: " -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "p4-clockmod", msg) /* * Duty Cycle (3bits), note DC_DISABLE is not specified in @@ -66,7 +64,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h); if (l & 0x01) - dprintk("CPU#%d currently thermal throttled\n", cpu); + pr_debug("CPU#%d currently thermal throttled\n", cpu); if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT)) @@ -74,10 +72,10 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); if (newstate == DC_DISABLE) { - dprintk("CPU#%d disabling modulation\n", cpu); + pr_debug("CPU#%d disabling modulation\n", cpu); wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); } else { - dprintk("CPU#%d setting duty cycle to %d%%\n", + pr_debug("CPU#%d setting duty cycle to %d%%\n", cpu, ((125 * newstate) / 10)); /* bits 63 - 5 : reserved * bit 4 : enable/disable @@ -217,7 +215,7 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) case 0x0f11: case 0x0f12: has_N44_O17_errata[policy->cpu] = 1; - dprintk("has errata -- disabling low frequencies\n"); + pr_debug("has errata -- disabling low frequencies\n"); } if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4D && diff --git a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c similarity index 91% rename from arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c rename to drivers/cpufreq/pcc-cpufreq.c index 755a31e0f5b0..7b0603eb0129 100644 --- a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -39,7 +39,7 @@ #include -#define PCC_VERSION "1.00.00" +#define PCC_VERSION "1.10.00" #define POLL_LOOPS 300 #define CMD_COMPLETE 0x1 @@ -48,9 +48,6 @@ #define BUF_SZ 4 -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "pcc-cpufreq", msg) - struct pcc_register_resource { u8 descriptor; u16 length; @@ -102,7 +99,7 @@ static struct acpi_generic_address doorbell; static u64 doorbell_preserve; static u64 doorbell_write; -static u8 OSC_UUID[16] = {0x63, 0x9B, 0x2C, 0x9F, 0x70, 0x91, 0x49, 0x1f, +static u8 OSC_UUID[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 0x70, 0x1f, 0x49, 0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46}; struct pcc_cpu { @@ -152,7 +149,7 @@ static unsigned int pcc_get_freq(unsigned int cpu) spin_lock(&pcc_lock); - dprintk("get: get_freq for CPU %d\n", cpu); + pr_debug("get: get_freq for CPU %d\n", cpu); pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); input_buffer = 0x1; @@ -170,7 +167,7 @@ static unsigned int pcc_get_freq(unsigned int cpu) status = ioread16(&pcch_hdr->status); if (status != CMD_COMPLETE) { - dprintk("get: FAILED: for CPU %d, status is %d\n", + pr_debug("get: FAILED: for CPU %d, status is %d\n", cpu, status); goto cmd_incomplete; } @@ -178,14 +175,14 @@ static unsigned int pcc_get_freq(unsigned int cpu) curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff)) / 100) * 1000); - dprintk("get: SUCCESS: (virtual) output_offset for cpu %d is " - "0x%x, contains a value of: 0x%x. Speed is: %d MHz\n", + pr_debug("get: SUCCESS: (virtual) output_offset for cpu %d is " + "0x%p, contains a value of: 0x%x. Speed is: %d MHz\n", cpu, (pcch_virt_addr + pcc_cpu_data->output_offset), output_buffer, curr_freq); freq_limit = (output_buffer >> 8) & 0xff; if (freq_limit != 0xff) { - dprintk("get: frequency for cpu %d is being temporarily" + pr_debug("get: frequency for cpu %d is being temporarily" " capped at %d\n", cpu, curr_freq); } @@ -212,8 +209,8 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, cpu = policy->cpu; pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); - dprintk("target: CPU %d should go to target freq: %d " - "(virtual) input_offset is 0x%x\n", + pr_debug("target: CPU %d should go to target freq: %d " + "(virtual) input_offset is 0x%p\n", cpu, target_freq, (pcch_virt_addr + pcc_cpu_data->input_offset)); @@ -234,14 +231,14 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, status = ioread16(&pcch_hdr->status); if (status != CMD_COMPLETE) { - dprintk("target: FAILED for cpu %d, with status: 0x%x\n", + pr_debug("target: FAILED for cpu %d, with status: 0x%x\n", cpu, status); goto cmd_incomplete; } iowrite16(0, &pcch_hdr->status); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - dprintk("target: was SUCCESSFUL for cpu %d\n", cpu); + pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu); spin_unlock(&pcc_lock); return 0; @@ -293,7 +290,7 @@ static int pcc_get_offset(int cpu) memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ); - dprintk("pcc_get_offset: for CPU %d: pcc_cpu_data " + pr_debug("pcc_get_offset: for CPU %d: pcc_cpu_data " "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n", cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset); out_free: @@ -410,7 +407,7 @@ static int __init pcc_cpufreq_probe(void) if (ACPI_SUCCESS(status)) { ret = pcc_cpufreq_do_osc(&osc_handle); if (ret) - dprintk("probe: _OSC evaluation did not succeed\n"); + pr_debug("probe: _OSC evaluation did not succeed\n"); /* Firmware's use of _OSC is optional */ ret = 0; } @@ -433,7 +430,7 @@ static int __init pcc_cpufreq_probe(void) mem_resource = (struct pcc_memory_resource *)member->buffer.pointer; - dprintk("probe: mem_resource descriptor: 0x%x," + pr_debug("probe: mem_resource descriptor: 0x%x," " length: %d, space_id: %d, resource_usage: %d," " type_specific: %d, granularity: 0x%llx," " minimum: 0x%llx, maximum: 0x%llx," @@ -453,13 +450,13 @@ static int __init pcc_cpufreq_probe(void) pcch_virt_addr = ioremap_nocache(mem_resource->minimum, mem_resource->address_length); if (pcch_virt_addr == NULL) { - dprintk("probe: could not map shared mem region\n"); + pr_debug("probe: could not map shared mem region\n"); goto out_free; } pcch_hdr = pcch_virt_addr; - dprintk("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr); - dprintk("probe: PCCH header is at physical address: 0x%llx," + pr_debug("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr); + pr_debug("probe: PCCH header is at physical address: 0x%llx," " signature: 0x%x, length: %d bytes, major: %d, minor: %d," " supported features: 0x%x, command field: 0x%x," " status field: 0x%x, nominal latency: %d us\n", @@ -469,7 +466,7 @@ static int __init pcc_cpufreq_probe(void) ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status), ioread32(&pcch_hdr->latency)); - dprintk("probe: min time between commands: %d us," + pr_debug("probe: min time between commands: %d us," " max time between commands: %d us," " nominal CPU frequency: %d MHz," " minimum CPU frequency: %d MHz," @@ -494,7 +491,7 @@ static int __init pcc_cpufreq_probe(void) doorbell.access_width = 64; doorbell.address = reg_resource->address; - dprintk("probe: doorbell: space_id is %d, bit_width is %d, " + pr_debug("probe: doorbell: space_id is %d, bit_width is %d, " "bit_offset is %d, access_width is %d, address is 0x%llx\n", doorbell.space_id, doorbell.bit_width, doorbell.bit_offset, doorbell.access_width, reg_resource->address); @@ -515,7 +512,7 @@ static int __init pcc_cpufreq_probe(void) doorbell_write = member->integer.value; - dprintk("probe: doorbell_preserve: 0x%llx," + pr_debug("probe: doorbell_preserve: 0x%llx," " doorbell_write: 0x%llx\n", doorbell_preserve, doorbell_write); @@ -550,7 +547,7 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) result = pcc_get_offset(cpu); if (result) { - dprintk("init: PCCP evaluation failed\n"); + pr_debug("init: PCCP evaluation failed\n"); goto out; } @@ -561,12 +558,12 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cur = pcc_get_freq(cpu); if (!policy->cur) { - dprintk("init: Unable to get current CPU frequency\n"); + pr_debug("init: Unable to get current CPU frequency\n"); result = -EINVAL; goto out; } - dprintk("init: policy->max is %d, policy->min is %d\n", + pr_debug("init: policy->max is %d, policy->min is %d\n", policy->max, policy->min); out: return result; @@ -597,7 +594,7 @@ static int __init pcc_cpufreq_init(void) ret = pcc_cpufreq_probe(); if (ret) { - dprintk("pcc_cpufreq_init: PCCH evaluation failed\n"); + pr_debug("pcc_cpufreq_init: PCCH evaluation failed\n"); return ret; } diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c similarity index 100% rename from arch/x86/kernel/cpu/cpufreq/powernow-k6.c rename to drivers/cpufreq/powernow-k6.c diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c similarity index 95% rename from arch/x86/kernel/cpu/cpufreq/powernow-k7.c rename to drivers/cpufreq/powernow-k7.c index 4a45fd6e41ba..d71d9f372359 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c +++ b/drivers/cpufreq/powernow-k7.c @@ -68,7 +68,6 @@ union powernow_acpi_control_t { }; #endif -#ifdef CONFIG_CPU_FREQ_DEBUG /* divide by 1000 to get VCore voltage in V. */ static const int mobile_vid_table[32] = { 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, @@ -76,7 +75,6 @@ static const int mobile_vid_table[32] = { 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 1075, 1050, 1025, 1000, 975, 950, 925, 0, }; -#endif /* divide by 10 to get FID. */ static const int fid_codes[32] = { @@ -103,9 +101,6 @@ static unsigned int fsb; static unsigned int latency; static char have_a0; -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "powernow-k7", msg) - static int check_fsb(unsigned int fsbspeed) { int delta; @@ -209,7 +204,7 @@ static int get_ranges(unsigned char *pst) vid = *pst++; powernow_table[j].index |= (vid << 8); /* upper 8 bits */ - dprintk(" FID: 0x%x (%d.%dx [%dMHz]) " + pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) " "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000, vid, mobile_vid_table[vid]/1000, @@ -367,7 +362,7 @@ static int powernow_acpi_init(void) unsigned int speed, speed_mhz; pc.val = (unsigned long) state->control; - dprintk("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n", + pr_debug("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n", i, (u32) state->core_frequency, (u32) state->power, @@ -401,7 +396,7 @@ static int powernow_acpi_init(void) invalidate_entry(i); } - dprintk(" FID: 0x%x (%d.%dx [%dMHz]) " + pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) " "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10, fid_codes[fid] % 10, speed_mhz, vid, mobile_vid_table[vid]/1000, @@ -409,7 +404,7 @@ static int powernow_acpi_init(void) if (state->core_frequency != speed_mhz) { state->core_frequency = speed_mhz; - dprintk(" Corrected ACPI frequency to %d\n", + pr_debug(" Corrected ACPI frequency to %d\n", speed_mhz); } @@ -453,8 +448,8 @@ static int powernow_acpi_init(void) static void print_pst_entry(struct pst_s *pst, unsigned int j) { - dprintk("PST:%d (@%p)\n", j, pst); - dprintk(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n", + pr_debug("PST:%d (@%p)\n", j, pst); + pr_debug(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n", pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid); } @@ -474,20 +469,20 @@ static int powernow_decode_bios(int maxfid, int startvid) p = phys_to_virt(i); if (memcmp(p, "AMDK7PNOW!", 10) == 0) { - dprintk("Found PSB header at %p\n", p); + pr_debug("Found PSB header at %p\n", p); psb = (struct psb_s *) p; - dprintk("Table version: 0x%x\n", psb->tableversion); + pr_debug("Table version: 0x%x\n", psb->tableversion); if (psb->tableversion != 0x12) { printk(KERN_INFO PFX "Sorry, only v1.2 tables" " supported right now\n"); return -ENODEV; } - dprintk("Flags: 0x%x\n", psb->flags); + pr_debug("Flags: 0x%x\n", psb->flags); if ((psb->flags & 1) == 0) - dprintk("Mobile voltage regulator\n"); + pr_debug("Mobile voltage regulator\n"); else - dprintk("Desktop voltage regulator\n"); + pr_debug("Desktop voltage regulator\n"); latency = psb->settlingtime; if (latency < 100) { @@ -497,9 +492,9 @@ static int powernow_decode_bios(int maxfid, int startvid) "Correcting.\n", latency); latency = 100; } - dprintk("Settling Time: %d microseconds.\n", + pr_debug("Settling Time: %d microseconds.\n", psb->settlingtime); - dprintk("Has %d PST tables. (Only dumping ones " + pr_debug("Has %d PST tables. (Only dumping ones " "relevant to this CPU).\n", psb->numpst); @@ -650,7 +645,7 @@ static int __cpuinit powernow_cpu_init(struct cpufreq_policy *policy) printk(KERN_WARNING PFX "can not determine bus frequency\n"); return -EINVAL; } - dprintk("FSB: %3dMHz\n", fsb/1000); + pr_debug("FSB: %3dMHz\n", fsb/1000); if (dmi_check_system(powernow_dmi_table) || acpi_force) { printk(KERN_INFO PFX "PSB/PST known to be broken. " diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.h b/drivers/cpufreq/powernow-k7.h similarity index 100% rename from arch/x86/kernel/cpu/cpufreq/powernow-k7.h rename to drivers/cpufreq/powernow-k7.h diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c similarity index 93% rename from arch/x86/kernel/cpu/cpufreq/powernow-k8.c rename to drivers/cpufreq/powernow-k8.c index 2368e38327b3..83479b6fb9a1 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -139,7 +139,7 @@ static int query_current_values_with_pending_wait(struct powernow_k8_data *data) } do { if (i++ > 10000) { - dprintk("detected change pending stuck\n"); + pr_debug("detected change pending stuck\n"); return 1; } rdmsr(MSR_FIDVID_STATUS, lo, hi); @@ -176,7 +176,7 @@ static void fidvid_msr_init(void) fid = lo & MSR_S_LO_CURRENT_FID; lo = fid | (vid << MSR_C_LO_VID_SHIFT); hi = MSR_C_HI_STP_GNT_BENIGN; - dprintk("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi); + pr_debug("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi); wrmsr(MSR_FIDVID_CTL, lo, hi); } @@ -196,7 +196,7 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid) lo |= (data->currvid << MSR_C_LO_VID_SHIFT); lo |= MSR_C_LO_INIT_FID_VID; - dprintk("writing fid 0x%x, lo 0x%x, hi 0x%x\n", + pr_debug("writing fid 0x%x, lo 0x%x, hi 0x%x\n", fid, lo, data->plllock * PLL_LOCK_CONVERSION); do { @@ -244,7 +244,7 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid) lo |= (vid << MSR_C_LO_VID_SHIFT); lo |= MSR_C_LO_INIT_FID_VID; - dprintk("writing vid 0x%x, lo 0x%x, hi 0x%x\n", + pr_debug("writing vid 0x%x, lo 0x%x, hi 0x%x\n", vid, lo, STOP_GRANT_5NS); do { @@ -325,7 +325,7 @@ static int transition_fid_vid(struct powernow_k8_data *data, return 1; } - dprintk("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n", + pr_debug("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n", smp_processor_id(), data->currfid, data->currvid); return 0; @@ -339,7 +339,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 savefid = data->currfid; u32 maxvid, lo, rvomult = 1; - dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, " + pr_debug("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, " "reqvid 0x%x, rvo 0x%x\n", smp_processor_id(), data->currfid, data->currvid, reqvid, data->rvo); @@ -349,12 +349,12 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, rvosteps *= rvomult; rdmsr(MSR_FIDVID_STATUS, lo, maxvid); maxvid = 0x1f & (maxvid >> 16); - dprintk("ph1 maxvid=0x%x\n", maxvid); + pr_debug("ph1 maxvid=0x%x\n", maxvid); if (reqvid < maxvid) /* lower numbers are higher voltages */ reqvid = maxvid; while (data->currvid > reqvid) { - dprintk("ph1: curr 0x%x, req vid 0x%x\n", + pr_debug("ph1: curr 0x%x, req vid 0x%x\n", data->currvid, reqvid); if (decrease_vid_code_by_step(data, reqvid, data->vidmvs)) return 1; @@ -365,7 +365,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, if (data->currvid == maxvid) { rvosteps = 0; } else { - dprintk("ph1: changing vid for rvo, req 0x%x\n", + pr_debug("ph1: changing vid for rvo, req 0x%x\n", data->currvid - 1); if (decrease_vid_code_by_step(data, data->currvid-1, 1)) return 1; @@ -382,7 +382,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, return 1; } - dprintk("ph1 complete, currfid 0x%x, currvid 0x%x\n", + pr_debug("ph1 complete, currfid 0x%x, currvid 0x%x\n", data->currfid, data->currvid); return 0; @@ -400,7 +400,7 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) return 0; } - dprintk("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, " + pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, " "reqfid 0x%x\n", smp_processor_id(), data->currfid, data->currvid, reqfid); @@ -457,7 +457,7 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) return 1; } - dprintk("ph2 complete, currfid 0x%x, currvid 0x%x\n", + pr_debug("ph2 complete, currfid 0x%x, currvid 0x%x\n", data->currfid, data->currvid); return 0; @@ -470,7 +470,7 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, u32 savefid = data->currfid; u32 savereqvid = reqvid; - dprintk("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n", + pr_debug("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n", smp_processor_id(), data->currfid, data->currvid); @@ -498,17 +498,17 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, return 1; if (savereqvid != data->currvid) { - dprintk("ph3 failed, currvid 0x%x\n", data->currvid); + pr_debug("ph3 failed, currvid 0x%x\n", data->currvid); return 1; } if (savefid != data->currfid) { - dprintk("ph3 failed, currfid changed 0x%x\n", + pr_debug("ph3 failed, currfid changed 0x%x\n", data->currfid); return 1; } - dprintk("ph3 complete, currfid 0x%x, currvid 0x%x\n", + pr_debug("ph3 complete, currfid 0x%x, currvid 0x%x\n", data->currfid, data->currvid); return 0; @@ -707,7 +707,7 @@ static int fill_powernow_table(struct powernow_k8_data *data, return -EIO; } - dprintk("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid); + pr_debug("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid); data->powernow_table = powernow_table; if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu) print_basics(data); @@ -717,7 +717,7 @@ static int fill_powernow_table(struct powernow_k8_data *data, (pst[j].vid == data->currvid)) return 0; - dprintk("currfid/vid do not match PST, ignoring\n"); + pr_debug("currfid/vid do not match PST, ignoring\n"); return 0; } @@ -739,36 +739,36 @@ static int find_psb_table(struct powernow_k8_data *data) if (memcmp(psb, PSB_ID_STRING, PSB_ID_STRING_LEN) != 0) continue; - dprintk("found PSB header at 0x%p\n", psb); + pr_debug("found PSB header at 0x%p\n", psb); - dprintk("table vers: 0x%x\n", psb->tableversion); + pr_debug("table vers: 0x%x\n", psb->tableversion); if (psb->tableversion != PSB_VERSION_1_4) { printk(KERN_ERR FW_BUG PFX "PSB table is not v1.4\n"); return -ENODEV; } - dprintk("flags: 0x%x\n", psb->flags1); + pr_debug("flags: 0x%x\n", psb->flags1); if (psb->flags1) { printk(KERN_ERR FW_BUG PFX "unknown flags\n"); return -ENODEV; } data->vstable = psb->vstable; - dprintk("voltage stabilization time: %d(*20us)\n", + pr_debug("voltage stabilization time: %d(*20us)\n", data->vstable); - dprintk("flags2: 0x%x\n", psb->flags2); + pr_debug("flags2: 0x%x\n", psb->flags2); data->rvo = psb->flags2 & 3; data->irt = ((psb->flags2) >> 2) & 3; mvs = ((psb->flags2) >> 4) & 3; data->vidmvs = 1 << mvs; data->batps = ((psb->flags2) >> 6) & 3; - dprintk("ramp voltage offset: %d\n", data->rvo); - dprintk("isochronous relief time: %d\n", data->irt); - dprintk("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs); + pr_debug("ramp voltage offset: %d\n", data->rvo); + pr_debug("isochronous relief time: %d\n", data->irt); + pr_debug("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs); - dprintk("numpst: 0x%x\n", psb->num_tables); + pr_debug("numpst: 0x%x\n", psb->num_tables); cpst = psb->num_tables; if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0)) { @@ -783,13 +783,13 @@ static int find_psb_table(struct powernow_k8_data *data) } data->plllock = psb->plllocktime; - dprintk("plllocktime: 0x%x (units 1us)\n", psb->plllocktime); - dprintk("maxfid: 0x%x\n", psb->maxfid); - dprintk("maxvid: 0x%x\n", psb->maxvid); + pr_debug("plllocktime: 0x%x (units 1us)\n", psb->plllocktime); + pr_debug("maxfid: 0x%x\n", psb->maxfid); + pr_debug("maxvid: 0x%x\n", psb->maxvid); maxvid = psb->maxvid; data->numps = psb->numps; - dprintk("numpstates: 0x%x\n", data->numps); + pr_debug("numpstates: 0x%x\n", data->numps); return fill_powernow_table(data, (struct pst_s *)(psb+1), maxvid); } @@ -834,13 +834,13 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) u64 control, status; if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) { - dprintk("register performance failed: bad ACPI data\n"); + pr_debug("register performance failed: bad ACPI data\n"); return -EIO; } /* verify the data contained in the ACPI structures */ if (data->acpi_data.state_count <= 1) { - dprintk("No ACPI P-States\n"); + pr_debug("No ACPI P-States\n"); goto err_out; } @@ -849,7 +849,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) if ((control != ACPI_ADR_SPACE_FIXED_HARDWARE) || (status != ACPI_ADR_SPACE_FIXED_HARDWARE)) { - dprintk("Invalid control/status registers (%x - %x)\n", + pr_debug("Invalid control/status registers (%llx - %llx)\n", control, status); goto err_out; } @@ -858,7 +858,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1)), GFP_KERNEL); if (!powernow_table) { - dprintk("powernow_table memory alloc failure\n"); + pr_debug("powernow_table memory alloc failure\n"); goto err_out; } @@ -928,7 +928,7 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, } rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi); if (!(hi & HW_PSTATE_VALID_MASK)) { - dprintk("invalid pstate %d, ignoring\n", index); + pr_debug("invalid pstate %d, ignoring\n", index); invalidate_entry(powernow_table, i); continue; } @@ -968,7 +968,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, vid = (control >> VID_SHIFT) & VID_MASK; } - dprintk(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid); + pr_debug(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid); index = fid | (vid<<8); powernow_table[i].index = index; @@ -978,7 +978,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, /* verify frequency is OK */ if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) { - dprintk("invalid freq %u kHz, ignoring\n", freq); + pr_debug("invalid freq %u kHz, ignoring\n", freq); invalidate_entry(powernow_table, i); continue; } @@ -986,7 +986,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, /* verify voltage is OK - * BIOSs are using "off" to indicate invalid */ if (vid == VID_OFF) { - dprintk("invalid vid %u, ignoring\n", vid); + pr_debug("invalid vid %u, ignoring\n", vid); invalidate_entry(powernow_table, i); continue; } @@ -1047,7 +1047,7 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, int res, i; struct cpufreq_freqs freqs; - dprintk("cpu %d transition to index %u\n", smp_processor_id(), index); + pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index); /* fid/vid correctness check for k8 */ /* fid are the lower 8 bits of the index we stored into @@ -1057,18 +1057,18 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, fid = data->powernow_table[index].index & 0xFF; vid = (data->powernow_table[index].index & 0xFF00) >> 8; - dprintk("table matched fid 0x%x, giving vid 0x%x\n", fid, vid); + pr_debug("table matched fid 0x%x, giving vid 0x%x\n", fid, vid); if (query_current_values_with_pending_wait(data)) return 1; if ((data->currvid == vid) && (data->currfid == fid)) { - dprintk("target matches current values (fid 0x%x, vid 0x%x)\n", + pr_debug("target matches current values (fid 0x%x, vid 0x%x)\n", fid, vid); return 0; } - dprintk("cpu %d, changing to fid 0x%x, vid 0x%x\n", + pr_debug("cpu %d, changing to fid 0x%x, vid 0x%x\n", smp_processor_id(), fid, vid); freqs.old = find_khz_freq_from_fid(data->currfid); freqs.new = find_khz_freq_from_fid(fid); @@ -1096,7 +1096,7 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, int res, i; struct cpufreq_freqs freqs; - dprintk("cpu %d transition to index %u\n", smp_processor_id(), index); + pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index); /* get MSR index for hardware pstate transition */ pstate = index & HW_PSTATE_MASK; @@ -1156,14 +1156,14 @@ static int powernowk8_target(struct cpufreq_policy *pol, goto err_out; } - dprintk("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", + pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", pol->cpu, targfreq, pol->min, pol->max, relation); if (query_current_values_with_pending_wait(data)) goto err_out; if (cpu_family != CPU_HW_PSTATE) { - dprintk("targ: curr fid 0x%x, vid 0x%x\n", + pr_debug("targ: curr fid 0x%x, vid 0x%x\n", data->currfid, data->currvid); if ((checkvid != data->currvid) || @@ -1319,7 +1319,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) data->currpstate); else pol->cur = find_khz_freq_from_fid(data->currfid); - dprintk("policy current frequency %d kHz\n", pol->cur); + pr_debug("policy current frequency %d kHz\n", pol->cur); /* min/max the cpu is capable of */ if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) { @@ -1337,10 +1337,10 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu); if (cpu_family == CPU_HW_PSTATE) - dprintk("cpu_init done, current pstate 0x%x\n", + pr_debug("cpu_init done, current pstate 0x%x\n", data->currpstate); else - dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n", + pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n", data->currfid, data->currvid); per_cpu(powernow_data, pol->cpu) = data; @@ -1586,7 +1586,7 @@ static int __cpuinit powernowk8_init(void) /* driver entry point for term */ static void __exit powernowk8_exit(void) { - dprintk("exit\n"); + pr_debug("exit\n"); if (boot_cpu_has(X86_FEATURE_CPB)) { msrs_free(msrs); diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h b/drivers/cpufreq/powernow-k8.h similarity index 98% rename from arch/x86/kernel/cpu/cpufreq/powernow-k8.h rename to drivers/cpufreq/powernow-k8.h index df3529b1c02d..3744d26cdc2b 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h +++ b/drivers/cpufreq/powernow-k8.h @@ -211,8 +211,6 @@ struct pst_s { u8 vid; }; -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "powernow-k8", msg) - static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid, u32 regfid); static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid); diff --git a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c similarity index 95% rename from arch/x86/kernel/cpu/cpufreq/sc520_freq.c rename to drivers/cpufreq/sc520_freq.c index 435a996a613a..1e205e6b1727 100644 --- a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c +++ b/drivers/cpufreq/sc520_freq.c @@ -29,8 +29,6 @@ static __u8 __iomem *cpuctl; -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "sc520_freq", msg) #define PFX "sc520_freq: " static struct cpufreq_frequency_table sc520_freq_table[] = { @@ -66,7 +64,7 @@ static void sc520_freq_set_cpu_state(unsigned int state) cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - dprintk("attempting to set frequency to %i kHz\n", + pr_debug("attempting to set frequency to %i kHz\n", sc520_freq_table[state].frequency); local_irq_disable(); @@ -161,7 +159,7 @@ static int __init sc520_freq_init(void) /* Test if we have the right hardware */ if (c->x86_vendor != X86_VENDOR_AMD || c->x86 != 4 || c->x86_model != 9) { - dprintk("no Elan SC520 processor found!\n"); + pr_debug("no Elan SC520 processor found!\n"); return -ENODEV; } cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1); diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c similarity index 96% rename from arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c rename to drivers/cpufreq/speedstep-centrino.c index 9b1ff37de46a..6ea3455def21 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/drivers/cpufreq/speedstep-centrino.c @@ -29,9 +29,6 @@ #define PFX "speedstep-centrino: " #define MAINTAINER "cpufreq@vger.kernel.org" -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg) - #define INTEL_MSR_RANGE (0xffff) struct cpu_id @@ -244,7 +241,7 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) if (model->cpu_id == NULL) { /* No match at all */ - dprintk("no support for CPU model \"%s\": " + pr_debug("no support for CPU model \"%s\": " "send /proc/cpuinfo to " MAINTAINER "\n", cpu->x86_model_id); return -ENOENT; @@ -252,15 +249,15 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) if (model->op_points == NULL) { /* Matched a non-match */ - dprintk("no table support for CPU model \"%s\"\n", + pr_debug("no table support for CPU model \"%s\"\n", cpu->x86_model_id); - dprintk("try using the acpi-cpufreq driver\n"); + pr_debug("try using the acpi-cpufreq driver\n"); return -ENOENT; } per_cpu(centrino_model, policy->cpu) = model; - dprintk("found \"%s\": max frequency: %dkHz\n", + pr_debug("found \"%s\": max frequency: %dkHz\n", model->model_name, model->max_freq); return 0; @@ -369,7 +366,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) per_cpu(centrino_cpu, policy->cpu) = &cpu_ids[i]; if (!per_cpu(centrino_cpu, policy->cpu)) { - dprintk("found unsupported CPU with " + pr_debug("found unsupported CPU with " "Enhanced SpeedStep: send /proc/cpuinfo to " MAINTAINER "\n"); return -ENODEV; @@ -385,7 +382,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { l |= MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP; - dprintk("trying to enable Enhanced SpeedStep (%x)\n", l); + pr_debug("trying to enable Enhanced SpeedStep (%x)\n", l); wrmsr(MSR_IA32_MISC_ENABLE, l, h); /* check to see if it stuck */ @@ -402,7 +399,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) /* 10uS transition latency */ policy->cur = freq; - dprintk("centrino_cpu_init: cur=%dkHz\n", policy->cur); + pr_debug("centrino_cpu_init: cur=%dkHz\n", policy->cur); ret = cpufreq_frequency_table_cpuinfo(policy, per_cpu(centrino_model, policy->cpu)->op_points); @@ -498,7 +495,7 @@ static int centrino_target (struct cpufreq_policy *policy, good_cpu = j; if (good_cpu >= nr_cpu_ids) { - dprintk("couldn't limit to CPUs in this domain\n"); + pr_debug("couldn't limit to CPUs in this domain\n"); retval = -EAGAIN; if (first_cpu) { /* We haven't started the transition yet. */ @@ -512,7 +509,7 @@ static int centrino_target (struct cpufreq_policy *policy, if (first_cpu) { rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h); if (msr == (oldmsr & 0xffff)) { - dprintk("no change needed - msr was and needs " + pr_debug("no change needed - msr was and needs " "to be %x\n", oldmsr); retval = 0; goto out; @@ -521,7 +518,7 @@ static int centrino_target (struct cpufreq_policy *policy, freqs.old = extract_clock(oldmsr, cpu, 0); freqs.new = extract_clock(msr, cpu, 0); - dprintk("target=%dkHz old=%d new=%d msr=%04x\n", + pr_debug("target=%dkHz old=%d new=%d msr=%04x\n", target_freq, freqs.old, freqs.new, msr); for_each_cpu(k, policy->cpus) { diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c similarity index 92% rename from arch/x86/kernel/cpu/cpufreq/speedstep-ich.c rename to drivers/cpufreq/speedstep-ich.c index 561758e95180..a748ce782fee 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c +++ b/drivers/cpufreq/speedstep-ich.c @@ -53,10 +53,6 @@ static struct cpufreq_frequency_table speedstep_freqs[] = { }; -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "speedstep-ich", msg) - - /** * speedstep_find_register - read the PMBASE address * @@ -80,7 +76,7 @@ static int speedstep_find_register(void) return -ENODEV; } - dprintk("pmbase is 0x%x\n", pmbase); + pr_debug("pmbase is 0x%x\n", pmbase); return 0; } @@ -106,13 +102,13 @@ static void speedstep_set_state(unsigned int state) /* read state */ value = inb(pmbase + 0x50); - dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); /* write new state */ value &= 0xFE; value |= state; - dprintk("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase); + pr_debug("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase); /* Disable bus master arbitration */ pm2_blk = inb(pmbase + 0x20); @@ -132,10 +128,10 @@ static void speedstep_set_state(unsigned int state) /* Enable IRQs */ local_irq_restore(flags); - dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); if (state == (value & 0x1)) - dprintk("change to %u MHz succeeded\n", + pr_debug("change to %u MHz succeeded\n", speedstep_get_frequency(speedstep_processor) / 1000); else printk(KERN_ERR "cpufreq: change failed - I/O error\n"); @@ -165,7 +161,7 @@ static int speedstep_activate(void) pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value); if (!(value & 0x08)) { value |= 0x08; - dprintk("activating SpeedStep (TM) registers\n"); + pr_debug("activating SpeedStep (TM) registers\n"); pci_write_config_word(speedstep_chipset_dev, 0x00A0, value); } @@ -218,7 +214,7 @@ static unsigned int speedstep_detect_chipset(void) return 2; /* 2-M */ if (hostbridge->revision < 5) { - dprintk("hostbridge does not support speedstep\n"); + pr_debug("hostbridge does not support speedstep\n"); speedstep_chipset_dev = NULL; pci_dev_put(hostbridge); return 0; @@ -246,7 +242,7 @@ static unsigned int speedstep_get(unsigned int cpu) if (smp_call_function_single(cpu, get_freq_data, &speed, 1) != 0) BUG(); - dprintk("detected %u kHz as current frequency\n", speed); + pr_debug("detected %u kHz as current frequency\n", speed); return speed; } @@ -276,7 +272,7 @@ static int speedstep_target(struct cpufreq_policy *policy, freqs.new = speedstep_freqs[newstate].frequency; freqs.cpu = policy->cpu; - dprintk("transiting from %u to %u kHz\n", freqs.old, freqs.new); + pr_debug("transiting from %u to %u kHz\n", freqs.old, freqs.new); /* no transition necessary */ if (freqs.old == freqs.new) @@ -351,7 +347,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) if (!speed) return -EIO; - dprintk("currently at %s speed setting - %i MHz\n", + pr_debug("currently at %s speed setting - %i MHz\n", (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high", (speed / 1000)); @@ -405,14 +401,14 @@ static int __init speedstep_init(void) /* detect processor */ speedstep_processor = speedstep_detect_processor(); if (!speedstep_processor) { - dprintk("Intel(R) SpeedStep(TM) capable processor " + pr_debug("Intel(R) SpeedStep(TM) capable processor " "not found\n"); return -ENODEV; } /* detect chipset */ if (!speedstep_detect_chipset()) { - dprintk("Intel(R) SpeedStep(TM) for this chipset not " + pr_debug("Intel(R) SpeedStep(TM) for this chipset not " "(yet) available.\n"); return -ENODEV; } diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c similarity index 90% rename from arch/x86/kernel/cpu/cpufreq/speedstep-lib.c rename to drivers/cpufreq/speedstep-lib.c index a94ec6be69fa..8af2d2fd9d51 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c +++ b/drivers/cpufreq/speedstep-lib.c @@ -18,9 +18,6 @@ #include #include "speedstep-lib.h" -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "speedstep-lib", msg) - #define PFX "speedstep-lib: " #ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK @@ -75,7 +72,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor) /* read MSR 0x2a - we only need the low 32 bits */ rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); - dprintk("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); + pr_debug("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); msr_tmp = msr_lo; /* decode the FSB */ @@ -89,7 +86,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor) /* decode the multiplier */ if (processor == SPEEDSTEP_CPU_PIII_C_EARLY) { - dprintk("workaround for early PIIIs\n"); + pr_debug("workaround for early PIIIs\n"); msr_lo &= 0x03c00000; } else msr_lo &= 0x0bc00000; @@ -100,7 +97,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor) j++; } - dprintk("speed is %u\n", + pr_debug("speed is %u\n", (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100)); return msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100; @@ -112,7 +109,7 @@ static unsigned int pentiumM_get_frequency(void) u32 msr_lo, msr_tmp; rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); - dprintk("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); + pr_debug("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); /* see table B-2 of 24547212.pdf */ if (msr_lo & 0x00040000) { @@ -122,7 +119,7 @@ static unsigned int pentiumM_get_frequency(void) } msr_tmp = (msr_lo >> 22) & 0x1f; - dprintk("bits 22-26 are 0x%x, speed is %u\n", + pr_debug("bits 22-26 are 0x%x, speed is %u\n", msr_tmp, (msr_tmp * 100 * 1000)); return msr_tmp * 100 * 1000; @@ -160,11 +157,11 @@ static unsigned int pentium_core_get_frequency(void) } rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); - dprintk("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", + pr_debug("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); msr_tmp = (msr_lo >> 22) & 0x1f; - dprintk("bits 22-26 are 0x%x, speed is %u\n", + pr_debug("bits 22-26 are 0x%x, speed is %u\n", msr_tmp, (msr_tmp * fsb)); ret = (msr_tmp * fsb); @@ -190,7 +187,7 @@ static unsigned int pentium4_get_frequency(void) rdmsr(0x2c, msr_lo, msr_hi); - dprintk("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi); + pr_debug("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi); /* decode the FSB: see IA-32 Intel (C) Architecture Software * Developer's Manual, Volume 3: System Prgramming Guide, @@ -217,7 +214,7 @@ static unsigned int pentium4_get_frequency(void) /* Multiplier. */ mult = msr_lo >> 24; - dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", + pr_debug("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", fsb, mult, (fsb * mult)); ret = (fsb * mult); @@ -257,7 +254,7 @@ unsigned int speedstep_detect_processor(void) struct cpuinfo_x86 *c = &cpu_data(0); u32 ebx, msr_lo, msr_hi; - dprintk("x86: %x, model: %x\n", c->x86, c->x86_model); + pr_debug("x86: %x, model: %x\n", c->x86, c->x86_model); if ((c->x86_vendor != X86_VENDOR_INTEL) || ((c->x86 != 6) && (c->x86 != 0xF))) @@ -272,7 +269,7 @@ unsigned int speedstep_detect_processor(void) ebx = cpuid_ebx(0x00000001); ebx &= 0x000000FF; - dprintk("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask); + pr_debug("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask); switch (c->x86_mask) { case 4: @@ -327,7 +324,7 @@ unsigned int speedstep_detect_processor(void) /* cpuid_ebx(1) is 0x04 for desktop PIII, * 0x06 for mobile PIII-M */ ebx = cpuid_ebx(0x00000001); - dprintk("ebx is %x\n", ebx); + pr_debug("ebx is %x\n", ebx); ebx &= 0x000000FF; @@ -344,7 +341,7 @@ unsigned int speedstep_detect_processor(void) /* all mobile PIII Coppermines have FSB 100 MHz * ==> sort out a few desktop PIIIs. */ rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi); - dprintk("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", + pr_debug("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", msr_lo, msr_hi); msr_lo &= 0x00c0000; if (msr_lo != 0x0080000) @@ -357,12 +354,12 @@ unsigned int speedstep_detect_processor(void) * bit 56 or 57 is set */ rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi); - dprintk("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", + pr_debug("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi); if ((msr_hi & (1<<18)) && (relaxed_check ? 1 : (msr_hi & (3<<24)))) { if (c->x86_mask == 0x01) { - dprintk("early PIII version\n"); + pr_debug("early PIII version\n"); return SPEEDSTEP_CPU_PIII_C_EARLY; } else return SPEEDSTEP_CPU_PIII_C; @@ -393,14 +390,14 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, if ((!processor) || (!low_speed) || (!high_speed) || (!set_state)) return -EINVAL; - dprintk("trying to determine both speeds\n"); + pr_debug("trying to determine both speeds\n"); /* get current speed */ prev_speed = speedstep_get_frequency(processor); if (!prev_speed) return -EIO; - dprintk("previous speed is %u\n", prev_speed); + pr_debug("previous speed is %u\n", prev_speed); local_irq_save(flags); @@ -412,7 +409,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, goto out; } - dprintk("low speed is %u\n", *low_speed); + pr_debug("low speed is %u\n", *low_speed); /* start latency measurement */ if (transition_latency) @@ -431,7 +428,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, goto out; } - dprintk("high speed is %u\n", *high_speed); + pr_debug("high speed is %u\n", *high_speed); if (*low_speed == *high_speed) { ret = -ENODEV; @@ -445,7 +442,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, if (transition_latency) { *transition_latency = (tv2.tv_sec - tv1.tv_sec) * USEC_PER_SEC + tv2.tv_usec - tv1.tv_usec; - dprintk("transition latency is %u uSec\n", *transition_latency); + pr_debug("transition latency is %u uSec\n", *transition_latency); /* convert uSec to nSec and add 20% for safety reasons */ *transition_latency *= 1200; diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.h b/drivers/cpufreq/speedstep-lib.h similarity index 100% rename from arch/x86/kernel/cpu/cpufreq/speedstep-lib.h rename to drivers/cpufreq/speedstep-lib.h diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c similarity index 90% rename from arch/x86/kernel/cpu/cpufreq/speedstep-smi.c rename to drivers/cpufreq/speedstep-smi.c index 91bc25b67bc1..c76ead3490bf 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c +++ b/drivers/cpufreq/speedstep-smi.c @@ -55,9 +55,6 @@ static struct cpufreq_frequency_table speedstep_freqs[] = { * of DMA activity going on? */ #define SMI_TRIES 5 -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "speedstep-smi", msg) - /** * speedstep_smi_ownership */ @@ -70,7 +67,7 @@ static int speedstep_smi_ownership(void) command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); magic = virt_to_phys(magic_data); - dprintk("trying to obtain ownership with command %x at port %x\n", + pr_debug("trying to obtain ownership with command %x at port %x\n", command, smi_port); __asm__ __volatile__( @@ -85,7 +82,7 @@ static int speedstep_smi_ownership(void) : "memory" ); - dprintk("result is %x\n", result); + pr_debug("result is %x\n", result); return result; } @@ -106,13 +103,13 @@ static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high) u32 function = GET_SPEEDSTEP_FREQS; if (!(ist_info.event & 0xFFFF)) { - dprintk("bug #1422 -- can't read freqs from BIOS\n"); + pr_debug("bug #1422 -- can't read freqs from BIOS\n"); return -ENODEV; } command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); - dprintk("trying to determine frequencies with command %x at port %x\n", + pr_debug("trying to determine frequencies with command %x at port %x\n", command, smi_port); __asm__ __volatile__( @@ -129,7 +126,7 @@ static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high) "d" (smi_port), "S" (0), "D" (0) ); - dprintk("result %x, low_freq %u, high_freq %u\n", + pr_debug("result %x, low_freq %u, high_freq %u\n", result, low_mhz, high_mhz); /* abort if results are obviously incorrect... */ @@ -154,7 +151,7 @@ static int speedstep_get_state(void) command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); - dprintk("trying to determine current setting with command %x " + pr_debug("trying to determine current setting with command %x " "at port %x\n", command, smi_port); __asm__ __volatile__( @@ -168,7 +165,7 @@ static int speedstep_get_state(void) "d" (smi_port), "S" (0), "D" (0) ); - dprintk("state is %x, result is %x\n", state, result); + pr_debug("state is %x, result is %x\n", state, result); return state & 1; } @@ -194,13 +191,13 @@ static void speedstep_set_state(unsigned int state) command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); - dprintk("trying to set frequency to state %u " + pr_debug("trying to set frequency to state %u " "with command %x at port %x\n", state, command, smi_port); do { if (retry) { - dprintk("retry %u, previous result %u, waiting...\n", + pr_debug("retry %u, previous result %u, waiting...\n", retry, result); mdelay(retry * 50); } @@ -221,7 +218,7 @@ static void speedstep_set_state(unsigned int state) local_irq_restore(flags); if (new_state == state) - dprintk("change to %u MHz succeeded after %u tries " + pr_debug("change to %u MHz succeeded after %u tries " "with result %u\n", (speedstep_freqs[new_state].frequency / 1000), retry, result); @@ -292,7 +289,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) result = speedstep_smi_ownership(); if (result) { - dprintk("fails in acquiring ownership of a SMI interface.\n"); + pr_debug("fails in acquiring ownership of a SMI interface.\n"); return -EINVAL; } @@ -304,7 +301,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) if (result) { /* fall back to speedstep_lib.c dection mechanism: * try both states out */ - dprintk("could not detect low and high frequencies " + pr_debug("could not detect low and high frequencies " "by SMI call.\n"); result = speedstep_get_freqs(speedstep_processor, low, high, @@ -312,18 +309,18 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) &speedstep_set_state); if (result) { - dprintk("could not detect two different speeds" + pr_debug("could not detect two different speeds" " -- aborting.\n"); return result; } else - dprintk("workaround worked.\n"); + pr_debug("workaround worked.\n"); } /* get current speed setting */ state = speedstep_get_state(); speed = speedstep_freqs[state].frequency; - dprintk("currently at %s speed setting - %i MHz\n", + pr_debug("currently at %s speed setting - %i MHz\n", (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high", (speed / 1000)); @@ -360,7 +357,7 @@ static int speedstep_resume(struct cpufreq_policy *policy) int result = speedstep_smi_ownership(); if (result) - dprintk("fails in re-acquiring ownership of a SMI interface.\n"); + pr_debug("fails in re-acquiring ownership of a SMI interface.\n"); return result; } @@ -403,12 +400,12 @@ static int __init speedstep_init(void) } if (!speedstep_processor) { - dprintk("No supported Intel CPU detected.\n"); + pr_debug("No supported Intel CPU detected.\n"); return -ENODEV; } - dprintk("signature:0x%.8lx, command:0x%.8lx, " - "event:0x%.8lx, perf_level:0x%.8lx.\n", + pr_debug("signature:0x%.8ulx, command:0x%.8ulx, " + "event:0x%.8ulx, perf_level:0x%.8ulx.\n", ist_info.signature, ist_info.command, ist_info.event, ist_info.perf_level); diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index e54185223c8c..c64c3807f516 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -91,6 +91,8 @@ config CRYPTO_SHA1_S390 This is the s390 hardware accelerated implementation of the SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). + It is available as of z990. + config CRYPTO_SHA256_S390 tristate "SHA256 digest algorithm" depends on S390 @@ -99,8 +101,7 @@ config CRYPTO_SHA256_S390 This is the s390 hardware accelerated implementation of the SHA256 secure hash standard (DFIPS 180-2). - This version of SHA implements a 256 bit hash with 128 bits of - security against collision attacks. + It is available as of z9. config CRYPTO_SHA512_S390 tristate "SHA384 and SHA512 digest algorithm" @@ -110,10 +111,7 @@ config CRYPTO_SHA512_S390 This is the s390 hardware accelerated implementation of the SHA512 secure hash standard. - This version of SHA implements a 512 bit hash with 256 bits of - security against collision attacks. The code also includes SHA-384, - a 384 bit hash with 192 bits of security against collision attacks. - + It is available as of z10. config CRYPTO_DES_S390 tristate "DES and Triple DES cipher algorithms" @@ -121,9 +119,12 @@ config CRYPTO_DES_S390 select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER help - This us the s390 hardware accelerated implementation of the + This is the s390 hardware accelerated implementation of the DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). + As of z990 the ECB and CBC mode are hardware accelerated. + As of z196 the CTR mode is hardware accelerated. + config CRYPTO_AES_S390 tristate "AES cipher algorithms" depends on S390 @@ -131,20 +132,15 @@ config CRYPTO_AES_S390 select CRYPTO_BLKCIPHER help This is the s390 hardware accelerated implementation of the - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. + AES cipher algorithms (FIPS-197). - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - On s390 the System z9-109 currently only supports the key size - of 128 bit. + As of z9 the ECB and CBC modes are hardware accelerated + for 128 bit keys. + As of z10 the ECB and CBC modes are hardware accelerated + for all AES key sizes. + As of z196 the CTR mode is hardware accelerated for all AES + key sizes and XTS mode is hardware accelerated for 256 and + 512 bit keys. config S390_PRNG tristate "Pseudo random number generator device driver" @@ -154,8 +150,20 @@ config S390_PRNG Select this option if you want to use the s390 pseudo random number generator. The PRNG is part of the cryptographic processor functions and uses triple-DES to generate secure random numbers like the - ANSI X9.17 standard. The PRNG is usable via the char device - /dev/prandom. + ANSI X9.17 standard. User-space programs access the + pseudo-random-number device through the char device /dev/prandom. + + It is available as of z9. + +config CRYPTO_GHASH_S390 + tristate "GHASH digest algorithm" + depends on S390 + select CRYPTO_HASH + help + This is the s390 hardware accelerated implementation of the + GHASH message digest algorithm for GCM (Galois/Counter Mode). + + It is available as of z196. config CRYPTO_DEV_MV_CESA tristate "Marvell's Cryptographic Engine" @@ -200,6 +208,8 @@ config CRYPTO_DEV_HIFN_795X_RNG Select this option if you want to enable the random number generator on the HIFN 795x crypto adapters. +source drivers/crypto/caam/Kconfig + config CRYPTO_DEV_TALITOS tristate "Talitos Freescale Security Engine (SEC)" select CRYPTO_ALGAPI @@ -269,4 +279,15 @@ config CRYPTO_DEV_PICOXCELL Saying m here will build a module named pipcoxcell_crypto. +config CRYPTO_DEV_S5P + tristate "Support for Samsung S5PV210 crypto accelerator" + depends on ARCH_S5PV210 + select CRYPTO_AES + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + help + This option allows you to have support for S5P crypto acceleration. + Select this to offload Samsung S5PV210 or S5PC110 from AES + algorithms execution. + endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 5203e34248d7..53ea50155319 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -6,8 +6,10 @@ n2_crypto-y := n2_core.o n2_asm.o obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/ obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o +obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig new file mode 100644 index 000000000000..2d876bb98ff4 --- /dev/null +++ b/drivers/crypto/caam/Kconfig @@ -0,0 +1,72 @@ +config CRYPTO_DEV_FSL_CAAM + tristate "Freescale CAAM-Multicore driver backend" + depends on FSL_SOC + help + Enables the driver module for Freescale's Cryptographic Accelerator + and Assurance Module (CAAM), also known as the SEC version 4 (SEC4). + This module adds a job ring operation interface, and configures h/w + to operate as a DPAA component automatically, depending + on h/w feature availability. + + To compile this driver as a module, choose M here: the module + will be called caam. + +config CRYPTO_DEV_FSL_CAAM_RINGSIZE + int "Job Ring size" + depends on CRYPTO_DEV_FSL_CAAM + range 2 9 + default "9" + help + Select size of Job Rings as a power of 2, within the + range 2-9 (ring size 4-512). + Examples: + 2 => 4 + 3 => 8 + 4 => 16 + 5 => 32 + 6 => 64 + 7 => 128 + 8 => 256 + 9 => 512 + +config CRYPTO_DEV_FSL_CAAM_INTC + bool "Job Ring interrupt coalescing" + depends on CRYPTO_DEV_FSL_CAAM + default y + help + Enable the Job Ring's interrupt coalescing feature. + +config CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD + int "Job Ring interrupt coalescing count threshold" + depends on CRYPTO_DEV_FSL_CAAM_INTC + range 1 255 + default 255 + help + Select number of descriptor completions to queue before + raising an interrupt, in the range 1-255. Note that a selection + of 1 functionally defeats the coalescing feature, and a selection + equal or greater than the job ring size will force timeouts. + +config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD + int "Job Ring interrupt coalescing timer threshold" + depends on CRYPTO_DEV_FSL_CAAM_INTC + range 1 65535 + default 2048 + help + Select number of bus clocks/64 to timeout in the case that one or + more descriptor completions are queued without reaching the count + threshold. Range is 1-65535. + +config CRYPTO_DEV_FSL_CAAM_CRYPTO_API + tristate "Register algorithm implementations with the Crypto API" + depends on CRYPTO_DEV_FSL_CAAM + default y + select CRYPTO_ALGAPI + select CRYPTO_AUTHENC + help + Selecting this will offload crypto for users of the + scatterlist crypto API (such as the linux native IPSec + stack) to the SEC4 via job ring. + + To compile this as a module, choose M here: the module + will be called caamalg. diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile new file mode 100644 index 000000000000..ef39011b4505 --- /dev/null +++ b/drivers/crypto/caam/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the CAAM backend and dependent components +# + +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o + +caam-objs := ctrl.o jr.o error.o diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c new file mode 100644 index 000000000000..d0e65d6ddc77 --- /dev/null +++ b/drivers/crypto/caam/caamalg.c @@ -0,0 +1,1268 @@ +/* + * caam - Freescale FSL CAAM support for crypto API + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Based on talitos crypto API driver. + * + * relationship of job descriptors to shared descriptors (SteveC Dec 10 2008): + * + * --------------- --------------- + * | JobDesc #1 |-------------------->| ShareDesc | + * | *(packet 1) | | (PDB) | + * --------------- |------------->| (hashKey) | + * . | | (cipherKey) | + * . | |-------->| (operation) | + * --------------- | | --------------- + * | JobDesc #2 |------| | + * | *(packet 2) | | + * --------------- | + * . | + * . | + * --------------- | + * | JobDesc #3 |------------ + * | *(packet 3) | + * --------------- + * + * The SharedDesc never changes for a connection unless rekeyed, but + * each packet will likely be in a different place. So all we need + * to know to process the packet is where the input is, where the + * output goes, and what context we want to process with. Context is + * in the SharedDesc, packet references in the JobDesc. + * + * So, a job desc looks like: + * + * --------------------- + * | Header | + * | ShareDesc Pointer | + * | SEQ_OUT_PTR | + * | (output buffer) | + * | SEQ_IN_PTR | + * | (input buffer) | + * | LOAD (to DECO) | + * --------------------- + */ + +#include "compat.h" + +#include "regs.h" +#include "intern.h" +#include "desc_constr.h" +#include "jr.h" +#include "error.h" + +/* + * crypto alg + */ +#define CAAM_CRA_PRIORITY 3000 +/* max key is sum of AES_MAX_KEY_SIZE, max split key size */ +#define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + \ + SHA512_DIGEST_SIZE * 2) +/* max IV is max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */ +#define CAAM_MAX_IV_LENGTH 16 + +/* length of descriptors text */ +#define DESC_AEAD_SHARED_TEXT_LEN 4 +#define DESC_AEAD_ENCRYPT_TEXT_LEN 21 +#define DESC_AEAD_DECRYPT_TEXT_LEN 24 +#define DESC_AEAD_GIVENCRYPT_TEXT_LEN 27 + +#ifdef DEBUG +/* for print_hex_dumps with line references */ +#define xstr(s) str(s) +#define str(s) #s +#define debug(format, arg...) printk(format, arg) +#else +#define debug(format, arg...) +#endif + +/* + * per-session context + */ +struct caam_ctx { + struct device *jrdev; + u32 *sh_desc; + dma_addr_t shared_desc_phys; + u32 class1_alg_type; + u32 class2_alg_type; + u32 alg_op; + u8 *key; + dma_addr_t key_phys; + unsigned int enckeylen; + unsigned int split_key_len; + unsigned int split_key_pad_len; + unsigned int authsize; +}; + +static int aead_authenc_setauthsize(struct crypto_aead *authenc, + unsigned int authsize) +{ + struct caam_ctx *ctx = crypto_aead_ctx(authenc); + + ctx->authsize = authsize; + + return 0; +} + +struct split_key_result { + struct completion completion; + int err; +}; + +static void split_key_done(struct device *dev, u32 *desc, u32 err, + void *context) +{ + struct split_key_result *res = context; + +#ifdef DEBUG + dev_err(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); +#endif + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + + dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } + + res->err = err; + + complete(&res->completion); +} + +/* +get a split ipad/opad key + +Split key generation----------------------------------------------- + +[00] 0xb0810008 jobdesc: stidx=1 share=never len=8 +[01] 0x04000014 key: class2->keyreg len=20 + @0xffe01000 +[03] 0x84410014 operation: cls2-op sha1 hmac init dec +[04] 0x24940000 fifold: class2 msgdata-last2 len=0 imm +[05] 0xa4000001 jump: class2 local all ->1 [06] +[06] 0x64260028 fifostr: class2 mdsplit-jdk len=40 + @0xffe04000 +*/ +static u32 gen_split_key(struct caam_ctx *ctx, const u8 *key_in, u32 authkeylen) +{ + struct device *jrdev = ctx->jrdev; + u32 *desc; + struct split_key_result result; + dma_addr_t dma_addr_in, dma_addr_out; + int ret = 0; + + desc = kmalloc(CAAM_CMD_SZ * 6 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA); + + init_job_desc(desc, 0); + + dma_addr_in = dma_map_single(jrdev, (void *)key_in, authkeylen, + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, dma_addr_in)) { + dev_err(jrdev, "unable to map key input memory\n"); + kfree(desc); + return -ENOMEM; + } + append_key(desc, dma_addr_in, authkeylen, CLASS_2 | + KEY_DEST_CLASS_REG); + + /* Sets MDHA up into an HMAC-INIT */ + append_operation(desc, ctx->alg_op | OP_ALG_DECRYPT | + OP_ALG_AS_INIT); + + /* + * do a FIFO_LOAD of zero, this will trigger the internal key expansion + into both pads inside MDHA + */ + append_fifo_load_as_imm(desc, NULL, 0, LDST_CLASS_2_CCB | + FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST2); + + /* + * FIFO_STORE with the explicit split-key content store + * (0x26 output type) + */ + dma_addr_out = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len, + DMA_FROM_DEVICE); + if (dma_mapping_error(jrdev, dma_addr_out)) { + dev_err(jrdev, "unable to map key output memory\n"); + kfree(desc); + return -ENOMEM; + } + append_fifo_store(desc, dma_addr_out, ctx->split_key_len, + LDST_CLASS_2_CCB | FIFOST_TYPE_SPLIT_KEK); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key_in, authkeylen, 1); + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif + + result.err = 0; + init_completion(&result.completion); + + ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result); + if (!ret) { + /* in progress */ + wait_for_completion_interruptible(&result.completion); + ret = result.err; +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->split_key_pad_len, 1); +#endif + } + + dma_unmap_single(jrdev, dma_addr_out, ctx->split_key_pad_len, + DMA_FROM_DEVICE); + dma_unmap_single(jrdev, dma_addr_in, authkeylen, DMA_TO_DEVICE); + + kfree(desc); + + return ret; +} + +static int build_sh_desc_ipsec(struct caam_ctx *ctx) +{ + struct device *jrdev = ctx->jrdev; + u32 *sh_desc; + u32 *jump_cmd; + bool keys_fit_inline = 0; + + /* + * largest Job Descriptor and its Shared Descriptor + * must both fit into the 64-word Descriptor h/w Buffer + */ + if ((DESC_AEAD_GIVENCRYPT_TEXT_LEN + + DESC_AEAD_SHARED_TEXT_LEN) * CAAM_CMD_SZ + + ctx->split_key_pad_len + ctx->enckeylen <= CAAM_DESC_BYTES_MAX) + keys_fit_inline = 1; + + /* build shared descriptor for this session */ + sh_desc = kmalloc(CAAM_CMD_SZ * DESC_AEAD_SHARED_TEXT_LEN + + keys_fit_inline ? + ctx->split_key_pad_len + ctx->enckeylen : + CAAM_PTR_SZ * 2, GFP_DMA | GFP_KERNEL); + if (!sh_desc) { + dev_err(jrdev, "could not allocate shared descriptor\n"); + return -ENOMEM; + } + + init_sh_desc(sh_desc, HDR_SAVECTX | HDR_SHARE_SERIAL); + + jump_cmd = append_jump(sh_desc, CLASS_BOTH | JUMP_TEST_ALL | + JUMP_COND_SHRD | JUMP_COND_SELF); + + /* + * process keys, starting with class 2/authentication. + */ + if (keys_fit_inline) { + append_key_as_imm(sh_desc, ctx->key, ctx->split_key_pad_len, + ctx->split_key_len, + CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); + + append_key_as_imm(sh_desc, (void *)ctx->key + + ctx->split_key_pad_len, ctx->enckeylen, + ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + } else { + append_key(sh_desc, ctx->key_phys, ctx->split_key_len, CLASS_2 | + KEY_DEST_MDHA_SPLIT | KEY_ENC); + append_key(sh_desc, ctx->key_phys + ctx->split_key_pad_len, + ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + } + + /* update jump cmd now that we are at the jump target */ + set_jump_tgt_here(sh_desc, jump_cmd); + + ctx->shared_desc_phys = dma_map_single(jrdev, sh_desc, + desc_bytes(sh_desc), + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->shared_desc_phys)) { + dev_err(jrdev, "unable to map shared descriptor\n"); + kfree(sh_desc); + return -ENOMEM; + } + + ctx->sh_desc = sh_desc; + + return 0; +} + +static int aead_authenc_setkey(struct crypto_aead *aead, + const u8 *key, unsigned int keylen) +{ + /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ + static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + struct rtattr *rta = (void *)key; + struct crypto_authenc_key_param *param; + unsigned int authkeylen; + unsigned int enckeylen; + int ret = 0; + + param = RTA_DATA(rta); + enckeylen = be32_to_cpu(param->enckeylen); + + key += RTA_ALIGN(rta->rta_len); + keylen -= RTA_ALIGN(rta->rta_len); + + if (keylen < enckeylen) + goto badkey; + + authkeylen = keylen - enckeylen; + + if (keylen > CAAM_MAX_KEY_SIZE) + goto badkey; + + /* Pick class 2 key length from algorithm submask */ + ctx->split_key_len = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> + OP_ALG_ALGSEL_SHIFT] * 2; + ctx->split_key_pad_len = ALIGN(ctx->split_key_len, 16); + +#ifdef DEBUG + printk(KERN_ERR "keylen %d enckeylen %d authkeylen %d\n", + keylen, enckeylen, authkeylen); + printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", + ctx->split_key_len, ctx->split_key_pad_len); + print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); +#endif + ctx->key = kmalloc(ctx->split_key_pad_len + enckeylen, + GFP_KERNEL | GFP_DMA); + if (!ctx->key) { + dev_err(jrdev, "could not allocate key output memory\n"); + return -ENOMEM; + } + + ret = gen_split_key(ctx, key, authkeylen); + if (ret) { + kfree(ctx->key); + goto badkey; + } + + /* postpend encryption key to auth split key */ + memcpy(ctx->key + ctx->split_key_pad_len, key + authkeylen, enckeylen); + + ctx->key_phys = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len + + enckeylen, DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->key_phys)) { + dev_err(jrdev, "unable to map key i/o memory\n"); + kfree(ctx->key); + return -ENOMEM; + } +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->split_key_pad_len + enckeylen, 1); +#endif + + ctx->enckeylen = enckeylen; + + ret = build_sh_desc_ipsec(ctx); + if (ret) { + dma_unmap_single(jrdev, ctx->key_phys, ctx->split_key_pad_len + + enckeylen, DMA_TO_DEVICE); + kfree(ctx->key); + } + + return ret; +badkey: + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; +} + +struct link_tbl_entry { + u64 ptr; + u32 len; + u8 reserved; + u8 buf_pool_id; + u16 offset; +}; + +/* + * ipsec_esp_edesc - s/w-extended ipsec_esp descriptor + * @src_nents: number of segments in input scatterlist + * @dst_nents: number of segments in output scatterlist + * @assoc_nents: number of segments in associated data (SPI+Seq) scatterlist + * @desc: h/w descriptor (variable length; must not exceed MAX_CAAM_DESCSIZE) + * @link_tbl_bytes: length of dma mapped link_tbl space + * @link_tbl_dma: bus physical mapped address of h/w link table + * @hw_desc: the h/w job descriptor followed by any referenced link tables + */ +struct ipsec_esp_edesc { + int assoc_nents; + int src_nents; + int dst_nents; + int link_tbl_bytes; + dma_addr_t link_tbl_dma; + struct link_tbl_entry *link_tbl; + u32 hw_desc[0]; +}; + +static void ipsec_esp_unmap(struct device *dev, + struct ipsec_esp_edesc *edesc, + struct aead_request *areq) +{ + dma_unmap_sg(dev, areq->assoc, edesc->assoc_nents, DMA_TO_DEVICE); + + if (unlikely(areq->dst != areq->src)) { + dma_unmap_sg(dev, areq->src, edesc->src_nents, + DMA_TO_DEVICE); + dma_unmap_sg(dev, areq->dst, edesc->dst_nents, + DMA_FROM_DEVICE); + } else { + dma_unmap_sg(dev, areq->src, edesc->src_nents, + DMA_BIDIRECTIONAL); + } + + if (edesc->link_tbl_bytes) + dma_unmap_single(dev, edesc->link_tbl_dma, + edesc->link_tbl_bytes, + DMA_TO_DEVICE); +} + +/* + * ipsec_esp descriptor callbacks + */ +static void ipsec_esp_encrypt_done(struct device *jrdev, u32 *desc, u32 err, + void *context) +{ + struct aead_request *areq = context; + struct ipsec_esp_edesc *edesc; +#ifdef DEBUG + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + int ivsize = crypto_aead_ivsize(aead); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + + dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); +#endif + edesc = (struct ipsec_esp_edesc *)((char *)desc - + offsetof(struct ipsec_esp_edesc, hw_desc)); + + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } + + ipsec_esp_unmap(jrdev, edesc, areq); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, "assoc @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->assoc), + areq->assoclen , 1); + print_hex_dump(KERN_ERR, "dstiv @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src) - ivsize, + edesc->src_nents ? 100 : ivsize, 1); + print_hex_dump(KERN_ERR, "dst @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src), + edesc->src_nents ? 100 : areq->cryptlen + + ctx->authsize + 4, 1); +#endif + + kfree(edesc); + + aead_request_complete(areq, err); +} + +static void ipsec_esp_decrypt_done(struct device *jrdev, u32 *desc, u32 err, + void *context) +{ + struct aead_request *areq = context; + struct ipsec_esp_edesc *edesc; +#ifdef DEBUG + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + + dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); +#endif + edesc = (struct ipsec_esp_edesc *)((char *)desc - + offsetof(struct ipsec_esp_edesc, hw_desc)); + + if (err) { + char tmp[CAAM_ERROR_STR_MAX]; + + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } + + ipsec_esp_unmap(jrdev, edesc, areq); + + /* + * verify hw auth check passed else return -EBADMSG + */ + if ((err & JRSTA_CCBERR_ERRID_MASK) == JRSTA_CCBERR_ERRID_ICVCHK) + err = -EBADMSG; + +#ifdef DEBUG + print_hex_dump(KERN_ERR, "iphdrout@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, + ((char *)sg_virt(areq->assoc) - sizeof(struct iphdr)), + sizeof(struct iphdr) + areq->assoclen + + ((areq->cryptlen > 1500) ? 1500 : areq->cryptlen) + + ctx->authsize + 36, 1); + if (!err && edesc->link_tbl_bytes) { + struct scatterlist *sg = sg_last(areq->src, edesc->src_nents); + print_hex_dump(KERN_ERR, "sglastout@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(sg), + sg->length + ctx->authsize + 16, 1); + } +#endif + kfree(edesc); + + aead_request_complete(areq, err); +} + +/* + * convert scatterlist to h/w link table format + * scatterlist must have been previously dma mapped + */ +static void sg_to_link_tbl(struct scatterlist *sg, int sg_count, + struct link_tbl_entry *link_tbl_ptr, u32 offset) +{ + while (sg_count) { + link_tbl_ptr->ptr = sg_dma_address(sg); + link_tbl_ptr->len = sg_dma_len(sg); + link_tbl_ptr->reserved = 0; + link_tbl_ptr->buf_pool_id = 0; + link_tbl_ptr->offset = offset; + link_tbl_ptr++; + sg = sg_next(sg); + sg_count--; + } + + /* set Final bit (marks end of link table) */ + link_tbl_ptr--; + link_tbl_ptr->len |= 0x40000000; +} + +/* + * fill in and submit ipsec_esp job descriptor + */ +static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, + u32 encrypt, + void (*callback) (struct device *dev, u32 *desc, + u32 err, void *context)) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + u32 *desc = edesc->hw_desc, options; + int ret, sg_count, assoc_sg_count; + int ivsize = crypto_aead_ivsize(aead); + int authsize = ctx->authsize; + dma_addr_t ptr, dst_dma, src_dma; +#ifdef DEBUG + u32 *sh_desc = ctx->sh_desc; + + debug("assoclen %d cryptlen %d authsize %d\n", + areq->assoclen, areq->cryptlen, authsize); + print_hex_dump(KERN_ERR, "assoc @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->assoc), + areq->assoclen , 1); + print_hex_dump(KERN_ERR, "presciv@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src) - ivsize, + edesc->src_nents ? 100 : ivsize, 1); + print_hex_dump(KERN_ERR, "src @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src), + edesc->src_nents ? 100 : areq->cryptlen + authsize, 1); + print_hex_dump(KERN_ERR, "shrdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sh_desc, + desc_bytes(sh_desc), 1); +#endif + assoc_sg_count = dma_map_sg(jrdev, areq->assoc, edesc->assoc_nents ?: 1, + DMA_TO_DEVICE); + if (areq->src == areq->dst) + sg_count = dma_map_sg(jrdev, areq->src, edesc->src_nents ? : 1, + DMA_BIDIRECTIONAL); + else + sg_count = dma_map_sg(jrdev, areq->src, edesc->src_nents ? : 1, + DMA_TO_DEVICE); + + /* start auth operation */ + append_operation(desc, ctx->class2_alg_type | OP_ALG_AS_INITFINAL | + (encrypt ? : OP_ALG_ICV_ON)); + + /* Load FIFO with data for Class 2 CHA */ + options = FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG; + if (!edesc->assoc_nents) { + ptr = sg_dma_address(areq->assoc); + } else { + sg_to_link_tbl(areq->assoc, edesc->assoc_nents, + edesc->link_tbl, 0); + ptr = edesc->link_tbl_dma; + options |= LDST_SGF; + } + append_fifo_load(desc, ptr, areq->assoclen, options); + + /* copy iv from cipher/class1 input context to class2 infifo */ + append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | ivsize); + + if (!encrypt) { + u32 *jump_cmd, *uncond_jump_cmd; + + /* JUMP if shared */ + jump_cmd = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD); + + /* start class 1 (cipher) operation, non-shared version */ + append_operation(desc, ctx->class1_alg_type | + OP_ALG_AS_INITFINAL); + + uncond_jump_cmd = append_jump(desc, 0); + + set_jump_tgt_here(desc, jump_cmd); + + /* start class 1 (cipher) operation, shared version */ + append_operation(desc, ctx->class1_alg_type | + OP_ALG_AS_INITFINAL | OP_ALG_AAI_DK); + set_jump_tgt_here(desc, uncond_jump_cmd); + } else + append_operation(desc, ctx->class1_alg_type | + OP_ALG_AS_INITFINAL | encrypt); + + /* load payload & instruct to class2 to snoop class 1 if encrypting */ + options = 0; + if (!edesc->src_nents) { + src_dma = sg_dma_address(areq->src); + } else { + sg_to_link_tbl(areq->src, edesc->src_nents, edesc->link_tbl + + edesc->assoc_nents, 0); + src_dma = edesc->link_tbl_dma + edesc->assoc_nents * + sizeof(struct link_tbl_entry); + options |= LDST_SGF; + } + append_seq_in_ptr(desc, src_dma, areq->cryptlen + authsize, options); + append_seq_fifo_load(desc, areq->cryptlen, FIFOLD_CLASS_BOTH | + FIFOLD_TYPE_LASTBOTH | + (encrypt ? FIFOLD_TYPE_MSG1OUT2 + : FIFOLD_TYPE_MSG)); + + /* specify destination */ + if (areq->src == areq->dst) { + dst_dma = src_dma; + } else { + sg_count = dma_map_sg(jrdev, areq->dst, edesc->dst_nents ? : 1, + DMA_FROM_DEVICE); + if (!edesc->dst_nents) { + dst_dma = sg_dma_address(areq->dst); + options = 0; + } else { + sg_to_link_tbl(areq->dst, edesc->dst_nents, + edesc->link_tbl + edesc->assoc_nents + + edesc->src_nents, 0); + dst_dma = edesc->link_tbl_dma + (edesc->assoc_nents + + edesc->src_nents) * + sizeof(struct link_tbl_entry); + options = LDST_SGF; + } + } + append_seq_out_ptr(desc, dst_dma, areq->cryptlen + authsize, options); + append_seq_fifo_store(desc, areq->cryptlen, FIFOST_TYPE_MESSAGE_DATA); + + /* ICV */ + if (encrypt) + append_seq_store(desc, authsize, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); + else + append_seq_fifo_load(desc, authsize, FIFOLD_CLASS_CLASS2 | + FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); + +#ifdef DEBUG + debug("job_desc_len %d\n", desc_len(desc)); + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc) , 1); + print_hex_dump(KERN_ERR, "jdlinkt@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->link_tbl, + edesc->link_tbl_bytes, 1); +#endif + + ret = caam_jr_enqueue(jrdev, desc, callback, areq); + if (!ret) + ret = -EINPROGRESS; + else { + ipsec_esp_unmap(jrdev, edesc, areq); + kfree(edesc); + } + + return ret; +} + +/* + * derive number of elements in scatterlist + */ +static int sg_count(struct scatterlist *sg_list, int nbytes, int *chained) +{ + struct scatterlist *sg = sg_list; + int sg_nents = 0; + + *chained = 0; + while (nbytes > 0) { + sg_nents++; + nbytes -= sg->length; + if (!sg_is_last(sg) && (sg + 1)->length == 0) + *chained = 1; + sg = scatterwalk_sg_next(sg); + } + + return sg_nents; +} + +/* + * allocate and map the ipsec_esp extended descriptor + */ +static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq, + int desc_bytes) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + gfp_t flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : + GFP_ATOMIC; + int assoc_nents, src_nents, dst_nents = 0, chained, link_tbl_bytes; + struct ipsec_esp_edesc *edesc; + + assoc_nents = sg_count(areq->assoc, areq->assoclen, &chained); + BUG_ON(chained); + if (likely(assoc_nents == 1)) + assoc_nents = 0; + + src_nents = sg_count(areq->src, areq->cryptlen + ctx->authsize, + &chained); + BUG_ON(chained); + if (src_nents == 1) + src_nents = 0; + + if (unlikely(areq->dst != areq->src)) { + dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize, + &chained); + BUG_ON(chained); + if (dst_nents == 1) + dst_nents = 0; + } + + link_tbl_bytes = (assoc_nents + src_nents + dst_nents) * + sizeof(struct link_tbl_entry); + debug("link_tbl_bytes %d\n", link_tbl_bytes); + + /* allocate space for base edesc and hw desc commands, link tables */ + edesc = kmalloc(sizeof(struct ipsec_esp_edesc) + desc_bytes + + link_tbl_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); + return ERR_PTR(-ENOMEM); + } + + edesc->assoc_nents = assoc_nents; + edesc->src_nents = src_nents; + edesc->dst_nents = dst_nents; + edesc->link_tbl = (void *)edesc + sizeof(struct ipsec_esp_edesc) + + desc_bytes; + edesc->link_tbl_dma = dma_map_single(jrdev, edesc->link_tbl, + link_tbl_bytes, DMA_TO_DEVICE); + edesc->link_tbl_bytes = link_tbl_bytes; + + return edesc; +} + +static int aead_authenc_encrypt(struct aead_request *areq) +{ + struct ipsec_esp_edesc *edesc; + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + int ivsize = crypto_aead_ivsize(aead); + u32 *desc; + dma_addr_t iv_dma; + + /* allocate extended descriptor */ + edesc = ipsec_esp_edesc_alloc(areq, DESC_AEAD_ENCRYPT_TEXT_LEN * + CAAM_CMD_SZ); + if (IS_ERR(edesc)) + return PTR_ERR(edesc); + + desc = edesc->hw_desc; + + /* insert shared descriptor pointer */ + init_job_desc_shared(desc, ctx->shared_desc_phys, + desc_len(ctx->sh_desc), HDR_SHARE_DEFER); + + iv_dma = dma_map_single(jrdev, areq->iv, ivsize, DMA_TO_DEVICE); + /* check dma error */ + + append_load(desc, iv_dma, ivsize, + LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT); + + return ipsec_esp(edesc, areq, OP_ALG_ENCRYPT, ipsec_esp_encrypt_done); +} + +static int aead_authenc_decrypt(struct aead_request *req) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + int ivsize = crypto_aead_ivsize(aead); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + struct ipsec_esp_edesc *edesc; + u32 *desc; + dma_addr_t iv_dma; + + req->cryptlen -= ctx->authsize; + + /* allocate extended descriptor */ + edesc = ipsec_esp_edesc_alloc(req, DESC_AEAD_DECRYPT_TEXT_LEN * + CAAM_CMD_SZ); + if (IS_ERR(edesc)) + return PTR_ERR(edesc); + + desc = edesc->hw_desc; + + /* insert shared descriptor pointer */ + init_job_desc_shared(desc, ctx->shared_desc_phys, + desc_len(ctx->sh_desc), HDR_SHARE_DEFER); + + iv_dma = dma_map_single(jrdev, req->iv, ivsize, DMA_TO_DEVICE); + /* check dma error */ + + append_load(desc, iv_dma, ivsize, + LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT); + + return ipsec_esp(edesc, req, !OP_ALG_ENCRYPT, ipsec_esp_decrypt_done); +} + +static int aead_authenc_givencrypt(struct aead_givcrypt_request *req) +{ + struct aead_request *areq = &req->areq; + struct ipsec_esp_edesc *edesc; + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + int ivsize = crypto_aead_ivsize(aead); + dma_addr_t iv_dma; + u32 *desc; + + iv_dma = dma_map_single(jrdev, req->giv, ivsize, DMA_FROM_DEVICE); + + debug("%s: giv %p\n", __func__, req->giv); + + /* allocate extended descriptor */ + edesc = ipsec_esp_edesc_alloc(areq, DESC_AEAD_GIVENCRYPT_TEXT_LEN * + CAAM_CMD_SZ); + if (IS_ERR(edesc)) + return PTR_ERR(edesc); + + desc = edesc->hw_desc; + + /* insert shared descriptor pointer */ + init_job_desc_shared(desc, ctx->shared_desc_phys, + desc_len(ctx->sh_desc), HDR_SHARE_DEFER); + + /* + * LOAD IMM Info FIFO + * to DECO, Last, Padding, Random, Message, 16 bytes + */ + append_load_imm_u32(desc, NFIFOENTRY_DEST_DECO | NFIFOENTRY_LC1 | + NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DTYPE_MSG | + NFIFOENTRY_PTYPE_RND | ivsize, + LDST_SRCDST_WORD_INFO_FIFO); + + /* + * disable info fifo entries since the above serves as the entry + * this way, the MOVE command won't generate an entry. + * Note that this isn't required in more recent versions of + * SEC as a MOVE that doesn't do info FIFO entries is available. + */ + append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); + + /* MOVE DECO Alignment -> C1 Context 16 bytes */ + append_move(desc, MOVE_SRC_INFIFO | MOVE_DEST_CLASS1CTX | ivsize); + + /* re-enable info fifo entries */ + append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); + + /* MOVE C1 Context -> OFIFO 16 bytes */ + append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_OUTFIFO | ivsize); + + append_fifo_store(desc, iv_dma, ivsize, FIFOST_TYPE_MESSAGE_DATA); + + return ipsec_esp(edesc, areq, OP_ALG_ENCRYPT, ipsec_esp_encrypt_done); +} + +struct caam_alg_template { + char name[CRYPTO_MAX_ALG_NAME]; + char driver_name[CRYPTO_MAX_ALG_NAME]; + unsigned int blocksize; + struct aead_alg aead; + u32 class1_alg_type; + u32 class2_alg_type; + u32 alg_op; +}; + +static struct caam_alg_template driver_algs[] = { + /* single-pass ipsec_esp descriptor */ + { + .name = "authenc(hmac(sha1),cbc(aes))", + .driver_name = "authenc-hmac-sha1-cbc-aes-caam", + .blocksize = AES_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha256),cbc(aes))", + .driver_name = "authenc-hmac-sha256-cbc-aes-caam", + .blocksize = AES_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha512),cbc(aes))", + .driver_name = "authenc-hmac-sha512-cbc-aes-caam", + .blocksize = AES_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha1),cbc(des3_ede))", + .driver_name = "authenc-hmac-sha1-cbc-des3_ede-caam", + .blocksize = DES3_EDE_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha256),cbc(des3_ede))", + .driver_name = "authenc-hmac-sha256-cbc-des3_ede-caam", + .blocksize = DES3_EDE_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha512),cbc(des3_ede))", + .driver_name = "authenc-hmac-sha512-cbc-des3_ede-caam", + .blocksize = DES3_EDE_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha1),cbc(des))", + .driver_name = "authenc-hmac-sha1-cbc-des-caam", + .blocksize = DES_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha256),cbc(des))", + .driver_name = "authenc-hmac-sha256-cbc-des-caam", + .blocksize = DES_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha512),cbc(des))", + .driver_name = "authenc-hmac-sha512-cbc-des-caam", + .blocksize = DES_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, +}; + +struct caam_crypto_alg { + struct list_head entry; + struct device *ctrldev; + int class1_alg_type; + int class2_alg_type; + int alg_op; + struct crypto_alg crypto_alg; +}; + +static int caam_cra_init(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg = tfm->__crt_alg; + struct caam_crypto_alg *caam_alg = + container_of(alg, struct caam_crypto_alg, crypto_alg); + struct caam_ctx *ctx = crypto_tfm_ctx(tfm); + struct caam_drv_private *priv = dev_get_drvdata(caam_alg->ctrldev); + int tgt_jr = atomic_inc_return(&priv->tfm_count); + + /* + * distribute tfms across job rings to ensure in-order + * crypto request processing per tfm + */ + ctx->jrdev = priv->algapi_jr[(tgt_jr / 2) % priv->num_jrs_for_algapi]; + + /* copy descriptor header template value */ + ctx->class1_alg_type = OP_TYPE_CLASS1_ALG | caam_alg->class1_alg_type; + ctx->class2_alg_type = OP_TYPE_CLASS2_ALG | caam_alg->class2_alg_type; + ctx->alg_op = OP_TYPE_CLASS2_ALG | caam_alg->alg_op; + + return 0; +} + +static void caam_cra_exit(struct crypto_tfm *tfm) +{ + struct caam_ctx *ctx = crypto_tfm_ctx(tfm); + + if (!dma_mapping_error(ctx->jrdev, ctx->shared_desc_phys)) + dma_unmap_single(ctx->jrdev, ctx->shared_desc_phys, + desc_bytes(ctx->sh_desc), DMA_TO_DEVICE); + kfree(ctx->sh_desc); + + if (!dma_mapping_error(ctx->jrdev, ctx->key_phys)) + dma_unmap_single(ctx->jrdev, ctx->key_phys, + ctx->split_key_pad_len + ctx->enckeylen, + DMA_TO_DEVICE); + kfree(ctx->key); +} + +static void __exit caam_algapi_exit(void) +{ + + struct device_node *dev_node; + struct platform_device *pdev; + struct device *ctrldev; + struct caam_drv_private *priv; + struct caam_crypto_alg *t_alg, *n; + int i, err; + + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); + if (!dev_node) + return; + + pdev = of_find_device_by_node(dev_node); + if (!pdev) + return; + + ctrldev = &pdev->dev; + of_node_put(dev_node); + priv = dev_get_drvdata(ctrldev); + + if (!priv->alg_list.next) + return; + + list_for_each_entry_safe(t_alg, n, &priv->alg_list, entry) { + crypto_unregister_alg(&t_alg->crypto_alg); + list_del(&t_alg->entry); + kfree(t_alg); + } + + for (i = 0; i < priv->total_jobrs; i++) { + err = caam_jr_deregister(priv->algapi_jr[i]); + if (err < 0) + break; + } + kfree(priv->algapi_jr); +} + +static struct caam_crypto_alg *caam_alg_alloc(struct device *ctrldev, + struct caam_alg_template + *template) +{ + struct caam_crypto_alg *t_alg; + struct crypto_alg *alg; + + t_alg = kzalloc(sizeof(struct caam_crypto_alg), GFP_KERNEL); + if (!t_alg) { + dev_err(ctrldev, "failed to allocate t_alg\n"); + return ERR_PTR(-ENOMEM); + } + + alg = &t_alg->crypto_alg; + + snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name); + snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", + template->driver_name); + alg->cra_module = THIS_MODULE; + alg->cra_init = caam_cra_init; + alg->cra_exit = caam_cra_exit; + alg->cra_priority = CAAM_CRA_PRIORITY; + alg->cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC; + alg->cra_blocksize = template->blocksize; + alg->cra_alignmask = 0; + alg->cra_type = &crypto_aead_type; + alg->cra_ctxsize = sizeof(struct caam_ctx); + alg->cra_u.aead = template->aead; + + t_alg->class1_alg_type = template->class1_alg_type; + t_alg->class2_alg_type = template->class2_alg_type; + t_alg->alg_op = template->alg_op; + t_alg->ctrldev = ctrldev; + + return t_alg; +} + +static int __init caam_algapi_init(void) +{ + struct device_node *dev_node; + struct platform_device *pdev; + struct device *ctrldev, **jrdev; + struct caam_drv_private *priv; + int i = 0, err = 0; + + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); + if (!dev_node) + return -ENODEV; + + pdev = of_find_device_by_node(dev_node); + if (!pdev) + return -ENODEV; + + ctrldev = &pdev->dev; + priv = dev_get_drvdata(ctrldev); + of_node_put(dev_node); + + INIT_LIST_HEAD(&priv->alg_list); + + jrdev = kmalloc(sizeof(*jrdev) * priv->total_jobrs, GFP_KERNEL); + if (!jrdev) + return -ENOMEM; + + for (i = 0; i < priv->total_jobrs; i++) { + err = caam_jr_register(ctrldev, &jrdev[i]); + if (err < 0) + break; + } + if (err < 0 && i == 0) { + dev_err(ctrldev, "algapi error in job ring registration: %d\n", + err); + kfree(jrdev); + return err; + } + + priv->num_jrs_for_algapi = i; + priv->algapi_jr = jrdev; + atomic_set(&priv->tfm_count, -1); + + /* register crypto algorithms the device supports */ + for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { + /* TODO: check if h/w supports alg */ + struct caam_crypto_alg *t_alg; + + t_alg = caam_alg_alloc(ctrldev, &driver_algs[i]); + if (IS_ERR(t_alg)) { + err = PTR_ERR(t_alg); + dev_warn(ctrldev, "%s alg allocation failed\n", + driver_algs[i].driver_name); + continue; + } + + err = crypto_register_alg(&t_alg->crypto_alg); + if (err) { + dev_warn(ctrldev, "%s alg registration failed\n", + t_alg->crypto_alg.cra_driver_name); + kfree(t_alg); + } else { + list_add_tail(&t_alg->entry, &priv->alg_list); + dev_info(ctrldev, "%s\n", + t_alg->crypto_alg.cra_driver_name); + } + } + + return err; +} + +module_init(caam_algapi_init); +module_exit(caam_algapi_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("FSL CAAM support for crypto API"); +MODULE_AUTHOR("Freescale Semiconductor - NMG/STC"); diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h new file mode 100644 index 000000000000..950450346f70 --- /dev/null +++ b/drivers/crypto/caam/compat.h @@ -0,0 +1,35 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#ifndef CAAM_COMPAT_H +#define CAAM_COMPAT_H + +#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 + +#endif /* !defined(CAAM_COMPAT_H) */ diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c new file mode 100644 index 000000000000..9009713a3c2e --- /dev/null +++ b/drivers/crypto/caam/ctrl.c @@ -0,0 +1,269 @@ +/* + * CAAM control-plane driver backend + * Controller-level driver, kernel property detection, initialization + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#include "compat.h" +#include "regs.h" +#include "intern.h" +#include "jr.h" + +static int caam_remove(struct platform_device *pdev) +{ + struct device *ctrldev; + struct caam_drv_private *ctrlpriv; + struct caam_drv_private_jr *jrpriv; + struct caam_full __iomem *topregs; + int ring, ret = 0; + + ctrldev = &pdev->dev; + ctrlpriv = dev_get_drvdata(ctrldev); + topregs = (struct caam_full __iomem *)ctrlpriv->ctrl; + + /* shut down JobRs */ + for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) { + ret |= caam_jr_shutdown(ctrlpriv->jrdev[ring]); + jrpriv = dev_get_drvdata(ctrlpriv->jrdev[ring]); + irq_dispose_mapping(jrpriv->irq); + } + + /* Shut down debug views */ +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(ctrlpriv->dfs_root); +#endif + + /* Unmap controller region */ + iounmap(&topregs->ctrl); + + kfree(ctrlpriv->jrdev); + kfree(ctrlpriv); + + return ret; +} + +/* Probe routine for CAAM top (controller) level */ +static int caam_probe(struct platform_device *pdev) +{ + int d, ring, rspec; + struct device *dev; + struct device_node *nprop, *np; + struct caam_ctrl __iomem *ctrl; + struct caam_full __iomem *topregs; + struct caam_drv_private *ctrlpriv; + struct caam_perfmon *perfmon; + struct caam_deco **deco; + u32 deconum; + + ctrlpriv = kzalloc(sizeof(struct caam_drv_private), GFP_KERNEL); + if (!ctrlpriv) + return -ENOMEM; + + dev = &pdev->dev; + dev_set_drvdata(dev, ctrlpriv); + ctrlpriv->pdev = pdev; + nprop = pdev->dev.of_node; + + /* Get configuration properties from device tree */ + /* First, get register page */ + ctrl = of_iomap(nprop, 0); + if (ctrl == NULL) { + dev_err(dev, "caam: of_iomap() failed\n"); + return -ENOMEM; + } + ctrlpriv->ctrl = (struct caam_ctrl __force *)ctrl; + + /* topregs used to derive pointers to CAAM sub-blocks only */ + topregs = (struct caam_full __iomem *)ctrl; + + /* Get the IRQ of the controller (for security violations only) */ + ctrlpriv->secvio_irq = of_irq_to_resource(nprop, 0, NULL); + + /* + * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, + * 36-bit pointers in master configuration register + */ + setbits32(&topregs->ctrl.mcr, MCFGR_WDENABLE | + (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0)); + + if (sizeof(dma_addr_t) == sizeof(u64)) + dma_set_mask(dev, DMA_BIT_MASK(36)); + + /* Find out how many DECOs are present */ + deconum = (rd_reg64(&topregs->ctrl.perfmon.cha_num) & + CHA_NUM_DECONUM_MASK) >> CHA_NUM_DECONUM_SHIFT; + + ctrlpriv->deco = kmalloc(deconum * sizeof(struct caam_deco *), + GFP_KERNEL); + + deco = (struct caam_deco __force **)&topregs->deco; + for (d = 0; d < deconum; d++) + ctrlpriv->deco[d] = deco[d]; + + /* + * Detect and enable JobRs + * First, find out how many ring spec'ed, allocate references + * for all, then go probe each one. + */ + rspec = 0; + for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring") + rspec++; + ctrlpriv->jrdev = kzalloc(sizeof(struct device *) * rspec, GFP_KERNEL); + if (ctrlpriv->jrdev == NULL) { + iounmap(&topregs->ctrl); + return -ENOMEM; + } + + ring = 0; + ctrlpriv->total_jobrs = 0; + for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring") { + caam_jr_probe(pdev, np, ring); + ctrlpriv->total_jobrs++; + ring++; + } + + /* Check to see if QI present. If so, enable */ + ctrlpriv->qi_present = !!(rd_reg64(&topregs->ctrl.perfmon.comp_parms) & + CTPR_QI_MASK); + if (ctrlpriv->qi_present) { + ctrlpriv->qi = (struct caam_queue_if __force *)&topregs->qi; + /* This is all that's required to physically enable QI */ + wr_reg32(&topregs->qi.qi_control_lo, QICTL_DQEN); + } + + /* If no QI and no rings specified, quit and go home */ + if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) { + dev_err(dev, "no queues configured, terminating\n"); + caam_remove(pdev); + return -ENOMEM; + } + + /* NOTE: RTIC detection ought to go here, around Si time */ + + /* Initialize queue allocator lock */ + spin_lock_init(&ctrlpriv->jr_alloc_lock); + + /* Report "alive" for developer to see */ + dev_info(dev, "device ID = 0x%016llx\n", + rd_reg64(&topregs->ctrl.perfmon.caam_id)); + dev_info(dev, "job rings = %d, qi = %d\n", + ctrlpriv->total_jobrs, ctrlpriv->qi_present); + +#ifdef CONFIG_DEBUG_FS + /* + * FIXME: needs better naming distinction, as some amalgamation of + * "caam" and nprop->full_name. The OF name isn't distinctive, + * but does separate instances + */ + perfmon = (struct caam_perfmon __force *)&ctrl->perfmon; + + ctrlpriv->dfs_root = debugfs_create_dir("caam", NULL); + ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root); + + /* Controller-level - performance monitor counters */ + ctrlpriv->ctl_rq_dequeued = + debugfs_create_u64("rq_dequeued", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->req_dequeued); + ctrlpriv->ctl_ob_enc_req = + debugfs_create_u64("ob_rq_encrypted", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->ob_enc_req); + ctrlpriv->ctl_ib_dec_req = + debugfs_create_u64("ib_rq_decrypted", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->ib_dec_req); + ctrlpriv->ctl_ob_enc_bytes = + debugfs_create_u64("ob_bytes_encrypted", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->ob_enc_bytes); + ctrlpriv->ctl_ob_prot_bytes = + debugfs_create_u64("ob_bytes_protected", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->ob_prot_bytes); + ctrlpriv->ctl_ib_dec_bytes = + debugfs_create_u64("ib_bytes_decrypted", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->ib_dec_bytes); + ctrlpriv->ctl_ib_valid_bytes = + debugfs_create_u64("ib_bytes_validated", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->ib_valid_bytes); + + /* Controller level - global status values */ + ctrlpriv->ctl_faultaddr = + debugfs_create_u64("fault_addr", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->faultaddr); + ctrlpriv->ctl_faultdetail = + debugfs_create_u32("fault_detail", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->faultdetail); + ctrlpriv->ctl_faultstatus = + debugfs_create_u32("fault_status", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->status); + + /* Internal covering keys (useful in non-secure mode only) */ + ctrlpriv->ctl_kek_wrap.data = &ctrlpriv->ctrl->kek[0]; + ctrlpriv->ctl_kek_wrap.size = KEK_KEY_SIZE * sizeof(u32); + ctrlpriv->ctl_kek = debugfs_create_blob("kek", + S_IFCHR | S_IRUSR | + S_IRGRP | S_IROTH, + ctrlpriv->ctl, + &ctrlpriv->ctl_kek_wrap); + + ctrlpriv->ctl_tkek_wrap.data = &ctrlpriv->ctrl->tkek[0]; + ctrlpriv->ctl_tkek_wrap.size = KEK_KEY_SIZE * sizeof(u32); + ctrlpriv->ctl_tkek = debugfs_create_blob("tkek", + S_IFCHR | S_IRUSR | + S_IRGRP | S_IROTH, + ctrlpriv->ctl, + &ctrlpriv->ctl_tkek_wrap); + + ctrlpriv->ctl_tdsk_wrap.data = &ctrlpriv->ctrl->tdsk[0]; + ctrlpriv->ctl_tdsk_wrap.size = KEK_KEY_SIZE * sizeof(u32); + ctrlpriv->ctl_tdsk = debugfs_create_blob("tdsk", + S_IFCHR | S_IRUSR | + S_IRGRP | S_IROTH, + ctrlpriv->ctl, + &ctrlpriv->ctl_tdsk_wrap); +#endif + return 0; +} + +static struct of_device_id caam_match[] = { + { + .compatible = "fsl,sec-v4.0", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, caam_match); + +static struct platform_driver caam_driver = { + .driver = { + .name = "caam", + .owner = THIS_MODULE, + .of_match_table = caam_match, + }, + .probe = caam_probe, + .remove = __devexit_p(caam_remove), +}; + +static int __init caam_base_init(void) +{ + return platform_driver_register(&caam_driver); +} + +static void __exit caam_base_exit(void) +{ + return platform_driver_unregister(&caam_driver); +} + +module_init(caam_base_init); +module_exit(caam_base_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("FSL CAAM request backend"); +MODULE_AUTHOR("Freescale Semiconductor - NMG/STC"); diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h new file mode 100644 index 000000000000..974a75842da9 --- /dev/null +++ b/drivers/crypto/caam/desc.h @@ -0,0 +1,1605 @@ +/* + * CAAM descriptor composition header + * Definitions to support CAAM descriptor instruction generation + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#ifndef DESC_H +#define DESC_H + +/* Max size of any CAAM descriptor in 32-bit words, inclusive of header */ +#define MAX_CAAM_DESCSIZE 64 + +/* Block size of any entity covered/uncovered with a KEK/TKEK */ +#define KEK_BLOCKSIZE 16 + +/* + * Supported descriptor command types as they show up + * inside a descriptor command word. + */ +#define CMD_SHIFT 27 +#define CMD_MASK 0xf8000000 + +#define CMD_KEY (0x00 << CMD_SHIFT) +#define CMD_SEQ_KEY (0x01 << CMD_SHIFT) +#define CMD_LOAD (0x02 << CMD_SHIFT) +#define CMD_SEQ_LOAD (0x03 << CMD_SHIFT) +#define CMD_FIFO_LOAD (0x04 << CMD_SHIFT) +#define CMD_SEQ_FIFO_LOAD (0x05 << CMD_SHIFT) +#define CMD_STORE (0x0a << CMD_SHIFT) +#define CMD_SEQ_STORE (0x0b << CMD_SHIFT) +#define CMD_FIFO_STORE (0x0c << CMD_SHIFT) +#define CMD_SEQ_FIFO_STORE (0x0d << CMD_SHIFT) +#define CMD_MOVE_LEN (0x0e << CMD_SHIFT) +#define CMD_MOVE (0x0f << CMD_SHIFT) +#define CMD_OPERATION (0x10 << CMD_SHIFT) +#define CMD_SIGNATURE (0x12 << CMD_SHIFT) +#define CMD_JUMP (0x14 << CMD_SHIFT) +#define CMD_MATH (0x15 << CMD_SHIFT) +#define CMD_DESC_HDR (0x16 << CMD_SHIFT) +#define CMD_SHARED_DESC_HDR (0x17 << CMD_SHIFT) +#define CMD_SEQ_IN_PTR (0x1e << CMD_SHIFT) +#define CMD_SEQ_OUT_PTR (0x1f << CMD_SHIFT) + +/* General-purpose class selector for all commands */ +#define CLASS_SHIFT 25 +#define CLASS_MASK (0x03 << CLASS_SHIFT) + +#define CLASS_NONE (0x00 << CLASS_SHIFT) +#define CLASS_1 (0x01 << CLASS_SHIFT) +#define CLASS_2 (0x02 << CLASS_SHIFT) +#define CLASS_BOTH (0x03 << CLASS_SHIFT) + +/* + * Descriptor header command constructs + * Covers shared, job, and trusted descriptor headers + */ + +/* + * Do Not Run - marks a descriptor inexecutable if there was + * a preceding error somewhere + */ +#define HDR_DNR 0x01000000 + +/* + * ONE - should always be set. Combination of ONE (always + * set) and ZRO (always clear) forms an endianness sanity check + */ +#define HDR_ONE 0x00800000 +#define HDR_ZRO 0x00008000 + +/* Start Index or SharedDesc Length */ +#define HDR_START_IDX_MASK 0x3f +#define HDR_START_IDX_SHIFT 16 + +/* If shared descriptor header, 6-bit length */ +#define HDR_DESCLEN_SHR_MASK 0x3f + +/* If non-shared header, 7-bit length */ +#define HDR_DESCLEN_MASK 0x7f + +/* This is a TrustedDesc (if not SharedDesc) */ +#define HDR_TRUSTED 0x00004000 + +/* Make into TrustedDesc (if not SharedDesc) */ +#define HDR_MAKE_TRUSTED 0x00002000 + +/* Save context if self-shared (if SharedDesc) */ +#define HDR_SAVECTX 0x00001000 + +/* Next item points to SharedDesc */ +#define HDR_SHARED 0x00001000 + +/* + * Reverse Execution Order - execute JobDesc first, then + * execute SharedDesc (normally SharedDesc goes first). + */ +#define HDR_REVERSE 0x00000800 + +/* Propogate DNR property to SharedDesc */ +#define HDR_PROP_DNR 0x00000800 + +/* JobDesc/SharedDesc share property */ +#define HDR_SD_SHARE_MASK 0x03 +#define HDR_SD_SHARE_SHIFT 8 +#define HDR_JD_SHARE_MASK 0x07 +#define HDR_JD_SHARE_SHIFT 8 + +#define HDR_SHARE_NEVER (0x00 << HDR_SD_SHARE_SHIFT) +#define HDR_SHARE_WAIT (0x01 << HDR_SD_SHARE_SHIFT) +#define HDR_SHARE_SERIAL (0x02 << HDR_SD_SHARE_SHIFT) +#define HDR_SHARE_ALWAYS (0x03 << HDR_SD_SHARE_SHIFT) +#define HDR_SHARE_DEFER (0x04 << HDR_SD_SHARE_SHIFT) + +/* JobDesc/SharedDesc descriptor length */ +#define HDR_JD_LENGTH_MASK 0x7f +#define HDR_SD_LENGTH_MASK 0x3f + +/* + * KEY/SEQ_KEY Command Constructs + */ + +/* Key Destination Class: 01 = Class 1, 02 - Class 2 */ +#define KEY_DEST_CLASS_SHIFT 25 /* use CLASS_1 or CLASS_2 */ +#define KEY_DEST_CLASS_MASK (0x03 << KEY_DEST_CLASS_SHIFT) + +/* Scatter-Gather Table/Variable Length Field */ +#define KEY_SGF 0x01000000 +#define KEY_VLF 0x01000000 + +/* Immediate - Key follows command in the descriptor */ +#define KEY_IMM 0x00800000 + +/* + * Encrypted - Key is encrypted either with the KEK, or + * with the TDKEK if TK is set + */ +#define KEY_ENC 0x00400000 + +/* + * No Write Back - Do not allow key to be FIFO STOREd + */ +#define KEY_NWB 0x00200000 + +/* + * Enhanced Encryption of Key + */ +#define KEY_EKT 0x00100000 + +/* + * Encrypted with Trusted Key + */ +#define KEY_TK 0x00008000 + +/* + * KDEST - Key Destination: 0 - class key register, + * 1 - PKHA 'e', 2 - AFHA Sbox, 3 - MDHA split-key + */ +#define KEY_DEST_SHIFT 16 +#define KEY_DEST_MASK (0x03 << KEY_DEST_SHIFT) + +#define KEY_DEST_CLASS_REG (0x00 << KEY_DEST_SHIFT) +#define KEY_DEST_PKHA_E (0x01 << KEY_DEST_SHIFT) +#define KEY_DEST_AFHA_SBOX (0x02 << KEY_DEST_SHIFT) +#define KEY_DEST_MDHA_SPLIT (0x03 << KEY_DEST_SHIFT) + +/* Length in bytes */ +#define KEY_LENGTH_MASK 0x000003ff + +/* + * LOAD/SEQ_LOAD/STORE/SEQ_STORE Command Constructs + */ + +/* + * Load/Store Destination: 0 = class independent CCB, + * 1 = class 1 CCB, 2 = class 2 CCB, 3 = DECO + */ +#define LDST_CLASS_SHIFT 25 +#define LDST_CLASS_MASK (0x03 << LDST_CLASS_SHIFT) +#define LDST_CLASS_IND_CCB (0x00 << LDST_CLASS_SHIFT) +#define LDST_CLASS_1_CCB (0x01 << LDST_CLASS_SHIFT) +#define LDST_CLASS_2_CCB (0x02 << LDST_CLASS_SHIFT) +#define LDST_CLASS_DECO (0x03 << LDST_CLASS_SHIFT) + +/* Scatter-Gather Table/Variable Length Field */ +#define LDST_SGF 0x01000000 +#define LDST_VLF LDST_SGF + +/* Immediate - Key follows this command in descriptor */ +#define LDST_IMM_MASK 1 +#define LDST_IMM_SHIFT 23 +#define LDST_IMM (LDST_IMM_MASK << LDST_IMM_SHIFT) + +/* SRC/DST - Destination for LOAD, Source for STORE */ +#define LDST_SRCDST_SHIFT 16 +#define LDST_SRCDST_MASK (0x7f << LDST_SRCDST_SHIFT) + +#define LDST_SRCDST_BYTE_CONTEXT (0x20 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_BYTE_KEY (0x40 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_BYTE_INFIFO (0x7c << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_BYTE_OUTFIFO (0x7e << LDST_SRCDST_SHIFT) + +#define LDST_SRCDST_WORD_MODE_REG (0x00 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_KEYSZ_REG (0x01 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DATASZ_REG (0x02 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_ICVSZ_REG (0x03 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_CHACTRL (0x06 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECOCTRL (0x06 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_IRQCTRL (0x07 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECO_PCLOVRD (0x07 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_CLRW (0x08 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECO_MATH0 (0x08 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_STAT (0x09 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECO_MATH1 (0x09 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECO_MATH2 (0x0a << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECO_AAD_SZ (0x0b << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECO_MATH3 (0x0b << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_CLASS1_ICV_SZ (0x0c << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_ALTDS_CLASS1 (0x0f << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_PKHA_A_SZ (0x10 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_PKHA_B_SZ (0x11 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_PKHA_N_SZ (0x12 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_PKHA_E_SZ (0x13 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DESCBUF (0x40 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_INFO_FIFO (0x7a << LDST_SRCDST_SHIFT) + +/* Offset in source/destination */ +#define LDST_OFFSET_SHIFT 8 +#define LDST_OFFSET_MASK (0xff << LDST_OFFSET_SHIFT) + +/* LDOFF definitions used when DST = LDST_SRCDST_WORD_DECOCTRL */ +/* These could also be shifted by LDST_OFFSET_SHIFT - this reads better */ +#define LDOFF_CHG_SHARE_SHIFT 0 +#define LDOFF_CHG_SHARE_MASK (0x3 << LDOFF_CHG_SHARE_SHIFT) +#define LDOFF_CHG_SHARE_NEVER (0x1 << LDOFF_CHG_SHARE_SHIFT) +#define LDOFF_CHG_SHARE_OK_NO_PROP (0x2 << LDOFF_CHG_SHARE_SHIFT) +#define LDOFF_CHG_SHARE_OK_PROP (0x3 << LDOFF_CHG_SHARE_SHIFT) + +#define LDOFF_ENABLE_AUTO_NFIFO (1 << 2) +#define LDOFF_DISABLE_AUTO_NFIFO (1 << 3) + +#define LDOFF_CHG_NONSEQLIODN_SHIFT 4 +#define LDOFF_CHG_NONSEQLIODN_MASK (0x3 << LDOFF_CHG_NONSEQLIODN_SHIFT) +#define LDOFF_CHG_NONSEQLIODN_SEQ (0x1 << LDOFF_CHG_NONSEQLIODN_SHIFT) +#define LDOFF_CHG_NONSEQLIODN_NON_SEQ (0x2 << LDOFF_CHG_NONSEQLIODN_SHIFT) +#define LDOFF_CHG_NONSEQLIODN_TRUSTED (0x3 << LDOFF_CHG_NONSEQLIODN_SHIFT) + +#define LDOFF_CHG_SEQLIODN_SHIFT 6 +#define LDOFF_CHG_SEQLIODN_MASK (0x3 << LDOFF_CHG_SEQLIODN_SHIFT) +#define LDOFF_CHG_SEQLIODN_SEQ (0x1 << LDOFF_CHG_SEQLIODN_SHIFT) +#define LDOFF_CHG_SEQLIODN_NON_SEQ (0x2 << LDOFF_CHG_SEQLIODN_SHIFT) +#define LDOFF_CHG_SEQLIODN_TRUSTED (0x3 << LDOFF_CHG_SEQLIODN_SHIFT) + +/* Data length in bytes */ +#define LDST_LEN_SHIFT 0 +#define LDST_LEN_MASK (0xff << LDST_LEN_SHIFT) + +/* Special Length definitions when dst=deco-ctrl */ +#define LDLEN_ENABLE_OSL_COUNT (1 << 7) +#define LDLEN_RST_CHA_OFIFO_PTR (1 << 6) +#define LDLEN_RST_OFIFO (1 << 5) +#define LDLEN_SET_OFIFO_OFF_VALID (1 << 4) +#define LDLEN_SET_OFIFO_OFF_RSVD (1 << 3) +#define LDLEN_SET_OFIFO_OFFSET_SHIFT 0 +#define LDLEN_SET_OFIFO_OFFSET_MASK (3 << LDLEN_SET_OFIFO_OFFSET_SHIFT) + +/* + * FIFO_LOAD/FIFO_STORE/SEQ_FIFO_LOAD/SEQ_FIFO_STORE + * Command Constructs + */ + +/* + * Load Destination: 0 = skip (SEQ_FIFO_LOAD only), + * 1 = Load for Class1, 2 = Load for Class2, 3 = Load both + * Store Source: 0 = normal, 1 = Class1key, 2 = Class2key + */ +#define FIFOLD_CLASS_SHIFT 25 +#define FIFOLD_CLASS_MASK (0x03 << FIFOLD_CLASS_SHIFT) +#define FIFOLD_CLASS_SKIP (0x00 << FIFOLD_CLASS_SHIFT) +#define FIFOLD_CLASS_CLASS1 (0x01 << FIFOLD_CLASS_SHIFT) +#define FIFOLD_CLASS_CLASS2 (0x02 << FIFOLD_CLASS_SHIFT) +#define FIFOLD_CLASS_BOTH (0x03 << FIFOLD_CLASS_SHIFT) + +#define FIFOST_CLASS_SHIFT 25 +#define FIFOST_CLASS_MASK (0x03 << FIFOST_CLASS_SHIFT) +#define FIFOST_CLASS_NORMAL (0x00 << FIFOST_CLASS_SHIFT) +#define FIFOST_CLASS_CLASS1KEY (0x01 << FIFOST_CLASS_SHIFT) +#define FIFOST_CLASS_CLASS2KEY (0x02 << FIFOST_CLASS_SHIFT) + +/* + * Scatter-Gather Table/Variable Length Field + * If set for FIFO_LOAD, refers to a SG table. Within + * SEQ_FIFO_LOAD, is variable input sequence + */ +#define FIFOLDST_SGF_SHIFT 24 +#define FIFOLDST_SGF_MASK (1 << FIFOLDST_SGF_SHIFT) +#define FIFOLDST_VLF_MASK (1 << FIFOLDST_SGF_SHIFT) +#define FIFOLDST_SGF (1 << FIFOLDST_SGF_SHIFT) +#define FIFOLDST_VLF (1 << FIFOLDST_SGF_SHIFT) + +/* Immediate - Data follows command in descriptor */ +#define FIFOLD_IMM_SHIFT 23 +#define FIFOLD_IMM_MASK (1 << FIFOLD_IMM_SHIFT) +#define FIFOLD_IMM (1 << FIFOLD_IMM_SHIFT) + +/* Continue - Not the last FIFO store to come */ +#define FIFOST_CONT_SHIFT 23 +#define FIFOST_CONT_MASK (1 << FIFOST_CONT_SHIFT) +#define FIFOST_CONT_MASK (1 << FIFOST_CONT_SHIFT) + +/* + * Extended Length - use 32-bit extended length that + * follows the pointer field. Illegal with IMM set + */ +#define FIFOLDST_EXT_SHIFT 22 +#define FIFOLDST_EXT_MASK (1 << FIFOLDST_EXT_SHIFT) +#define FIFOLDST_EXT (1 << FIFOLDST_EXT_SHIFT) + +/* Input data type.*/ +#define FIFOLD_TYPE_SHIFT 16 +#define FIFOLD_CONT_TYPE_SHIFT 19 /* shift past last-flush bits */ +#define FIFOLD_TYPE_MASK (0x3f << FIFOLD_TYPE_SHIFT) + +/* PK types */ +#define FIFOLD_TYPE_PK (0x00 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_MASK (0x30 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_TYPEMASK (0x0f << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_A0 (0x00 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_A1 (0x01 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_A2 (0x02 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_A3 (0x03 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_B0 (0x04 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_B1 (0x05 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_B2 (0x06 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_B3 (0x07 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_N (0x08 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_A (0x0c << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_B (0x0d << FIFOLD_TYPE_SHIFT) + +/* Other types. Need to OR in last/flush bits as desired */ +#define FIFOLD_TYPE_MSG_MASK (0x38 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_MSG (0x10 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_MSG1OUT2 (0x18 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_IV (0x20 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_BITDATA (0x28 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_AAD (0x30 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_ICV (0x38 << FIFOLD_TYPE_SHIFT) + +/* Last/Flush bits for use with "other" types above */ +#define FIFOLD_TYPE_ACT_MASK (0x07 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_NOACTION (0x00 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_FLUSH1 (0x01 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_LAST1 (0x02 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_LAST2FLUSH (0x03 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_LAST2 (0x04 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_LAST2FLUSH1 (0x05 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_LASTBOTH (0x06 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_LASTBOTHFL (0x07 << FIFOLD_TYPE_SHIFT) + +#define FIFOLDST_LEN_MASK 0xffff +#define FIFOLDST_EXT_LEN_MASK 0xffffffff + +/* Output data types */ +#define FIFOST_TYPE_SHIFT 16 +#define FIFOST_TYPE_MASK (0x3f << FIFOST_TYPE_SHIFT) + +#define FIFOST_TYPE_PKHA_A0 (0x00 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_A1 (0x01 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_A2 (0x02 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_A3 (0x03 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_B0 (0x04 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_B1 (0x05 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_B2 (0x06 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_B3 (0x07 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_N (0x08 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_A (0x0c << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_B (0x0d << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_AF_SBOX_JKEK (0x10 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_AF_SBOX_TKEK (0x21 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_E_JKEK (0x22 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_E_TKEK (0x23 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_KEY_KEK (0x24 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_KEY_TKEK (0x25 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_SPLIT_KEK (0x26 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_SPLIT_TKEK (0x27 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_OUTFIFO_KEK (0x28 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_OUTFIFO_TKEK (0x29 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_MESSAGE_DATA (0x30 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_RNGSTORE (0x34 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_RNGFIFO (0x35 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_SKIP (0x3f << FIFOST_TYPE_SHIFT) + +/* + * OPERATION Command Constructs + */ + +/* Operation type selectors - OP TYPE */ +#define OP_TYPE_SHIFT 24 +#define OP_TYPE_MASK (0x07 << OP_TYPE_SHIFT) + +#define OP_TYPE_UNI_PROTOCOL (0x00 << OP_TYPE_SHIFT) +#define OP_TYPE_PK (0x01 << OP_TYPE_SHIFT) +#define OP_TYPE_CLASS1_ALG (0x02 << OP_TYPE_SHIFT) +#define OP_TYPE_CLASS2_ALG (0x04 << OP_TYPE_SHIFT) +#define OP_TYPE_DECAP_PROTOCOL (0x06 << OP_TYPE_SHIFT) +#define OP_TYPE_ENCAP_PROTOCOL (0x07 << OP_TYPE_SHIFT) + +/* ProtocolID selectors - PROTID */ +#define OP_PCLID_SHIFT 16 +#define OP_PCLID_MASK (0xff << 16) + +/* Assuming OP_TYPE = OP_TYPE_UNI_PROTOCOL */ +#define OP_PCLID_IKEV1_PRF (0x01 << OP_PCLID_SHIFT) +#define OP_PCLID_IKEV2_PRF (0x02 << OP_PCLID_SHIFT) +#define OP_PCLID_SSL30_PRF (0x08 << OP_PCLID_SHIFT) +#define OP_PCLID_TLS10_PRF (0x09 << OP_PCLID_SHIFT) +#define OP_PCLID_TLS11_PRF (0x0a << OP_PCLID_SHIFT) +#define OP_PCLID_DTLS10_PRF (0x0c << OP_PCLID_SHIFT) +#define OP_PCLID_PRF (0x06 << OP_PCLID_SHIFT) +#define OP_PCLID_BLOB (0x0d << OP_PCLID_SHIFT) +#define OP_PCLID_SECRETKEY (0x11 << OP_PCLID_SHIFT) +#define OP_PCLID_PUBLICKEYPAIR (0x14 << OP_PCLID_SHIFT) +#define OP_PCLID_DSASIGN (0x15 << OP_PCLID_SHIFT) +#define OP_PCLID_DSAVERIFY (0x16 << OP_PCLID_SHIFT) + +/* Assuming OP_TYPE = OP_TYPE_DECAP_PROTOCOL/ENCAP_PROTOCOL */ +#define OP_PCLID_IPSEC (0x01 << OP_PCLID_SHIFT) +#define OP_PCLID_SRTP (0x02 << OP_PCLID_SHIFT) +#define OP_PCLID_MACSEC (0x03 << OP_PCLID_SHIFT) +#define OP_PCLID_WIFI (0x04 << OP_PCLID_SHIFT) +#define OP_PCLID_WIMAX (0x05 << OP_PCLID_SHIFT) +#define OP_PCLID_SSL30 (0x08 << OP_PCLID_SHIFT) +#define OP_PCLID_TLS10 (0x09 << OP_PCLID_SHIFT) +#define OP_PCLID_TLS11 (0x0a << OP_PCLID_SHIFT) +#define OP_PCLID_TLS12 (0x0b << OP_PCLID_SHIFT) +#define OP_PCLID_DTLS (0x0c << OP_PCLID_SHIFT) + +/* + * ProtocolInfo selectors + */ +#define OP_PCLINFO_MASK 0xffff + +/* for OP_PCLID_IPSEC */ +#define OP_PCL_IPSEC_CIPHER_MASK 0xff00 +#define OP_PCL_IPSEC_AUTH_MASK 0x00ff + +#define OP_PCL_IPSEC_DES_IV64 0x0100 +#define OP_PCL_IPSEC_DES 0x0200 +#define OP_PCL_IPSEC_3DES 0x0300 +#define OP_PCL_IPSEC_AES_CBC 0x0c00 +#define OP_PCL_IPSEC_AES_CTR 0x0d00 +#define OP_PCL_IPSEC_AES_XTS 0x1600 +#define OP_PCL_IPSEC_AES_CCM8 0x0e00 +#define OP_PCL_IPSEC_AES_CCM12 0x0f00 +#define OP_PCL_IPSEC_AES_CCM16 0x1000 +#define OP_PCL_IPSEC_AES_GCM8 0x1200 +#define OP_PCL_IPSEC_AES_GCM12 0x1300 +#define OP_PCL_IPSEC_AES_GCM16 0x1400 + +#define OP_PCL_IPSEC_HMAC_NULL 0x0000 +#define OP_PCL_IPSEC_HMAC_MD5_96 0x0001 +#define OP_PCL_IPSEC_HMAC_SHA1_96 0x0002 +#define OP_PCL_IPSEC_AES_XCBC_MAC_96 0x0005 +#define OP_PCL_IPSEC_HMAC_MD5_128 0x0006 +#define OP_PCL_IPSEC_HMAC_SHA1_160 0x0007 +#define OP_PCL_IPSEC_HMAC_SHA2_256_128 0x000c +#define OP_PCL_IPSEC_HMAC_SHA2_384_192 0x000d +#define OP_PCL_IPSEC_HMAC_SHA2_512_256 0x000e + +/* For SRTP - OP_PCLID_SRTP */ +#define OP_PCL_SRTP_CIPHER_MASK 0xff00 +#define OP_PCL_SRTP_AUTH_MASK 0x00ff + +#define OP_PCL_SRTP_AES_CTR 0x0d00 + +#define OP_PCL_SRTP_HMAC_SHA1_160 0x0007 + +/* For SSL 3.0 - OP_PCLID_SSL30 */ +#define OP_PCL_SSL30_AES_128_CBC_SHA 0x002f +#define OP_PCL_SSL30_AES_128_CBC_SHA_2 0x0030 +#define OP_PCL_SSL30_AES_128_CBC_SHA_3 0x0031 +#define OP_PCL_SSL30_AES_128_CBC_SHA_4 0x0032 +#define OP_PCL_SSL30_AES_128_CBC_SHA_5 0x0033 +#define OP_PCL_SSL30_AES_128_CBC_SHA_6 0x0034 +#define OP_PCL_SSL30_AES_128_CBC_SHA_7 0x008c +#define OP_PCL_SSL30_AES_128_CBC_SHA_8 0x0090 +#define OP_PCL_SSL30_AES_128_CBC_SHA_9 0x0094 +#define OP_PCL_SSL30_AES_128_CBC_SHA_10 0xc004 +#define OP_PCL_SSL30_AES_128_CBC_SHA_11 0xc009 +#define OP_PCL_SSL30_AES_128_CBC_SHA_12 0xc00e +#define OP_PCL_SSL30_AES_128_CBC_SHA_13 0xc013 +#define OP_PCL_SSL30_AES_128_CBC_SHA_14 0xc018 +#define OP_PCL_SSL30_AES_128_CBC_SHA_15 0xc01d +#define OP_PCL_SSL30_AES_128_CBC_SHA_16 0xc01e +#define OP_PCL_SSL30_AES_128_CBC_SHA_17 0xc01f + +#define OP_PCL_SSL30_AES_256_CBC_SHA 0x0035 +#define OP_PCL_SSL30_AES_256_CBC_SHA_2 0x0036 +#define OP_PCL_SSL30_AES_256_CBC_SHA_3 0x0037 +#define OP_PCL_SSL30_AES_256_CBC_SHA_4 0x0038 +#define OP_PCL_SSL30_AES_256_CBC_SHA_5 0x0039 +#define OP_PCL_SSL30_AES_256_CBC_SHA_6 0x003a +#define OP_PCL_SSL30_AES_256_CBC_SHA_7 0x008d +#define OP_PCL_SSL30_AES_256_CBC_SHA_8 0x0091 +#define OP_PCL_SSL30_AES_256_CBC_SHA_9 0x0095 +#define OP_PCL_SSL30_AES_256_CBC_SHA_10 0xc005 +#define OP_PCL_SSL30_AES_256_CBC_SHA_11 0xc00a +#define OP_PCL_SSL30_AES_256_CBC_SHA_12 0xc00f +#define OP_PCL_SSL30_AES_256_CBC_SHA_13 0xc014 +#define OP_PCL_SSL30_AES_256_CBC_SHA_14 0xc019 +#define OP_PCL_SSL30_AES_256_CBC_SHA_15 0xc020 +#define OP_PCL_SSL30_AES_256_CBC_SHA_16 0xc021 +#define OP_PCL_SSL30_AES_256_CBC_SHA_17 0xc022 + +#define OP_PCL_SSL30_3DES_EDE_CBC_MD5 0x0023 + +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA 0x001f +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_2 0x008b +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_3 0x008f +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_4 0x0093 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_5 0x000a +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_6 0x000d +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_7 0x0010 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_8 0x0013 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_9 0x0016 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_10 0x001b +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_11 0xc003 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_12 0xc008 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_13 0xc00d +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_14 0xc012 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_15 0xc017 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_16 0xc01a +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_17 0xc01b +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_18 0xc01c + +#define OP_PCL_SSL30_DES40_CBC_MD5 0x0029 + +#define OP_PCL_SSL30_DES_CBC_MD5 0x0022 + +#define OP_PCL_SSL30_DES40_CBC_SHA 0x0008 +#define OP_PCL_SSL30_DES40_CBC_SHA_2 0x000b +#define OP_PCL_SSL30_DES40_CBC_SHA_3 0x000e +#define OP_PCL_SSL30_DES40_CBC_SHA_4 0x0011 +#define OP_PCL_SSL30_DES40_CBC_SHA_5 0x0014 +#define OP_PCL_SSL30_DES40_CBC_SHA_6 0x0019 +#define OP_PCL_SSL30_DES40_CBC_SHA_7 0x0026 + +#define OP_PCL_SSL30_DES_CBC_SHA 0x001e +#define OP_PCL_SSL30_DES_CBC_SHA_2 0x0009 +#define OP_PCL_SSL30_DES_CBC_SHA_3 0x000c +#define OP_PCL_SSL30_DES_CBC_SHA_4 0x000f +#define OP_PCL_SSL30_DES_CBC_SHA_5 0x0012 +#define OP_PCL_SSL30_DES_CBC_SHA_6 0x0015 +#define OP_PCL_SSL30_DES_CBC_SHA_7 0x001a + +#define OP_PCL_SSL30_RC4_128_MD5 0x0024 +#define OP_PCL_SSL30_RC4_128_MD5_2 0x0004 +#define OP_PCL_SSL30_RC4_128_MD5_3 0x0018 + +#define OP_PCL_SSL30_RC4_40_MD5 0x002b +#define OP_PCL_SSL30_RC4_40_MD5_2 0x0003 +#define OP_PCL_SSL30_RC4_40_MD5_3 0x0017 + +#define OP_PCL_SSL30_RC4_128_SHA 0x0020 +#define OP_PCL_SSL30_RC4_128_SHA_2 0x008a +#define OP_PCL_SSL30_RC4_128_SHA_3 0x008e +#define OP_PCL_SSL30_RC4_128_SHA_4 0x0092 +#define OP_PCL_SSL30_RC4_128_SHA_5 0x0005 +#define OP_PCL_SSL30_RC4_128_SHA_6 0xc002 +#define OP_PCL_SSL30_RC4_128_SHA_7 0xc007 +#define OP_PCL_SSL30_RC4_128_SHA_8 0xc00c +#define OP_PCL_SSL30_RC4_128_SHA_9 0xc011 +#define OP_PCL_SSL30_RC4_128_SHA_10 0xc016 + +#define OP_PCL_SSL30_RC4_40_SHA 0x0028 + + +/* For TLS 1.0 - OP_PCLID_TLS10 */ +#define OP_PCL_TLS10_AES_128_CBC_SHA 0x002f +#define OP_PCL_TLS10_AES_128_CBC_SHA_2 0x0030 +#define OP_PCL_TLS10_AES_128_CBC_SHA_3 0x0031 +#define OP_PCL_TLS10_AES_128_CBC_SHA_4 0x0032 +#define OP_PCL_TLS10_AES_128_CBC_SHA_5 0x0033 +#define OP_PCL_TLS10_AES_128_CBC_SHA_6 0x0034 +#define OP_PCL_TLS10_AES_128_CBC_SHA_7 0x008c +#define OP_PCL_TLS10_AES_128_CBC_SHA_8 0x0090 +#define OP_PCL_TLS10_AES_128_CBC_SHA_9 0x0094 +#define OP_PCL_TLS10_AES_128_CBC_SHA_10 0xc004 +#define OP_PCL_TLS10_AES_128_CBC_SHA_11 0xc009 +#define OP_PCL_TLS10_AES_128_CBC_SHA_12 0xc00e +#define OP_PCL_TLS10_AES_128_CBC_SHA_13 0xc013 +#define OP_PCL_TLS10_AES_128_CBC_SHA_14 0xc018 +#define OP_PCL_TLS10_AES_128_CBC_SHA_15 0xc01d +#define OP_PCL_TLS10_AES_128_CBC_SHA_16 0xc01e +#define OP_PCL_TLS10_AES_128_CBC_SHA_17 0xc01f + +#define OP_PCL_TLS10_AES_256_CBC_SHA 0x0035 +#define OP_PCL_TLS10_AES_256_CBC_SHA_2 0x0036 +#define OP_PCL_TLS10_AES_256_CBC_SHA_3 0x0037 +#define OP_PCL_TLS10_AES_256_CBC_SHA_4 0x0038 +#define OP_PCL_TLS10_AES_256_CBC_SHA_5 0x0039 +#define OP_PCL_TLS10_AES_256_CBC_SHA_6 0x003a +#define OP_PCL_TLS10_AES_256_CBC_SHA_7 0x008d +#define OP_PCL_TLS10_AES_256_CBC_SHA_8 0x0091 +#define OP_PCL_TLS10_AES_256_CBC_SHA_9 0x0095 +#define OP_PCL_TLS10_AES_256_CBC_SHA_10 0xc005 +#define OP_PCL_TLS10_AES_256_CBC_SHA_11 0xc00a +#define OP_PCL_TLS10_AES_256_CBC_SHA_12 0xc00f +#define OP_PCL_TLS10_AES_256_CBC_SHA_13 0xc014 +#define OP_PCL_TLS10_AES_256_CBC_SHA_14 0xc019 +#define OP_PCL_TLS10_AES_256_CBC_SHA_15 0xc020 +#define OP_PCL_TLS10_AES_256_CBC_SHA_16 0xc021 +#define OP_PCL_TLS10_AES_256_CBC_SHA_17 0xc022 + +/* #define OP_PCL_TLS10_3DES_EDE_CBC_MD5 0x0023 */ + +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA 0x001f +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_2 0x008b +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_3 0x008f +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_4 0x0093 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_5 0x000a +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_6 0x000d +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_7 0x0010 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_8 0x0013 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_9 0x0016 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_10 0x001b +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_11 0xc003 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_12 0xc008 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_13 0xc00d +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_14 0xc012 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_15 0xc017 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_16 0xc01a +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_17 0xc01b +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_18 0xc01c + +#define OP_PCL_TLS10_DES40_CBC_MD5 0x0029 + +#define OP_PCL_TLS10_DES_CBC_MD5 0x0022 + +#define OP_PCL_TLS10_DES40_CBC_SHA 0x0008 +#define OP_PCL_TLS10_DES40_CBC_SHA_2 0x000b +#define OP_PCL_TLS10_DES40_CBC_SHA_3 0x000e +#define OP_PCL_TLS10_DES40_CBC_SHA_4 0x0011 +#define OP_PCL_TLS10_DES40_CBC_SHA_5 0x0014 +#define OP_PCL_TLS10_DES40_CBC_SHA_6 0x0019 +#define OP_PCL_TLS10_DES40_CBC_SHA_7 0x0026 + + +#define OP_PCL_TLS10_DES_CBC_SHA 0x001e +#define OP_PCL_TLS10_DES_CBC_SHA_2 0x0009 +#define OP_PCL_TLS10_DES_CBC_SHA_3 0x000c +#define OP_PCL_TLS10_DES_CBC_SHA_4 0x000f +#define OP_PCL_TLS10_DES_CBC_SHA_5 0x0012 +#define OP_PCL_TLS10_DES_CBC_SHA_6 0x0015 +#define OP_PCL_TLS10_DES_CBC_SHA_7 0x001a + +#define OP_PCL_TLS10_RC4_128_MD5 0x0024 +#define OP_PCL_TLS10_RC4_128_MD5_2 0x0004 +#define OP_PCL_TLS10_RC4_128_MD5_3 0x0018 + +#define OP_PCL_TLS10_RC4_40_MD5 0x002b +#define OP_PCL_TLS10_RC4_40_MD5_2 0x0003 +#define OP_PCL_TLS10_RC4_40_MD5_3 0x0017 + +#define OP_PCL_TLS10_RC4_128_SHA 0x0020 +#define OP_PCL_TLS10_RC4_128_SHA_2 0x008a +#define OP_PCL_TLS10_RC4_128_SHA_3 0x008e +#define OP_PCL_TLS10_RC4_128_SHA_4 0x0092 +#define OP_PCL_TLS10_RC4_128_SHA_5 0x0005 +#define OP_PCL_TLS10_RC4_128_SHA_6 0xc002 +#define OP_PCL_TLS10_RC4_128_SHA_7 0xc007 +#define OP_PCL_TLS10_RC4_128_SHA_8 0xc00c +#define OP_PCL_TLS10_RC4_128_SHA_9 0xc011 +#define OP_PCL_TLS10_RC4_128_SHA_10 0xc016 + +#define OP_PCL_TLS10_RC4_40_SHA 0x0028 + +#define OP_PCL_TLS10_3DES_EDE_CBC_MD5 0xff23 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA160 0xff30 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA224 0xff34 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA256 0xff36 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA384 0xff33 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA512 0xff35 +#define OP_PCL_TLS10_AES_128_CBC_SHA160 0xff80 +#define OP_PCL_TLS10_AES_128_CBC_SHA224 0xff84 +#define OP_PCL_TLS10_AES_128_CBC_SHA256 0xff86 +#define OP_PCL_TLS10_AES_128_CBC_SHA384 0xff83 +#define OP_PCL_TLS10_AES_128_CBC_SHA512 0xff85 +#define OP_PCL_TLS10_AES_192_CBC_SHA160 0xff20 +#define OP_PCL_TLS10_AES_192_CBC_SHA224 0xff24 +#define OP_PCL_TLS10_AES_192_CBC_SHA256 0xff26 +#define OP_PCL_TLS10_AES_192_CBC_SHA384 0xff23 +#define OP_PCL_TLS10_AES_192_CBC_SHA512 0xff25 +#define OP_PCL_TLS10_AES_256_CBC_SHA160 0xff60 +#define OP_PCL_TLS10_AES_256_CBC_SHA224 0xff64 +#define OP_PCL_TLS10_AES_256_CBC_SHA256 0xff66 +#define OP_PCL_TLS10_AES_256_CBC_SHA384 0xff63 +#define OP_PCL_TLS10_AES_256_CBC_SHA512 0xff65 + + + +/* For TLS 1.1 - OP_PCLID_TLS11 */ +#define OP_PCL_TLS11_AES_128_CBC_SHA 0x002f +#define OP_PCL_TLS11_AES_128_CBC_SHA_2 0x0030 +#define OP_PCL_TLS11_AES_128_CBC_SHA_3 0x0031 +#define OP_PCL_TLS11_AES_128_CBC_SHA_4 0x0032 +#define OP_PCL_TLS11_AES_128_CBC_SHA_5 0x0033 +#define OP_PCL_TLS11_AES_128_CBC_SHA_6 0x0034 +#define OP_PCL_TLS11_AES_128_CBC_SHA_7 0x008c +#define OP_PCL_TLS11_AES_128_CBC_SHA_8 0x0090 +#define OP_PCL_TLS11_AES_128_CBC_SHA_9 0x0094 +#define OP_PCL_TLS11_AES_128_CBC_SHA_10 0xc004 +#define OP_PCL_TLS11_AES_128_CBC_SHA_11 0xc009 +#define OP_PCL_TLS11_AES_128_CBC_SHA_12 0xc00e +#define OP_PCL_TLS11_AES_128_CBC_SHA_13 0xc013 +#define OP_PCL_TLS11_AES_128_CBC_SHA_14 0xc018 +#define OP_PCL_TLS11_AES_128_CBC_SHA_15 0xc01d +#define OP_PCL_TLS11_AES_128_CBC_SHA_16 0xc01e +#define OP_PCL_TLS11_AES_128_CBC_SHA_17 0xc01f + +#define OP_PCL_TLS11_AES_256_CBC_SHA 0x0035 +#define OP_PCL_TLS11_AES_256_CBC_SHA_2 0x0036 +#define OP_PCL_TLS11_AES_256_CBC_SHA_3 0x0037 +#define OP_PCL_TLS11_AES_256_CBC_SHA_4 0x0038 +#define OP_PCL_TLS11_AES_256_CBC_SHA_5 0x0039 +#define OP_PCL_TLS11_AES_256_CBC_SHA_6 0x003a +#define OP_PCL_TLS11_AES_256_CBC_SHA_7 0x008d +#define OP_PCL_TLS11_AES_256_CBC_SHA_8 0x0091 +#define OP_PCL_TLS11_AES_256_CBC_SHA_9 0x0095 +#define OP_PCL_TLS11_AES_256_CBC_SHA_10 0xc005 +#define OP_PCL_TLS11_AES_256_CBC_SHA_11 0xc00a +#define OP_PCL_TLS11_AES_256_CBC_SHA_12 0xc00f +#define OP_PCL_TLS11_AES_256_CBC_SHA_13 0xc014 +#define OP_PCL_TLS11_AES_256_CBC_SHA_14 0xc019 +#define OP_PCL_TLS11_AES_256_CBC_SHA_15 0xc020 +#define OP_PCL_TLS11_AES_256_CBC_SHA_16 0xc021 +#define OP_PCL_TLS11_AES_256_CBC_SHA_17 0xc022 + +/* #define OP_PCL_TLS11_3DES_EDE_CBC_MD5 0x0023 */ + +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA 0x001f +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_2 0x008b +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_3 0x008f +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_4 0x0093 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_5 0x000a +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_6 0x000d +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_7 0x0010 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_8 0x0013 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_9 0x0016 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_10 0x001b +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_11 0xc003 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_12 0xc008 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_13 0xc00d +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_14 0xc012 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_15 0xc017 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_16 0xc01a +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_17 0xc01b +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_18 0xc01c + +#define OP_PCL_TLS11_DES40_CBC_MD5 0x0029 + +#define OP_PCL_TLS11_DES_CBC_MD5 0x0022 + +#define OP_PCL_TLS11_DES40_CBC_SHA 0x0008 +#define OP_PCL_TLS11_DES40_CBC_SHA_2 0x000b +#define OP_PCL_TLS11_DES40_CBC_SHA_3 0x000e +#define OP_PCL_TLS11_DES40_CBC_SHA_4 0x0011 +#define OP_PCL_TLS11_DES40_CBC_SHA_5 0x0014 +#define OP_PCL_TLS11_DES40_CBC_SHA_6 0x0019 +#define OP_PCL_TLS11_DES40_CBC_SHA_7 0x0026 + +#define OP_PCL_TLS11_DES_CBC_SHA 0x001e +#define OP_PCL_TLS11_DES_CBC_SHA_2 0x0009 +#define OP_PCL_TLS11_DES_CBC_SHA_3 0x000c +#define OP_PCL_TLS11_DES_CBC_SHA_4 0x000f +#define OP_PCL_TLS11_DES_CBC_SHA_5 0x0012 +#define OP_PCL_TLS11_DES_CBC_SHA_6 0x0015 +#define OP_PCL_TLS11_DES_CBC_SHA_7 0x001a + +#define OP_PCL_TLS11_RC4_128_MD5 0x0024 +#define OP_PCL_TLS11_RC4_128_MD5_2 0x0004 +#define OP_PCL_TLS11_RC4_128_MD5_3 0x0018 + +#define OP_PCL_TLS11_RC4_40_MD5 0x002b +#define OP_PCL_TLS11_RC4_40_MD5_2 0x0003 +#define OP_PCL_TLS11_RC4_40_MD5_3 0x0017 + +#define OP_PCL_TLS11_RC4_128_SHA 0x0020 +#define OP_PCL_TLS11_RC4_128_SHA_2 0x008a +#define OP_PCL_TLS11_RC4_128_SHA_3 0x008e +#define OP_PCL_TLS11_RC4_128_SHA_4 0x0092 +#define OP_PCL_TLS11_RC4_128_SHA_5 0x0005 +#define OP_PCL_TLS11_RC4_128_SHA_6 0xc002 +#define OP_PCL_TLS11_RC4_128_SHA_7 0xc007 +#define OP_PCL_TLS11_RC4_128_SHA_8 0xc00c +#define OP_PCL_TLS11_RC4_128_SHA_9 0xc011 +#define OP_PCL_TLS11_RC4_128_SHA_10 0xc016 + +#define OP_PCL_TLS11_RC4_40_SHA 0x0028 + +#define OP_PCL_TLS11_3DES_EDE_CBC_MD5 0xff23 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA160 0xff30 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA224 0xff34 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA256 0xff36 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA384 0xff33 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA512 0xff35 +#define OP_PCL_TLS11_AES_128_CBC_SHA160 0xff80 +#define OP_PCL_TLS11_AES_128_CBC_SHA224 0xff84 +#define OP_PCL_TLS11_AES_128_CBC_SHA256 0xff86 +#define OP_PCL_TLS11_AES_128_CBC_SHA384 0xff83 +#define OP_PCL_TLS11_AES_128_CBC_SHA512 0xff85 +#define OP_PCL_TLS11_AES_192_CBC_SHA160 0xff20 +#define OP_PCL_TLS11_AES_192_CBC_SHA224 0xff24 +#define OP_PCL_TLS11_AES_192_CBC_SHA256 0xff26 +#define OP_PCL_TLS11_AES_192_CBC_SHA384 0xff23 +#define OP_PCL_TLS11_AES_192_CBC_SHA512 0xff25 +#define OP_PCL_TLS11_AES_256_CBC_SHA160 0xff60 +#define OP_PCL_TLS11_AES_256_CBC_SHA224 0xff64 +#define OP_PCL_TLS11_AES_256_CBC_SHA256 0xff66 +#define OP_PCL_TLS11_AES_256_CBC_SHA384 0xff63 +#define OP_PCL_TLS11_AES_256_CBC_SHA512 0xff65 + + +/* For TLS 1.2 - OP_PCLID_TLS12 */ +#define OP_PCL_TLS12_AES_128_CBC_SHA 0x002f +#define OP_PCL_TLS12_AES_128_CBC_SHA_2 0x0030 +#define OP_PCL_TLS12_AES_128_CBC_SHA_3 0x0031 +#define OP_PCL_TLS12_AES_128_CBC_SHA_4 0x0032 +#define OP_PCL_TLS12_AES_128_CBC_SHA_5 0x0033 +#define OP_PCL_TLS12_AES_128_CBC_SHA_6 0x0034 +#define OP_PCL_TLS12_AES_128_CBC_SHA_7 0x008c +#define OP_PCL_TLS12_AES_128_CBC_SHA_8 0x0090 +#define OP_PCL_TLS12_AES_128_CBC_SHA_9 0x0094 +#define OP_PCL_TLS12_AES_128_CBC_SHA_10 0xc004 +#define OP_PCL_TLS12_AES_128_CBC_SHA_11 0xc009 +#define OP_PCL_TLS12_AES_128_CBC_SHA_12 0xc00e +#define OP_PCL_TLS12_AES_128_CBC_SHA_13 0xc013 +#define OP_PCL_TLS12_AES_128_CBC_SHA_14 0xc018 +#define OP_PCL_TLS12_AES_128_CBC_SHA_15 0xc01d +#define OP_PCL_TLS12_AES_128_CBC_SHA_16 0xc01e +#define OP_PCL_TLS12_AES_128_CBC_SHA_17 0xc01f + +#define OP_PCL_TLS12_AES_256_CBC_SHA 0x0035 +#define OP_PCL_TLS12_AES_256_CBC_SHA_2 0x0036 +#define OP_PCL_TLS12_AES_256_CBC_SHA_3 0x0037 +#define OP_PCL_TLS12_AES_256_CBC_SHA_4 0x0038 +#define OP_PCL_TLS12_AES_256_CBC_SHA_5 0x0039 +#define OP_PCL_TLS12_AES_256_CBC_SHA_6 0x003a +#define OP_PCL_TLS12_AES_256_CBC_SHA_7 0x008d +#define OP_PCL_TLS12_AES_256_CBC_SHA_8 0x0091 +#define OP_PCL_TLS12_AES_256_CBC_SHA_9 0x0095 +#define OP_PCL_TLS12_AES_256_CBC_SHA_10 0xc005 +#define OP_PCL_TLS12_AES_256_CBC_SHA_11 0xc00a +#define OP_PCL_TLS12_AES_256_CBC_SHA_12 0xc00f +#define OP_PCL_TLS12_AES_256_CBC_SHA_13 0xc014 +#define OP_PCL_TLS12_AES_256_CBC_SHA_14 0xc019 +#define OP_PCL_TLS12_AES_256_CBC_SHA_15 0xc020 +#define OP_PCL_TLS12_AES_256_CBC_SHA_16 0xc021 +#define OP_PCL_TLS12_AES_256_CBC_SHA_17 0xc022 + +/* #define OP_PCL_TLS12_3DES_EDE_CBC_MD5 0x0023 */ + +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA 0x001f +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_2 0x008b +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_3 0x008f +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_4 0x0093 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_5 0x000a +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_6 0x000d +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_7 0x0010 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_8 0x0013 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_9 0x0016 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_10 0x001b +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_11 0xc003 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_12 0xc008 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_13 0xc00d +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_14 0xc012 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_15 0xc017 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_16 0xc01a +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_17 0xc01b +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_18 0xc01c + +#define OP_PCL_TLS12_DES40_CBC_MD5 0x0029 + +#define OP_PCL_TLS12_DES_CBC_MD5 0x0022 + +#define OP_PCL_TLS12_DES40_CBC_SHA 0x0008 +#define OP_PCL_TLS12_DES40_CBC_SHA_2 0x000b +#define OP_PCL_TLS12_DES40_CBC_SHA_3 0x000e +#define OP_PCL_TLS12_DES40_CBC_SHA_4 0x0011 +#define OP_PCL_TLS12_DES40_CBC_SHA_5 0x0014 +#define OP_PCL_TLS12_DES40_CBC_SHA_6 0x0019 +#define OP_PCL_TLS12_DES40_CBC_SHA_7 0x0026 + +#define OP_PCL_TLS12_DES_CBC_SHA 0x001e +#define OP_PCL_TLS12_DES_CBC_SHA_2 0x0009 +#define OP_PCL_TLS12_DES_CBC_SHA_3 0x000c +#define OP_PCL_TLS12_DES_CBC_SHA_4 0x000f +#define OP_PCL_TLS12_DES_CBC_SHA_5 0x0012 +#define OP_PCL_TLS12_DES_CBC_SHA_6 0x0015 +#define OP_PCL_TLS12_DES_CBC_SHA_7 0x001a + +#define OP_PCL_TLS12_RC4_128_MD5 0x0024 +#define OP_PCL_TLS12_RC4_128_MD5_2 0x0004 +#define OP_PCL_TLS12_RC4_128_MD5_3 0x0018 + +#define OP_PCL_TLS12_RC4_40_MD5 0x002b +#define OP_PCL_TLS12_RC4_40_MD5_2 0x0003 +#define OP_PCL_TLS12_RC4_40_MD5_3 0x0017 + +#define OP_PCL_TLS12_RC4_128_SHA 0x0020 +#define OP_PCL_TLS12_RC4_128_SHA_2 0x008a +#define OP_PCL_TLS12_RC4_128_SHA_3 0x008e +#define OP_PCL_TLS12_RC4_128_SHA_4 0x0092 +#define OP_PCL_TLS12_RC4_128_SHA_5 0x0005 +#define OP_PCL_TLS12_RC4_128_SHA_6 0xc002 +#define OP_PCL_TLS12_RC4_128_SHA_7 0xc007 +#define OP_PCL_TLS12_RC4_128_SHA_8 0xc00c +#define OP_PCL_TLS12_RC4_128_SHA_9 0xc011 +#define OP_PCL_TLS12_RC4_128_SHA_10 0xc016 + +#define OP_PCL_TLS12_RC4_40_SHA 0x0028 + +/* #define OP_PCL_TLS12_AES_128_CBC_SHA256 0x003c */ +#define OP_PCL_TLS12_AES_128_CBC_SHA256_2 0x003e +#define OP_PCL_TLS12_AES_128_CBC_SHA256_3 0x003f +#define OP_PCL_TLS12_AES_128_CBC_SHA256_4 0x0040 +#define OP_PCL_TLS12_AES_128_CBC_SHA256_5 0x0067 +#define OP_PCL_TLS12_AES_128_CBC_SHA256_6 0x006c + +/* #define OP_PCL_TLS12_AES_256_CBC_SHA256 0x003d */ +#define OP_PCL_TLS12_AES_256_CBC_SHA256_2 0x0068 +#define OP_PCL_TLS12_AES_256_CBC_SHA256_3 0x0069 +#define OP_PCL_TLS12_AES_256_CBC_SHA256_4 0x006a +#define OP_PCL_TLS12_AES_256_CBC_SHA256_5 0x006b +#define OP_PCL_TLS12_AES_256_CBC_SHA256_6 0x006d + +/* AEAD_AES_xxx_CCM/GCM remain to be defined... */ + +#define OP_PCL_TLS12_3DES_EDE_CBC_MD5 0xff23 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA160 0xff30 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA224 0xff34 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA256 0xff36 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA384 0xff33 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA512 0xff35 +#define OP_PCL_TLS12_AES_128_CBC_SHA160 0xff80 +#define OP_PCL_TLS12_AES_128_CBC_SHA224 0xff84 +#define OP_PCL_TLS12_AES_128_CBC_SHA256 0xff86 +#define OP_PCL_TLS12_AES_128_CBC_SHA384 0xff83 +#define OP_PCL_TLS12_AES_128_CBC_SHA512 0xff85 +#define OP_PCL_TLS12_AES_192_CBC_SHA160 0xff20 +#define OP_PCL_TLS12_AES_192_CBC_SHA224 0xff24 +#define OP_PCL_TLS12_AES_192_CBC_SHA256 0xff26 +#define OP_PCL_TLS12_AES_192_CBC_SHA384 0xff23 +#define OP_PCL_TLS12_AES_192_CBC_SHA512 0xff25 +#define OP_PCL_TLS12_AES_256_CBC_SHA160 0xff60 +#define OP_PCL_TLS12_AES_256_CBC_SHA224 0xff64 +#define OP_PCL_TLS12_AES_256_CBC_SHA256 0xff66 +#define OP_PCL_TLS12_AES_256_CBC_SHA384 0xff63 +#define OP_PCL_TLS12_AES_256_CBC_SHA512 0xff65 + +/* For DTLS - OP_PCLID_DTLS */ + +#define OP_PCL_DTLS_AES_128_CBC_SHA 0x002f +#define OP_PCL_DTLS_AES_128_CBC_SHA_2 0x0030 +#define OP_PCL_DTLS_AES_128_CBC_SHA_3 0x0031 +#define OP_PCL_DTLS_AES_128_CBC_SHA_4 0x0032 +#define OP_PCL_DTLS_AES_128_CBC_SHA_5 0x0033 +#define OP_PCL_DTLS_AES_128_CBC_SHA_6 0x0034 +#define OP_PCL_DTLS_AES_128_CBC_SHA_7 0x008c +#define OP_PCL_DTLS_AES_128_CBC_SHA_8 0x0090 +#define OP_PCL_DTLS_AES_128_CBC_SHA_9 0x0094 +#define OP_PCL_DTLS_AES_128_CBC_SHA_10 0xc004 +#define OP_PCL_DTLS_AES_128_CBC_SHA_11 0xc009 +#define OP_PCL_DTLS_AES_128_CBC_SHA_12 0xc00e +#define OP_PCL_DTLS_AES_128_CBC_SHA_13 0xc013 +#define OP_PCL_DTLS_AES_128_CBC_SHA_14 0xc018 +#define OP_PCL_DTLS_AES_128_CBC_SHA_15 0xc01d +#define OP_PCL_DTLS_AES_128_CBC_SHA_16 0xc01e +#define OP_PCL_DTLS_AES_128_CBC_SHA_17 0xc01f + +#define OP_PCL_DTLS_AES_256_CBC_SHA 0x0035 +#define OP_PCL_DTLS_AES_256_CBC_SHA_2 0x0036 +#define OP_PCL_DTLS_AES_256_CBC_SHA_3 0x0037 +#define OP_PCL_DTLS_AES_256_CBC_SHA_4 0x0038 +#define OP_PCL_DTLS_AES_256_CBC_SHA_5 0x0039 +#define OP_PCL_DTLS_AES_256_CBC_SHA_6 0x003a +#define OP_PCL_DTLS_AES_256_CBC_SHA_7 0x008d +#define OP_PCL_DTLS_AES_256_CBC_SHA_8 0x0091 +#define OP_PCL_DTLS_AES_256_CBC_SHA_9 0x0095 +#define OP_PCL_DTLS_AES_256_CBC_SHA_10 0xc005 +#define OP_PCL_DTLS_AES_256_CBC_SHA_11 0xc00a +#define OP_PCL_DTLS_AES_256_CBC_SHA_12 0xc00f +#define OP_PCL_DTLS_AES_256_CBC_SHA_13 0xc014 +#define OP_PCL_DTLS_AES_256_CBC_SHA_14 0xc019 +#define OP_PCL_DTLS_AES_256_CBC_SHA_15 0xc020 +#define OP_PCL_DTLS_AES_256_CBC_SHA_16 0xc021 +#define OP_PCL_DTLS_AES_256_CBC_SHA_17 0xc022 + +/* #define OP_PCL_DTLS_3DES_EDE_CBC_MD5 0x0023 */ + +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA 0x001f +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_2 0x008b +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_3 0x008f +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_4 0x0093 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_5 0x000a +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_6 0x000d +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_7 0x0010 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_8 0x0013 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_9 0x0016 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_10 0x001b +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_11 0xc003 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_12 0xc008 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_13 0xc00d +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_14 0xc012 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_15 0xc017 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_16 0xc01a +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_17 0xc01b +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_18 0xc01c + +#define OP_PCL_DTLS_DES40_CBC_MD5 0x0029 + +#define OP_PCL_DTLS_DES_CBC_MD5 0x0022 + +#define OP_PCL_DTLS_DES40_CBC_SHA 0x0008 +#define OP_PCL_DTLS_DES40_CBC_SHA_2 0x000b +#define OP_PCL_DTLS_DES40_CBC_SHA_3 0x000e +#define OP_PCL_DTLS_DES40_CBC_SHA_4 0x0011 +#define OP_PCL_DTLS_DES40_CBC_SHA_5 0x0014 +#define OP_PCL_DTLS_DES40_CBC_SHA_6 0x0019 +#define OP_PCL_DTLS_DES40_CBC_SHA_7 0x0026 + + +#define OP_PCL_DTLS_DES_CBC_SHA 0x001e +#define OP_PCL_DTLS_DES_CBC_SHA_2 0x0009 +#define OP_PCL_DTLS_DES_CBC_SHA_3 0x000c +#define OP_PCL_DTLS_DES_CBC_SHA_4 0x000f +#define OP_PCL_DTLS_DES_CBC_SHA_5 0x0012 +#define OP_PCL_DTLS_DES_CBC_SHA_6 0x0015 +#define OP_PCL_DTLS_DES_CBC_SHA_7 0x001a + + +#define OP_PCL_DTLS_3DES_EDE_CBC_MD5 0xff23 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA160 0xff30 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA224 0xff34 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA256 0xff36 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA384 0xff33 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA512 0xff35 +#define OP_PCL_DTLS_AES_128_CBC_SHA160 0xff80 +#define OP_PCL_DTLS_AES_128_CBC_SHA224 0xff84 +#define OP_PCL_DTLS_AES_128_CBC_SHA256 0xff86 +#define OP_PCL_DTLS_AES_128_CBC_SHA384 0xff83 +#define OP_PCL_DTLS_AES_128_CBC_SHA512 0xff85 +#define OP_PCL_DTLS_AES_192_CBC_SHA160 0xff20 +#define OP_PCL_DTLS_AES_192_CBC_SHA224 0xff24 +#define OP_PCL_DTLS_AES_192_CBC_SHA256 0xff26 +#define OP_PCL_DTLS_AES_192_CBC_SHA384 0xff23 +#define OP_PCL_DTLS_AES_192_CBC_SHA512 0xff25 +#define OP_PCL_DTLS_AES_256_CBC_SHA160 0xff60 +#define OP_PCL_DTLS_AES_256_CBC_SHA224 0xff64 +#define OP_PCL_DTLS_AES_256_CBC_SHA256 0xff66 +#define OP_PCL_DTLS_AES_256_CBC_SHA384 0xff63 +#define OP_PCL_DTLS_AES_256_CBC_SHA512 0xff65 + +/* 802.16 WiMAX protinfos */ +#define OP_PCL_WIMAX_OFDM 0x0201 +#define OP_PCL_WIMAX_OFDMA 0x0231 + +/* 802.11 WiFi protinfos */ +#define OP_PCL_WIFI 0xac04 + +/* MacSec protinfos */ +#define OP_PCL_MACSEC 0x0001 + +/* PKI unidirectional protocol protinfo bits */ +#define OP_PCL_PKPROT_TEST 0x0008 +#define OP_PCL_PKPROT_DECRYPT 0x0004 +#define OP_PCL_PKPROT_ECC 0x0002 +#define OP_PCL_PKPROT_F2M 0x0001 + +/* For non-protocol/alg-only op commands */ +#define OP_ALG_TYPE_SHIFT 24 +#define OP_ALG_TYPE_MASK (0x7 << OP_ALG_TYPE_SHIFT) +#define OP_ALG_TYPE_CLASS1 2 +#define OP_ALG_TYPE_CLASS2 4 + +#define OP_ALG_ALGSEL_SHIFT 16 +#define OP_ALG_ALGSEL_MASK (0xff << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SUBMASK (0x0f << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_AES (0x10 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_DES (0x20 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_3DES (0x21 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_ARC4 (0x30 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_MD5 (0x40 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SHA1 (0x41 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SHA224 (0x42 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SHA256 (0x43 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SHA384 (0x44 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SHA512 (0x45 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_RNG (0x50 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SNOW (0x60 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SNOW_F8 (0x60 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_KASUMI (0x70 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_CRC (0x90 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SNOW_F9 (0xA0 << OP_ALG_ALGSEL_SHIFT) + +#define OP_ALG_AAI_SHIFT 4 +#define OP_ALG_AAI_MASK (0x1ff << OP_ALG_AAI_SHIFT) + +/* blockcipher AAI set */ +#define OP_ALG_AAI_CTR_MOD128 (0x00 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD8 (0x01 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD16 (0x02 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD24 (0x03 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD32 (0x04 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD40 (0x05 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD48 (0x06 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD56 (0x07 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD64 (0x08 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD72 (0x09 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD80 (0x0a << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD88 (0x0b << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD96 (0x0c << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD104 (0x0d << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD112 (0x0e << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD120 (0x0f << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CBC (0x10 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_ECB (0x20 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CFB (0x30 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_OFB (0x40 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_XTS (0x50 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CMAC (0x60 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_XCBC_MAC (0x70 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CCM (0x80 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_GCM (0x90 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CBC_XCBCMAC (0xa0 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_XCBCMAC (0xb0 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CHECKODD (0x80 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_DK (0x100 << OP_ALG_AAI_SHIFT) + +/* randomizer AAI set */ +#define OP_ALG_AAI_RNG (0x00 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_RNG_NOZERO (0x10 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_RNG_ODD (0x20 << OP_ALG_AAI_SHIFT) + +/* hmac/smac AAI set */ +#define OP_ALG_AAI_HASH (0x00 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_HMAC (0x01 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_SMAC (0x02 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_HMAC_PRECOMP (0x04 << OP_ALG_AAI_SHIFT) + +/* CRC AAI set*/ +#define OP_ALG_AAI_802 (0x01 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_3385 (0x02 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CUST_POLY (0x04 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_DIS (0x10 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_DOS (0x20 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_DOC (0x40 << OP_ALG_AAI_SHIFT) + +/* Kasumi/SNOW AAI set */ +#define OP_ALG_AAI_F8 (0xc0 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_F9 (0xc8 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_GSM (0x10 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_EDGE (0x20 << OP_ALG_AAI_SHIFT) + + +#define OP_ALG_AS_SHIFT 2 +#define OP_ALG_AS_MASK (0x3 << OP_ALG_AS_SHIFT) +#define OP_ALG_AS_UPDATE (0 << OP_ALG_AS_SHIFT) +#define OP_ALG_AS_INIT (1 << OP_ALG_AS_SHIFT) +#define OP_ALG_AS_FINALIZE (2 << OP_ALG_AS_SHIFT) +#define OP_ALG_AS_INITFINAL (3 << OP_ALG_AS_SHIFT) + +#define OP_ALG_ICV_SHIFT 1 +#define OP_ALG_ICV_MASK (1 << OP_ALG_ICV_SHIFT) +#define OP_ALG_ICV_OFF (0 << OP_ALG_ICV_SHIFT) +#define OP_ALG_ICV_ON (1 << OP_ALG_ICV_SHIFT) + +#define OP_ALG_DIR_SHIFT 0 +#define OP_ALG_DIR_MASK 1 +#define OP_ALG_DECRYPT 0 +#define OP_ALG_ENCRYPT 1 + +/* PKHA algorithm type set */ +#define OP_ALG_PK 0x00800000 +#define OP_ALG_PK_FUN_MASK 0x3f /* clrmem, modmath, or cpymem */ + +/* PKHA mode clear memory functions */ +#define OP_ALG_PKMODE_A_RAM 0x80000 +#define OP_ALG_PKMODE_B_RAM 0x40000 +#define OP_ALG_PKMODE_E_RAM 0x20000 +#define OP_ALG_PKMODE_N_RAM 0x10000 +#define OP_ALG_PKMODE_CLEARMEM 0x00001 + +/* PKHA mode modular-arithmetic functions */ +#define OP_ALG_PKMODE_MOD_IN_MONTY 0x80000 +#define OP_ALG_PKMODE_MOD_OUT_MONTY 0x40000 +#define OP_ALG_PKMODE_MOD_F2M 0x20000 +#define OP_ALG_PKMODE_MOD_R2_IN 0x10000 +#define OP_ALG_PKMODE_PRJECTV 0x00800 +#define OP_ALG_PKMODE_TIME_EQ 0x400 +#define OP_ALG_PKMODE_OUT_B 0x000 +#define OP_ALG_PKMODE_OUT_A 0x100 +#define OP_ALG_PKMODE_MOD_ADD 0x002 +#define OP_ALG_PKMODE_MOD_SUB_AB 0x003 +#define OP_ALG_PKMODE_MOD_SUB_BA 0x004 +#define OP_ALG_PKMODE_MOD_MULT 0x005 +#define OP_ALG_PKMODE_MOD_EXPO 0x006 +#define OP_ALG_PKMODE_MOD_REDUCT 0x007 +#define OP_ALG_PKMODE_MOD_INV 0x008 +#define OP_ALG_PKMODE_MOD_ECC_ADD 0x009 +#define OP_ALG_PKMODE_MOD_ECC_DBL 0x00a +#define OP_ALG_PKMODE_MOD_ECC_MULT 0x00b +#define OP_ALG_PKMODE_MOD_MONT_CNST 0x00c +#define OP_ALG_PKMODE_MOD_CRT_CNST 0x00d +#define OP_ALG_PKMODE_MOD_GCD 0x00e +#define OP_ALG_PKMODE_MOD_PRIMALITY 0x00f + +/* PKHA mode copy-memory functions */ +#define OP_ALG_PKMODE_SRC_REG_SHIFT 13 +#define OP_ALG_PKMODE_SRC_REG_MASK (7 << OP_ALG_PKMODE_SRC_REG_SHIFT) +#define OP_ALG_PKMODE_DST_REG_SHIFT 10 +#define OP_ALG_PKMODE_DST_REG_MASK (7 << OP_ALG_PKMODE_DST_REG_SHIFT) +#define OP_ALG_PKMODE_SRC_SEG_SHIFT 8 +#define OP_ALG_PKMODE_SRC_SEG_MASK (3 << OP_ALG_PKMODE_SRC_SEG_SHIFT) +#define OP_ALG_PKMODE_DST_SEG_SHIFT 6 +#define OP_ALG_PKMODE_DST_SEG_MASK (3 << OP_ALG_PKMODE_DST_SEG_SHIFT) + +#define OP_ALG_PKMODE_SRC_REG_A (0 << OP_ALG_PKMODE_SRC_REG_SHIFT) +#define OP_ALG_PKMODE_SRC_REG_B (1 << OP_ALG_PKMODE_SRC_REG_SHIFT) +#define OP_ALG_PKMODE_SRC_REG_N (3 << OP_ALG_PKMODE_SRC_REG_SHIFT) +#define OP_ALG_PKMODE_DST_REG_A (0 << OP_ALG_PKMODE_DST_REG_SHIFT) +#define OP_ALG_PKMODE_DST_REG_B (1 << OP_ALG_PKMODE_DST_REG_SHIFT) +#define OP_ALG_PKMODE_DST_REG_E (2 << OP_ALG_PKMODE_DST_REG_SHIFT) +#define OP_ALG_PKMODE_DST_REG_N (3 << OP_ALG_PKMODE_DST_REG_SHIFT) +#define OP_ALG_PKMODE_SRC_SEG_0 (0 << OP_ALG_PKMODE_SRC_SEG_SHIFT) +#define OP_ALG_PKMODE_SRC_SEG_1 (1 << OP_ALG_PKMODE_SRC_SEG_SHIFT) +#define OP_ALG_PKMODE_SRC_SEG_2 (2 << OP_ALG_PKMODE_SRC_SEG_SHIFT) +#define OP_ALG_PKMODE_SRC_SEG_3 (3 << OP_ALG_PKMODE_SRC_SEG_SHIFT) +#define OP_ALG_PKMODE_DST_SEG_0 (0 << OP_ALG_PKMODE_DST_SEG_SHIFT) +#define OP_ALG_PKMODE_DST_SEG_1 (1 << OP_ALG_PKMODE_DST_SEG_SHIFT) +#define OP_ALG_PKMODE_DST_SEG_2 (2 << OP_ALG_PKMODE_DST_SEG_SHIFT) +#define OP_ALG_PKMODE_DST_SEG_3 (3 << OP_ALG_PKMODE_DST_SEG_SHIFT) +#define OP_ALG_PKMODE_CPYMEM_N_SZ 0x80 +#define OP_ALG_PKMODE_CPYMEM_SRC_SZ 0x81 + +/* + * SEQ_IN_PTR Command Constructs + */ + +/* Release Buffers */ +#define SQIN_RBS 0x04000000 + +/* Sequence pointer is really a descriptor */ +#define SQIN_INL 0x02000000 + +/* Sequence pointer is a scatter-gather table */ +#define SQIN_SGF 0x01000000 + +/* Appends to a previous pointer */ +#define SQIN_PRE 0x00800000 + +/* Use extended length following pointer */ +#define SQIN_EXT 0x00400000 + +/* Restore sequence with pointer/length */ +#define SQIN_RTO 0x00200000 + +/* Replace job descriptor */ +#define SQIN_RJD 0x00100000 + +#define SQIN_LEN_SHIFT 0 +#define SQIN_LEN_MASK (0xffff << SQIN_LEN_SHIFT) + +/* + * SEQ_OUT_PTR Command Constructs + */ + +/* Sequence pointer is a scatter-gather table */ +#define SQOUT_SGF 0x01000000 + +/* Appends to a previous pointer */ +#define SQOUT_PRE 0x00800000 + +/* Restore sequence with pointer/length */ +#define SQOUT_RTO 0x00200000 + +/* Use extended length following pointer */ +#define SQOUT_EXT 0x00400000 + +#define SQOUT_LEN_SHIFT 0 +#define SQOUT_LEN_MASK (0xffff << SQOUT_LEN_SHIFT) + + +/* + * SIGNATURE Command Constructs + */ + +/* TYPE field is all that's relevant */ +#define SIGN_TYPE_SHIFT 16 +#define SIGN_TYPE_MASK (0x0f << SIGN_TYPE_SHIFT) + +#define SIGN_TYPE_FINAL (0x00 << SIGN_TYPE_SHIFT) +#define SIGN_TYPE_FINAL_RESTORE (0x01 << SIGN_TYPE_SHIFT) +#define SIGN_TYPE_FINAL_NONZERO (0x02 << SIGN_TYPE_SHIFT) +#define SIGN_TYPE_IMM_2 (0x0a << SIGN_TYPE_SHIFT) +#define SIGN_TYPE_IMM_3 (0x0b << SIGN_TYPE_SHIFT) +#define SIGN_TYPE_IMM_4 (0x0c << SIGN_TYPE_SHIFT) + +/* + * MOVE Command Constructs + */ + +#define MOVE_AUX_SHIFT 25 +#define MOVE_AUX_MASK (3 << MOVE_AUX_SHIFT) +#define MOVE_AUX_MS (2 << MOVE_AUX_SHIFT) +#define MOVE_AUX_LS (1 << MOVE_AUX_SHIFT) + +#define MOVE_WAITCOMP_SHIFT 24 +#define MOVE_WAITCOMP_MASK (1 << MOVE_WAITCOMP_SHIFT) +#define MOVE_WAITCOMP (1 << MOVE_WAITCOMP_SHIFT) + +#define MOVE_SRC_SHIFT 20 +#define MOVE_SRC_MASK (0x0f << MOVE_SRC_SHIFT) +#define MOVE_SRC_CLASS1CTX (0x00 << MOVE_SRC_SHIFT) +#define MOVE_SRC_CLASS2CTX (0x01 << MOVE_SRC_SHIFT) +#define MOVE_SRC_OUTFIFO (0x02 << MOVE_SRC_SHIFT) +#define MOVE_SRC_DESCBUF (0x03 << MOVE_SRC_SHIFT) +#define MOVE_SRC_MATH0 (0x04 << MOVE_SRC_SHIFT) +#define MOVE_SRC_MATH1 (0x05 << MOVE_SRC_SHIFT) +#define MOVE_SRC_MATH2 (0x06 << MOVE_SRC_SHIFT) +#define MOVE_SRC_MATH3 (0x07 << MOVE_SRC_SHIFT) +#define MOVE_SRC_INFIFO (0x08 << MOVE_SRC_SHIFT) +#define MOVE_SRC_INFIFO_CL (0x09 << MOVE_SRC_SHIFT) + +#define MOVE_DEST_SHIFT 16 +#define MOVE_DEST_MASK (0x0f << MOVE_DEST_SHIFT) +#define MOVE_DEST_CLASS1CTX (0x00 << MOVE_DEST_SHIFT) +#define MOVE_DEST_CLASS2CTX (0x01 << MOVE_DEST_SHIFT) +#define MOVE_DEST_OUTFIFO (0x02 << MOVE_DEST_SHIFT) +#define MOVE_DEST_DESCBUF (0x03 << MOVE_DEST_SHIFT) +#define MOVE_DEST_MATH0 (0x04 << MOVE_DEST_SHIFT) +#define MOVE_DEST_MATH1 (0x05 << MOVE_DEST_SHIFT) +#define MOVE_DEST_MATH2 (0x06 << MOVE_DEST_SHIFT) +#define MOVE_DEST_MATH3 (0x07 << MOVE_DEST_SHIFT) +#define MOVE_DEST_CLASS1INFIFO (0x08 << MOVE_DEST_SHIFT) +#define MOVE_DEST_CLASS2INFIFO (0x09 << MOVE_DEST_SHIFT) +#define MOVE_DEST_PK_A (0x0c << MOVE_DEST_SHIFT) +#define MOVE_DEST_CLASS1KEY (0x0d << MOVE_DEST_SHIFT) +#define MOVE_DEST_CLASS2KEY (0x0e << MOVE_DEST_SHIFT) + +#define MOVE_OFFSET_SHIFT 8 +#define MOVE_OFFSET_MASK (0xff << MOVE_OFFSET_SHIFT) + +#define MOVE_LEN_SHIFT 0 +#define MOVE_LEN_MASK (0xff << MOVE_LEN_SHIFT) + +#define MOVELEN_MRSEL_SHIFT 0 +#define MOVELEN_MRSEL_MASK (0x3 << MOVE_LEN_SHIFT) + +/* + * MATH Command Constructs + */ + +#define MATH_IFB_SHIFT 26 +#define MATH_IFB_MASK (1 << MATH_IFB_SHIFT) +#define MATH_IFB (1 << MATH_IFB_SHIFT) + +#define MATH_NFU_SHIFT 25 +#define MATH_NFU_MASK (1 << MATH_NFU_SHIFT) +#define MATH_NFU (1 << MATH_NFU_SHIFT) + +#define MATH_STL_SHIFT 24 +#define MATH_STL_MASK (1 << MATH_STL_SHIFT) +#define MATH_STL (1 << MATH_STL_SHIFT) + +/* Function selectors */ +#define MATH_FUN_SHIFT 20 +#define MATH_FUN_MASK (0x0f << MATH_FUN_SHIFT) +#define MATH_FUN_ADD (0x00 << MATH_FUN_SHIFT) +#define MATH_FUN_ADDC (0x01 << MATH_FUN_SHIFT) +#define MATH_FUN_SUB (0x02 << MATH_FUN_SHIFT) +#define MATH_FUN_SUBB (0x03 << MATH_FUN_SHIFT) +#define MATH_FUN_OR (0x04 << MATH_FUN_SHIFT) +#define MATH_FUN_AND (0x05 << MATH_FUN_SHIFT) +#define MATH_FUN_XOR (0x06 << MATH_FUN_SHIFT) +#define MATH_FUN_LSHIFT (0x07 << MATH_FUN_SHIFT) +#define MATH_FUN_RSHIFT (0x08 << MATH_FUN_SHIFT) +#define MATH_FUN_SHLD (0x09 << MATH_FUN_SHIFT) +#define MATH_FUN_ZBYT (0x0a << MATH_FUN_SHIFT) + +/* Source 0 selectors */ +#define MATH_SRC0_SHIFT 16 +#define MATH_SRC0_MASK (0x0f << MATH_SRC0_SHIFT) +#define MATH_SRC0_REG0 (0x00 << MATH_SRC0_SHIFT) +#define MATH_SRC0_REG1 (0x01 << MATH_SRC0_SHIFT) +#define MATH_SRC0_REG2 (0x02 << MATH_SRC0_SHIFT) +#define MATH_SRC0_REG3 (0x03 << MATH_SRC0_SHIFT) +#define MATH_SRC0_IMM (0x04 << MATH_SRC0_SHIFT) +#define MATH_SRC0_SEQINLEN (0x08 << MATH_SRC0_SHIFT) +#define MATH_SRC0_SEQOUTLEN (0x09 << MATH_SRC0_SHIFT) +#define MATH_SRC0_VARSEQINLEN (0x0a << MATH_SRC0_SHIFT) +#define MATH_SRC0_VARSEQOUTLEN (0x0b << MATH_SRC0_SHIFT) +#define MATH_SRC0_ZERO (0x0c << MATH_SRC0_SHIFT) + +/* Source 1 selectors */ +#define MATH_SRC1_SHIFT 12 +#define MATH_SRC1_MASK (0x0f << MATH_SRC1_SHIFT) +#define MATH_SRC1_REG0 (0x00 << MATH_SRC1_SHIFT) +#define MATH_SRC1_REG1 (0x01 << MATH_SRC1_SHIFT) +#define MATH_SRC1_REG2 (0x02 << MATH_SRC1_SHIFT) +#define MATH_SRC1_REG3 (0x03 << MATH_SRC1_SHIFT) +#define MATH_SRC1_IMM (0x04 << MATH_SRC1_SHIFT) +#define MATH_SRC1_INFIFO (0x0a << MATH_SRC1_SHIFT) +#define MATH_SRC1_OUTFIFO (0x0b << MATH_SRC1_SHIFT) +#define MATH_SRC1_ONE (0x0c << MATH_SRC1_SHIFT) + +/* Destination selectors */ +#define MATH_DEST_SHIFT 8 +#define MATH_DEST_MASK (0x0f << MATH_DEST_SHIFT) +#define MATH_DEST_REG0 (0x00 << MATH_DEST_SHIFT) +#define MATH_DEST_REG1 (0x01 << MATH_DEST_SHIFT) +#define MATH_DEST_REG2 (0x02 << MATH_DEST_SHIFT) +#define MATH_DEST_REG3 (0x03 << MATH_DEST_SHIFT) +#define MATH_DEST_SEQINLEN (0x08 << MATH_DEST_SHIFT) +#define MATH_DEST_SEQOUTLEN (0x09 << MATH_DEST_SHIFT) +#define MATH_DEST_VARSEQINLEN (0x0a << MATH_DEST_SHIFT) +#define MATH_DEST_VARSEQOUTLEN (0x0b << MATH_DEST_SHIFT) +#define MATH_DEST_NONE (0x0f << MATH_DEST_SHIFT) + +/* Length selectors */ +#define MATH_LEN_SHIFT 0 +#define MATH_LEN_MASK (0x0f << MATH_LEN_SHIFT) +#define MATH_LEN_1BYTE 0x01 +#define MATH_LEN_2BYTE 0x02 +#define MATH_LEN_4BYTE 0x04 +#define MATH_LEN_8BYTE 0x08 + +/* + * JUMP Command Constructs + */ + +#define JUMP_CLASS_SHIFT 25 +#define JUMP_CLASS_MASK (3 << JUMP_CLASS_SHIFT) +#define JUMP_CLASS_NONE 0 +#define JUMP_CLASS_CLASS1 (1 << JUMP_CLASS_SHIFT) +#define JUMP_CLASS_CLASS2 (2 << JUMP_CLASS_SHIFT) +#define JUMP_CLASS_BOTH (3 << JUMP_CLASS_SHIFT) + +#define JUMP_JSL_SHIFT 24 +#define JUMP_JSL_MASK (1 << JUMP_JSL_SHIFT) +#define JUMP_JSL (1 << JUMP_JSL_SHIFT) + +#define JUMP_TYPE_SHIFT 22 +#define JUMP_TYPE_MASK (0x03 << JUMP_TYPE_SHIFT) +#define JUMP_TYPE_LOCAL (0x00 << JUMP_TYPE_SHIFT) +#define JUMP_TYPE_NONLOCAL (0x01 << JUMP_TYPE_SHIFT) +#define JUMP_TYPE_HALT (0x02 << JUMP_TYPE_SHIFT) +#define JUMP_TYPE_HALT_USER (0x03 << JUMP_TYPE_SHIFT) + +#define JUMP_TEST_SHIFT 16 +#define JUMP_TEST_MASK (0x03 << JUMP_TEST_SHIFT) +#define JUMP_TEST_ALL (0x00 << JUMP_TEST_SHIFT) +#define JUMP_TEST_INVALL (0x01 << JUMP_TEST_SHIFT) +#define JUMP_TEST_ANY (0x02 << JUMP_TEST_SHIFT) +#define JUMP_TEST_INVANY (0x03 << JUMP_TEST_SHIFT) + +/* Condition codes. JSL bit is factored in */ +#define JUMP_COND_SHIFT 8 +#define JUMP_COND_MASK (0x100ff << JUMP_COND_SHIFT) +#define JUMP_COND_PK_0 (0x80 << JUMP_COND_SHIFT) +#define JUMP_COND_PK_GCD_1 (0x40 << JUMP_COND_SHIFT) +#define JUMP_COND_PK_PRIME (0x20 << JUMP_COND_SHIFT) +#define JUMP_COND_MATH_N (0x08 << JUMP_COND_SHIFT) +#define JUMP_COND_MATH_Z (0x04 << JUMP_COND_SHIFT) +#define JUMP_COND_MATH_C (0x02 << JUMP_COND_SHIFT) +#define JUMP_COND_MATH_NV (0x01 << JUMP_COND_SHIFT) + +#define JUMP_COND_JRP ((0x80 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_SHRD ((0x40 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_SELF ((0x20 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_CALM ((0x10 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_NIP ((0x08 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_NIFP ((0x04 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_NOP ((0x02 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_NCP ((0x01 << JUMP_COND_SHIFT) | JUMP_JSL) + +#define JUMP_OFFSET_SHIFT 0 +#define JUMP_OFFSET_MASK (0xff << JUMP_OFFSET_SHIFT) + +/* + * NFIFO ENTRY + * Data Constructs + * + */ +#define NFIFOENTRY_DEST_SHIFT 30 +#define NFIFOENTRY_DEST_MASK (3 << NFIFOENTRY_DEST_SHIFT) +#define NFIFOENTRY_DEST_DECO (0 << NFIFOENTRY_DEST_SHIFT) +#define NFIFOENTRY_DEST_CLASS1 (1 << NFIFOENTRY_DEST_SHIFT) +#define NFIFOENTRY_DEST_CLASS2 (2 << NFIFOENTRY_DEST_SHIFT) +#define NFIFOENTRY_DEST_BOTH (3 << NFIFOENTRY_DEST_SHIFT) + +#define NFIFOENTRY_LC2_SHIFT 29 +#define NFIFOENTRY_LC2_MASK (1 << NFIFOENTRY_LC2_SHIFT) +#define NFIFOENTRY_LC2 (1 << NFIFOENTRY_LC2_SHIFT) + +#define NFIFOENTRY_LC1_SHIFT 28 +#define NFIFOENTRY_LC1_MASK (1 << NFIFOENTRY_LC1_SHIFT) +#define NFIFOENTRY_LC1 (1 << NFIFOENTRY_LC1_SHIFT) + +#define NFIFOENTRY_FC2_SHIFT 27 +#define NFIFOENTRY_FC2_MASK (1 << NFIFOENTRY_FC2_SHIFT) +#define NFIFOENTRY_FC2 (1 << NFIFOENTRY_FC2_SHIFT) + +#define NFIFOENTRY_FC1_SHIFT 26 +#define NFIFOENTRY_FC1_MASK (1 << NFIFOENTRY_FC1_SHIFT) +#define NFIFOENTRY_FC1 (1 << NFIFOENTRY_FC1_SHIFT) + +#define NFIFOENTRY_STYPE_SHIFT 24 +#define NFIFOENTRY_STYPE_MASK (3 << NFIFOENTRY_STYPE_SHIFT) +#define NFIFOENTRY_STYPE_DFIFO (0 << NFIFOENTRY_STYPE_SHIFT) +#define NFIFOENTRY_STYPE_OFIFO (1 << NFIFOENTRY_STYPE_SHIFT) +#define NFIFOENTRY_STYPE_PAD (2 << NFIFOENTRY_STYPE_SHIFT) +#define NFIFOENTRY_STYPE_SNOOP (3 << NFIFOENTRY_STYPE_SHIFT) + +#define NFIFOENTRY_DTYPE_SHIFT 20 +#define NFIFOENTRY_DTYPE_MASK (0xF << NFIFOENTRY_DTYPE_SHIFT) + +#define NFIFOENTRY_DTYPE_SBOX (0x0 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_AAD (0x1 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_IV (0x2 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_SAD (0x3 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_ICV (0xA << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_SKIP (0xE << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_MSG (0xF << NFIFOENTRY_DTYPE_SHIFT) + +#define NFIFOENTRY_DTYPE_PK_A0 (0x0 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_A1 (0x1 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_A2 (0x2 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_A3 (0x3 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_B0 (0x4 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_B1 (0x5 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_B2 (0x6 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_B3 (0x7 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_N (0x8 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_E (0x9 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_A (0xC << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_B (0xD << NFIFOENTRY_DTYPE_SHIFT) + + +#define NFIFOENTRY_BND_SHIFT 19 +#define NFIFOENTRY_BND_MASK (1 << NFIFOENTRY_BND_SHIFT) +#define NFIFOENTRY_BND (1 << NFIFOENTRY_BND_SHIFT) + +#define NFIFOENTRY_PTYPE_SHIFT 16 +#define NFIFOENTRY_PTYPE_MASK (0x7 << NFIFOENTRY_PTYPE_SHIFT) + +#define NFIFOENTRY_PTYPE_ZEROS (0x0 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_RND_NOZEROS (0x1 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_INCREMENT (0x2 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_RND (0x3 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_ZEROS_NZ (0x4 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_RND_NZ_LZ (0x5 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_N (0x6 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_RND_NZ_N (0x7 << NFIFOENTRY_PTYPE_SHIFT) + +#define NFIFOENTRY_OC_SHIFT 15 +#define NFIFOENTRY_OC_MASK (1 << NFIFOENTRY_OC_SHIFT) +#define NFIFOENTRY_OC (1 << NFIFOENTRY_OC_SHIFT) + +#define NFIFOENTRY_AST_SHIFT 14 +#define NFIFOENTRY_AST_MASK (1 << NFIFOENTRY_OC_SHIFT) +#define NFIFOENTRY_AST (1 << NFIFOENTRY_OC_SHIFT) + +#define NFIFOENTRY_BM_SHIFT 11 +#define NFIFOENTRY_BM_MASK (1 << NFIFOENTRY_BM_SHIFT) +#define NFIFOENTRY_BM (1 << NFIFOENTRY_BM_SHIFT) + +#define NFIFOENTRY_PS_SHIFT 10 +#define NFIFOENTRY_PS_MASK (1 << NFIFOENTRY_PS_SHIFT) +#define NFIFOENTRY_PS (1 << NFIFOENTRY_PS_SHIFT) + + +#define NFIFOENTRY_DLEN_SHIFT 0 +#define NFIFOENTRY_DLEN_MASK (0xFFF << NFIFOENTRY_DLEN_SHIFT) + +#define NFIFOENTRY_PLEN_SHIFT 0 +#define NFIFOENTRY_PLEN_MASK (0xFF << NFIFOENTRY_PLEN_SHIFT) + +/* + * PDB internal definitions + */ + +/* IPSec ESP CBC Encap/Decap Options */ +#define PDBOPTS_ESPCBC_ARSNONE 0x00 /* no antireplay window */ +#define PDBOPTS_ESPCBC_ARS32 0x40 /* 32-entry antireplay window */ +#define PDBOPTS_ESPCBC_ARS64 0xc0 /* 64-entry antireplay window */ +#define PDBOPTS_ESPCBC_IVSRC 0x20 /* IV comes from internal random gen */ +#define PDBOPTS_ESPCBC_ESN 0x10 /* extended sequence included */ +#define PDBOPTS_ESPCBC_OUTFMT 0x08 /* output only decapsulation (decap) */ +#define PDBOPTS_ESPCBC_IPHDRSRC 0x08 /* IP header comes from PDB (encap) */ +#define PDBOPTS_ESPCBC_INCIPHDR 0x04 /* Prepend IP header to output frame */ +#define PDBOPTS_ESPCBC_IPVSN 0x02 /* process IPv6 header */ +#define PDBOPTS_ESPCBC_TUNNEL 0x01 /* tunnel mode next-header byte */ + +#endif /* DESC_H */ diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h new file mode 100644 index 000000000000..46915800c26f --- /dev/null +++ b/drivers/crypto/caam/desc_constr.h @@ -0,0 +1,205 @@ +/* + * caam descriptor construction helper functions + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#include "desc.h" + +#define IMMEDIATE (1 << 23) +#define CAAM_CMD_SZ sizeof(u32) +#define CAAM_PTR_SZ sizeof(dma_addr_t) +#define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * 64) + +#ifdef DEBUG +#define PRINT_POS do { printk(KERN_DEBUG "%02d: %s\n", desc_len(desc),\ + &__func__[sizeof("append")]); } while (0) +#else +#define PRINT_POS +#endif + +#define DISABLE_AUTO_INFO_FIFO (IMMEDIATE | LDST_CLASS_DECO | \ + LDST_SRCDST_WORD_DECOCTRL | \ + (LDOFF_DISABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT)) +#define ENABLE_AUTO_INFO_FIFO (IMMEDIATE | LDST_CLASS_DECO | \ + LDST_SRCDST_WORD_DECOCTRL | \ + (LDOFF_ENABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT)) + +static inline int desc_len(u32 *desc) +{ + return *desc & HDR_DESCLEN_MASK; +} + +static inline int desc_bytes(void *desc) +{ + return desc_len(desc) * CAAM_CMD_SZ; +} + +static inline u32 *desc_end(u32 *desc) +{ + return desc + desc_len(desc); +} + +static inline void *sh_desc_pdb(u32 *desc) +{ + return desc + 1; +} + +static inline void init_desc(u32 *desc, u32 options) +{ + *desc = options | HDR_ONE | 1; +} + +static inline void init_sh_desc(u32 *desc, u32 options) +{ + PRINT_POS; + init_desc(desc, CMD_SHARED_DESC_HDR | options); +} + +static inline void init_sh_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes) +{ + u32 pdb_len = pdb_bytes / CAAM_CMD_SZ + 1; + + init_sh_desc(desc, ((pdb_len << HDR_START_IDX_SHIFT) + pdb_len) | + options); +} + +static inline void init_job_desc(u32 *desc, u32 options) +{ + init_desc(desc, CMD_DESC_HDR | options); +} + +static inline void append_ptr(u32 *desc, dma_addr_t ptr) +{ + dma_addr_t *offset = (dma_addr_t *)desc_end(desc); + + *offset = ptr; + + (*desc) += CAAM_PTR_SZ / CAAM_CMD_SZ; +} + +static inline void init_job_desc_shared(u32 *desc, dma_addr_t ptr, int len, + u32 options) +{ + PRINT_POS; + init_job_desc(desc, HDR_SHARED | options | + (len << HDR_START_IDX_SHIFT)); + append_ptr(desc, ptr); +} + +static inline void append_data(u32 *desc, void *data, int len) +{ + u32 *offset = desc_end(desc); + + if (len) /* avoid sparse warning: memcpy with byte count of 0 */ + memcpy(offset, data, len); + + (*desc) += (len + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ; +} + +static inline void append_cmd(u32 *desc, u32 command) +{ + u32 *cmd = desc_end(desc); + + *cmd = command; + + (*desc)++; +} + +static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len, + u32 command) +{ + append_cmd(desc, command | len); + append_ptr(desc, ptr); +} + +static inline void append_cmd_data(u32 *desc, void *data, int len, + u32 command) +{ + append_cmd(desc, command | IMMEDIATE | len); + append_data(desc, data, len); +} + +static inline u32 *append_jump(u32 *desc, u32 options) +{ + u32 *cmd = desc_end(desc); + + PRINT_POS; + append_cmd(desc, CMD_JUMP | options); + + return cmd; +} + +static inline void set_jump_tgt_here(u32 *desc, u32 *jump_cmd) +{ + *jump_cmd = *jump_cmd | (desc_len(desc) - (jump_cmd - desc)); +} + +#define APPEND_CMD(cmd, op) \ +static inline void append_##cmd(u32 *desc, u32 options) \ +{ \ + PRINT_POS; \ + append_cmd(desc, CMD_##op | options); \ +} +APPEND_CMD(operation, OPERATION) +APPEND_CMD(move, MOVE) + +#define APPEND_CMD_LEN(cmd, op) \ +static inline void append_##cmd(u32 *desc, unsigned int len, u32 options) \ +{ \ + PRINT_POS; \ + append_cmd(desc, CMD_##op | len | options); \ +} +APPEND_CMD_LEN(seq_store, SEQ_STORE) +APPEND_CMD_LEN(seq_fifo_load, SEQ_FIFO_LOAD) +APPEND_CMD_LEN(seq_fifo_store, SEQ_FIFO_STORE) + +#define APPEND_CMD_PTR(cmd, op) \ +static inline void append_##cmd(u32 *desc, dma_addr_t ptr, unsigned int len, \ + u32 options) \ +{ \ + PRINT_POS; \ + append_cmd_ptr(desc, ptr, len, CMD_##op | options); \ +} +APPEND_CMD_PTR(key, KEY) +APPEND_CMD_PTR(seq_in_ptr, SEQ_IN_PTR) +APPEND_CMD_PTR(seq_out_ptr, SEQ_OUT_PTR) +APPEND_CMD_PTR(load, LOAD) +APPEND_CMD_PTR(store, STORE) +APPEND_CMD_PTR(fifo_load, FIFO_LOAD) +APPEND_CMD_PTR(fifo_store, FIFO_STORE) + +#define APPEND_CMD_PTR_TO_IMM(cmd, op) \ +static inline void append_##cmd##_as_imm(u32 *desc, void *data, \ + unsigned int len, u32 options) \ +{ \ + PRINT_POS; \ + append_cmd_data(desc, data, len, CMD_##op | options); \ +} +APPEND_CMD_PTR_TO_IMM(load, LOAD); +APPEND_CMD_PTR_TO_IMM(fifo_load, FIFO_LOAD); + +/* + * 2nd variant for commands whose specified immediate length differs + * from length of immediate data provided, e.g., split keys + */ +#define APPEND_CMD_PTR_TO_IMM2(cmd, op) \ +static inline void append_##cmd##_as_imm(u32 *desc, void *data, \ + unsigned int data_len, \ + unsigned int len, u32 options) \ +{ \ + PRINT_POS; \ + append_cmd(desc, CMD_##op | IMMEDIATE | len | options); \ + append_data(desc, data, data_len); \ +} +APPEND_CMD_PTR_TO_IMM2(key, KEY); + +#define APPEND_CMD_RAW_IMM(cmd, op, type) \ +static inline void append_##cmd##_imm_##type(u32 *desc, type immediate, \ + u32 options) \ +{ \ + PRINT_POS; \ + append_cmd(desc, CMD_##op | IMMEDIATE | options | sizeof(type)); \ + append_cmd(desc, immediate); \ +} +APPEND_CMD_RAW_IMM(load, LOAD, u32); diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c new file mode 100644 index 000000000000..7e2d54bffad6 --- /dev/null +++ b/drivers/crypto/caam/error.c @@ -0,0 +1,248 @@ +/* + * CAAM Error Reporting + * + * Copyright 2009-2011 Freescale Semiconductor, Inc. + */ + +#include "compat.h" +#include "regs.h" +#include "intern.h" +#include "desc.h" +#include "jr.h" +#include "error.h" + +#define SPRINTFCAT(str, format, param, max_alloc) \ +{ \ + char *tmp; \ + \ + tmp = kmalloc(sizeof(format) + max_alloc, GFP_ATOMIC); \ + sprintf(tmp, format, param); \ + strcat(str, tmp); \ + kfree(tmp); \ +} + +static void report_jump_idx(u32 status, char *outstr) +{ + u8 idx = (status & JRSTA_DECOERR_INDEX_MASK) >> + JRSTA_DECOERR_INDEX_SHIFT; + + if (status & JRSTA_DECOERR_JUMP) + strcat(outstr, "jump tgt desc idx "); + else + strcat(outstr, "desc idx "); + + SPRINTFCAT(outstr, "%d: ", idx, sizeof("255")); +} + +static void report_ccb_status(u32 status, char *outstr) +{ + char *cha_id_list[] = { + "", + "AES", + "DES, 3DES", + "ARC4", + "MD5, SHA-1, SH-224, SHA-256, SHA-384, SHA-512", + "RNG", + "SNOW f8", + "Kasumi f8, f9", + "All Public Key Algorithms", + "CRC", + "SNOW f9", + }; + char *err_id_list[] = { + "None. No error.", + "Mode error.", + "Data size error.", + "Key size error.", + "PKHA A memory size error.", + "PKHA B memory size error.", + "Data arrived out of sequence error.", + "PKHA divide-by-zero error.", + "PKHA modulus even error.", + "DES key parity error.", + "ICV check failed.", + "Hardware error.", + "Unsupported CCM AAD size.", + "Class 1 CHA is not reset", + "Invalid CHA combination was selected", + "Invalid CHA selected.", + }; + u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >> + JRSTA_CCBERR_CHAID_SHIFT; + u8 err_id = status & JRSTA_CCBERR_ERRID_MASK; + + report_jump_idx(status, outstr); + + if (cha_id < ARRAY_SIZE(cha_id_list)) { + SPRINTFCAT(outstr, "%s: ", cha_id_list[cha_id], + strlen(cha_id_list[cha_id])); + } else { + SPRINTFCAT(outstr, "unidentified cha_id value 0x%02x: ", + cha_id, sizeof("ff")); + } + + if (err_id < ARRAY_SIZE(err_id_list)) { + SPRINTFCAT(outstr, "%s", err_id_list[err_id], + strlen(err_id_list[err_id])); + } else { + SPRINTFCAT(outstr, "unidentified err_id value 0x%02x", + err_id, sizeof("ff")); + } +} + +static void report_jump_status(u32 status, char *outstr) +{ + SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__)); +} + +static void report_deco_status(u32 status, char *outstr) +{ + const struct { + u8 value; + char *error_text; + } desc_error_list[] = { + { 0x00, "None. No error." }, + { 0x01, "SGT Length Error. The descriptor is trying to read " + "more data than is contained in the SGT table." }, + { 0x02, "Reserved." }, + { 0x03, "Job Ring Control Error. There is a bad value in the " + "Job Ring Control register." }, + { 0x04, "Invalid Descriptor Command. The Descriptor Command " + "field is invalid." }, + { 0x05, "Reserved." }, + { 0x06, "Invalid KEY Command" }, + { 0x07, "Invalid LOAD Command" }, + { 0x08, "Invalid STORE Command" }, + { 0x09, "Invalid OPERATION Command" }, + { 0x0A, "Invalid FIFO LOAD Command" }, + { 0x0B, "Invalid FIFO STORE Command" }, + { 0x0C, "Invalid MOVE Command" }, + { 0x0D, "Invalid JUMP Command. A nonlocal JUMP Command is " + "invalid because the target is not a Job Header " + "Command, or the jump is from a Trusted Descriptor to " + "a Job Descriptor, or because the target Descriptor " + "contains a Shared Descriptor." }, + { 0x0E, "Invalid MATH Command" }, + { 0x0F, "Invalid SIGNATURE Command" }, + { 0x10, "Invalid Sequence Command. A SEQ IN PTR OR SEQ OUT PTR " + "Command is invalid or a SEQ KEY, SEQ LOAD, SEQ FIFO " + "LOAD, or SEQ FIFO STORE decremented the input or " + "output sequence length below 0. This error may result " + "if a built-in PROTOCOL Command has encountered a " + "malformed PDU." }, + { 0x11, "Skip data type invalid. The type must be 0xE or 0xF."}, + { 0x12, "Shared Descriptor Header Error" }, + { 0x13, "Header Error. Invalid length or parity, or certain " + "other problems." }, + { 0x14, "Burster Error. Burster has gotten to an illegal " + "state" }, + { 0x15, "Context Register Length Error. The descriptor is " + "trying to read or write past the end of the Context " + "Register. A SEQ LOAD or SEQ STORE with the VLF bit " + "set was executed with too large a length in the " + "variable length register (VSOL for SEQ STORE or VSIL " + "for SEQ LOAD)." }, + { 0x16, "DMA Error" }, + { 0x17, "Reserved." }, + { 0x1A, "Job failed due to JR reset" }, + { 0x1B, "Job failed due to Fail Mode" }, + { 0x1C, "DECO Watchdog timer timeout error" }, + { 0x1D, "DECO tried to copy a key from another DECO but the " + "other DECO's Key Registers were locked" }, + { 0x1E, "DECO attempted to copy data from a DECO that had an " + "unmasked Descriptor error" }, + { 0x1F, "LIODN error. DECO was trying to share from itself or " + "from another DECO but the two Non-SEQ LIODN values " + "didn't match or the 'shared from' DECO's Descriptor " + "required that the SEQ LIODNs be the same and they " + "aren't." }, + { 0x20, "DECO has completed a reset initiated via the DRR " + "register" }, + { 0x21, "Nonce error. When using EKT (CCM) key encryption " + "option in the FIFO STORE Command, the Nonce counter " + "reached its maximum value and this encryption mode " + "can no longer be used." }, + { 0x22, "Meta data is too large (> 511 bytes) for TLS decap " + "(input frame; block ciphers) and IPsec decap (output " + "frame, when doing the next header byte update) and " + "DCRC (output frame)." }, + { 0x80, "DNR (do not run) error" }, + { 0x81, "undefined protocol command" }, + { 0x82, "invalid setting in PDB" }, + { 0x83, "Anti-replay LATE error" }, + { 0x84, "Anti-replay REPLAY error" }, + { 0x85, "Sequence number overflow" }, + { 0x86, "Sigver invalid signature" }, + { 0x87, "DSA Sign Illegal test descriptor" }, + { 0x88, "Protocol Format Error - A protocol has seen an error " + "in the format of data received. When running RSA, " + "this means that formatting with random padding was " + "used, and did not follow the form: 0x00, 0x02, 8-to-N " + "bytes of non-zero pad, 0x00, F data." }, + { 0x89, "Protocol Size Error - A protocol has seen an error in " + "size. When running RSA, pdb size N < (size of F) when " + "no formatting is used; or pdb size N < (F + 11) when " + "formatting is used." }, + { 0xC1, "Blob Command error: Undefined mode" }, + { 0xC2, "Blob Command error: Secure Memory Blob mode error" }, + { 0xC4, "Blob Command error: Black Blob key or input size " + "error" }, + { 0xC5, "Blob Command error: Invalid key destination" }, + { 0xC8, "Blob Command error: Trusted/Secure mode error" }, + { 0xF0, "IPsec TTL or hop limit field either came in as 0, " + "or was decremented to 0" }, + { 0xF1, "3GPP HFN matches or exceeds the Threshold" }, + }; + u8 desc_error = status & JRSTA_DECOERR_ERROR_MASK; + int i; + + report_jump_idx(status, outstr); + + for (i = 0; i < ARRAY_SIZE(desc_error_list); i++) + if (desc_error_list[i].value == desc_error) + break; + + if (i != ARRAY_SIZE(desc_error_list) && desc_error_list[i].error_text) { + SPRINTFCAT(outstr, "%s", desc_error_list[i].error_text, + strlen(desc_error_list[i].error_text)); + } else { + SPRINTFCAT(outstr, "unidentified error value 0x%02x", + desc_error, sizeof("ff")); + } +} + +static void report_jr_status(u32 status, char *outstr) +{ + SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__)); +} + +static void report_cond_code_status(u32 status, char *outstr) +{ + SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__)); +} + +char *caam_jr_strstatus(char *outstr, u32 status) +{ + struct stat_src { + void (*report_ssed)(u32 status, char *outstr); + char *error; + } status_src[] = { + { NULL, "No error" }, + { NULL, NULL }, + { report_ccb_status, "CCB" }, + { report_jump_status, "Jump" }, + { report_deco_status, "DECO" }, + { NULL, NULL }, + { report_jr_status, "Job Ring" }, + { report_cond_code_status, "Condition Code" }, + }; + u32 ssrc = status >> JRSTA_SSRC_SHIFT; + + sprintf(outstr, "%s: ", status_src[ssrc].error); + + if (status_src[ssrc].report_ssed) + status_src[ssrc].report_ssed(status, outstr); + + return outstr; +} +EXPORT_SYMBOL(caam_jr_strstatus); diff --git a/drivers/crypto/caam/error.h b/drivers/crypto/caam/error.h new file mode 100644 index 000000000000..02c7baa1748e --- /dev/null +++ b/drivers/crypto/caam/error.h @@ -0,0 +1,11 @@ +/* + * CAAM Error Reporting code header + * + * Copyright 2009-2011 Freescale Semiconductor, Inc. + */ + +#ifndef CAAM_ERROR_H +#define CAAM_ERROR_H +#define CAAM_ERROR_STR_MAX 302 +extern char *caam_jr_strstatus(char *outstr, u32 status); +#endif /* CAAM_ERROR_H */ diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h new file mode 100644 index 000000000000..a34be01b0b29 --- /dev/null +++ b/drivers/crypto/caam/intern.h @@ -0,0 +1,113 @@ +/* + * CAAM/SEC 4.x driver backend + * Private/internal definitions between modules + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + */ + +#ifndef INTERN_H +#define INTERN_H + +#define JOBR_UNASSIGNED 0 +#define JOBR_ASSIGNED 1 + +/* Currently comes from Kconfig param as a ^2 (driver-required) */ +#define JOBR_DEPTH (1 << CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE) + +/* Kconfig params for interrupt coalescing if selected (else zero) */ +#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_INTC +#define JOBR_INTC JRCFG_ICEN +#define JOBR_INTC_TIME_THLD CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD +#define JOBR_INTC_COUNT_THLD CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD +#else +#define JOBR_INTC 0 +#define JOBR_INTC_TIME_THLD 0 +#define JOBR_INTC_COUNT_THLD 0 +#endif + +/* + * Storage for tracking each in-process entry moving across a ring + * Each entry on an output ring needs one of these + */ +struct caam_jrentry_info { + void (*callbk)(struct device *dev, u32 *desc, u32 status, void *arg); + void *cbkarg; /* Argument per ring entry */ + u32 *desc_addr_virt; /* Stored virt addr for postprocessing */ + dma_addr_t desc_addr_dma; /* Stored bus addr for done matching */ + u32 desc_size; /* Stored size for postprocessing, header derived */ +}; + +/* Private sub-storage for a single JobR */ +struct caam_drv_private_jr { + struct device *parentdev; /* points back to controller dev */ + int ridx; + struct caam_job_ring __iomem *rregs; /* JobR's register space */ + struct tasklet_struct irqtask[NR_CPUS]; + int irq; /* One per queue */ + int assign; /* busy/free */ + + /* Job ring info */ + int ringsize; /* Size of rings (assume input = output) */ + struct caam_jrentry_info *entinfo; /* Alloc'ed 1 per ring entry */ + spinlock_t inplock ____cacheline_aligned; /* Input ring index lock */ + int inp_ring_write_index; /* Input index "tail" */ + int head; /* entinfo (s/w ring) head index */ + dma_addr_t *inpring; /* Base of input ring, alloc DMA-safe */ + spinlock_t outlock ____cacheline_aligned; /* Output ring index lock */ + int out_ring_read_index; /* Output index "tail" */ + int tail; /* entinfo (s/w ring) tail index */ + struct jr_outentry *outring; /* Base of output ring, DMA-safe */ +}; + +/* + * Driver-private storage for a single CAAM block instance + */ +struct caam_drv_private { + + struct device *dev; + struct device **jrdev; /* Alloc'ed array per sub-device */ + spinlock_t jr_alloc_lock; + struct platform_device *pdev; + + /* Physical-presence section */ + struct caam_ctrl *ctrl; /* controller region */ + struct caam_deco **deco; /* DECO/CCB views */ + struct caam_assurance *ac; + struct caam_queue_if *qi; /* QI control region */ + + /* + * Detected geometry block. Filled in from device tree if powerpc, + * or from register-based version detection code + */ + u8 total_jobrs; /* Total Job Rings in device */ + u8 qi_present; /* Nonzero if QI present in device */ + int secvio_irq; /* Security violation interrupt number */ + + /* which jr allocated to scatterlist crypto */ + atomic_t tfm_count ____cacheline_aligned; + int num_jrs_for_algapi; + struct device **algapi_jr; + /* list of registered crypto algorithms (mk generic context handle?) */ + struct list_head alg_list; + + /* + * debugfs entries for developer view into driver/device + * variables at runtime. + */ +#ifdef CONFIG_DEBUG_FS + struct dentry *dfs_root; + struct dentry *ctl; /* controller dir */ + struct dentry *ctl_rq_dequeued, *ctl_ob_enc_req, *ctl_ib_dec_req; + struct dentry *ctl_ob_enc_bytes, *ctl_ob_prot_bytes; + struct dentry *ctl_ib_dec_bytes, *ctl_ib_valid_bytes; + struct dentry *ctl_faultaddr, *ctl_faultdetail, *ctl_faultstatus; + + struct debugfs_blob_wrapper ctl_kek_wrap, ctl_tkek_wrap, ctl_tdsk_wrap; + struct dentry *ctl_kek, *ctl_tkek, *ctl_tdsk; +#endif +}; + +void caam_jr_algapi_init(struct device *dev); +void caam_jr_algapi_remove(struct device *dev); +#endif /* INTERN_H */ diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c new file mode 100644 index 000000000000..340fa322c0f0 --- /dev/null +++ b/drivers/crypto/caam/jr.c @@ -0,0 +1,517 @@ +/* + * CAAM/SEC 4.x transport/backend driver + * JobR backend functionality + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#include "compat.h" +#include "regs.h" +#include "jr.h" +#include "desc.h" +#include "intern.h" + +/* Main per-ring interrupt handler */ +static irqreturn_t caam_jr_interrupt(int irq, void *st_dev) +{ + struct device *dev = st_dev; + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + u32 irqstate; + + /* + * Check the output ring for ready responses, kick + * tasklet if jobs done. + */ + irqstate = rd_reg32(&jrp->rregs->jrintstatus); + if (!irqstate) + return IRQ_NONE; + + /* + * If JobR error, we got more development work to do + * Flag a bug now, but we really need to shut down and + * restart the queue (and fix code). + */ + if (irqstate & JRINT_JR_ERROR) { + dev_err(dev, "job ring error: irqstate: %08x\n", irqstate); + BUG(); + } + + /* mask valid interrupts */ + setbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); + + /* Have valid interrupt at this point, just ACK and trigger */ + wr_reg32(&jrp->rregs->jrintstatus, irqstate); + + preempt_disable(); + tasklet_schedule(&jrp->irqtask[smp_processor_id()]); + preempt_enable(); + + return IRQ_HANDLED; +} + +/* Deferred service handler, run as interrupt-fired tasklet */ +static void caam_jr_dequeue(unsigned long devarg) +{ + int hw_idx, sw_idx, i, head, tail; + struct device *dev = (struct device *)devarg; + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg); + u32 *userdesc, userstatus; + void *userarg; + unsigned long flags; + + spin_lock_irqsave(&jrp->outlock, flags); + + head = ACCESS_ONCE(jrp->head); + sw_idx = tail = jrp->tail; + + while (CIRC_CNT(head, tail, JOBR_DEPTH) >= 1 && + rd_reg32(&jrp->rregs->outring_used)) { + + hw_idx = jrp->out_ring_read_index; + for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) { + sw_idx = (tail + i) & (JOBR_DEPTH - 1); + + smp_read_barrier_depends(); + + if (jrp->outring[hw_idx].desc == + jrp->entinfo[sw_idx].desc_addr_dma) + break; /* found */ + } + /* we should never fail to find a matching descriptor */ + BUG_ON(CIRC_CNT(head, tail + i, JOBR_DEPTH) <= 0); + + /* Unmap just-run descriptor so we can post-process */ + dma_unmap_single(dev, jrp->outring[hw_idx].desc, + jrp->entinfo[sw_idx].desc_size, + DMA_TO_DEVICE); + + /* mark completed, avoid matching on a recycled desc addr */ + jrp->entinfo[sw_idx].desc_addr_dma = 0; + + /* Stash callback params for use outside of lock */ + usercall = jrp->entinfo[sw_idx].callbk; + userarg = jrp->entinfo[sw_idx].cbkarg; + userdesc = jrp->entinfo[sw_idx].desc_addr_virt; + userstatus = jrp->outring[hw_idx].jrstatus; + + smp_mb(); + + jrp->out_ring_read_index = (jrp->out_ring_read_index + 1) & + (JOBR_DEPTH - 1); + + /* + * if this job completed out-of-order, do not increment + * the tail. Otherwise, increment tail by 1 plus the + * number of subsequent jobs already completed out-of-order + */ + if (sw_idx == tail) { + do { + tail = (tail + 1) & (JOBR_DEPTH - 1); + smp_read_barrier_depends(); + } while (CIRC_CNT(head, tail, JOBR_DEPTH) >= 1 && + jrp->entinfo[tail].desc_addr_dma == 0); + + jrp->tail = tail; + } + + /* set done */ + wr_reg32(&jrp->rregs->outring_rmvd, 1); + + spin_unlock_irqrestore(&jrp->outlock, flags); + + /* Finally, execute user's callback */ + usercall(dev, userdesc, userstatus, userarg); + + spin_lock_irqsave(&jrp->outlock, flags); + + head = ACCESS_ONCE(jrp->head); + sw_idx = tail = jrp->tail; + } + + spin_unlock_irqrestore(&jrp->outlock, flags); + + /* reenable / unmask IRQs */ + clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); +} + +/** + * caam_jr_register() - Alloc a ring for someone to use as needed. Returns + * an ordinal of the rings allocated, else returns -ENODEV if no rings + * are available. + * @ctrldev: points to the controller level dev (parent) that + * owns rings available for use. + * @dev: points to where a pointer to the newly allocated queue's + * dev can be written to if successful. + **/ +int caam_jr_register(struct device *ctrldev, struct device **rdev) +{ + struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); + struct caam_drv_private_jr *jrpriv = NULL; + unsigned long flags; + int ring; + + /* Lock, if free ring - assign, unlock */ + spin_lock_irqsave(&ctrlpriv->jr_alloc_lock, flags); + for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) { + jrpriv = dev_get_drvdata(ctrlpriv->jrdev[ring]); + if (jrpriv->assign == JOBR_UNASSIGNED) { + jrpriv->assign = JOBR_ASSIGNED; + *rdev = ctrlpriv->jrdev[ring]; + spin_unlock_irqrestore(&ctrlpriv->jr_alloc_lock, flags); + return ring; + } + } + + /* If assigned, write dev where caller needs it */ + spin_unlock_irqrestore(&ctrlpriv->jr_alloc_lock, flags); + *rdev = NULL; + + return -ENODEV; +} +EXPORT_SYMBOL(caam_jr_register); + +/** + * caam_jr_deregister() - Deregister an API and release the queue. + * Returns 0 if OK, -EBUSY if queue still contains pending entries + * or unprocessed results at the time of the call + * @dev - points to the dev that identifies the queue to + * be released. + **/ +int caam_jr_deregister(struct device *rdev) +{ + struct caam_drv_private_jr *jrpriv = dev_get_drvdata(rdev); + struct caam_drv_private *ctrlpriv; + unsigned long flags; + + /* Get the owning controller's private space */ + ctrlpriv = dev_get_drvdata(jrpriv->parentdev); + + /* + * Make sure ring empty before release + */ + if (rd_reg32(&jrpriv->rregs->outring_used) || + (rd_reg32(&jrpriv->rregs->inpring_avail) != JOBR_DEPTH)) + return -EBUSY; + + /* Release ring */ + spin_lock_irqsave(&ctrlpriv->jr_alloc_lock, flags); + jrpriv->assign = JOBR_UNASSIGNED; + spin_unlock_irqrestore(&ctrlpriv->jr_alloc_lock, flags); + + return 0; +} +EXPORT_SYMBOL(caam_jr_deregister); + +/** + * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK, + * -EBUSY if the queue is full, -EIO if it cannot map the caller's + * descriptor. + * @dev: device of the job ring to be used. This device should have + * been assigned prior by caam_jr_register(). + * @desc: points to a job descriptor that execute our request. All + * descriptors (and all referenced data) must be in a DMAable + * region, and all data references must be physical addresses + * accessible to CAAM (i.e. within a PAMU window granted + * to it). + * @cbk: pointer to a callback function to be invoked upon completion + * of this request. This has the form: + * callback(struct device *dev, u32 *desc, u32 stat, void *arg) + * where: + * @dev: contains the job ring device that processed this + * response. + * @desc: descriptor that initiated the request, same as + * "desc" being argued to caam_jr_enqueue(). + * @status: untranslated status received from CAAM. See the + * reference manual for a detailed description of + * error meaning, or see the JRSTA definitions in the + * register header file + * @areq: optional pointer to an argument passed with the + * original request + * @areq: optional pointer to a user argument for use at callback + * time. + **/ +int caam_jr_enqueue(struct device *dev, u32 *desc, + void (*cbk)(struct device *dev, u32 *desc, + u32 status, void *areq), + void *areq) +{ + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + struct caam_jrentry_info *head_entry; + unsigned long flags; + int head, tail, desc_size; + dma_addr_t desc_dma; + + desc_size = (*desc & HDR_JD_LENGTH_MASK) * sizeof(u32); + desc_dma = dma_map_single(dev, desc, desc_size, DMA_TO_DEVICE); + if (dma_mapping_error(dev, desc_dma)) { + dev_err(dev, "caam_jr_enqueue(): can't map jobdesc\n"); + return -EIO; + } + + spin_lock_irqsave(&jrp->inplock, flags); + + head = jrp->head; + tail = ACCESS_ONCE(jrp->tail); + + if (!rd_reg32(&jrp->rregs->inpring_avail) || + CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) { + spin_unlock_irqrestore(&jrp->inplock, flags); + dma_unmap_single(dev, desc_dma, desc_size, DMA_TO_DEVICE); + return -EBUSY; + } + + head_entry = &jrp->entinfo[head]; + head_entry->desc_addr_virt = desc; + head_entry->desc_size = desc_size; + head_entry->callbk = (void *)cbk; + head_entry->cbkarg = areq; + head_entry->desc_addr_dma = desc_dma; + + jrp->inpring[jrp->inp_ring_write_index] = desc_dma; + + smp_wmb(); + + jrp->inp_ring_write_index = (jrp->inp_ring_write_index + 1) & + (JOBR_DEPTH - 1); + jrp->head = (head + 1) & (JOBR_DEPTH - 1); + + wmb(); + + wr_reg32(&jrp->rregs->inpring_jobadd, 1); + + spin_unlock_irqrestore(&jrp->inplock, flags); + + return 0; +} +EXPORT_SYMBOL(caam_jr_enqueue); + +static int caam_reset_hw_jr(struct device *dev) +{ + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + unsigned int timeout = 100000; + + /* + * mask interrupts since we are going to poll + * for reset completion status + */ + setbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); + + /* initiate flush (required prior to reset) */ + wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); + while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) == + JRINT_ERR_HALT_INPROGRESS) && --timeout) + cpu_relax(); + + if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) != + JRINT_ERR_HALT_COMPLETE || timeout == 0) { + dev_err(dev, "failed to flush job ring %d\n", jrp->ridx); + return -EIO; + } + + /* initiate reset */ + timeout = 100000; + wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); + while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout) + cpu_relax(); + + if (timeout == 0) { + dev_err(dev, "failed to reset job ring %d\n", jrp->ridx); + return -EIO; + } + + /* unmask interrupts */ + clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); + + return 0; +} + +/* + * Init JobR independent of platform property detection + */ +static int caam_jr_init(struct device *dev) +{ + struct caam_drv_private_jr *jrp; + dma_addr_t inpbusaddr, outbusaddr; + int i, error; + + jrp = dev_get_drvdata(dev); + + /* Connect job ring interrupt handler. */ + for_each_possible_cpu(i) + tasklet_init(&jrp->irqtask[i], caam_jr_dequeue, + (unsigned long)dev); + + error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED, + "caam-jobr", dev); + if (error) { + dev_err(dev, "can't connect JobR %d interrupt (%d)\n", + jrp->ridx, jrp->irq); + irq_dispose_mapping(jrp->irq); + jrp->irq = 0; + return -EINVAL; + } + + error = caam_reset_hw_jr(dev); + if (error) + return error; + + jrp->inpring = kzalloc(sizeof(dma_addr_t) * JOBR_DEPTH, + GFP_KERNEL | GFP_DMA); + jrp->outring = kzalloc(sizeof(struct jr_outentry) * + JOBR_DEPTH, GFP_KERNEL | GFP_DMA); + + jrp->entinfo = kzalloc(sizeof(struct caam_jrentry_info) * JOBR_DEPTH, + GFP_KERNEL); + + if ((jrp->inpring == NULL) || (jrp->outring == NULL) || + (jrp->entinfo == NULL)) { + dev_err(dev, "can't allocate job rings for %d\n", + jrp->ridx); + return -ENOMEM; + } + + for (i = 0; i < JOBR_DEPTH; i++) + jrp->entinfo[i].desc_addr_dma = !0; + + /* Setup rings */ + inpbusaddr = dma_map_single(dev, jrp->inpring, + sizeof(u32 *) * JOBR_DEPTH, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(dev, inpbusaddr)) { + dev_err(dev, "caam_jr_init(): can't map input ring\n"); + kfree(jrp->inpring); + kfree(jrp->outring); + kfree(jrp->entinfo); + return -EIO; + } + + outbusaddr = dma_map_single(dev, jrp->outring, + sizeof(struct jr_outentry) * JOBR_DEPTH, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(dev, outbusaddr)) { + dev_err(dev, "caam_jr_init(): can't map output ring\n"); + dma_unmap_single(dev, inpbusaddr, + sizeof(u32 *) * JOBR_DEPTH, + DMA_BIDIRECTIONAL); + kfree(jrp->inpring); + kfree(jrp->outring); + kfree(jrp->entinfo); + return -EIO; + } + + jrp->inp_ring_write_index = 0; + jrp->out_ring_read_index = 0; + jrp->head = 0; + jrp->tail = 0; + + wr_reg64(&jrp->rregs->inpring_base, inpbusaddr); + wr_reg64(&jrp->rregs->outring_base, outbusaddr); + wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH); + wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH); + + jrp->ringsize = JOBR_DEPTH; + + spin_lock_init(&jrp->inplock); + spin_lock_init(&jrp->outlock); + + /* Select interrupt coalescing parameters */ + setbits32(&jrp->rregs->rconfig_lo, JOBR_INTC | + (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) | + (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT)); + + jrp->assign = JOBR_UNASSIGNED; + return 0; +} + +/* + * Shutdown JobR independent of platform property code + */ +int caam_jr_shutdown(struct device *dev) +{ + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + dma_addr_t inpbusaddr, outbusaddr; + int ret, i; + + ret = caam_reset_hw_jr(dev); + + for_each_possible_cpu(i) + tasklet_kill(&jrp->irqtask[i]); + + /* Release interrupt */ + free_irq(jrp->irq, dev); + + /* Free rings */ + inpbusaddr = rd_reg64(&jrp->rregs->inpring_base); + outbusaddr = rd_reg64(&jrp->rregs->outring_base); + dma_unmap_single(dev, outbusaddr, + sizeof(struct jr_outentry) * JOBR_DEPTH, + DMA_BIDIRECTIONAL); + dma_unmap_single(dev, inpbusaddr, sizeof(u32 *) * JOBR_DEPTH, + DMA_BIDIRECTIONAL); + kfree(jrp->outring); + kfree(jrp->inpring); + kfree(jrp->entinfo); + + return ret; +} + +/* + * Probe routine for each detected JobR subsystem. It assumes that + * property detection was picked up externally. + */ +int caam_jr_probe(struct platform_device *pdev, struct device_node *np, + int ring) +{ + struct device *ctrldev, *jrdev; + struct platform_device *jr_pdev; + struct caam_drv_private *ctrlpriv; + struct caam_drv_private_jr *jrpriv; + u32 *jroffset; + int error; + + ctrldev = &pdev->dev; + ctrlpriv = dev_get_drvdata(ctrldev); + + jrpriv = kmalloc(sizeof(struct caam_drv_private_jr), + GFP_KERNEL); + if (jrpriv == NULL) { + dev_err(ctrldev, "can't alloc private mem for job ring %d\n", + ring); + return -ENOMEM; + } + jrpriv->parentdev = ctrldev; /* point back to parent */ + jrpriv->ridx = ring; /* save ring identity relative to detection */ + + /* + * Derive a pointer to the detected JobRs regs + * Driver has already iomapped the entire space, we just + * need to add in the offset to this JobR. Don't know if I + * like this long-term, but it'll run + */ + jroffset = (u32 *)of_get_property(np, "reg", NULL); + jrpriv->rregs = (struct caam_job_ring __iomem *)((void *)ctrlpriv->ctrl + + *jroffset); + + /* Build a local dev for each detected queue */ + jr_pdev = of_platform_device_create(np, NULL, ctrldev); + if (jr_pdev == NULL) { + kfree(jrpriv); + return -EINVAL; + } + jrdev = &jr_pdev->dev; + dev_set_drvdata(jrdev, jrpriv); + ctrlpriv->jrdev[ring] = jrdev; + + /* Identify the interrupt */ + jrpriv->irq = of_irq_to_resource(np, 0, NULL); + + /* Now do the platform independent part */ + error = caam_jr_init(jrdev); /* now turn on hardware */ + if (error) { + kfree(jrpriv); + return error; + } + + return error; +} diff --git a/drivers/crypto/caam/jr.h b/drivers/crypto/caam/jr.h new file mode 100644 index 000000000000..c23df395b622 --- /dev/null +++ b/drivers/crypto/caam/jr.h @@ -0,0 +1,21 @@ +/* + * CAAM public-level include definitions for the JobR backend + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#ifndef JR_H +#define JR_H + +/* Prototypes for backend-level services exposed to APIs */ +int caam_jr_register(struct device *ctrldev, struct device **rdev); +int caam_jr_deregister(struct device *rdev); +int caam_jr_enqueue(struct device *dev, u32 *desc, + void (*cbk)(struct device *dev, u32 *desc, u32 status, + void *areq), + void *areq); + +extern int caam_jr_probe(struct platform_device *pdev, struct device_node *np, + int ring); +extern int caam_jr_shutdown(struct device *dev); +#endif /* JR_H */ diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h new file mode 100644 index 000000000000..aee394e39056 --- /dev/null +++ b/drivers/crypto/caam/regs.h @@ -0,0 +1,663 @@ +/* + * CAAM hardware register-level view + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#ifndef REGS_H +#define REGS_H + +#include +#include + +/* + * Architecture-specific register access methods + * + * CAAM's bus-addressable registers are 64 bits internally. + * They have been wired to be safely accessible on 32-bit + * architectures, however. Registers were organized such + * that (a) they can be contained in 32 bits, (b) if not, then they + * can be treated as two 32-bit entities, or finally (c) if they + * must be treated as a single 64-bit value, then this can safely + * be done with two 32-bit cycles. + * + * For 32-bit operations on 64-bit values, CAAM follows the same + * 64-bit register access conventions as it's predecessors, in that + * writes are "triggered" by a write to the register at the numerically + * higher address, thus, a full 64-bit write cycle requires a write + * to the lower address, followed by a write to the higher address, + * which will latch/execute the write cycle. + * + * For example, let's assume a SW reset of CAAM through the master + * configuration register. + * - SWRST is in bit 31 of MCFG. + * - MCFG begins at base+0x0000. + * - Bits 63-32 are a 32-bit word at base+0x0000 (numerically-lower) + * - Bits 31-0 are a 32-bit word at base+0x0004 (numerically-higher) + * + * (and on Power, the convention is 0-31, 32-63, I know...) + * + * Assuming a 64-bit write to this MCFG to perform a software reset + * would then require a write of 0 to base+0x0000, followed by a + * write of 0x80000000 to base+0x0004, which would "execute" the + * reset. + * + * Of course, since MCFG 63-32 is all zero, we could cheat and simply + * write 0x8000000 to base+0x0004, and the reset would work fine. + * However, since CAAM does contain some write-and-read-intended + * 64-bit registers, this code defines 64-bit access methods for + * the sake of internal consistency and simplicity, and so that a + * clean transition to 64-bit is possible when it becomes necessary. + * + * There are limitations to this that the developer must recognize. + * 32-bit architectures cannot enforce an atomic-64 operation, + * Therefore: + * + * - On writes, since the HW is assumed to latch the cycle on the + * write of the higher-numeric-address word, then ordered + * writes work OK. + * + * - For reads, where a register contains a relevant value of more + * that 32 bits, the hardware employs logic to latch the other + * "half" of the data until read, ensuring an accurate value. + * This is of particular relevance when dealing with CAAM's + * performance counters. + * + */ + +#ifdef __BIG_ENDIAN +#define wr_reg32(reg, data) out_be32(reg, data) +#define rd_reg32(reg) in_be32(reg) +#ifdef CONFIG_64BIT +#define wr_reg64(reg, data) out_be64(reg, data) +#define rd_reg64(reg) in_be64(reg) +#endif +#else +#ifdef __LITTLE_ENDIAN +#define wr_reg32(reg, data) __raw_writel(reg, data) +#define rd_reg32(reg) __raw_readl(reg) +#ifdef CONFIG_64BIT +#define wr_reg64(reg, data) __raw_writeq(reg, data) +#define rd_reg64(reg) __raw_readq(reg) +#endif +#endif +#endif + +#ifndef CONFIG_64BIT +static inline void wr_reg64(u64 __iomem *reg, u64 data) +{ + wr_reg32((u32 __iomem *)reg, (data & 0xffffffff00000000ull) >> 32); + wr_reg32((u32 __iomem *)reg + 1, data & 0x00000000ffffffffull); +} + +static inline u64 rd_reg64(u64 __iomem *reg) +{ + return (((u64)rd_reg32((u32 __iomem *)reg)) << 32) | + ((u64)rd_reg32((u32 __iomem *)reg + 1)); +} +#endif + +/* + * jr_outentry + * Represents each entry in a JobR output ring + */ +struct jr_outentry { + dma_addr_t desc;/* Pointer to completed descriptor */ + u32 jrstatus; /* Status for completed descriptor */ +} __packed; + +/* + * caam_perfmon - Performance Monitor/Secure Memory Status/ + * CAAM Global Status/Component Version IDs + * + * Spans f00-fff wherever instantiated + */ + +/* Number of DECOs */ +#define CHA_NUM_DECONUM_SHIFT 56 +#define CHA_NUM_DECONUM_MASK (0xfull << CHA_NUM_DECONUM_SHIFT) + +struct caam_perfmon { + /* Performance Monitor Registers f00-f9f */ + u64 req_dequeued; /* PC_REQ_DEQ - Dequeued Requests */ + u64 ob_enc_req; /* PC_OB_ENC_REQ - Outbound Encrypt Requests */ + u64 ib_dec_req; /* PC_IB_DEC_REQ - Inbound Decrypt Requests */ + u64 ob_enc_bytes; /* PC_OB_ENCRYPT - Outbound Bytes Encrypted */ + u64 ob_prot_bytes; /* PC_OB_PROTECT - Outbound Bytes Protected */ + u64 ib_dec_bytes; /* PC_IB_DECRYPT - Inbound Bytes Decrypted */ + u64 ib_valid_bytes; /* PC_IB_VALIDATED Inbound Bytes Validated */ + u64 rsvd[13]; + + /* CAAM Hardware Instantiation Parameters fa0-fbf */ + u64 cha_rev; /* CRNR - CHA Revision Number */ +#define CTPR_QI_SHIFT 57 +#define CTPR_QI_MASK (0x1ull << CTPR_QI_SHIFT) + u64 comp_parms; /* CTPR - Compile Parameters Register */ + u64 rsvd1[2]; + + /* CAAM Global Status fc0-fdf */ + u64 faultaddr; /* FAR - Fault Address */ + u32 faultliodn; /* FALR - Fault Address LIODN */ + u32 faultdetail; /* FADR - Fault Addr Detail */ + u32 rsvd2; + u32 status; /* CSTA - CAAM Status */ + u64 rsvd3; + + /* Component Instantiation Parameters fe0-fff */ + u32 rtic_id; /* RVID - RTIC Version ID */ + u32 ccb_id; /* CCBVID - CCB Version ID */ + u64 cha_id; /* CHAVID - CHA Version ID */ + u64 cha_num; /* CHANUM - CHA Number */ + u64 caam_id; /* CAAMVID - CAAM Version ID */ +}; + +/* LIODN programming for DMA configuration */ +#define MSTRID_LOCK_LIODN 0x80000000 +#define MSTRID_LOCK_MAKETRUSTED 0x00010000 /* only for JR masterid */ + +#define MSTRID_LIODN_MASK 0x0fff +struct masterid { + u32 liodn_ms; /* lock and make-trusted control bits */ + u32 liodn_ls; /* LIODN for non-sequence and seq access */ +}; + +/* Partition ID for DMA configuration */ +struct partid { + u32 rsvd1; + u32 pidr; /* partition ID, DECO */ +}; + +/* RNG test mode (replicated twice in some configurations) */ +/* Padded out to 0x100 */ +struct rngtst { + u32 mode; /* RTSTMODEx - Test mode */ + u32 rsvd1[3]; + u32 reset; /* RTSTRESETx - Test reset control */ + u32 rsvd2[3]; + u32 status; /* RTSTSSTATUSx - Test status */ + u32 rsvd3; + u32 errstat; /* RTSTERRSTATx - Test error status */ + u32 rsvd4; + u32 errctl; /* RTSTERRCTLx - Test error control */ + u32 rsvd5; + u32 entropy; /* RTSTENTROPYx - Test entropy */ + u32 rsvd6[15]; + u32 verifctl; /* RTSTVERIFCTLx - Test verification control */ + u32 rsvd7; + u32 verifstat; /* RTSTVERIFSTATx - Test verification status */ + u32 rsvd8; + u32 verifdata; /* RTSTVERIFDx - Test verification data */ + u32 rsvd9; + u32 xkey; /* RTSTXKEYx - Test XKEY */ + u32 rsvd10; + u32 oscctctl; /* RTSTOSCCTCTLx - Test osc. counter control */ + u32 rsvd11; + u32 oscct; /* RTSTOSCCTx - Test oscillator counter */ + u32 rsvd12; + u32 oscctstat; /* RTSTODCCTSTATx - Test osc counter status */ + u32 rsvd13[2]; + u32 ofifo[4]; /* RTSTOFIFOx - Test output FIFO */ + u32 rsvd14[15]; +}; + +/* + * caam_ctrl - basic core configuration + * starts base + 0x0000 padded out to 0x1000 + */ + +#define KEK_KEY_SIZE 8 +#define TKEK_KEY_SIZE 8 +#define TDSK_KEY_SIZE 8 + +#define DECO_RESET 1 /* Use with DECO reset/availability regs */ +#define DECO_RESET_0 (DECO_RESET << 0) +#define DECO_RESET_1 (DECO_RESET << 1) +#define DECO_RESET_2 (DECO_RESET << 2) +#define DECO_RESET_3 (DECO_RESET << 3) +#define DECO_RESET_4 (DECO_RESET << 4) + +struct caam_ctrl { + /* Basic Configuration Section 000-01f */ + /* Read/Writable */ + u32 rsvd1; + u32 mcr; /* MCFG Master Config Register */ + u32 rsvd2[2]; + + /* Bus Access Configuration Section 010-11f */ + /* Read/Writable */ + struct masterid jr_mid[4]; /* JRxLIODNR - JobR LIODN setup */ + u32 rsvd3[12]; + struct masterid rtic_mid[4]; /* RTICxLIODNR - RTIC LIODN setup */ + u32 rsvd4[7]; + u32 deco_rq; /* DECORR - DECO Request */ + struct partid deco_mid[5]; /* DECOxLIODNR - 1 per DECO */ + u32 rsvd5[22]; + + /* DECO Availability/Reset Section 120-3ff */ + u32 deco_avail; /* DAR - DECO availability */ + u32 deco_reset; /* DRR - DECO reset */ + u32 rsvd6[182]; + + /* Key Encryption/Decryption Configuration 400-5ff */ + /* Read/Writable only while in Non-secure mode */ + u32 kek[KEK_KEY_SIZE]; /* JDKEKR - Key Encryption Key */ + u32 tkek[TKEK_KEY_SIZE]; /* TDKEKR - Trusted Desc KEK */ + u32 tdsk[TDSK_KEY_SIZE]; /* TDSKR - Trusted Desc Signing Key */ + u32 rsvd7[32]; + u64 sknonce; /* SKNR - Secure Key Nonce */ + u32 rsvd8[70]; + + /* RNG Test/Verification/Debug Access 600-7ff */ + /* (Useful in Test/Debug modes only...) */ + struct rngtst rtst[2]; + + u32 rsvd9[448]; + + /* Performance Monitor f00-fff */ + struct caam_perfmon perfmon; +}; + +/* + * Controller master config register defs + */ +#define MCFGR_SWRESET 0x80000000 /* software reset */ +#define MCFGR_WDENABLE 0x40000000 /* DECO watchdog enable */ +#define MCFGR_WDFAIL 0x20000000 /* DECO watchdog force-fail */ +#define MCFGR_DMA_RESET 0x10000000 +#define MCFGR_LONG_PTR 0x00010000 /* Use >32-bit desc addressing */ + +/* AXI read cache control */ +#define MCFGR_ARCACHE_SHIFT 12 +#define MCFGR_ARCACHE_MASK (0xf << MCFGR_ARCACHE_SHIFT) + +/* AXI write cache control */ +#define MCFGR_AWCACHE_SHIFT 8 +#define MCFGR_AWCACHE_MASK (0xf << MCFGR_AWCACHE_SHIFT) + +/* AXI pipeline depth */ +#define MCFGR_AXIPIPE_SHIFT 4 +#define MCFGR_AXIPIPE_MASK (0xf << MCFGR_AXIPIPE_SHIFT) + +#define MCFGR_AXIPRI 0x00000008 /* Assert AXI priority sideband */ +#define MCFGR_BURST_64 0x00000001 /* Max burst size */ + +/* + * caam_job_ring - direct job ring setup + * 1-4 possible per instantiation, base + 1000/2000/3000/4000 + * Padded out to 0x1000 + */ +struct caam_job_ring { + /* Input ring */ + u64 inpring_base; /* IRBAx - Input desc ring baseaddr */ + u32 rsvd1; + u32 inpring_size; /* IRSx - Input ring size */ + u32 rsvd2; + u32 inpring_avail; /* IRSAx - Input ring room remaining */ + u32 rsvd3; + u32 inpring_jobadd; /* IRJAx - Input ring jobs added */ + + /* Output Ring */ + u64 outring_base; /* ORBAx - Output status ring base addr */ + u32 rsvd4; + u32 outring_size; /* ORSx - Output ring size */ + u32 rsvd5; + u32 outring_rmvd; /* ORJRx - Output ring jobs removed */ + u32 rsvd6; + u32 outring_used; /* ORSFx - Output ring slots full */ + + /* Status/Configuration */ + u32 rsvd7; + u32 jroutstatus; /* JRSTAx - JobR output status */ + u32 rsvd8; + u32 jrintstatus; /* JRINTx - JobR interrupt status */ + u32 rconfig_hi; /* JRxCFG - Ring configuration */ + u32 rconfig_lo; + + /* Indices. CAAM maintains as "heads" of each queue */ + u32 rsvd9; + u32 inp_rdidx; /* IRRIx - Input ring read index */ + u32 rsvd10; + u32 out_wtidx; /* ORWIx - Output ring write index */ + + /* Command/control */ + u32 rsvd11; + u32 jrcommand; /* JRCRx - JobR command */ + + u32 rsvd12[932]; + + /* Performance Monitor f00-fff */ + struct caam_perfmon perfmon; +}; + +#define JR_RINGSIZE_MASK 0x03ff +/* + * jrstatus - Job Ring Output Status + * All values in lo word + * Also note, same values written out as status through QI + * in the command/status field of a frame descriptor + */ +#define JRSTA_SSRC_SHIFT 28 +#define JRSTA_SSRC_MASK 0xf0000000 + +#define JRSTA_SSRC_NONE 0x00000000 +#define JRSTA_SSRC_CCB_ERROR 0x20000000 +#define JRSTA_SSRC_JUMP_HALT_USER 0x30000000 +#define JRSTA_SSRC_DECO 0x40000000 +#define JRSTA_SSRC_JRERROR 0x60000000 +#define JRSTA_SSRC_JUMP_HALT_CC 0x70000000 + +#define JRSTA_DECOERR_JUMP 0x08000000 +#define JRSTA_DECOERR_INDEX_SHIFT 8 +#define JRSTA_DECOERR_INDEX_MASK 0xff00 +#define JRSTA_DECOERR_ERROR_MASK 0x00ff + +#define JRSTA_DECOERR_NONE 0x00 +#define JRSTA_DECOERR_LINKLEN 0x01 +#define JRSTA_DECOERR_LINKPTR 0x02 +#define JRSTA_DECOERR_JRCTRL 0x03 +#define JRSTA_DECOERR_DESCCMD 0x04 +#define JRSTA_DECOERR_ORDER 0x05 +#define JRSTA_DECOERR_KEYCMD 0x06 +#define JRSTA_DECOERR_LOADCMD 0x07 +#define JRSTA_DECOERR_STORECMD 0x08 +#define JRSTA_DECOERR_OPCMD 0x09 +#define JRSTA_DECOERR_FIFOLDCMD 0x0a +#define JRSTA_DECOERR_FIFOSTCMD 0x0b +#define JRSTA_DECOERR_MOVECMD 0x0c +#define JRSTA_DECOERR_JUMPCMD 0x0d +#define JRSTA_DECOERR_MATHCMD 0x0e +#define JRSTA_DECOERR_SHASHCMD 0x0f +#define JRSTA_DECOERR_SEQCMD 0x10 +#define JRSTA_DECOERR_DECOINTERNAL 0x11 +#define JRSTA_DECOERR_SHDESCHDR 0x12 +#define JRSTA_DECOERR_HDRLEN 0x13 +#define JRSTA_DECOERR_BURSTER 0x14 +#define JRSTA_DECOERR_DESCSIGNATURE 0x15 +#define JRSTA_DECOERR_DMA 0x16 +#define JRSTA_DECOERR_BURSTFIFO 0x17 +#define JRSTA_DECOERR_JRRESET 0x1a +#define JRSTA_DECOERR_JOBFAIL 0x1b +#define JRSTA_DECOERR_DNRERR 0x80 +#define JRSTA_DECOERR_UNDEFPCL 0x81 +#define JRSTA_DECOERR_PDBERR 0x82 +#define JRSTA_DECOERR_ANRPLY_LATE 0x83 +#define JRSTA_DECOERR_ANRPLY_REPLAY 0x84 +#define JRSTA_DECOERR_SEQOVF 0x85 +#define JRSTA_DECOERR_INVSIGN 0x86 +#define JRSTA_DECOERR_DSASIGN 0x87 + +#define JRSTA_CCBERR_JUMP 0x08000000 +#define JRSTA_CCBERR_INDEX_MASK 0xff00 +#define JRSTA_CCBERR_INDEX_SHIFT 8 +#define JRSTA_CCBERR_CHAID_MASK 0x00f0 +#define JRSTA_CCBERR_CHAID_SHIFT 4 +#define JRSTA_CCBERR_ERRID_MASK 0x000f + +#define JRSTA_CCBERR_CHAID_AES (0x01 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_DES (0x02 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_ARC4 (0x03 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_MD (0x04 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_RNG (0x05 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_SNOW (0x06 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_KASUMI (0x07 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_PK (0x08 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_CRC (0x09 << JRSTA_CCBERR_CHAID_SHIFT) + +#define JRSTA_CCBERR_ERRID_NONE 0x00 +#define JRSTA_CCBERR_ERRID_MODE 0x01 +#define JRSTA_CCBERR_ERRID_DATASIZ 0x02 +#define JRSTA_CCBERR_ERRID_KEYSIZ 0x03 +#define JRSTA_CCBERR_ERRID_PKAMEMSZ 0x04 +#define JRSTA_CCBERR_ERRID_PKBMEMSZ 0x05 +#define JRSTA_CCBERR_ERRID_SEQUENCE 0x06 +#define JRSTA_CCBERR_ERRID_PKDIVZRO 0x07 +#define JRSTA_CCBERR_ERRID_PKMODEVN 0x08 +#define JRSTA_CCBERR_ERRID_KEYPARIT 0x09 +#define JRSTA_CCBERR_ERRID_ICVCHK 0x0a +#define JRSTA_CCBERR_ERRID_HARDWARE 0x0b +#define JRSTA_CCBERR_ERRID_CCMAAD 0x0c +#define JRSTA_CCBERR_ERRID_INVCHA 0x0f + +#define JRINT_ERR_INDEX_MASK 0x3fff0000 +#define JRINT_ERR_INDEX_SHIFT 16 +#define JRINT_ERR_TYPE_MASK 0xf00 +#define JRINT_ERR_TYPE_SHIFT 8 +#define JRINT_ERR_HALT_MASK 0xc +#define JRINT_ERR_HALT_SHIFT 2 +#define JRINT_ERR_HALT_INPROGRESS 0x4 +#define JRINT_ERR_HALT_COMPLETE 0x8 +#define JRINT_JR_ERROR 0x02 +#define JRINT_JR_INT 0x01 + +#define JRINT_ERR_TYPE_WRITE 1 +#define JRINT_ERR_TYPE_BAD_INPADDR 3 +#define JRINT_ERR_TYPE_BAD_OUTADDR 4 +#define JRINT_ERR_TYPE_INV_INPWRT 5 +#define JRINT_ERR_TYPE_INV_OUTWRT 6 +#define JRINT_ERR_TYPE_RESET 7 +#define JRINT_ERR_TYPE_REMOVE_OFL 8 +#define JRINT_ERR_TYPE_ADD_OFL 9 + +#define JRCFG_SOE 0x04 +#define JRCFG_ICEN 0x02 +#define JRCFG_IMSK 0x01 +#define JRCFG_ICDCT_SHIFT 8 +#define JRCFG_ICTT_SHIFT 16 + +#define JRCR_RESET 0x01 + +/* + * caam_assurance - Assurance Controller View + * base + 0x6000 padded out to 0x1000 + */ + +struct rtic_element { + u64 address; + u32 rsvd; + u32 length; +}; + +struct rtic_block { + struct rtic_element element[2]; +}; + +struct rtic_memhash { + u32 memhash_be[32]; + u32 memhash_le[32]; +}; + +struct caam_assurance { + /* Status/Command/Watchdog */ + u32 rsvd1; + u32 status; /* RSTA - Status */ + u32 rsvd2; + u32 cmd; /* RCMD - Command */ + u32 rsvd3; + u32 ctrl; /* RCTL - Control */ + u32 rsvd4; + u32 throttle; /* RTHR - Throttle */ + u32 rsvd5[2]; + u64 watchdog; /* RWDOG - Watchdog Timer */ + u32 rsvd6; + u32 rend; /* REND - Endian corrections */ + u32 rsvd7[50]; + + /* Block access/configuration @ 100/110/120/130 */ + struct rtic_block memblk[4]; /* Memory Blocks A-D */ + u32 rsvd8[32]; + + /* Block hashes @ 200/300/400/500 */ + struct rtic_memhash hash[4]; /* Block hash values A-D */ + u32 rsvd_3[640]; +}; + +/* + * caam_queue_if - QI configuration and control + * starts base + 0x7000, padded out to 0x1000 long + */ + +struct caam_queue_if { + u32 qi_control_hi; /* QICTL - QI Control */ + u32 qi_control_lo; + u32 rsvd1; + u32 qi_status; /* QISTA - QI Status */ + u32 qi_deq_cfg_hi; /* QIDQC - QI Dequeue Configuration */ + u32 qi_deq_cfg_lo; + u32 qi_enq_cfg_hi; /* QISEQC - QI Enqueue Command */ + u32 qi_enq_cfg_lo; + u32 rsvd2[1016]; +}; + +/* QI control bits - low word */ +#define QICTL_DQEN 0x01 /* Enable frame pop */ +#define QICTL_STOP 0x02 /* Stop dequeue/enqueue */ +#define QICTL_SOE 0x04 /* Stop on error */ + +/* QI control bits - high word */ +#define QICTL_MBSI 0x01 +#define QICTL_MHWSI 0x02 +#define QICTL_MWSI 0x04 +#define QICTL_MDWSI 0x08 +#define QICTL_CBSI 0x10 /* CtrlDataByteSwapInput */ +#define QICTL_CHWSI 0x20 /* CtrlDataHalfSwapInput */ +#define QICTL_CWSI 0x40 /* CtrlDataWordSwapInput */ +#define QICTL_CDWSI 0x80 /* CtrlDataDWordSwapInput */ +#define QICTL_MBSO 0x0100 +#define QICTL_MHWSO 0x0200 +#define QICTL_MWSO 0x0400 +#define QICTL_MDWSO 0x0800 +#define QICTL_CBSO 0x1000 /* CtrlDataByteSwapOutput */ +#define QICTL_CHWSO 0x2000 /* CtrlDataHalfSwapOutput */ +#define QICTL_CWSO 0x4000 /* CtrlDataWordSwapOutput */ +#define QICTL_CDWSO 0x8000 /* CtrlDataDWordSwapOutput */ +#define QICTL_DMBS 0x010000 +#define QICTL_EPO 0x020000 + +/* QI status bits */ +#define QISTA_PHRDERR 0x01 /* PreHeader Read Error */ +#define QISTA_CFRDERR 0x02 /* Compound Frame Read Error */ +#define QISTA_OFWRERR 0x04 /* Output Frame Read Error */ +#define QISTA_BPDERR 0x08 /* Buffer Pool Depleted */ +#define QISTA_BTSERR 0x10 /* Buffer Undersize */ +#define QISTA_CFWRERR 0x20 /* Compound Frame Write Err */ +#define QISTA_STOPD 0x80000000 /* QI Stopped (see QICTL) */ + +/* deco_sg_table - DECO view of scatter/gather table */ +struct deco_sg_table { + u64 addr; /* Segment Address */ + u32 elen; /* E, F bits + 30-bit length */ + u32 bpid_offset; /* Buffer Pool ID + 16-bit length */ +}; + +/* + * caam_deco - descriptor controller - CHA cluster block + * + * Only accessible when direct DECO access is turned on + * (done in DECORR, via MID programmed in DECOxMID + * + * 5 typical, base + 0x8000/9000/a000/b000 + * Padded out to 0x1000 long + */ +struct caam_deco { + u32 rsvd1; + u32 cls1_mode; /* CxC1MR - Class 1 Mode */ + u32 rsvd2; + u32 cls1_keysize; /* CxC1KSR - Class 1 Key Size */ + u32 cls1_datasize_hi; /* CxC1DSR - Class 1 Data Size */ + u32 cls1_datasize_lo; + u32 rsvd3; + u32 cls1_icvsize; /* CxC1ICVSR - Class 1 ICV size */ + u32 rsvd4[5]; + u32 cha_ctrl; /* CCTLR - CHA control */ + u32 rsvd5; + u32 irq_crtl; /* CxCIRQ - CCB interrupt done/error/clear */ + u32 rsvd6; + u32 clr_written; /* CxCWR - Clear-Written */ + u32 ccb_status_hi; /* CxCSTA - CCB Status/Error */ + u32 ccb_status_lo; + u32 rsvd7[3]; + u32 aad_size; /* CxAADSZR - Current AAD Size */ + u32 rsvd8; + u32 cls1_iv_size; /* CxC1IVSZR - Current Class 1 IV Size */ + u32 rsvd9[7]; + u32 pkha_a_size; /* PKASZRx - Size of PKHA A */ + u32 rsvd10; + u32 pkha_b_size; /* PKBSZRx - Size of PKHA B */ + u32 rsvd11; + u32 pkha_n_size; /* PKNSZRx - Size of PKHA N */ + u32 rsvd12; + u32 pkha_e_size; /* PKESZRx - Size of PKHA E */ + u32 rsvd13[24]; + u32 cls1_ctx[16]; /* CxC1CTXR - Class 1 Context @100 */ + u32 rsvd14[48]; + u32 cls1_key[8]; /* CxC1KEYR - Class 1 Key @200 */ + u32 rsvd15[121]; + u32 cls2_mode; /* CxC2MR - Class 2 Mode */ + u32 rsvd16; + u32 cls2_keysize; /* CxX2KSR - Class 2 Key Size */ + u32 cls2_datasize_hi; /* CxC2DSR - Class 2 Data Size */ + u32 cls2_datasize_lo; + u32 rsvd17; + u32 cls2_icvsize; /* CxC2ICVSZR - Class 2 ICV Size */ + u32 rsvd18[56]; + u32 cls2_ctx[18]; /* CxC2CTXR - Class 2 Context @500 */ + u32 rsvd19[46]; + u32 cls2_key[32]; /* CxC2KEYR - Class2 Key @600 */ + u32 rsvd20[84]; + u32 inp_infofifo_hi; /* CxIFIFO - Input Info FIFO @7d0 */ + u32 inp_infofifo_lo; + u32 rsvd21[2]; + u64 inp_datafifo; /* CxDFIFO - Input Data FIFO */ + u32 rsvd22[2]; + u64 out_datafifo; /* CxOFIFO - Output Data FIFO */ + u32 rsvd23[2]; + u32 jr_ctl_hi; /* CxJRR - JobR Control Register @800 */ + u32 jr_ctl_lo; + u64 jr_descaddr; /* CxDADR - JobR Descriptor Address */ + u32 op_status_hi; /* DxOPSTA - DECO Operation Status */ + u32 op_status_lo; + u32 rsvd24[2]; + u32 liodn; /* DxLSR - DECO LIODN Status - non-seq */ + u32 td_liodn; /* DxLSR - DECO LIODN Status - trustdesc */ + u32 rsvd26[6]; + u64 math[4]; /* DxMTH - Math register */ + u32 rsvd27[8]; + struct deco_sg_table gthr_tbl[4]; /* DxGTR - Gather Tables */ + u32 rsvd28[16]; + struct deco_sg_table sctr_tbl[4]; /* DxSTR - Scatter Tables */ + u32 rsvd29[48]; + u32 descbuf[64]; /* DxDESB - Descriptor buffer */ + u32 rsvd30[320]; +}; + +/* + * Current top-level view of memory map is: + * + * 0x0000 - 0x0fff - CAAM Top-Level Control + * 0x1000 - 0x1fff - Job Ring 0 + * 0x2000 - 0x2fff - Job Ring 1 + * 0x3000 - 0x3fff - Job Ring 2 + * 0x4000 - 0x4fff - Job Ring 3 + * 0x5000 - 0x5fff - (unused) + * 0x6000 - 0x6fff - Assurance Controller + * 0x7000 - 0x7fff - Queue Interface + * 0x8000 - 0x8fff - DECO-CCB 0 + * 0x9000 - 0x9fff - DECO-CCB 1 + * 0xa000 - 0xafff - DECO-CCB 2 + * 0xb000 - 0xbfff - DECO-CCB 3 + * 0xc000 - 0xcfff - DECO-CCB 4 + * + * caam_full describes the full register view of CAAM if useful, + * although many configurations may choose to implement parts of + * the register map separately, in differing privilege regions + */ +struct caam_full { + struct caam_ctrl __iomem ctrl; + struct caam_job_ring jr[4]; + u64 rsvd[512]; + struct caam_assurance assure; + struct caam_queue_if qi; + struct caam_deco *deco; +}; + +#endif /* REGS_H */ diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index c99305afa58a..3cf303ee3fe3 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -133,7 +133,6 @@ struct mv_req_hash_ctx { int extra_bytes; /* unprocessed bytes in buffer */ enum hash_op op; int count_add; - struct scatterlist dummysg; }; static void compute_aes_dec_key(struct mv_ctx *ctx) @@ -187,9 +186,9 @@ static void copy_src_to_buf(struct req_progress *p, char *dbuf, int len) { int ret; void *sbuf; - int copied = 0; + int copy_len; - while (1) { + while (len) { if (!p->sg_src_left) { ret = sg_miter_next(&p->src_sg_it); BUG_ON(!ret); @@ -199,19 +198,14 @@ static void copy_src_to_buf(struct req_progress *p, char *dbuf, int len) sbuf = p->src_sg_it.addr + p->src_start; - if (p->sg_src_left <= len - copied) { - memcpy(dbuf + copied, sbuf, p->sg_src_left); - copied += p->sg_src_left; - p->sg_src_left = 0; - if (copied >= len) - break; - } else { - int copy_len = len - copied; - memcpy(dbuf + copied, sbuf, copy_len); - p->src_start += copy_len; - p->sg_src_left -= copy_len; - break; - } + copy_len = min(p->sg_src_left, len); + memcpy(dbuf, sbuf, copy_len); + + p->src_start += copy_len; + p->sg_src_left -= copy_len; + + len -= copy_len; + dbuf += copy_len; } } @@ -275,7 +269,6 @@ static void mv_process_current_q(int first_block) memcpy(cpg->sram + SRAM_CONFIG, &op, sizeof(struct sec_accel_config)); - writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); /* GO */ writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD); @@ -302,6 +295,7 @@ static void mv_crypto_algo_completion(void) static void mv_process_hash_current(int first_block) { struct ahash_request *req = ahash_request_cast(cpg->cur_req); + const struct mv_tfm_hash_ctx *tfm_ctx = crypto_tfm_ctx(req->base.tfm); struct mv_req_hash_ctx *req_ctx = ahash_request_ctx(req); struct req_progress *p = &cpg->p; struct sec_accel_config op = { 0 }; @@ -314,6 +308,8 @@ static void mv_process_hash_current(int first_block) break; case COP_HMAC_SHA1: op.config = CFG_OP_MAC_ONLY | CFG_MACM_HMAC_SHA1; + memcpy(cpg->sram + SRAM_HMAC_IV_IN, + tfm_ctx->ivs, sizeof(tfm_ctx->ivs)); break; } @@ -345,11 +341,16 @@ static void mv_process_hash_current(int first_block) op.config |= CFG_LAST_FRAG; else op.config |= CFG_MID_FRAG; + + writel(req_ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A); + writel(req_ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B); + writel(req_ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C); + writel(req_ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D); + writel(req_ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E); } memcpy(cpg->sram + SRAM_CONFIG, &op, sizeof(struct sec_accel_config)); - writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); /* GO */ writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD); @@ -409,12 +410,6 @@ static void mv_hash_algo_completion(void) copy_src_to_buf(&cpg->p, ctx->buffer, ctx->extra_bytes); sg_miter_stop(&cpg->p.src_sg_it); - ctx->state[0] = readl(cpg->reg + DIGEST_INITIAL_VAL_A); - ctx->state[1] = readl(cpg->reg + DIGEST_INITIAL_VAL_B); - ctx->state[2] = readl(cpg->reg + DIGEST_INITIAL_VAL_C); - ctx->state[3] = readl(cpg->reg + DIGEST_INITIAL_VAL_D); - ctx->state[4] = readl(cpg->reg + DIGEST_INITIAL_VAL_E); - if (likely(ctx->last_chunk)) { if (likely(ctx->count <= MAX_HW_HASH_SIZE)) { memcpy(req->result, cpg->sram + SRAM_DIGEST_BUF, @@ -422,6 +417,12 @@ static void mv_hash_algo_completion(void) (req))); } else mv_hash_final_fallback(req); + } else { + ctx->state[0] = readl(cpg->reg + DIGEST_INITIAL_VAL_A); + ctx->state[1] = readl(cpg->reg + DIGEST_INITIAL_VAL_B); + ctx->state[2] = readl(cpg->reg + DIGEST_INITIAL_VAL_C); + ctx->state[3] = readl(cpg->reg + DIGEST_INITIAL_VAL_D); + ctx->state[4] = readl(cpg->reg + DIGEST_INITIAL_VAL_E); } } @@ -480,7 +481,7 @@ static int count_sgs(struct scatterlist *sl, unsigned int total_bytes) int i = 0; size_t cur_len; - while (1) { + while (sl) { cur_len = sl[i].length; ++i; if (total_bytes > cur_len) @@ -517,29 +518,12 @@ static void mv_start_new_hash_req(struct ahash_request *req) { struct req_progress *p = &cpg->p; struct mv_req_hash_ctx *ctx = ahash_request_ctx(req); - const struct mv_tfm_hash_ctx *tfm_ctx = crypto_tfm_ctx(req->base.tfm); int num_sgs, hw_bytes, old_extra_bytes, rc; cpg->cur_req = &req->base; memset(p, 0, sizeof(struct req_progress)); hw_bytes = req->nbytes + ctx->extra_bytes; old_extra_bytes = ctx->extra_bytes; - if (unlikely(ctx->extra_bytes)) { - memcpy(cpg->sram + SRAM_DATA_IN_START, ctx->buffer, - ctx->extra_bytes); - p->crypt_len = ctx->extra_bytes; - } - - memcpy(cpg->sram + SRAM_HMAC_IV_IN, tfm_ctx->ivs, sizeof(tfm_ctx->ivs)); - - if (unlikely(!ctx->first_hash)) { - writel(ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A); - writel(ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B); - writel(ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C); - writel(ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D); - writel(ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E); - } - ctx->extra_bytes = hw_bytes % SHA1_BLOCK_SIZE; if (ctx->extra_bytes != 0 && (!ctx->last_chunk || ctx->count > MAX_HW_HASH_SIZE)) @@ -555,6 +539,12 @@ static void mv_start_new_hash_req(struct ahash_request *req) p->complete = mv_hash_algo_completion; p->process = mv_process_hash_current; + if (unlikely(old_extra_bytes)) { + memcpy(cpg->sram + SRAM_DATA_IN_START, ctx->buffer, + old_extra_bytes); + p->crypt_len = old_extra_bytes; + } + mv_process_hash_current(1); } else { copy_src_to_buf(p, ctx->buffer + old_extra_bytes, @@ -603,9 +593,7 @@ static int queue_manag(void *data) if (async_req->tfm->__crt_alg->cra_type != &crypto_ahash_type) { struct ablkcipher_request *req = - container_of(async_req, - struct ablkcipher_request, - base); + ablkcipher_request_cast(async_req); mv_start_new_crypt_req(req); } else { struct ahash_request *req = @@ -722,19 +710,13 @@ static int mv_hash_update(struct ahash_request *req) static int mv_hash_final(struct ahash_request *req) { struct mv_req_hash_ctx *ctx = ahash_request_ctx(req); - /* dummy buffer of 4 bytes */ - sg_init_one(&ctx->dummysg, ctx->buffer, 4); - /* I think I'm allowed to do that... */ - ahash_request_set_crypt(req, &ctx->dummysg, req->result, 0); + mv_update_hash_req_ctx(ctx, 1, 0); return mv_handle_req(&req->base); } static int mv_hash_finup(struct ahash_request *req) { - if (!req->nbytes) - return mv_hash_final(req); - mv_update_hash_req_ctx(ahash_request_ctx(req), 1, req->nbytes); return mv_handle_req(&req->base); } @@ -1065,14 +1047,21 @@ static int mv_probe(struct platform_device *pdev) writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK); writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG); + writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); ret = crypto_register_alg(&mv_aes_alg_ecb); - if (ret) + if (ret) { + printk(KERN_WARNING MV_CESA + "Could not register aes-ecb driver\n"); goto err_irq; + } ret = crypto_register_alg(&mv_aes_alg_cbc); - if (ret) + if (ret) { + printk(KERN_WARNING MV_CESA + "Could not register aes-cbc driver\n"); goto err_unreg_ecb; + } ret = crypto_register_ahash(&mv_sha1_alg); if (ret == 0) diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 465cde3e4f60..ba8f1ea84c5e 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -78,7 +78,6 @@ #define FLAGS_SHA1 0x0010 #define FLAGS_DMA_ACTIVE 0x0020 #define FLAGS_OUTPUT_READY 0x0040 -#define FLAGS_CLEAN 0x0080 #define FLAGS_INIT 0x0100 #define FLAGS_CPU 0x0200 #define FLAGS_HMAC 0x0400 @@ -511,26 +510,6 @@ static int omap_sham_update_dma_stop(struct omap_sham_dev *dd) return 0; } -static void omap_sham_cleanup(struct ahash_request *req) -{ - struct omap_sham_reqctx *ctx = ahash_request_ctx(req); - struct omap_sham_dev *dd = ctx->dd; - unsigned long flags; - - spin_lock_irqsave(&dd->lock, flags); - if (ctx->flags & FLAGS_CLEAN) { - spin_unlock_irqrestore(&dd->lock, flags); - return; - } - ctx->flags |= FLAGS_CLEAN; - spin_unlock_irqrestore(&dd->lock, flags); - - if (ctx->digcnt) - omap_sham_copy_ready_hash(req); - - dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt, ctx->bufcnt); -} - static int omap_sham_init(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); @@ -618,9 +597,8 @@ static int omap_sham_final_req(struct omap_sham_dev *dd) return err; } -static int omap_sham_finish_req_hmac(struct ahash_request *req) +static int omap_sham_finish_hmac(struct ahash_request *req) { - struct omap_sham_reqctx *ctx = ahash_request_ctx(req); struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm); struct omap_sham_hmac_ctx *bctx = tctx->base; int bs = crypto_shash_blocksize(bctx->shash); @@ -635,7 +613,24 @@ static int omap_sham_finish_req_hmac(struct ahash_request *req) return crypto_shash_init(&desc.shash) ?: crypto_shash_update(&desc.shash, bctx->opad, bs) ?: - crypto_shash_finup(&desc.shash, ctx->digest, ds, ctx->digest); + crypto_shash_finup(&desc.shash, req->result, ds, req->result); +} + +static int omap_sham_finish(struct ahash_request *req) +{ + struct omap_sham_reqctx *ctx = ahash_request_ctx(req); + struct omap_sham_dev *dd = ctx->dd; + int err = 0; + + if (ctx->digcnt) { + omap_sham_copy_ready_hash(req); + if (ctx->flags & FLAGS_HMAC) + err = omap_sham_finish_hmac(req); + } + + dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt, ctx->bufcnt); + + return err; } static void omap_sham_finish_req(struct ahash_request *req, int err) @@ -645,15 +640,12 @@ static void omap_sham_finish_req(struct ahash_request *req, int err) if (!err) { omap_sham_copy_hash(ctx->dd->req, 1); - if (ctx->flags & FLAGS_HMAC) - err = omap_sham_finish_req_hmac(req); + if (ctx->flags & FLAGS_FINAL) + err = omap_sham_finish(req); } else { ctx->flags |= FLAGS_ERROR; } - if ((ctx->flags & FLAGS_FINAL) || err) - omap_sham_cleanup(req); - clk_disable(dd->iclk); dd->flags &= ~FLAGS_BUSY; @@ -809,22 +801,21 @@ static int omap_sham_final_shash(struct ahash_request *req) static int omap_sham_final(struct ahash_request *req) { struct omap_sham_reqctx *ctx = ahash_request_ctx(req); - int err = 0; ctx->flags |= FLAGS_FINUP; - if (!(ctx->flags & FLAGS_ERROR)) { - /* OMAP HW accel works only with buffers >= 9 */ - /* HMAC is always >= 9 because of ipad */ - if ((ctx->digcnt + ctx->bufcnt) < 9) - err = omap_sham_final_shash(req); - else if (ctx->bufcnt) - return omap_sham_enqueue(req, OP_FINAL); - } + if (ctx->flags & FLAGS_ERROR) + return 0; /* uncompleted hash is not needed */ - omap_sham_cleanup(req); + /* OMAP HW accel works only with buffers >= 9 */ + /* HMAC is always >= 9 because ipad == block size */ + if ((ctx->digcnt + ctx->bufcnt) < 9) + return omap_sham_final_shash(req); + else if (ctx->bufcnt) + return omap_sham_enqueue(req, OP_FINAL); - return err; + /* copy ready hash (+ finalize hmac) */ + return omap_sham_finish(req); } static int omap_sham_finup(struct ahash_request *req) @@ -835,7 +826,7 @@ static int omap_sham_finup(struct ahash_request *req) ctx->flags |= FLAGS_FINUP; err1 = omap_sham_update(req); - if (err1 == -EINPROGRESS) + if (err1 == -EINPROGRESS || err1 == -EBUSY) return err1; /* * final() has to be always called to cleanup resources @@ -890,8 +881,6 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base) struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm); const char *alg_name = crypto_tfm_alg_name(tfm); - pr_info("enter\n"); - /* Allocate a fallback and abort if it failed. */ tctx->fallback = crypto_alloc_shash(alg_name, 0, CRYPTO_ALG_NEED_FALLBACK); @@ -1297,7 +1286,8 @@ static int __init omap_sham_mod_init(void) pr_info("loading %s driver\n", "omap-sham"); if (!cpu_class_is_omap2() || - omap_type() != OMAP2_DEVICE_TYPE_SEC) { + (omap_type() != OMAP2_DEVICE_TYPE_SEC && + omap_type() != OMAP2_DEVICE_TYPE_EMU)) { pr_err("Unsupported cpu\n"); return -ENODEV; } diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index adf075b6b9a8..06bdb4b2c6a6 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -288,9 +288,250 @@ static struct shash_alg sha256_alg = { } }; +/* Add two shash_alg instance for hardware-implemented * +* multiple-parts hash supported by VIA Nano Processor.*/ +static int padlock_sha1_init_nano(struct shash_desc *desc) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + *sctx = (struct sha1_state){ + .state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, + }; + + return 0; +} + +static int padlock_sha1_update_nano(struct shash_desc *desc, + const u8 *data, unsigned int len) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + unsigned int partial, done; + const u8 *src; + /*The PHE require the out buffer must 128 bytes and 16-bytes aligned*/ + u8 buf[128 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__ + ((aligned(STACK_ALIGN))); + u8 *dst = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); + int ts_state; + + partial = sctx->count & 0x3f; + sctx->count += len; + done = 0; + src = data; + memcpy(dst, (u8 *)(sctx->state), SHA1_DIGEST_SIZE); + + if ((partial + len) >= SHA1_BLOCK_SIZE) { + + /* Append the bytes in state's buffer to a block to handle */ + if (partial) { + done = -partial; + memcpy(sctx->buffer + partial, data, + done + SHA1_BLOCK_SIZE); + src = sctx->buffer; + ts_state = irq_ts_save(); + asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" + : "+S"(src), "+D"(dst) \ + : "a"((long)-1), "c"((unsigned long)1)); + irq_ts_restore(ts_state); + done += SHA1_BLOCK_SIZE; + src = data + done; + } + + /* Process the left bytes from the input data */ + if (len - done >= SHA1_BLOCK_SIZE) { + ts_state = irq_ts_save(); + asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" + : "+S"(src), "+D"(dst) + : "a"((long)-1), + "c"((unsigned long)((len - done) / SHA1_BLOCK_SIZE))); + irq_ts_restore(ts_state); + done += ((len - done) - (len - done) % SHA1_BLOCK_SIZE); + src = data + done; + } + partial = 0; + } + memcpy((u8 *)(sctx->state), dst, SHA1_DIGEST_SIZE); + memcpy(sctx->buffer + partial, src, len - done); + + return 0; +} + +static int padlock_sha1_final_nano(struct shash_desc *desc, u8 *out) +{ + struct sha1_state *state = (struct sha1_state *)shash_desc_ctx(desc); + unsigned int partial, padlen; + __be64 bits; + static const u8 padding[64] = { 0x80, }; + + bits = cpu_to_be64(state->count << 3); + + /* Pad out to 56 mod 64 */ + partial = state->count & 0x3f; + padlen = (partial < 56) ? (56 - partial) : ((64+56) - partial); + padlock_sha1_update_nano(desc, padding, padlen); + + /* Append length field bytes */ + padlock_sha1_update_nano(desc, (const u8 *)&bits, sizeof(bits)); + + /* Swap to output */ + padlock_output_block((uint32_t *)(state->state), (uint32_t *)out, 5); + + return 0; +} + +static int padlock_sha256_init_nano(struct shash_desc *desc) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + *sctx = (struct sha256_state){ + .state = { SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3, \ + SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7}, + }; + + return 0; +} + +static int padlock_sha256_update_nano(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + unsigned int partial, done; + const u8 *src; + /*The PHE require the out buffer must 128 bytes and 16-bytes aligned*/ + u8 buf[128 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__ + ((aligned(STACK_ALIGN))); + u8 *dst = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); + int ts_state; + + partial = sctx->count & 0x3f; + sctx->count += len; + done = 0; + src = data; + memcpy(dst, (u8 *)(sctx->state), SHA256_DIGEST_SIZE); + + if ((partial + len) >= SHA256_BLOCK_SIZE) { + + /* Append the bytes in state's buffer to a block to handle */ + if (partial) { + done = -partial; + memcpy(sctx->buf + partial, data, + done + SHA256_BLOCK_SIZE); + src = sctx->buf; + ts_state = irq_ts_save(); + asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" + : "+S"(src), "+D"(dst) + : "a"((long)-1), "c"((unsigned long)1)); + irq_ts_restore(ts_state); + done += SHA256_BLOCK_SIZE; + src = data + done; + } + + /* Process the left bytes from input data*/ + if (len - done >= SHA256_BLOCK_SIZE) { + ts_state = irq_ts_save(); + asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" + : "+S"(src), "+D"(dst) + : "a"((long)-1), + "c"((unsigned long)((len - done) / 64))); + irq_ts_restore(ts_state); + done += ((len - done) - (len - done) % 64); + src = data + done; + } + partial = 0; + } + memcpy((u8 *)(sctx->state), dst, SHA256_DIGEST_SIZE); + memcpy(sctx->buf + partial, src, len - done); + + return 0; +} + +static int padlock_sha256_final_nano(struct shash_desc *desc, u8 *out) +{ + struct sha256_state *state = + (struct sha256_state *)shash_desc_ctx(desc); + unsigned int partial, padlen; + __be64 bits; + static const u8 padding[64] = { 0x80, }; + + bits = cpu_to_be64(state->count << 3); + + /* Pad out to 56 mod 64 */ + partial = state->count & 0x3f; + padlen = (partial < 56) ? (56 - partial) : ((64+56) - partial); + padlock_sha256_update_nano(desc, padding, padlen); + + /* Append length field bytes */ + padlock_sha256_update_nano(desc, (const u8 *)&bits, sizeof(bits)); + + /* Swap to output */ + padlock_output_block((uint32_t *)(state->state), (uint32_t *)out, 8); + + return 0; +} + +static int padlock_sha_export_nano(struct shash_desc *desc, + void *out) +{ + int statesize = crypto_shash_statesize(desc->tfm); + void *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, statesize); + return 0; +} + +static int padlock_sha_import_nano(struct shash_desc *desc, + const void *in) +{ + int statesize = crypto_shash_statesize(desc->tfm); + void *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, statesize); + return 0; +} + +static struct shash_alg sha1_alg_nano = { + .digestsize = SHA1_DIGEST_SIZE, + .init = padlock_sha1_init_nano, + .update = padlock_sha1_update_nano, + .final = padlock_sha1_final_nano, + .export = padlock_sha_export_nano, + .import = padlock_sha_import_nano, + .descsize = sizeof(struct sha1_state), + .statesize = sizeof(struct sha1_state), + .base = { + .cra_name = "sha1", + .cra_driver_name = "sha1-padlock-nano", + .cra_priority = PADLOCK_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +static struct shash_alg sha256_alg_nano = { + .digestsize = SHA256_DIGEST_SIZE, + .init = padlock_sha256_init_nano, + .update = padlock_sha256_update_nano, + .final = padlock_sha256_final_nano, + .export = padlock_sha_export_nano, + .import = padlock_sha_import_nano, + .descsize = sizeof(struct sha256_state), + .statesize = sizeof(struct sha256_state), + .base = { + .cra_name = "sha256", + .cra_driver_name = "sha256-padlock-nano", + .cra_priority = PADLOCK_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + static int __init padlock_init(void) { int rc = -ENODEV; + struct cpuinfo_x86 *c = &cpu_data(0); + struct shash_alg *sha1; + struct shash_alg *sha256; if (!cpu_has_phe) { printk(KERN_NOTICE PFX "VIA PadLock Hash Engine not detected.\n"); @@ -302,11 +543,21 @@ static int __init padlock_init(void) return -ENODEV; } - rc = crypto_register_shash(&sha1_alg); + /* Register the newly added algorithm module if on * + * VIA Nano processor, or else just do as before */ + if (c->x86_model < 0x0f) { + sha1 = &sha1_alg; + sha256 = &sha256_alg; + } else { + sha1 = &sha1_alg_nano; + sha256 = &sha256_alg_nano; + } + + rc = crypto_register_shash(sha1); if (rc) goto out; - rc = crypto_register_shash(&sha256_alg); + rc = crypto_register_shash(sha256); if (rc) goto out_unreg1; @@ -315,7 +566,8 @@ static int __init padlock_init(void) return 0; out_unreg1: - crypto_unregister_shash(&sha1_alg); + crypto_unregister_shash(sha1); + out: printk(KERN_ERR PFX "VIA PadLock SHA1/SHA256 initialization failed.\n"); return rc; @@ -323,8 +575,15 @@ static int __init padlock_init(void) static void __exit padlock_fini(void) { - crypto_unregister_shash(&sha1_alg); - crypto_unregister_shash(&sha256_alg); + struct cpuinfo_x86 *c = &cpu_data(0); + + if (c->x86_model >= 0x0f) { + crypto_unregister_shash(&sha1_alg_nano); + crypto_unregister_shash(&sha256_alg_nano); + } else { + crypto_unregister_shash(&sha1_alg); + crypto_unregister_shash(&sha256_alg); + } } module_init(padlock_init); diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c index b092d0a65837..230b5b8cda1f 100644 --- a/drivers/crypto/picoxcell_crypto.c +++ b/drivers/crypto/picoxcell_crypto.c @@ -176,6 +176,8 @@ struct spacc_aead_ctx { u8 salt[AES_BLOCK_SIZE]; }; +static int spacc_ablk_submit(struct spacc_req *req); + static inline struct spacc_alg *to_spacc_alg(struct crypto_alg *alg) { return alg ? container_of(alg, struct spacc_alg, alg) : NULL; @@ -666,6 +668,24 @@ static int spacc_aead_submit(struct spacc_req *req) return -EINPROGRESS; } +static int spacc_req_submit(struct spacc_req *req); + +static void spacc_push(struct spacc_engine *engine) +{ + struct spacc_req *req; + + while (!list_empty(&engine->pending) && + engine->in_flight + 1 <= engine->fifo_sz) { + + ++engine->in_flight; + req = list_first_entry(&engine->pending, struct spacc_req, + list); + list_move_tail(&req->list, &engine->in_progress); + + req->result = spacc_req_submit(req); + } +} + /* * Setup an AEAD request for processing. This will configure the engine, load * the context and then start the packet processing. @@ -698,7 +718,8 @@ static int spacc_aead_setup(struct aead_request *req, u8 *giv, err = -EINPROGRESS; spin_lock_irqsave(&engine->hw_lock, flags); - if (unlikely(spacc_fifo_cmd_full(engine))) { + if (unlikely(spacc_fifo_cmd_full(engine)) || + engine->in_flight + 1 > engine->fifo_sz) { if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { err = -EBUSY; spin_unlock_irqrestore(&engine->hw_lock, flags); @@ -706,9 +727,8 @@ static int spacc_aead_setup(struct aead_request *req, u8 *giv, } list_add_tail(&dev_req->list, &engine->pending); } else { - ++engine->in_flight; - list_add_tail(&dev_req->list, &engine->in_progress); - spacc_aead_submit(dev_req); + list_add_tail(&dev_req->list, &engine->pending); + spacc_push(engine); } spin_unlock_irqrestore(&engine->hw_lock, flags); @@ -1041,7 +1061,8 @@ static int spacc_ablk_setup(struct ablkcipher_request *req, unsigned alg_type, * we either stick it on the end of a pending list if we can backlog, * or bailout with an error if not. */ - if (unlikely(spacc_fifo_cmd_full(engine))) { + if (unlikely(spacc_fifo_cmd_full(engine)) || + engine->in_flight + 1 > engine->fifo_sz) { if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { err = -EBUSY; spin_unlock_irqrestore(&engine->hw_lock, flags); @@ -1049,9 +1070,8 @@ static int spacc_ablk_setup(struct ablkcipher_request *req, unsigned alg_type, } list_add_tail(&dev_req->list, &engine->pending); } else { - ++engine->in_flight; - list_add_tail(&dev_req->list, &engine->in_progress); - spacc_ablk_submit(dev_req); + list_add_tail(&dev_req->list, &engine->pending); + spacc_push(engine); } spin_unlock_irqrestore(&engine->hw_lock, flags); @@ -1139,6 +1159,7 @@ static void spacc_process_done(struct spacc_engine *engine) req = list_first_entry(&engine->in_progress, struct spacc_req, list); list_move_tail(&req->list, &engine->completed); + --engine->in_flight; /* POP the status register. */ writel(~0, engine->regs + SPA_STAT_POP_REG_OFFSET); @@ -1208,36 +1229,21 @@ static void spacc_spacc_complete(unsigned long data) struct spacc_engine *engine = (struct spacc_engine *)data; struct spacc_req *req, *tmp; unsigned long flags; - int num_removed = 0; LIST_HEAD(completed); spin_lock_irqsave(&engine->hw_lock, flags); + list_splice_init(&engine->completed, &completed); - spin_unlock_irqrestore(&engine->hw_lock, flags); - - list_for_each_entry_safe(req, tmp, &completed, list) { - ++num_removed; - req->complete(req); - } - - /* Try and fill the engine back up again. */ - spin_lock_irqsave(&engine->hw_lock, flags); - - engine->in_flight -= num_removed; - - list_for_each_entry_safe(req, tmp, &engine->pending, list) { - if (spacc_fifo_cmd_full(engine)) - break; - - list_move_tail(&req->list, &engine->in_progress); - ++engine->in_flight; - req->result = spacc_req_submit(req); - } - + spacc_push(engine); if (engine->in_flight) mod_timer(&engine->packet_timeout, jiffies + PACKET_TIMEOUT); spin_unlock_irqrestore(&engine->hw_lock, flags); + + list_for_each_entry_safe(req, tmp, &completed, list) { + req->complete(req); + list_del(&req->list); + } } #ifdef CONFIG_PM diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c new file mode 100644 index 000000000000..8115417a1c93 --- /dev/null +++ b/drivers/crypto/s5p-sss.c @@ -0,0 +1,701 @@ +/* + * Cryptographic API. + * + * Support for Samsung S5PV210 HW acceleration. + * + * Copyright (C) 2011 NetUP 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 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 + +#define _SBF(s, v) ((v) << (s)) +#define _BIT(b) _SBF(b, 1) + +/* Feed control registers */ +#define SSS_REG_FCINTSTAT 0x0000 +#define SSS_FCINTSTAT_BRDMAINT _BIT(3) +#define SSS_FCINTSTAT_BTDMAINT _BIT(2) +#define SSS_FCINTSTAT_HRDMAINT _BIT(1) +#define SSS_FCINTSTAT_PKDMAINT _BIT(0) + +#define SSS_REG_FCINTENSET 0x0004 +#define SSS_FCINTENSET_BRDMAINTENSET _BIT(3) +#define SSS_FCINTENSET_BTDMAINTENSET _BIT(2) +#define SSS_FCINTENSET_HRDMAINTENSET _BIT(1) +#define SSS_FCINTENSET_PKDMAINTENSET _BIT(0) + +#define SSS_REG_FCINTENCLR 0x0008 +#define SSS_FCINTENCLR_BRDMAINTENCLR _BIT(3) +#define SSS_FCINTENCLR_BTDMAINTENCLR _BIT(2) +#define SSS_FCINTENCLR_HRDMAINTENCLR _BIT(1) +#define SSS_FCINTENCLR_PKDMAINTENCLR _BIT(0) + +#define SSS_REG_FCINTPEND 0x000C +#define SSS_FCINTPEND_BRDMAINTP _BIT(3) +#define SSS_FCINTPEND_BTDMAINTP _BIT(2) +#define SSS_FCINTPEND_HRDMAINTP _BIT(1) +#define SSS_FCINTPEND_PKDMAINTP _BIT(0) + +#define SSS_REG_FCFIFOSTAT 0x0010 +#define SSS_FCFIFOSTAT_BRFIFOFUL _BIT(7) +#define SSS_FCFIFOSTAT_BRFIFOEMP _BIT(6) +#define SSS_FCFIFOSTAT_BTFIFOFUL _BIT(5) +#define SSS_FCFIFOSTAT_BTFIFOEMP _BIT(4) +#define SSS_FCFIFOSTAT_HRFIFOFUL _BIT(3) +#define SSS_FCFIFOSTAT_HRFIFOEMP _BIT(2) +#define SSS_FCFIFOSTAT_PKFIFOFUL _BIT(1) +#define SSS_FCFIFOSTAT_PKFIFOEMP _BIT(0) + +#define SSS_REG_FCFIFOCTRL 0x0014 +#define SSS_FCFIFOCTRL_DESSEL _BIT(2) +#define SSS_HASHIN_INDEPENDENT _SBF(0, 0x00) +#define SSS_HASHIN_CIPHER_INPUT _SBF(0, 0x01) +#define SSS_HASHIN_CIPHER_OUTPUT _SBF(0, 0x02) + +#define SSS_REG_FCBRDMAS 0x0020 +#define SSS_REG_FCBRDMAL 0x0024 +#define SSS_REG_FCBRDMAC 0x0028 +#define SSS_FCBRDMAC_BYTESWAP _BIT(1) +#define SSS_FCBRDMAC_FLUSH _BIT(0) + +#define SSS_REG_FCBTDMAS 0x0030 +#define SSS_REG_FCBTDMAL 0x0034 +#define SSS_REG_FCBTDMAC 0x0038 +#define SSS_FCBTDMAC_BYTESWAP _BIT(1) +#define SSS_FCBTDMAC_FLUSH _BIT(0) + +#define SSS_REG_FCHRDMAS 0x0040 +#define SSS_REG_FCHRDMAL 0x0044 +#define SSS_REG_FCHRDMAC 0x0048 +#define SSS_FCHRDMAC_BYTESWAP _BIT(1) +#define SSS_FCHRDMAC_FLUSH _BIT(0) + +#define SSS_REG_FCPKDMAS 0x0050 +#define SSS_REG_FCPKDMAL 0x0054 +#define SSS_REG_FCPKDMAC 0x0058 +#define SSS_FCPKDMAC_BYTESWAP _BIT(3) +#define SSS_FCPKDMAC_DESCEND _BIT(2) +#define SSS_FCPKDMAC_TRANSMIT _BIT(1) +#define SSS_FCPKDMAC_FLUSH _BIT(0) + +#define SSS_REG_FCPKDMAO 0x005C + +/* AES registers */ +#define SSS_REG_AES_CONTROL 0x4000 +#define SSS_AES_BYTESWAP_DI _BIT(11) +#define SSS_AES_BYTESWAP_DO _BIT(10) +#define SSS_AES_BYTESWAP_IV _BIT(9) +#define SSS_AES_BYTESWAP_CNT _BIT(8) +#define SSS_AES_BYTESWAP_KEY _BIT(7) +#define SSS_AES_KEY_CHANGE_MODE _BIT(6) +#define SSS_AES_KEY_SIZE_128 _SBF(4, 0x00) +#define SSS_AES_KEY_SIZE_192 _SBF(4, 0x01) +#define SSS_AES_KEY_SIZE_256 _SBF(4, 0x02) +#define SSS_AES_FIFO_MODE _BIT(3) +#define SSS_AES_CHAIN_MODE_ECB _SBF(1, 0x00) +#define SSS_AES_CHAIN_MODE_CBC _SBF(1, 0x01) +#define SSS_AES_CHAIN_MODE_CTR _SBF(1, 0x02) +#define SSS_AES_MODE_DECRYPT _BIT(0) + +#define SSS_REG_AES_STATUS 0x4004 +#define SSS_AES_BUSY _BIT(2) +#define SSS_AES_INPUT_READY _BIT(1) +#define SSS_AES_OUTPUT_READY _BIT(0) + +#define SSS_REG_AES_IN_DATA(s) (0x4010 + (s << 2)) +#define SSS_REG_AES_OUT_DATA(s) (0x4020 + (s << 2)) +#define SSS_REG_AES_IV_DATA(s) (0x4030 + (s << 2)) +#define SSS_REG_AES_CNT_DATA(s) (0x4040 + (s << 2)) +#define SSS_REG_AES_KEY_DATA(s) (0x4080 + (s << 2)) + +#define SSS_REG(dev, reg) ((dev)->ioaddr + (SSS_REG_##reg)) +#define SSS_READ(dev, reg) __raw_readl(SSS_REG(dev, reg)) +#define SSS_WRITE(dev, reg, val) __raw_writel((val), SSS_REG(dev, reg)) + +/* HW engine modes */ +#define FLAGS_AES_DECRYPT _BIT(0) +#define FLAGS_AES_MODE_MASK _SBF(1, 0x03) +#define FLAGS_AES_CBC _SBF(1, 0x01) +#define FLAGS_AES_CTR _SBF(1, 0x02) + +#define AES_KEY_LEN 16 +#define CRYPTO_QUEUE_LEN 1 + +struct s5p_aes_reqctx { + unsigned long mode; +}; + +struct s5p_aes_ctx { + struct s5p_aes_dev *dev; + + uint8_t aes_key[AES_MAX_KEY_SIZE]; + uint8_t nonce[CTR_RFC3686_NONCE_SIZE]; + int keylen; +}; + +struct s5p_aes_dev { + struct device *dev; + struct clk *clk; + void __iomem *ioaddr; + int irq_hash; + int irq_fc; + + struct ablkcipher_request *req; + struct s5p_aes_ctx *ctx; + struct scatterlist *sg_src; + struct scatterlist *sg_dst; + + struct tasklet_struct tasklet; + struct crypto_queue queue; + bool busy; + spinlock_t lock; +}; + +static struct s5p_aes_dev *s5p_dev; + +static void s5p_set_dma_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) +{ + SSS_WRITE(dev, FCBRDMAS, sg_dma_address(sg)); + SSS_WRITE(dev, FCBRDMAL, sg_dma_len(sg)); +} + +static void s5p_set_dma_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg) +{ + SSS_WRITE(dev, FCBTDMAS, sg_dma_address(sg)); + SSS_WRITE(dev, FCBTDMAL, sg_dma_len(sg)); +} + +static void s5p_aes_complete(struct s5p_aes_dev *dev, int err) +{ + /* holding a lock outside */ + dev->req->base.complete(&dev->req->base, err); + dev->busy = false; +} + +static void s5p_unset_outdata(struct s5p_aes_dev *dev) +{ + dma_unmap_sg(dev->dev, dev->sg_dst, 1, DMA_FROM_DEVICE); +} + +static void s5p_unset_indata(struct s5p_aes_dev *dev) +{ + dma_unmap_sg(dev->dev, dev->sg_src, 1, DMA_TO_DEVICE); +} + +static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg) +{ + int err; + + if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) { + err = -EINVAL; + goto exit; + } + if (!sg_dma_len(sg)) { + err = -EINVAL; + goto exit; + } + + err = dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE); + if (!err) { + err = -ENOMEM; + goto exit; + } + + dev->sg_dst = sg; + err = 0; + + exit: + return err; +} + +static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) +{ + int err; + + if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) { + err = -EINVAL; + goto exit; + } + if (!sg_dma_len(sg)) { + err = -EINVAL; + goto exit; + } + + err = dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE); + if (!err) { + err = -ENOMEM; + goto exit; + } + + dev->sg_src = sg; + err = 0; + + exit: + return err; +} + +static void s5p_aes_tx(struct s5p_aes_dev *dev) +{ + int err = 0; + + s5p_unset_outdata(dev); + + if (!sg_is_last(dev->sg_dst)) { + err = s5p_set_outdata(dev, sg_next(dev->sg_dst)); + if (err) { + s5p_aes_complete(dev, err); + return; + } + + s5p_set_dma_outdata(dev, dev->sg_dst); + } else + s5p_aes_complete(dev, err); +} + +static void s5p_aes_rx(struct s5p_aes_dev *dev) +{ + int err; + + s5p_unset_indata(dev); + + if (!sg_is_last(dev->sg_src)) { + err = s5p_set_indata(dev, sg_next(dev->sg_src)); + if (err) { + s5p_aes_complete(dev, err); + return; + } + + s5p_set_dma_indata(dev, dev->sg_src); + } +} + +static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct s5p_aes_dev *dev = platform_get_drvdata(pdev); + uint32_t status; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + + if (irq == dev->irq_fc) { + status = SSS_READ(dev, FCINTSTAT); + if (status & SSS_FCINTSTAT_BRDMAINT) + s5p_aes_rx(dev); + if (status & SSS_FCINTSTAT_BTDMAINT) + s5p_aes_tx(dev); + + SSS_WRITE(dev, FCINTPEND, status); + } + + spin_unlock_irqrestore(&dev->lock, flags); + + return IRQ_HANDLED; +} + +static void s5p_set_aes(struct s5p_aes_dev *dev, + uint8_t *key, uint8_t *iv, unsigned int keylen) +{ + void __iomem *keystart; + + memcpy(dev->ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10); + + if (keylen == AES_KEYSIZE_256) + keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(0); + else if (keylen == AES_KEYSIZE_192) + keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(2); + else + keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(4); + + memcpy(keystart, key, keylen); +} + +static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) +{ + struct ablkcipher_request *req = dev->req; + + uint32_t aes_control; + int err; + unsigned long flags; + + aes_control = SSS_AES_KEY_CHANGE_MODE; + if (mode & FLAGS_AES_DECRYPT) + aes_control |= SSS_AES_MODE_DECRYPT; + + if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) + aes_control |= SSS_AES_CHAIN_MODE_CBC; + else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) + aes_control |= SSS_AES_CHAIN_MODE_CTR; + + if (dev->ctx->keylen == AES_KEYSIZE_192) + aes_control |= SSS_AES_KEY_SIZE_192; + else if (dev->ctx->keylen == AES_KEYSIZE_256) + aes_control |= SSS_AES_KEY_SIZE_256; + + aes_control |= SSS_AES_FIFO_MODE; + + /* as a variant it is possible to use byte swapping on DMA side */ + aes_control |= SSS_AES_BYTESWAP_DI + | SSS_AES_BYTESWAP_DO + | SSS_AES_BYTESWAP_IV + | SSS_AES_BYTESWAP_KEY + | SSS_AES_BYTESWAP_CNT; + + spin_lock_irqsave(&dev->lock, flags); + + SSS_WRITE(dev, FCINTENCLR, + SSS_FCINTENCLR_BTDMAINTENCLR | SSS_FCINTENCLR_BRDMAINTENCLR); + SSS_WRITE(dev, FCFIFOCTRL, 0x00); + + err = s5p_set_indata(dev, req->src); + if (err) + goto indata_error; + + err = s5p_set_outdata(dev, req->dst); + if (err) + goto outdata_error; + + SSS_WRITE(dev, AES_CONTROL, aes_control); + s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen); + + s5p_set_dma_indata(dev, req->src); + s5p_set_dma_outdata(dev, req->dst); + + SSS_WRITE(dev, FCINTENSET, + SSS_FCINTENSET_BTDMAINTENSET | SSS_FCINTENSET_BRDMAINTENSET); + + spin_unlock_irqrestore(&dev->lock, flags); + + return; + + outdata_error: + s5p_unset_indata(dev); + + indata_error: + s5p_aes_complete(dev, err); + spin_unlock_irqrestore(&dev->lock, flags); +} + +static void s5p_tasklet_cb(unsigned long data) +{ + struct s5p_aes_dev *dev = (struct s5p_aes_dev *)data; + struct crypto_async_request *async_req, *backlog; + struct s5p_aes_reqctx *reqctx; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + backlog = crypto_get_backlog(&dev->queue); + async_req = crypto_dequeue_request(&dev->queue); + spin_unlock_irqrestore(&dev->lock, flags); + + if (!async_req) + return; + + if (backlog) + backlog->complete(backlog, -EINPROGRESS); + + dev->req = ablkcipher_request_cast(async_req); + dev->ctx = crypto_tfm_ctx(dev->req->base.tfm); + reqctx = ablkcipher_request_ctx(dev->req); + + s5p_aes_crypt_start(dev, reqctx->mode); +} + +static int s5p_aes_handle_req(struct s5p_aes_dev *dev, + struct ablkcipher_request *req) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->busy) { + err = -EAGAIN; + spin_unlock_irqrestore(&dev->lock, flags); + goto exit; + } + dev->busy = true; + + err = ablkcipher_enqueue_request(&dev->queue, req); + spin_unlock_irqrestore(&dev->lock, flags); + + tasklet_schedule(&dev->tasklet); + + exit: + return err; +} + +static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); + struct s5p_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); + struct s5p_aes_reqctx *reqctx = ablkcipher_request_ctx(req); + struct s5p_aes_dev *dev = ctx->dev; + + if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) { + pr_err("request size is not exact amount of AES blocks\n"); + return -EINVAL; + } + + reqctx->mode = mode; + + return s5p_aes_handle_req(dev, req); +} + +static int s5p_aes_setkey(struct crypto_ablkcipher *cipher, + const uint8_t *key, unsigned int keylen) +{ + struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); + struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + if (keylen != AES_KEYSIZE_128 && + keylen != AES_KEYSIZE_192 && + keylen != AES_KEYSIZE_256) + return -EINVAL; + + memcpy(ctx->aes_key, key, keylen); + ctx->keylen = keylen; + + return 0; +} + +static int s5p_aes_ecb_encrypt(struct ablkcipher_request *req) +{ + return s5p_aes_crypt(req, 0); +} + +static int s5p_aes_ecb_decrypt(struct ablkcipher_request *req) +{ + return s5p_aes_crypt(req, FLAGS_AES_DECRYPT); +} + +static int s5p_aes_cbc_encrypt(struct ablkcipher_request *req) +{ + return s5p_aes_crypt(req, FLAGS_AES_CBC); +} + +static int s5p_aes_cbc_decrypt(struct ablkcipher_request *req) +{ + return s5p_aes_crypt(req, FLAGS_AES_DECRYPT | FLAGS_AES_CBC); +} + +static int s5p_aes_cra_init(struct crypto_tfm *tfm) +{ + struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->dev = s5p_dev; + tfm->crt_ablkcipher.reqsize = sizeof(struct s5p_aes_reqctx); + + return 0; +} + +static struct crypto_alg algs[] = { + { + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-aes-s5p", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s5p_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = s5p_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = s5p_aes_setkey, + .encrypt = s5p_aes_ecb_encrypt, + .decrypt = s5p_aes_ecb_decrypt, + } + }, + { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-s5p", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s5p_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = s5p_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = s5p_aes_setkey, + .encrypt = s5p_aes_cbc_encrypt, + .decrypt = s5p_aes_cbc_decrypt, + } + }, +}; + +static int s5p_aes_probe(struct platform_device *pdev) +{ + int i, j, err = -ENODEV; + struct s5p_aes_dev *pdata; + struct device *dev = &pdev->dev; + struct resource *res; + + if (s5p_dev) + return -EEXIST; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (!devm_request_mem_region(dev, res->start, + resource_size(res), pdev->name)) + return -EBUSY; + + pdata->clk = clk_get(dev, "secss"); + if (IS_ERR(pdata->clk)) { + dev_err(dev, "failed to find secss clock source\n"); + return -ENOENT; + } + + clk_enable(pdata->clk); + + spin_lock_init(&pdata->lock); + pdata->ioaddr = devm_ioremap(dev, res->start, + resource_size(res)); + + pdata->irq_hash = platform_get_irq_byname(pdev, "hash"); + if (pdata->irq_hash < 0) { + err = pdata->irq_hash; + dev_warn(dev, "hash interrupt is not available.\n"); + goto err_irq; + } + err = devm_request_irq(dev, pdata->irq_hash, s5p_aes_interrupt, + IRQF_SHARED, pdev->name, pdev); + if (err < 0) { + dev_warn(dev, "hash interrupt is not available.\n"); + goto err_irq; + } + + pdata->irq_fc = platform_get_irq_byname(pdev, "feed control"); + if (pdata->irq_fc < 0) { + err = pdata->irq_fc; + dev_warn(dev, "feed control interrupt is not available.\n"); + goto err_irq; + } + err = devm_request_irq(dev, pdata->irq_fc, s5p_aes_interrupt, + IRQF_SHARED, pdev->name, pdev); + if (err < 0) { + dev_warn(dev, "feed control interrupt is not available.\n"); + goto err_irq; + } + + pdata->dev = dev; + platform_set_drvdata(pdev, pdata); + s5p_dev = pdata; + + tasklet_init(&pdata->tasklet, s5p_tasklet_cb, (unsigned long)pdata); + crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN); + + for (i = 0; i < ARRAY_SIZE(algs); i++) { + INIT_LIST_HEAD(&algs[i].cra_list); + err = crypto_register_alg(&algs[i]); + if (err) + goto err_algs; + } + + pr_info("s5p-sss driver registered\n"); + + return 0; + + err_algs: + dev_err(dev, "can't register '%s': %d\n", algs[i].cra_name, err); + + for (j = 0; j < i; j++) + crypto_unregister_alg(&algs[j]); + + tasklet_kill(&pdata->tasklet); + + err_irq: + clk_disable(pdata->clk); + clk_put(pdata->clk); + + s5p_dev = NULL; + platform_set_drvdata(pdev, NULL); + + return err; +} + +static int s5p_aes_remove(struct platform_device *pdev) +{ + struct s5p_aes_dev *pdata = platform_get_drvdata(pdev); + int i; + + if (!pdata) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(algs); i++) + crypto_unregister_alg(&algs[i]); + + tasklet_kill(&pdata->tasklet); + + clk_disable(pdata->clk); + clk_put(pdata->clk); + + s5p_dev = NULL; + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver s5p_aes_crypto = { + .probe = s5p_aes_probe, + .remove = s5p_aes_remove, + .driver = { + .owner = THIS_MODULE, + .name = "s5p-secss", + }, +}; + +static int __init s5p_aes_mod_init(void) +{ + return platform_driver_register(&s5p_aes_crypto); +} + +static void __exit s5p_aes_mod_exit(void) +{ + platform_driver_unregister(&s5p_aes_crypto); +} + +module_init(s5p_aes_mod_init); +module_exit(s5p_aes_mod_exit); + +MODULE_DESCRIPTION("S5PV210 AES hw acceleration support."); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Vladimir Zapolskiy "); diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 31e71c4fc831..9a8bebcf6b17 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -211,8 +211,6 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci) scrubval = scrubval & 0x001F; - amd64_debug("pci-read, sdram scrub control value: %d\n", scrubval); - for (i = 0; i < ARRAY_SIZE(scrubrates); i++) { if (scrubrates[i].scrubval == scrubval) { retval = scrubrates[i].bandwidth; @@ -933,25 +931,74 @@ static int k8_early_channel_count(struct amd64_pvt *pvt) /* On F10h and later ErrAddr is MC4_ADDR[47:1] */ static u64 get_error_address(struct mce *m) { + struct cpuinfo_x86 *c = &boot_cpu_data; + u64 addr; u8 start_bit = 1; u8 end_bit = 47; - if (boot_cpu_data.x86 == 0xf) { + if (c->x86 == 0xf) { start_bit = 3; end_bit = 39; } - return m->addr & GENMASK(start_bit, end_bit); + addr = m->addr & GENMASK(start_bit, end_bit); + + /* + * Erratum 637 workaround + */ + if (c->x86 == 0x15) { + struct amd64_pvt *pvt; + u64 cc6_base, tmp_addr; + u32 tmp; + u8 mce_nid, intlv_en; + + if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7) + return addr; + + mce_nid = amd_get_nb_id(m->extcpu); + pvt = mcis[mce_nid]->pvt_info; + + amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_LIM, &tmp); + intlv_en = tmp >> 21 & 0x7; + + /* add [47:27] + 3 trailing bits */ + cc6_base = (tmp & GENMASK(0, 20)) << 3; + + /* reverse and add DramIntlvEn */ + cc6_base |= intlv_en ^ 0x7; + + /* pin at [47:24] */ + cc6_base <<= 24; + + if (!intlv_en) + return cc6_base | (addr & GENMASK(0, 23)); + + amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp); + + /* faster log2 */ + tmp_addr = (addr & GENMASK(12, 23)) << __fls(intlv_en + 1); + + /* OR DramIntlvSel into bits [14:12] */ + tmp_addr |= (tmp & GENMASK(21, 23)) >> 9; + + /* add remaining [11:0] bits from original MC4_ADDR */ + tmp_addr |= addr & GENMASK(0, 11); + + return cc6_base | tmp_addr; + } + + return addr; } static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) { + struct cpuinfo_x86 *c = &boot_cpu_data; int off = range << 3; amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo); amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo); - if (boot_cpu_data.x86 == 0xf) + if (c->x86 == 0xf) return; if (!dram_rw(pvt, range)) @@ -959,6 +1006,31 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi); amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi); + + /* Factor in CC6 save area by reading dst node's limit reg */ + if (c->x86 == 0x15) { + struct pci_dev *f1 = NULL; + u8 nid = dram_dst_node(pvt, range); + u32 llim; + + f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1)); + if (WARN_ON(!f1)) + return; + + amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim); + + pvt->ranges[range].lim.lo &= GENMASK(0, 15); + + /* {[39:27],111b} */ + pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16; + + pvt->ranges[range].lim.hi &= GENMASK(0, 7); + + /* [47:40] */ + pvt->ranges[range].lim.hi |= llim >> 13; + + pci_dev_put(f1); + } } static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, @@ -1403,12 +1475,8 @@ static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range, return -EINVAL; } - if (intlv_en && - (intlv_sel != ((sys_addr >> 12) & intlv_en))) { - amd64_warn("Botched intlv bits, en: 0x%x, sel: 0x%x\n", - intlv_en, intlv_sel); + if (intlv_en && (intlv_sel != ((sys_addr >> 12) & intlv_en))) return -EINVAL; - } sys_addr = f1x_swap_interleaved_region(pvt, sys_addr); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 11be36a311eb..9a666cb985b2 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -196,6 +196,9 @@ #define DCT_CFG_SEL 0x10C +#define DRAM_LOCAL_NODE_BASE 0x120 +#define DRAM_LOCAL_NODE_LIM 0x124 + #define DRAM_BASE_HI 0x140 #define DRAM_LIMIT_HI 0x144 diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 26343fd46596..29ffa350bfbe 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -458,13 +458,13 @@ static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci, return -EINVAL; new_bw = mci->set_sdram_scrub_rate(mci, bandwidth); - if (new_bw >= 0) { - edac_printk(KERN_DEBUG, EDAC_MC, "Scrub rate set to %d\n", new_bw); - return count; + if (new_bw < 0) { + edac_printk(KERN_WARNING, EDAC_MC, + "Error setting scrub rate to: %lu\n", bandwidth); + return -EINVAL; } - edac_printk(KERN_DEBUG, EDAC_MC, "Error setting scrub rate to: %lu\n", bandwidth); - return -EINVAL; + return count; } /* @@ -483,7 +483,6 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data) return bandwidth; } - edac_printk(KERN_DEBUG, EDAC_MC, "Read scrub rate: %d\n", bandwidth); return sprintf(data, "%d\n", bandwidth); } diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index c1f0045ceb8e..af8e7b1aa290 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -1019,7 +1019,7 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci, struct ppc4xx_edac_pdata *pdata = NULL; const struct device_node *np = op->dev.of_node; - if (op->dev.of_match == NULL) + if (of_match_device(ppc4xx_edac_match, &op->dev) == NULL) return -EINVAL; /* Initial driver pointers and private data */ diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 3c44fbc81acb..29d2423fae6d 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -228,8 +228,8 @@ void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset) /* Use an arbitrary short delay to combine multiple reset requests. */ fw_card_get(card); - if (!schedule_delayed_work(&card->br_work, - delayed ? DIV_ROUND_UP(HZ, 100) : 0)) + if (!queue_delayed_work(fw_workqueue, &card->br_work, + delayed ? DIV_ROUND_UP(HZ, 100) : 0)) fw_card_put(card); } EXPORT_SYMBOL(fw_schedule_bus_reset); @@ -241,7 +241,7 @@ static void br_work(struct work_struct *work) /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */ if (card->reset_jiffies != 0 && time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) { - if (!schedule_delayed_work(&card->br_work, 2 * HZ)) + if (!queue_delayed_work(fw_workqueue, &card->br_work, 2 * HZ)) fw_card_put(card); return; } @@ -258,8 +258,7 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation) if (!card->broadcast_channel_allocated) { fw_iso_resource_manage(card, generation, 1ULL << 31, - &channel, &bandwidth, true, - card->bm_transaction_data); + &channel, &bandwidth, true); if (channel != 31) { fw_notify("failed to allocate broadcast channel\n"); return; @@ -294,6 +293,7 @@ static void bm_work(struct work_struct *work) bool root_device_is_cmc; bool irm_is_1394_1995_only; bool keep_this_irm; + __be32 transaction_data[2]; spin_lock_irq(&card->lock); @@ -355,21 +355,21 @@ static void bm_work(struct work_struct *work) goto pick_me; } - card->bm_transaction_data[0] = cpu_to_be32(0x3f); - card->bm_transaction_data[1] = cpu_to_be32(local_id); + transaction_data[0] = cpu_to_be32(0x3f); + transaction_data[1] = cpu_to_be32(local_id); spin_unlock_irq(&card->lock); rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, irm_id, generation, SCODE_100, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, - card->bm_transaction_data, 8); + transaction_data, 8); if (rcode == RCODE_GENERATION) /* Another bus reset, BM work has been rescheduled. */ goto out; - bm_id = be32_to_cpu(card->bm_transaction_data[0]); + bm_id = be32_to_cpu(transaction_data[0]); spin_lock_irq(&card->lock); if (rcode == RCODE_COMPLETE && generation == card->generation) @@ -490,11 +490,11 @@ static void bm_work(struct work_struct *work) /* * Make sure that the cycle master sends cycle start packets. */ - card->bm_transaction_data[0] = cpu_to_be32(CSR_STATE_BIT_CMSTR); + transaction_data[0] = cpu_to_be32(CSR_STATE_BIT_CMSTR); rcode = fw_run_transaction(card, TCODE_WRITE_QUADLET_REQUEST, root_id, generation, SCODE_100, CSR_REGISTER_BASE + CSR_STATE_SET, - card->bm_transaction_data, 4); + transaction_data, 4); if (rcode == RCODE_GENERATION) goto out; } @@ -630,6 +630,10 @@ static int dummy_queue_iso(struct fw_iso_context *ctx, struct fw_iso_packet *p, return -ENODEV; } +static void dummy_flush_queue_iso(struct fw_iso_context *ctx) +{ +} + static const struct fw_card_driver dummy_driver_template = { .read_phy_reg = dummy_read_phy_reg, .update_phy_reg = dummy_update_phy_reg, @@ -641,6 +645,7 @@ static const struct fw_card_driver dummy_driver_template = { .start_iso = dummy_start_iso, .set_iso_channels = dummy_set_iso_channels, .queue_iso = dummy_queue_iso, + .flush_queue_iso = dummy_flush_queue_iso, }; void fw_card_release(struct kref *kref) diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 62ac111af243..b1c11775839c 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -141,7 +141,6 @@ struct iso_resource { int generation; u64 channels; s32 bandwidth; - __be32 transaction_data[2]; struct iso_resource_event *e_alloc, *e_dealloc; }; @@ -150,7 +149,7 @@ static void release_iso_resource(struct client *, struct client_resource *); static void schedule_iso_resource(struct iso_resource *r, unsigned long delay) { client_get(r->client); - if (!schedule_delayed_work(&r->work, delay)) + if (!queue_delayed_work(fw_workqueue, &r->work, delay)) client_put(r->client); } @@ -1108,6 +1107,7 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg) payload += u.packet.payload_length; count++; } + fw_iso_context_queue_flush(ctx); a->size -= uptr_to_u64(p) - a->packets; a->packets = uptr_to_u64(p); @@ -1229,8 +1229,7 @@ static void iso_resource_work(struct work_struct *work) r->channels, &channel, &bandwidth, todo == ISO_RES_ALLOC || todo == ISO_RES_REALLOC || - todo == ISO_RES_ALLOC_ONCE, - r->transaction_data); + todo == ISO_RES_ALLOC_ONCE); /* * Is this generation outdated already? As long as this resource sticks * in the idr, it will be scheduled again for a newer generation or at diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 9a262439e3a7..95a471401892 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -725,6 +725,15 @@ struct fw_device *fw_device_get_by_devt(dev_t devt) return device; } +struct workqueue_struct *fw_workqueue; +EXPORT_SYMBOL(fw_workqueue); + +static void fw_schedule_device_work(struct fw_device *device, + unsigned long delay) +{ + queue_delayed_work(fw_workqueue, &device->work, delay); +} + /* * These defines control the retry behavior for reading the config * rom. It shouldn't be necessary to tweak these; if the device @@ -750,7 +759,7 @@ static void fw_device_shutdown(struct work_struct *work) if (time_before64(get_jiffies_64(), device->card->reset_jiffies + SHUTDOWN_DELAY) && !list_empty(&device->card->link)) { - schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + fw_schedule_device_work(device, SHUTDOWN_DELAY); return; } @@ -862,7 +871,7 @@ static int lookup_existing_device(struct device *dev, void *data) fw_notify("rediscovered device %s\n", dev_name(dev)); PREPARE_DELAYED_WORK(&old->work, fw_device_update); - schedule_delayed_work(&old->work, 0); + fw_schedule_device_work(old, 0); if (current_node == card->root_node) fw_schedule_bm_work(card, 0); @@ -953,7 +962,7 @@ static void fw_device_init(struct work_struct *work) if (device->config_rom_retries < MAX_RETRIES && atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { device->config_rom_retries++; - schedule_delayed_work(&device->work, RETRY_DELAY); + fw_schedule_device_work(device, RETRY_DELAY); } else { if (device->node->link_on) fw_notify("giving up on config rom for node id %x\n", @@ -1019,7 +1028,7 @@ static void fw_device_init(struct work_struct *work) FW_DEVICE_INITIALIZING, FW_DEVICE_RUNNING) == FW_DEVICE_GONE) { PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); - schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + fw_schedule_device_work(device, SHUTDOWN_DELAY); } else { if (device->config_rom_retries) fw_notify("created device %s: GUID %08x%08x, S%d00, " @@ -1098,7 +1107,7 @@ static void fw_device_refresh(struct work_struct *work) if (device->config_rom_retries < MAX_RETRIES / 2 && atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { device->config_rom_retries++; - schedule_delayed_work(&device->work, RETRY_DELAY / 2); + fw_schedule_device_work(device, RETRY_DELAY / 2); return; } @@ -1131,7 +1140,7 @@ static void fw_device_refresh(struct work_struct *work) if (device->config_rom_retries < MAX_RETRIES && atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { device->config_rom_retries++; - schedule_delayed_work(&device->work, RETRY_DELAY); + fw_schedule_device_work(device, RETRY_DELAY); return; } @@ -1158,7 +1167,7 @@ static void fw_device_refresh(struct work_struct *work) gone: atomic_set(&device->state, FW_DEVICE_GONE); PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); - schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + fw_schedule_device_work(device, SHUTDOWN_DELAY); out: if (node_id == card->root_node->node_id) fw_schedule_bm_work(card, 0); @@ -1214,7 +1223,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) * first config rom scan half a second after bus reset. */ INIT_DELAYED_WORK(&device->work, fw_device_init); - schedule_delayed_work(&device->work, INITIAL_DELAY); + fw_schedule_device_work(device, INITIAL_DELAY); break; case FW_NODE_INITIATED_RESET: @@ -1230,7 +1239,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) FW_DEVICE_RUNNING, FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) { PREPARE_DELAYED_WORK(&device->work, fw_device_refresh); - schedule_delayed_work(&device->work, + fw_schedule_device_work(device, device->is_local ? 0 : INITIAL_DELAY); } break; @@ -1245,7 +1254,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) device->generation = card->generation; if (atomic_read(&device->state) == FW_DEVICE_RUNNING) { PREPARE_DELAYED_WORK(&device->work, fw_device_update); - schedule_delayed_work(&device->work, 0); + fw_schedule_device_work(device, 0); } break; @@ -1270,7 +1279,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) if (atomic_xchg(&device->state, FW_DEVICE_GONE) == FW_DEVICE_RUNNING) { PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); - schedule_delayed_work(&device->work, + fw_schedule_device_work(device, list_empty(&card->link) ? 0 : SHUTDOWN_DELAY); } break; diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 481056df9268..57c3973093ad 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -185,6 +185,12 @@ int fw_iso_context_queue(struct fw_iso_context *ctx, } EXPORT_SYMBOL(fw_iso_context_queue); +void fw_iso_context_queue_flush(struct fw_iso_context *ctx) +{ + ctx->card->driver->flush_queue_iso(ctx); +} +EXPORT_SYMBOL(fw_iso_context_queue_flush); + int fw_iso_context_stop(struct fw_iso_context *ctx) { return ctx->card->driver->stop_iso(ctx); @@ -196,9 +202,10 @@ EXPORT_SYMBOL(fw_iso_context_stop); */ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, - int bandwidth, bool allocate, __be32 data[2]) + int bandwidth, bool allocate) { int try, new, old = allocate ? BANDWIDTH_AVAILABLE_INITIAL : 0; + __be32 data[2]; /* * On a 1394a IRM with low contention, try < 1 is enough. @@ -233,9 +240,10 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, } static int manage_channel(struct fw_card *card, int irm_id, int generation, - u32 channels_mask, u64 offset, bool allocate, __be32 data[2]) + u32 channels_mask, u64 offset, bool allocate) { __be32 bit, all, old; + __be32 data[2]; int channel, ret = -EIO, retry = 5; old = all = allocate ? cpu_to_be32(~0) : 0; @@ -284,7 +292,7 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation, } static void deallocate_channel(struct fw_card *card, int irm_id, - int generation, int channel, __be32 buffer[2]) + int generation, int channel) { u32 mask; u64 offset; @@ -293,7 +301,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id, offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI : CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO; - manage_channel(card, irm_id, generation, mask, offset, false, buffer); + manage_channel(card, irm_id, generation, mask, offset, false); } /** @@ -322,7 +330,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id, */ void fw_iso_resource_manage(struct fw_card *card, int generation, u64 channels_mask, int *channel, int *bandwidth, - bool allocate, __be32 buffer[2]) + bool allocate) { u32 channels_hi = channels_mask; /* channels 31...0 */ u32 channels_lo = channels_mask >> 32; /* channels 63...32 */ @@ -335,11 +343,11 @@ void fw_iso_resource_manage(struct fw_card *card, int generation, if (channels_hi) c = manage_channel(card, irm_id, generation, channels_hi, CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI, - allocate, buffer); + allocate); if (channels_lo && c < 0) { c = manage_channel(card, irm_id, generation, channels_lo, CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO, - allocate, buffer); + allocate); if (c >= 0) c += 32; } @@ -351,14 +359,13 @@ void fw_iso_resource_manage(struct fw_card *card, int generation, if (*bandwidth == 0) return; - ret = manage_bandwidth(card, irm_id, generation, *bandwidth, - allocate, buffer); + ret = manage_bandwidth(card, irm_id, generation, *bandwidth, allocate); if (ret < 0) *bandwidth = 0; if (allocate && ret < 0) { if (c >= 0) - deallocate_channel(card, irm_id, generation, c, buffer); + deallocate_channel(card, irm_id, generation, c); *channel = ret; } } diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index d00f8ce902cc..334b82a3542c 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -326,8 +327,8 @@ static int allocate_tlabel(struct fw_card *card) * It will contain tag, channel, and sy data instead of a node ID then. * * The payload buffer at @data is going to be DMA-mapped except in case of - * quadlet-sized payload or of local (loopback) requests. Hence make sure that - * the buffer complies with the restrictions for DMA-mapped memory. The + * @length <= 8 or of local (loopback) requests. Hence make sure that the + * buffer complies with the restrictions of the streaming DMA mapping API. * @payload must not be freed before the @callback is called. * * In case of request types without payload, @data is NULL and @length is 0. @@ -411,7 +412,8 @@ static void transaction_callback(struct fw_card *card, int rcode, * * Returns the RCODE. See fw_send_request() for parameter documentation. * Unlike fw_send_request(), @data points to the payload of the request or/and - * to the payload of the response. + * to the payload of the response. DMA mapping restrictions apply to outbound + * request payloads of >= 8 bytes but not to inbound response payloads. */ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, int generation, int speed, unsigned long long offset, @@ -1212,13 +1214,21 @@ static int __init fw_core_init(void) { int ret; + fw_workqueue = alloc_workqueue("firewire", + WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); + if (!fw_workqueue) + return -ENOMEM; + ret = bus_register(&fw_bus_type); - if (ret < 0) + if (ret < 0) { + destroy_workqueue(fw_workqueue); return ret; + } fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); if (fw_cdev_major < 0) { bus_unregister(&fw_bus_type); + destroy_workqueue(fw_workqueue); return fw_cdev_major; } @@ -1234,6 +1244,7 @@ static void __exit fw_core_cleanup(void) { unregister_chrdev(fw_cdev_major, "firewire"); bus_unregister(&fw_bus_type); + destroy_workqueue(fw_workqueue); idr_destroy(&fw_device_idr); } diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 25e729cde2f7..0fe4e4e6eda7 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -97,6 +97,8 @@ struct fw_card_driver { struct fw_iso_buffer *buffer, unsigned long payload); + void (*flush_queue_iso)(struct fw_iso_context *ctx); + int (*stop_iso)(struct fw_iso_context *ctx); }; diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 3f04dd3681cf..b9762d07198d 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -881,7 +881,9 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, spin_unlock_irqrestore(&dev->lock, flags); - if (retval < 0) + if (retval >= 0) + fw_iso_context_queue_flush(dev->broadcast_rcv_context); + else fw_error("requeue failed\n"); } diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index f903d7b6f34a..438e6c831170 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1006,13 +1006,12 @@ static void ar_context_run(struct ar_context *ctx) static struct descriptor *find_branch_descriptor(struct descriptor *d, int z) { - int b, key; + __le16 branch; - b = (le16_to_cpu(d->control) & DESCRIPTOR_BRANCH_ALWAYS) >> 2; - key = (le16_to_cpu(d->control) & DESCRIPTOR_KEY_IMMEDIATE) >> 8; + branch = d->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS); /* figure out which descriptor the branch address goes in */ - if (z == 2 && (b == 3 || key == 2)) + if (z == 2 && branch == cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS)) return d; else return d + z - 1; @@ -1193,9 +1192,6 @@ static void context_append(struct context *ctx, wmb(); /* finish init of new descriptors before branch_address update */ ctx->prev->branch_address = cpu_to_le32(d_bus | z); ctx->prev = find_branch_descriptor(d, z); - - reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); - flush_writes(ctx->ohci); } static void context_stop(struct context *ctx) @@ -1218,6 +1214,7 @@ static void context_stop(struct context *ctx) } struct driver_data { + u8 inline_data[8]; struct fw_packet *packet; }; @@ -1301,20 +1298,28 @@ static int at_context_queue_packet(struct context *ctx, return -1; } + BUILD_BUG_ON(sizeof(struct driver_data) > sizeof(struct descriptor)); driver_data = (struct driver_data *) &d[3]; driver_data->packet = packet; packet->driver_data = driver_data; if (packet->payload_length > 0) { - payload_bus = - dma_map_single(ohci->card.device, packet->payload, - packet->payload_length, DMA_TO_DEVICE); - if (dma_mapping_error(ohci->card.device, payload_bus)) { - packet->ack = RCODE_SEND_ERROR; - return -1; + if (packet->payload_length > sizeof(driver_data->inline_data)) { + payload_bus = dma_map_single(ohci->card.device, + packet->payload, + packet->payload_length, + DMA_TO_DEVICE); + if (dma_mapping_error(ohci->card.device, payload_bus)) { + packet->ack = RCODE_SEND_ERROR; + return -1; + } + packet->payload_bus = payload_bus; + packet->payload_mapped = true; + } else { + memcpy(driver_data->inline_data, packet->payload, + packet->payload_length); + payload_bus = d_bus + 3 * sizeof(*d); } - packet->payload_bus = payload_bus; - packet->payload_mapped = true; d[2].req_count = cpu_to_le16(packet->payload_length); d[2].data_address = cpu_to_le32(payload_bus); @@ -1340,8 +1345,12 @@ static int at_context_queue_packet(struct context *ctx, context_append(ctx, d, z, 4 - z); - if (!ctx->running) + if (ctx->running) { + reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); + flush_writes(ohci); + } else { context_run(ctx, 0); + } return 0; } @@ -2066,8 +2075,6 @@ static int ohci_enable(struct fw_card *card, reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus); reg_write(ohci, OHCI1394_LinkControlSet, - OHCI1394_LinkControl_rcvSelfID | - OHCI1394_LinkControl_rcvPhyPkt | OHCI1394_LinkControl_cycleTimerEnable | OHCI1394_LinkControl_cycleMaster); @@ -2094,9 +2101,6 @@ static int ohci_enable(struct fw_card *card, reg_write(ohci, OHCI1394_FairnessControl, 0); card->priority_budget_implemented = ohci->pri_req_max != 0; - ar_context_run(&ohci->ar_request_ctx); - ar_context_run(&ohci->ar_response_ctx); - reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000); reg_write(ohci, OHCI1394_IntEventClear, ~0); reg_write(ohci, OHCI1394_IntMaskClear, ~0); @@ -2186,7 +2190,13 @@ static int ohci_enable(struct fw_card *card, reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable | OHCI1394_HCControl_BIBimageValid); - flush_writes(ohci); + + reg_write(ohci, OHCI1394_LinkControlSet, + OHCI1394_LinkControl_rcvSelfID | + OHCI1394_LinkControl_rcvPhyPkt); + + ar_context_run(&ohci->ar_request_ctx); + ar_context_run(&ohci->ar_response_ctx); /* also flushes writes */ /* We are ready to go, reset bus to finish initialization. */ fw_schedule_bus_reset(&ohci->card, false, true); @@ -2199,7 +2209,6 @@ static int ohci_set_config_rom(struct fw_card *card, { struct fw_ohci *ohci; unsigned long flags; - int ret = -EBUSY; __be32 *next_config_rom; dma_addr_t uninitialized_var(next_config_rom_bus); @@ -2240,22 +2249,37 @@ static int ohci_set_config_rom(struct fw_card *card, spin_lock_irqsave(&ohci->lock, flags); + /* + * If there is not an already pending config_rom update, + * push our new allocation into the ohci->next_config_rom + * and then mark the local variable as null so that we + * won't deallocate the new buffer. + * + * OTOH, if there is a pending config_rom update, just + * use that buffer with the new config_rom data, and + * let this routine free the unused DMA allocation. + */ + if (ohci->next_config_rom == NULL) { ohci->next_config_rom = next_config_rom; ohci->next_config_rom_bus = next_config_rom_bus; - - copy_config_rom(ohci->next_config_rom, config_rom, length); - - ohci->next_header = config_rom[0]; - ohci->next_config_rom[0] = 0; - - reg_write(ohci, OHCI1394_ConfigROMmap, - ohci->next_config_rom_bus); - ret = 0; + next_config_rom = NULL; } + copy_config_rom(ohci->next_config_rom, config_rom, length); + + ohci->next_header = config_rom[0]; + ohci->next_config_rom[0] = 0; + + reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus); + spin_unlock_irqrestore(&ohci->lock, flags); + /* If we didn't use the DMA allocation, delete it. */ + if (next_config_rom != NULL) + dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, + next_config_rom, next_config_rom_bus); + /* * Now initiate a bus reset to have the changes take * effect. We clean up the old config rom memory and DMA @@ -2263,13 +2287,10 @@ static int ohci_set_config_rom(struct fw_card *card, * controller could need to access it before the bus reset * takes effect. */ - if (ret == 0) - fw_schedule_bus_reset(&ohci->card, true, true); - else - dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, - next_config_rom, next_config_rom_bus); - return ret; + fw_schedule_bus_reset(&ohci->card, true, true); + + return 0; } static void ohci_send_request(struct fw_card *card, struct fw_packet *packet) @@ -3101,6 +3122,15 @@ static int ohci_queue_iso(struct fw_iso_context *base, return ret; } +static void ohci_flush_queue_iso(struct fw_iso_context *base) +{ + struct context *ctx = + &container_of(base, struct iso_context, base)->context; + + reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); + flush_writes(ctx->ohci); +} + static const struct fw_card_driver ohci_driver = { .enable = ohci_enable, .read_phy_reg = ohci_read_phy_reg, @@ -3117,6 +3147,7 @@ static const struct fw_card_driver ohci_driver = { .free_iso_context = ohci_free_iso_context, .set_iso_channels = ohci_set_iso_channels, .queue_iso = ohci_queue_iso, + .flush_queue_iso = ohci_flush_queue_iso, .start_iso = ohci_start_iso, .stop_iso = ohci_stop_iso, }; diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 77ed589b360d..41841a3e3f99 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -125,9 +125,6 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0" ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE) ", or a combination)"); -/* I don't know why the SCSI stack doesn't define something like this... */ -typedef void (*scsi_done_fn_t)(struct scsi_cmnd *); - static const char sbp2_driver_name[] = "sbp2"; /* @@ -261,7 +258,6 @@ struct sbp2_orb { struct kref kref; dma_addr_t request_bus; int rcode; - struct sbp2_pointer pointer; void (*callback)(struct sbp2_orb * orb, struct sbp2_status * status); struct list_head link; }; @@ -314,7 +310,6 @@ struct sbp2_command_orb { u8 command_block[SBP2_MAX_CDB_SIZE]; } request; struct scsi_cmnd *cmd; - scsi_done_fn_t done; struct sbp2_logical_unit *lu; struct sbp2_pointer page_table[SG_ALL] __attribute__((aligned(8))); @@ -494,10 +489,11 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, int node_id, int generation, u64 offset) { struct fw_device *device = target_device(lu->tgt); + struct sbp2_pointer orb_pointer; unsigned long flags; - orb->pointer.high = 0; - orb->pointer.low = cpu_to_be32(orb->request_bus); + orb_pointer.high = 0; + orb_pointer.low = cpu_to_be32(orb->request_bus); spin_lock_irqsave(&device->card->lock, flags); list_add_tail(&orb->link, &lu->orb_list); @@ -508,7 +504,7 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, node_id, generation, device->max_speed, offset, - &orb->pointer, 8, complete_transaction, orb); + &orb_pointer, 8, complete_transaction, orb); } static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu) @@ -830,8 +826,6 @@ static void sbp2_target_put(struct sbp2_target *tgt) kref_put(&tgt->kref, sbp2_release_target); } -static struct workqueue_struct *sbp2_wq; - /* * Always get the target's kref when scheduling work on one its units. * Each workqueue job is responsible to call sbp2_target_put() upon return. @@ -839,7 +833,7 @@ static struct workqueue_struct *sbp2_wq; static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) { sbp2_target_get(lu->tgt); - if (!queue_delayed_work(sbp2_wq, &lu->work, delay)) + if (!queue_delayed_work(fw_workqueue, &lu->work, delay)) sbp2_target_put(lu->tgt); } @@ -1398,7 +1392,7 @@ static void complete_command_orb(struct sbp2_orb *base_orb, sbp2_unmap_scatterlist(device->card->device, orb); orb->cmd->result = result; - orb->done(orb->cmd); + orb->cmd->scsi_done(orb->cmd); } static int sbp2_map_scatterlist(struct sbp2_command_orb *orb, @@ -1463,7 +1457,8 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb, /* SCSI stack integration */ -static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done) +static int sbp2_scsi_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmd) { struct sbp2_logical_unit *lu = cmd->device->hostdata; struct fw_device *device = target_device(lu->tgt); @@ -1477,7 +1472,7 @@ static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done if (cmd->sc_data_direction == DMA_BIDIRECTIONAL) { fw_error("Can't handle DMA_BIDIRECTIONAL, rejecting command\n"); cmd->result = DID_ERROR << 16; - done(cmd); + cmd->scsi_done(cmd); return 0; } @@ -1490,11 +1485,8 @@ static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done /* Initialize rcode to something not RCODE_COMPLETE. */ orb->base.rcode = -1; kref_init(&orb->base.kref); - - orb->lu = lu; - orb->done = done; - orb->cmd = cmd; - + orb->lu = lu; + orb->cmd = cmd; orb->request.next.high = cpu_to_be32(SBP2_ORB_NULL); orb->request.misc = cpu_to_be32( COMMAND_ORB_MAX_PAYLOAD(lu->tgt->max_payload) | @@ -1529,8 +1521,6 @@ static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done return retval; } -static DEF_SCSI_QCMD(sbp2_scsi_queuecommand) - static int sbp2_scsi_slave_alloc(struct scsi_device *sdev) { struct sbp2_logical_unit *lu = sdev->hostdata; @@ -1653,17 +1643,12 @@ MODULE_ALIAS("sbp2"); static int __init sbp2_init(void) { - sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME); - if (!sbp2_wq) - return -ENOMEM; - return driver_register(&sbp2_driver.driver); } static void __exit sbp2_cleanup(void) { driver_unregister(&sbp2_driver.driver); - destroy_workqueue(sbp2_wq); } module_init(sbp2_init); diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index b3a25a55ba23..efba163595db 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -157,4 +157,6 @@ config SIGMA If unsure, say N here. Drivers that need these helpers will select this option automatically. +source "drivers/firmware/google/Kconfig" + endmenu diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 00bb0b80a79f..47338c979126 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -13,3 +13,5 @@ obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o obj-$(CONFIG_SIGMA) += sigma.o + +obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 96c25d93eed1..f1b7f659d3c9 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -531,8 +531,8 @@ static int edd_has_edd30(struct edd_device *edev) { struct edd_info *info; - int i, nonzero_path = 0; - char c; + int i; + u8 csum = 0; if (!edev) return 0; @@ -544,16 +544,16 @@ edd_has_edd30(struct edd_device *edev) return 0; } - for (i = 30; i <= 73; i++) { - c = *(((uint8_t *) info) + i + 4); - if (c) { - nonzero_path++; - break; - } - } - if (!nonzero_path) { + + /* We support only T13 spec */ + if (info->params.device_path_info_length != 44) + return 0; + + for (i = 30; i < info->params.device_path_info_length + 30; i++) + csum += *(((u8 *)&info->params) + i); + + if (csum) return 0; - } return 1; } diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index ff0c373e3bbf..a2d2f1f0d4f3 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -677,8 +677,8 @@ create_efivars_bin_attributes(struct efivars *efivars) return 0; out_free: - kfree(efivars->new_var); - efivars->new_var = NULL; + kfree(efivars->del_var); + efivars->del_var = NULL; kfree(efivars->new_var); efivars->new_var = NULL; return error; @@ -803,6 +803,8 @@ efivars_init(void) ops.set_variable = efi.set_variable; ops.get_next_variable = efi.get_next_variable; error = register_efivars(&__efivars, &ops, efi_kobj); + if (error) + goto err_put; /* Don't forget the systab entry */ error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); @@ -810,18 +812,25 @@ efivars_init(void) printk(KERN_ERR "efivars: Sysfs attribute export failed with error %d.\n", error); - unregister_efivars(&__efivars); - kobject_put(efi_kobj); + goto err_unregister; } + return 0; + +err_unregister: + unregister_efivars(&__efivars); +err_put: + kobject_put(efi_kobj); return error; } static void __exit efivars_exit(void) { - unregister_efivars(&__efivars); - kobject_put(efi_kobj); + if (efi_enabled) { + unregister_efivars(&__efivars); + kobject_put(efi_kobj); + } } module_init(efivars_init); diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig new file mode 100644 index 000000000000..87096b6ca5c9 --- /dev/null +++ b/drivers/firmware/google/Kconfig @@ -0,0 +1,31 @@ +config GOOGLE_FIRMWARE + bool "Google Firmware Drivers" + depends on X86 + default n + help + These firmware drivers are used by Google's servers. They are + only useful if you are working directly on one of their + proprietary servers. If in doubt, say "N". + +menu "Google Firmware Drivers" + depends on GOOGLE_FIRMWARE + +config GOOGLE_SMI + tristate "SMI interface for Google platforms" + depends on ACPI && DMI + select EFI_VARS + help + Say Y here if you want to enable SMI callbacks for Google + platforms. This provides an interface for writing to and + clearing the EFI event log and reading and writing NVRAM + variables. + +config GOOGLE_MEMCONSOLE + tristate "Firmware Memory Console" + depends on DMI + help + This option enables the kernel to search for a firmware log in + the EBDA on Google servers. If found, this log is exported to + userland in the file /sys/firmware/log. + +endmenu diff --git a/drivers/firmware/google/Makefile b/drivers/firmware/google/Makefile new file mode 100644 index 000000000000..54a294e3cb61 --- /dev/null +++ b/drivers/firmware/google/Makefile @@ -0,0 +1,3 @@ + +obj-$(CONFIG_GOOGLE_SMI) += gsmi.o +obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c new file mode 100644 index 000000000000..fa7f0b3e81dd --- /dev/null +++ b/drivers/firmware/google/gsmi.c @@ -0,0 +1,940 @@ +/* + * Copyright 2010 Google Inc. All Rights Reserved. + * Author: dlaurie@google.com (Duncan Laurie) + * + * Re-worked to expose sysfs APIs by mikew@google.com (Mike Waychison) + * + * EFI SMI interface for Google platforms + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GSMI_SHUTDOWN_CLEAN 0 /* Clean Shutdown */ +/* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */ +#define GSMI_SHUTDOWN_NMIWDT 1 /* NMI Watchdog */ +#define GSMI_SHUTDOWN_PANIC 2 /* Panic */ +#define GSMI_SHUTDOWN_OOPS 3 /* Oops */ +#define GSMI_SHUTDOWN_DIE 4 /* Die -- No longer meaningful */ +#define GSMI_SHUTDOWN_MCE 5 /* Machine Check */ +#define GSMI_SHUTDOWN_SOFTWDT 6 /* Software Watchdog */ +#define GSMI_SHUTDOWN_MBE 7 /* Uncorrected ECC */ +#define GSMI_SHUTDOWN_TRIPLE 8 /* Triple Fault */ + +#define DRIVER_VERSION "1.0" +#define GSMI_GUID_SIZE 16 +#define GSMI_BUF_SIZE 1024 +#define GSMI_BUF_ALIGN sizeof(u64) +#define GSMI_CALLBACK 0xef + +/* SMI return codes */ +#define GSMI_SUCCESS 0x00 +#define GSMI_UNSUPPORTED2 0x03 +#define GSMI_LOG_FULL 0x0b +#define GSMI_VAR_NOT_FOUND 0x0e +#define GSMI_HANDSHAKE_SPIN 0x7d +#define GSMI_HANDSHAKE_CF 0x7e +#define GSMI_HANDSHAKE_NONE 0x7f +#define GSMI_INVALID_PARAMETER 0x82 +#define GSMI_UNSUPPORTED 0x83 +#define GSMI_BUFFER_TOO_SMALL 0x85 +#define GSMI_NOT_READY 0x86 +#define GSMI_DEVICE_ERROR 0x87 +#define GSMI_NOT_FOUND 0x8e + +#define QUIRKY_BOARD_HASH 0x78a30a50 + +/* Internally used commands passed to the firmware */ +#define GSMI_CMD_GET_NVRAM_VAR 0x01 +#define GSMI_CMD_GET_NEXT_VAR 0x02 +#define GSMI_CMD_SET_NVRAM_VAR 0x03 +#define GSMI_CMD_SET_EVENT_LOG 0x08 +#define GSMI_CMD_CLEAR_EVENT_LOG 0x09 +#define GSMI_CMD_CLEAR_CONFIG 0x20 +#define GSMI_CMD_HANDSHAKE_TYPE 0xC1 + +/* Magic entry type for kernel events */ +#define GSMI_LOG_ENTRY_TYPE_KERNEL 0xDEAD + +/* SMI buffers must be in 32bit physical address space */ +struct gsmi_buf { + u8 *start; /* start of buffer */ + size_t length; /* length of buffer */ + dma_addr_t handle; /* dma allocation handle */ + u32 address; /* physical address of buffer */ +}; + +struct gsmi_device { + struct platform_device *pdev; /* platform device */ + struct gsmi_buf *name_buf; /* variable name buffer */ + struct gsmi_buf *data_buf; /* generic data buffer */ + struct gsmi_buf *param_buf; /* parameter buffer */ + spinlock_t lock; /* serialize access to SMIs */ + u16 smi_cmd; /* SMI command port */ + int handshake_type; /* firmware handler interlock type */ + struct dma_pool *dma_pool; /* DMA buffer pool */ +} gsmi_dev; + +/* Packed structures for communicating with the firmware */ +struct gsmi_nvram_var_param { + efi_guid_t guid; + u32 name_ptr; + u32 attributes; + u32 data_len; + u32 data_ptr; +} __packed; + +struct gsmi_get_next_var_param { + u8 guid[GSMI_GUID_SIZE]; + u32 name_ptr; + u32 name_len; +} __packed; + +struct gsmi_set_eventlog_param { + u32 data_ptr; + u32 data_len; + u32 type; +} __packed; + +/* Event log formats */ +struct gsmi_log_entry_type_1 { + u16 type; + u32 instance; +} __packed; + + +/* + * Some platforms don't have explicit SMI handshake + * and need to wait for SMI to complete. + */ +#define GSMI_DEFAULT_SPINCOUNT 0x10000 +static unsigned int spincount = GSMI_DEFAULT_SPINCOUNT; +module_param(spincount, uint, 0600); +MODULE_PARM_DESC(spincount, + "The number of loop iterations to use when using the spin handshake."); + +static struct gsmi_buf *gsmi_buf_alloc(void) +{ + struct gsmi_buf *smibuf; + + smibuf = kzalloc(sizeof(*smibuf), GFP_KERNEL); + if (!smibuf) { + printk(KERN_ERR "gsmi: out of memory\n"); + return NULL; + } + + /* allocate buffer in 32bit address space */ + smibuf->start = dma_pool_alloc(gsmi_dev.dma_pool, GFP_KERNEL, + &smibuf->handle); + if (!smibuf->start) { + printk(KERN_ERR "gsmi: failed to allocate name buffer\n"); + kfree(smibuf); + return NULL; + } + + /* fill in the buffer handle */ + smibuf->length = GSMI_BUF_SIZE; + smibuf->address = (u32)virt_to_phys(smibuf->start); + + return smibuf; +} + +static void gsmi_buf_free(struct gsmi_buf *smibuf) +{ + if (smibuf) { + if (smibuf->start) + dma_pool_free(gsmi_dev.dma_pool, smibuf->start, + smibuf->handle); + kfree(smibuf); + } +} + +/* + * Make a call to gsmi func(sub). GSMI error codes are translated to + * in-kernel errnos (0 on success, -ERRNO on error). + */ +static int gsmi_exec(u8 func, u8 sub) +{ + u16 cmd = (sub << 8) | func; + u16 result = 0; + int rc = 0; + + /* + * AH : Subfunction number + * AL : Function number + * EBX : Parameter block address + * DX : SMI command port + * + * Three protocols here. See also the comment in gsmi_init(). + */ + if (gsmi_dev.handshake_type == GSMI_HANDSHAKE_CF) { + /* + * If handshake_type == HANDSHAKE_CF then set CF on the + * way in and wait for the handler to clear it; this avoids + * corrupting register state on those chipsets which have + * a delay between writing the SMI trigger register and + * entering SMM. + */ + asm volatile ( + "stc\n" + "outb %%al, %%dx\n" + "1: jc 1b\n" + : "=a" (result) + : "0" (cmd), + "d" (gsmi_dev.smi_cmd), + "b" (gsmi_dev.param_buf->address) + : "memory", "cc" + ); + } else if (gsmi_dev.handshake_type == GSMI_HANDSHAKE_SPIN) { + /* + * If handshake_type == HANDSHAKE_SPIN we spin a + * hundred-ish usecs to ensure the SMI has triggered. + */ + asm volatile ( + "outb %%al, %%dx\n" + "1: loop 1b\n" + : "=a" (result) + : "0" (cmd), + "d" (gsmi_dev.smi_cmd), + "b" (gsmi_dev.param_buf->address), + "c" (spincount) + : "memory", "cc" + ); + } else { + /* + * If handshake_type == HANDSHAKE_NONE we do nothing; + * either we don't need to or it's legacy firmware that + * doesn't understand the CF protocol. + */ + asm volatile ( + "outb %%al, %%dx\n\t" + : "=a" (result) + : "0" (cmd), + "d" (gsmi_dev.smi_cmd), + "b" (gsmi_dev.param_buf->address) + : "memory", "cc" + ); + } + + /* check return code from SMI handler */ + switch (result) { + case GSMI_SUCCESS: + break; + case GSMI_VAR_NOT_FOUND: + /* not really an error, but let the caller know */ + rc = 1; + break; + case GSMI_INVALID_PARAMETER: + printk(KERN_ERR "gsmi: exec 0x%04x: Invalid parameter\n", cmd); + rc = -EINVAL; + break; + case GSMI_BUFFER_TOO_SMALL: + printk(KERN_ERR "gsmi: exec 0x%04x: Buffer too small\n", cmd); + rc = -ENOMEM; + break; + case GSMI_UNSUPPORTED: + case GSMI_UNSUPPORTED2: + if (sub != GSMI_CMD_HANDSHAKE_TYPE) + printk(KERN_ERR "gsmi: exec 0x%04x: Not supported\n", + cmd); + rc = -ENOSYS; + break; + case GSMI_NOT_READY: + printk(KERN_ERR "gsmi: exec 0x%04x: Not ready\n", cmd); + rc = -EBUSY; + break; + case GSMI_DEVICE_ERROR: + printk(KERN_ERR "gsmi: exec 0x%04x: Device error\n", cmd); + rc = -EFAULT; + break; + case GSMI_NOT_FOUND: + printk(KERN_ERR "gsmi: exec 0x%04x: Data not found\n", cmd); + rc = -ENOENT; + break; + case GSMI_LOG_FULL: + printk(KERN_ERR "gsmi: exec 0x%04x: Log full\n", cmd); + rc = -ENOSPC; + break; + case GSMI_HANDSHAKE_CF: + case GSMI_HANDSHAKE_SPIN: + case GSMI_HANDSHAKE_NONE: + rc = result; + break; + default: + printk(KERN_ERR "gsmi: exec 0x%04x: Unknown error 0x%04x\n", + cmd, result); + rc = -ENXIO; + } + + return rc; +} + +/* Return the number of unicode characters in data */ +static size_t +utf16_strlen(efi_char16_t *data, unsigned long maxlength) +{ + unsigned long length = 0; + + while (*data++ != 0 && length < maxlength) + length++; + return length; +} + +static efi_status_t gsmi_get_variable(efi_char16_t *name, + efi_guid_t *vendor, u32 *attr, + unsigned long *data_size, + void *data) +{ + struct gsmi_nvram_var_param param = { + .name_ptr = gsmi_dev.name_buf->address, + .data_ptr = gsmi_dev.data_buf->address, + .data_len = (u32)*data_size, + }; + efi_status_t ret = EFI_SUCCESS; + unsigned long flags; + size_t name_len = utf16_strlen(name, GSMI_BUF_SIZE / 2); + int rc; + + if (name_len >= GSMI_BUF_SIZE / 2) + return EFI_BAD_BUFFER_SIZE; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + /* Vendor guid */ + memcpy(¶m.guid, vendor, sizeof(param.guid)); + + /* variable name, already in UTF-16 */ + memset(gsmi_dev.name_buf->start, 0, gsmi_dev.name_buf->length); + memcpy(gsmi_dev.name_buf->start, name, name_len * 2); + + /* data pointer */ + memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length); + + /* parameter buffer */ + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + memcpy(gsmi_dev.param_buf->start, ¶m, sizeof(param)); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_GET_NVRAM_VAR); + if (rc < 0) { + printk(KERN_ERR "gsmi: Get Variable failed\n"); + ret = EFI_LOAD_ERROR; + } else if (rc == 1) { + /* variable was not found */ + ret = EFI_NOT_FOUND; + } else { + /* Get the arguments back */ + memcpy(¶m, gsmi_dev.param_buf->start, sizeof(param)); + + /* The size reported is the min of all of our buffers */ + *data_size = min(*data_size, gsmi_dev.data_buf->length); + *data_size = min_t(unsigned long, *data_size, param.data_len); + + /* Copy data back to return buffer. */ + memcpy(data, gsmi_dev.data_buf->start, *data_size); + + /* All variables are have the following attributes */ + *attr = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; + } + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + return ret; +} + +static efi_status_t gsmi_get_next_variable(unsigned long *name_size, + efi_char16_t *name, + efi_guid_t *vendor) +{ + struct gsmi_get_next_var_param param = { + .name_ptr = gsmi_dev.name_buf->address, + .name_len = gsmi_dev.name_buf->length, + }; + efi_status_t ret = EFI_SUCCESS; + int rc; + unsigned long flags; + + /* For the moment, only support buffers that exactly match in size */ + if (*name_size != GSMI_BUF_SIZE) + return EFI_BAD_BUFFER_SIZE; + + /* Let's make sure the thing is at least null-terminated */ + if (utf16_strlen(name, GSMI_BUF_SIZE / 2) == GSMI_BUF_SIZE / 2) + return EFI_INVALID_PARAMETER; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + /* guid */ + memcpy(¶m.guid, vendor, sizeof(param.guid)); + + /* variable name, already in UTF-16 */ + memcpy(gsmi_dev.name_buf->start, name, *name_size); + + /* parameter buffer */ + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + memcpy(gsmi_dev.param_buf->start, ¶m, sizeof(param)); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_GET_NEXT_VAR); + if (rc < 0) { + printk(KERN_ERR "gsmi: Get Next Variable Name failed\n"); + ret = EFI_LOAD_ERROR; + } else if (rc == 1) { + /* variable not found -- end of list */ + ret = EFI_NOT_FOUND; + } else { + /* copy variable data back to return buffer */ + memcpy(¶m, gsmi_dev.param_buf->start, sizeof(param)); + + /* Copy the name back */ + memcpy(name, gsmi_dev.name_buf->start, GSMI_BUF_SIZE); + *name_size = utf16_strlen(name, GSMI_BUF_SIZE / 2) * 2; + + /* copy guid to return buffer */ + memcpy(vendor, ¶m.guid, sizeof(param.guid)); + ret = EFI_SUCCESS; + } + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + return ret; +} + +static efi_status_t gsmi_set_variable(efi_char16_t *name, + efi_guid_t *vendor, + unsigned long attr, + unsigned long data_size, + void *data) +{ + struct gsmi_nvram_var_param param = { + .name_ptr = gsmi_dev.name_buf->address, + .data_ptr = gsmi_dev.data_buf->address, + .data_len = (u32)data_size, + .attributes = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + }; + size_t name_len = utf16_strlen(name, GSMI_BUF_SIZE / 2); + efi_status_t ret = EFI_SUCCESS; + int rc; + unsigned long flags; + + if (name_len >= GSMI_BUF_SIZE / 2) + return EFI_BAD_BUFFER_SIZE; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + /* guid */ + memcpy(¶m.guid, vendor, sizeof(param.guid)); + + /* variable name, already in UTF-16 */ + memset(gsmi_dev.name_buf->start, 0, gsmi_dev.name_buf->length); + memcpy(gsmi_dev.name_buf->start, name, name_len * 2); + + /* data pointer */ + memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length); + memcpy(gsmi_dev.data_buf->start, data, data_size); + + /* parameter buffer */ + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + memcpy(gsmi_dev.param_buf->start, ¶m, sizeof(param)); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_SET_NVRAM_VAR); + if (rc < 0) { + printk(KERN_ERR "gsmi: Set Variable failed\n"); + ret = EFI_INVALID_PARAMETER; + } + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + return ret; +} + +static const struct efivar_operations efivar_ops = { + .get_variable = gsmi_get_variable, + .set_variable = gsmi_set_variable, + .get_next_variable = gsmi_get_next_variable, +}; + +static ssize_t eventlog_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t count) +{ + struct gsmi_set_eventlog_param param = { + .data_ptr = gsmi_dev.data_buf->address, + }; + int rc = 0; + unsigned long flags; + + /* Pull the type out */ + if (count < sizeof(u32)) + return -EINVAL; + param.type = *(u32 *)buf; + count -= sizeof(u32); + buf += sizeof(u32); + + /* The remaining buffer is the data payload */ + if (count > gsmi_dev.data_buf->length) + return -EINVAL; + param.data_len = count - sizeof(u32); + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + /* data pointer */ + memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length); + memcpy(gsmi_dev.data_buf->start, buf, param.data_len); + + /* parameter buffer */ + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + memcpy(gsmi_dev.param_buf->start, ¶m, sizeof(param)); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_SET_EVENT_LOG); + if (rc < 0) + printk(KERN_ERR "gsmi: Set Event Log failed\n"); + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + return rc; + +} + +static struct bin_attribute eventlog_bin_attr = { + .attr = {.name = "append_to_eventlog", .mode = 0200}, + .write = eventlog_write, +}; + +static ssize_t gsmi_clear_eventlog_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int rc; + unsigned long flags; + unsigned long val; + struct { + u32 percentage; + u32 data_type; + } param; + + rc = strict_strtoul(buf, 0, &val); + if (rc) + return rc; + + /* + * Value entered is a percentage, 0 through 100, anything else + * is invalid. + */ + if (val > 100) + return -EINVAL; + + /* data_type here selects the smbios event log. */ + param.percentage = val; + param.data_type = 0; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + /* parameter buffer */ + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + memcpy(gsmi_dev.param_buf->start, ¶m, sizeof(param)); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_CLEAR_EVENT_LOG); + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + if (rc) + return rc; + return count; +} + +static struct kobj_attribute gsmi_clear_eventlog_attr = { + .attr = {.name = "clear_eventlog", .mode = 0200}, + .store = gsmi_clear_eventlog_store, +}; + +static ssize_t gsmi_clear_config_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + /* clear parameter buffer */ + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_CLEAR_CONFIG); + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + if (rc) + return rc; + return count; +} + +static struct kobj_attribute gsmi_clear_config_attr = { + .attr = {.name = "clear_config", .mode = 0200}, + .store = gsmi_clear_config_store, +}; + +static const struct attribute *gsmi_attrs[] = { + &gsmi_clear_config_attr.attr, + &gsmi_clear_eventlog_attr.attr, + NULL, +}; + +static int gsmi_shutdown_reason(int reason) +{ + struct gsmi_log_entry_type_1 entry = { + .type = GSMI_LOG_ENTRY_TYPE_KERNEL, + .instance = reason, + }; + struct gsmi_set_eventlog_param param = { + .data_len = sizeof(entry), + .type = 1, + }; + static int saved_reason; + int rc = 0; + unsigned long flags; + + /* avoid duplicate entries in the log */ + if (saved_reason & (1 << reason)) + return 0; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + saved_reason |= (1 << reason); + + /* data pointer */ + memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length); + memcpy(gsmi_dev.data_buf->start, &entry, sizeof(entry)); + + /* parameter buffer */ + param.data_ptr = gsmi_dev.data_buf->address; + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + memcpy(gsmi_dev.param_buf->start, ¶m, sizeof(param)); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_SET_EVENT_LOG); + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + if (rc < 0) + printk(KERN_ERR "gsmi: Log Shutdown Reason failed\n"); + else + printk(KERN_EMERG "gsmi: Log Shutdown Reason 0x%02x\n", + reason); + + return rc; +} + +static int gsmi_reboot_callback(struct notifier_block *nb, + unsigned long reason, void *arg) +{ + gsmi_shutdown_reason(GSMI_SHUTDOWN_CLEAN); + return NOTIFY_DONE; +} + +static struct notifier_block gsmi_reboot_notifier = { + .notifier_call = gsmi_reboot_callback +}; + +static int gsmi_die_callback(struct notifier_block *nb, + unsigned long reason, void *arg) +{ + if (reason == DIE_OOPS) + gsmi_shutdown_reason(GSMI_SHUTDOWN_OOPS); + return NOTIFY_DONE; +} + +static struct notifier_block gsmi_die_notifier = { + .notifier_call = gsmi_die_callback +}; + +static int gsmi_panic_callback(struct notifier_block *nb, + unsigned long reason, void *arg) +{ + gsmi_shutdown_reason(GSMI_SHUTDOWN_PANIC); + return NOTIFY_DONE; +} + +static struct notifier_block gsmi_panic_notifier = { + .notifier_call = gsmi_panic_callback, +}; + +/* + * This hash function was blatantly copied from include/linux/hash.h. + * It is used by this driver to obfuscate a board name that requires a + * quirk within this driver. + * + * Please do not remove this copy of the function as any changes to the + * global utility hash_64() function would break this driver's ability + * to identify a board and provide the appropriate quirk -- mikew@google.com + */ +static u64 __init local_hash_64(u64 val, unsigned bits) +{ + u64 hash = val; + + /* Sigh, gcc can't optimise this alone like it does for 32 bits. */ + u64 n = hash; + n <<= 18; + hash -= n; + n <<= 33; + hash -= n; + n <<= 3; + hash += n; + n <<= 3; + hash -= n; + n <<= 4; + hash += n; + n <<= 2; + hash += n; + + /* High bits are more random, so use them. */ + return hash >> (64 - bits); +} + +static u32 __init hash_oem_table_id(char s[8]) +{ + u64 input; + memcpy(&input, s, 8); + return local_hash_64(input, 32); +} + +static struct dmi_system_id gsmi_dmi_table[] __initdata = { + { + .ident = "Google Board", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."), + }, + }, + {} +}; +MODULE_DEVICE_TABLE(dmi, gsmi_dmi_table); + +static __init int gsmi_system_valid(void) +{ + u32 hash; + + if (!dmi_check_system(gsmi_dmi_table)) + return -ENODEV; + + /* + * Only newer firmware supports the gsmi interface. All older + * firmware that didn't support this interface used to plug the + * table name in the first four bytes of the oem_table_id field. + * Newer firmware doesn't do that though, so use that as the + * discriminant factor. We have to do this in order to + * whitewash our board names out of the public driver. + */ + if (!strncmp(acpi_gbl_FADT.header.oem_table_id, "FACP", 4)) { + printk(KERN_INFO "gsmi: Board is too old\n"); + return -ENODEV; + } + + /* Disable on board with 1.0 BIOS due to Google bug 2602657 */ + hash = hash_oem_table_id(acpi_gbl_FADT.header.oem_table_id); + if (hash == QUIRKY_BOARD_HASH) { + const char *bios_ver = dmi_get_system_info(DMI_BIOS_VERSION); + if (strncmp(bios_ver, "1.0", 3) == 0) { + pr_info("gsmi: disabled on this board's BIOS %s\n", + bios_ver); + return -ENODEV; + } + } + + /* check for valid SMI command port in ACPI FADT */ + if (acpi_gbl_FADT.smi_command == 0) { + pr_info("gsmi: missing smi_command\n"); + return -ENODEV; + } + + /* Found */ + return 0; +} + +static struct kobject *gsmi_kobj; +static struct efivars efivars; + +static __init int gsmi_init(void) +{ + unsigned long flags; + int ret; + + ret = gsmi_system_valid(); + if (ret) + return ret; + + gsmi_dev.smi_cmd = acpi_gbl_FADT.smi_command; + + /* register device */ + gsmi_dev.pdev = platform_device_register_simple("gsmi", -1, NULL, 0); + if (IS_ERR(gsmi_dev.pdev)) { + printk(KERN_ERR "gsmi: unable to register platform device\n"); + return PTR_ERR(gsmi_dev.pdev); + } + + /* SMI access needs to be serialized */ + spin_lock_init(&gsmi_dev.lock); + + /* SMI callbacks require 32bit addresses */ + gsmi_dev.pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + gsmi_dev.pdev->dev.dma_mask = + &gsmi_dev.pdev->dev.coherent_dma_mask; + ret = -ENOMEM; + gsmi_dev.dma_pool = dma_pool_create("gsmi", &gsmi_dev.pdev->dev, + GSMI_BUF_SIZE, GSMI_BUF_ALIGN, 0); + if (!gsmi_dev.dma_pool) + goto out_err; + + /* + * pre-allocate buffers because sometimes we are called when + * this is not feasible: oops, panic, die, mce, etc + */ + gsmi_dev.name_buf = gsmi_buf_alloc(); + if (!gsmi_dev.name_buf) { + printk(KERN_ERR "gsmi: failed to allocate name buffer\n"); + goto out_err; + } + + gsmi_dev.data_buf = gsmi_buf_alloc(); + if (!gsmi_dev.data_buf) { + printk(KERN_ERR "gsmi: failed to allocate data buffer\n"); + goto out_err; + } + + gsmi_dev.param_buf = gsmi_buf_alloc(); + if (!gsmi_dev.param_buf) { + printk(KERN_ERR "gsmi: failed to allocate param buffer\n"); + goto out_err; + } + + /* + * Determine type of handshake used to serialize the SMI + * entry. See also gsmi_exec(). + * + * There's a "behavior" present on some chipsets where writing the + * SMI trigger register in the southbridge doesn't result in an + * immediate SMI. Rather, the processor can execute "a few" more + * instructions before the SMI takes effect. To ensure synchronous + * behavior, implement a handshake between the kernel driver and the + * firmware handler to spin until released. This ioctl determines + * the type of handshake. + * + * NONE: The firmware handler does not implement any + * handshake. Either it doesn't need to, or it's legacy firmware + * that doesn't know it needs to and never will. + * + * CF: The firmware handler will clear the CF in the saved + * state before returning. The driver may set the CF and test for + * it to clear before proceeding. + * + * SPIN: The firmware handler does not implement any handshake + * but the driver should spin for a hundred or so microseconds + * to ensure the SMI has triggered. + * + * Finally, the handler will return -ENOSYS if + * GSMI_CMD_HANDSHAKE_TYPE is unimplemented, which implies + * HANDSHAKE_NONE. + */ + spin_lock_irqsave(&gsmi_dev.lock, flags); + gsmi_dev.handshake_type = GSMI_HANDSHAKE_SPIN; + gsmi_dev.handshake_type = + gsmi_exec(GSMI_CALLBACK, GSMI_CMD_HANDSHAKE_TYPE); + if (gsmi_dev.handshake_type == -ENOSYS) + gsmi_dev.handshake_type = GSMI_HANDSHAKE_NONE; + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + /* Remove and clean up gsmi if the handshake could not complete. */ + if (gsmi_dev.handshake_type == -ENXIO) { + printk(KERN_INFO "gsmi version " DRIVER_VERSION + " failed to load\n"); + ret = -ENODEV; + goto out_err; + } + + printk(KERN_INFO "gsmi version " DRIVER_VERSION " loaded\n"); + + /* Register in the firmware directory */ + ret = -ENOMEM; + gsmi_kobj = kobject_create_and_add("gsmi", firmware_kobj); + if (!gsmi_kobj) { + printk(KERN_INFO "gsmi: Failed to create firmware kobj\n"); + goto out_err; + } + + /* Setup eventlog access */ + ret = sysfs_create_bin_file(gsmi_kobj, &eventlog_bin_attr); + if (ret) { + printk(KERN_INFO "gsmi: Failed to setup eventlog"); + goto out_err; + } + + /* Other attributes */ + ret = sysfs_create_files(gsmi_kobj, gsmi_attrs); + if (ret) { + printk(KERN_INFO "gsmi: Failed to add attrs"); + goto out_err; + } + + if (register_efivars(&efivars, &efivar_ops, gsmi_kobj)) { + printk(KERN_INFO "gsmi: Failed to register efivars\n"); + goto out_err; + } + + register_reboot_notifier(&gsmi_reboot_notifier); + register_die_notifier(&gsmi_die_notifier); + atomic_notifier_chain_register(&panic_notifier_list, + &gsmi_panic_notifier); + + return 0; + + out_err: + kobject_put(gsmi_kobj); + gsmi_buf_free(gsmi_dev.param_buf); + gsmi_buf_free(gsmi_dev.data_buf); + gsmi_buf_free(gsmi_dev.name_buf); + if (gsmi_dev.dma_pool) + dma_pool_destroy(gsmi_dev.dma_pool); + platform_device_unregister(gsmi_dev.pdev); + pr_info("gsmi: failed to load: %d\n", ret); + return ret; +} + +static void __exit gsmi_exit(void) +{ + unregister_reboot_notifier(&gsmi_reboot_notifier); + unregister_die_notifier(&gsmi_die_notifier); + atomic_notifier_chain_unregister(&panic_notifier_list, + &gsmi_panic_notifier); + unregister_efivars(&efivars); + + kobject_put(gsmi_kobj); + gsmi_buf_free(gsmi_dev.param_buf); + gsmi_buf_free(gsmi_dev.data_buf); + gsmi_buf_free(gsmi_dev.name_buf); + dma_pool_destroy(gsmi_dev.dma_pool); + platform_device_unregister(gsmi_dev.pdev); +} + +module_init(gsmi_init); +module_exit(gsmi_exit); + +MODULE_AUTHOR("Google, Inc."); +MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/google/memconsole.c b/drivers/firmware/google/memconsole.c new file mode 100644 index 000000000000..2a90ba613613 --- /dev/null +++ b/drivers/firmware/google/memconsole.c @@ -0,0 +1,166 @@ +/* + * memconsole.c + * + * Infrastructure for importing the BIOS memory based console + * into the kernel log ringbuffer. + * + * Copyright 2010 Google Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE +#define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24)) + +struct biosmemcon_ebda { + u32 signature; + union { + struct { + u8 enabled; + u32 buffer_addr; + u16 start; + u16 end; + u16 num_chars; + u8 wrapped; + } __packed v1; + struct { + u32 buffer_addr; + /* Misdocumented as number of pages! */ + u16 num_bytes; + u16 start; + u16 end; + } __packed v2; + }; +} __packed; + +static char *memconsole_baseaddr; +static size_t memconsole_length; + +static ssize_t memconsole_read(struct file *filp, struct kobject *kobp, + struct bin_attribute *bin_attr, char *buf, + loff_t pos, size_t count) +{ + return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr, + memconsole_length); +} + +static struct bin_attribute memconsole_bin_attr = { + .attr = {.name = "log", .mode = 0444}, + .read = memconsole_read, +}; + + +static void found_v1_header(struct biosmemcon_ebda *hdr) +{ + printk(KERN_INFO "BIOS console v1 EBDA structure found at %p\n", hdr); + printk(KERN_INFO "BIOS console buffer at 0x%.8x, " + "start = %d, end = %d, num = %d\n", + hdr->v1.buffer_addr, hdr->v1.start, + hdr->v1.end, hdr->v1.num_chars); + + memconsole_length = hdr->v1.num_chars; + memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr); +} + +static void found_v2_header(struct biosmemcon_ebda *hdr) +{ + printk(KERN_INFO "BIOS console v2 EBDA structure found at %p\n", hdr); + printk(KERN_INFO "BIOS console buffer at 0x%.8x, " + "start = %d, end = %d, num_bytes = %d\n", + hdr->v2.buffer_addr, hdr->v2.start, + hdr->v2.end, hdr->v2.num_bytes); + + memconsole_length = hdr->v2.end - hdr->v2.start; + memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr + + hdr->v2.start); +} + +/* + * Search through the EBDA for the BIOS Memory Console, and + * set the global variables to point to it. Return true if found. + */ +static bool found_memconsole(void) +{ + unsigned int address; + size_t length, cur; + + address = get_bios_ebda(); + if (!address) { + printk(KERN_INFO "BIOS EBDA non-existent.\n"); + return false; + } + + /* EBDA length is byte 0 of EBDA (in KB) */ + length = *(u8 *)phys_to_virt(address); + length <<= 10; /* convert to bytes */ + + /* + * Search through EBDA for BIOS memory console structure + * note: signature is not necessarily dword-aligned + */ + for (cur = 0; cur < length; cur++) { + struct biosmemcon_ebda *hdr = phys_to_virt(address + cur); + + /* memconsole v1 */ + if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) { + found_v1_header(hdr); + return true; + } + + /* memconsole v2 */ + if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) { + found_v2_header(hdr); + return true; + } + } + + printk(KERN_INFO "BIOS console EBDA structure not found!\n"); + return false; +} + +static struct dmi_system_id memconsole_dmi_table[] __initdata = { + { + .ident = "Google Board", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."), + }, + }, + {} +}; +MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table); + +static int __init memconsole_init(void) +{ + int ret; + + if (!dmi_check_system(memconsole_dmi_table)) + return -ENODEV; + + if (!found_memconsole()) + return -ENODEV; + + memconsole_bin_attr.size = memconsole_length; + + ret = sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr); + + return ret; +} + +static void __exit memconsole_exit(void) +{ + sysfs_remove_bin_file(firmware_kobj, &memconsole_bin_attr); +} + +module_init(memconsole_init); +module_exit(memconsole_exit); + +MODULE_AUTHOR("Google, Inc."); +MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index 2192456dfd68..f032e446fc11 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c @@ -42,7 +42,20 @@ struct acpi_table_ibft *ibft_addr; EXPORT_SYMBOL_GPL(ibft_addr); -#define IBFT_SIGN "iBFT" +static const struct { + char *sign; +} ibft_signs[] = { +#ifdef CONFIG_ACPI + /* + * One spec says "IBFT", the other says "iBFT". We have to check + * for both. + */ + { ACPI_SIG_IBFT }, +#endif + { "iBFT" }, + { "BIFT" }, /* Broadcom iSCSI Offload */ +}; + #define IBFT_SIGN_LEN 4 #define IBFT_START 0x80000 /* 512kB */ #define IBFT_END 0x100000 /* 1MB */ @@ -62,6 +75,7 @@ static int __init find_ibft_in_mem(void) unsigned long pos; unsigned int len = 0; void *virt; + int i; for (pos = IBFT_START; pos < IBFT_END; pos += 16) { /* The table can't be inside the VGA BIOS reserved space, @@ -69,18 +83,23 @@ static int __init find_ibft_in_mem(void) if (pos == VGA_MEM) pos += VGA_SIZE; virt = isa_bus_to_virt(pos); - if (memcmp(virt, IBFT_SIGN, IBFT_SIGN_LEN) == 0) { - unsigned long *addr = - (unsigned long *)isa_bus_to_virt(pos + 4); - len = *addr; - /* if the length of the table extends past 1M, - * the table cannot be valid. */ - if (pos + len <= (IBFT_END-1)) { - ibft_addr = (struct acpi_table_ibft *)virt; - break; + + for (i = 0; i < ARRAY_SIZE(ibft_signs); i++) { + if (memcmp(virt, ibft_signs[i].sign, IBFT_SIGN_LEN) == + 0) { + unsigned long *addr = + (unsigned long *)isa_bus_to_virt(pos + 4); + len = *addr; + /* if the length of the table extends past 1M, + * the table cannot be valid. */ + if (pos + len <= (IBFT_END-1)) { + ibft_addr = (struct acpi_table_ibft *)virt; + goto done; + } } } } +done: return len; } /* @@ -89,18 +108,12 @@ static int __init find_ibft_in_mem(void) */ unsigned long __init find_ibft_region(unsigned long *sizep) { - + int i; ibft_addr = NULL; #ifdef CONFIG_ACPI - /* - * One spec says "IBFT", the other says "iBFT". We have to check - * for both. - */ - if (!ibft_addr) - acpi_table_parse(ACPI_SIG_IBFT, acpi_find_ibft); - if (!ibft_addr) - acpi_table_parse(IBFT_SIGN, acpi_find_ibft); + for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) + acpi_table_parse(ibft_signs[i].sign, acpi_find_ibft); #endif /* CONFIG_ACPI */ /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index c58f691ec3ce..b493663c7ba7 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -24,6 +24,7 @@ config DRM_KMS_HELPER depends on DRM select FB select FRAMEBUFFER_CONSOLE if !EXPERT + select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE help FB and CRTC helpers for KMS drivers. diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 950720473967..140b9525b48a 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -342,9 +342,22 @@ int drm_fb_helper_debug_leave(struct fb_info *info) } EXPORT_SYMBOL(drm_fb_helper_debug_leave); +bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) +{ + bool error = false; + int i, ret; + for (i = 0; i < fb_helper->crtc_count; i++) { + struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; + ret = drm_crtc_helper_set_config(mode_set); + if (ret) + error = true; + } + return error; +} +EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode); + bool drm_fb_helper_force_kernel_mode(void) { - int i = 0; bool ret, error = false; struct drm_fb_helper *helper; @@ -352,12 +365,12 @@ bool drm_fb_helper_force_kernel_mode(void) return false; list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { - for (i = 0; i < helper->crtc_count; i++) { - struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set; - ret = drm_crtc_helper_set_config(mode_set); - if (ret) - error = true; - } + if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF) + continue; + + ret = drm_fb_helper_restore_fbdev_mode(helper); + if (ret) + error = true; } return error; } @@ -1503,17 +1516,33 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) } EXPORT_SYMBOL(drm_fb_helper_initial_config); -bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) +/** + * drm_fb_helper_hotplug_event - respond to a hotplug notification by + * probing all the outputs attached to the fb. + * @fb_helper: the drm_fb_helper + * + * LOCKING: + * Called at runtime, must take mode config lock. + * + * Scan the connectors attached to the fb_helper and try to put together a + * setup after *notification of a change in output configuration. + * + * RETURNS: + * 0 on success and a non-zero error code otherwise. + */ +int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) { + struct drm_device *dev = fb_helper->dev; int count = 0; u32 max_width, max_height, bpp_sel; bool bound = false, crtcs_bound = false; struct drm_crtc *crtc; if (!fb_helper->fb) - return false; + return 0; - list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) { + mutex_lock(&dev->mode_config.mutex); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb) crtcs_bound = true; if (crtc->fb == fb_helper->fb) @@ -1522,7 +1551,8 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) if (!bound && crtcs_bound) { fb_helper->delayed_hotplug = true; - return false; + mutex_unlock(&dev->mode_config.mutex); + return 0; } DRM_DEBUG_KMS("\n"); @@ -1533,6 +1563,7 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, max_height); drm_setup_crtcs(fb_helper); + mutex_unlock(&dev->mode_config.mutex); return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); } diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 741457bd1c46..a1f12cb043de 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -932,11 +932,34 @@ EXPORT_SYMBOL(drm_vblank_put); void drm_vblank_off(struct drm_device *dev, int crtc) { + struct drm_pending_vblank_event *e, *t; + struct timeval now; unsigned long irqflags; + unsigned int seq; spin_lock_irqsave(&dev->vbl_lock, irqflags); vblank_disable_and_save(dev, crtc); DRM_WAKEUP(&dev->vbl_queue[crtc]); + + /* Send any queued vblank events, lest the natives grow disquiet */ + seq = drm_vblank_count_and_time(dev, crtc, &now); + list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { + if (e->pipe != crtc) + continue; + DRM_DEBUG("Sending premature vblank event on disable: \ + wanted %d, current %d\n", + e->event.sequence, seq); + + e->event.sequence = seq; + e->event.tv_sec = now.tv_sec; + e->event.tv_usec = now.tv_usec; + drm_vblank_put(dev, e->pipe); + list_move_tail(&e->base.link, &e->base.file_priv->event_list); + wake_up_interruptible(&e->base.file_priv->event_wait); + trace_drm_vblank_event_delivered(e->base.pid, e->pipe, + e->event.sequence); + } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } EXPORT_SYMBOL(drm_vblank_off); diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 5d00b0fc0d91..959186cbf328 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -431,7 +431,7 @@ EXPORT_SYMBOL(drm_mm_search_free_in_range); void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new) { list_replace(&old->node_list, &new->node_list); - list_replace(&old->node_list, &new->hole_stack); + list_replace(&old->hole_stack, &new->hole_stack); new->hole_follows = old->hole_follows; new->mm = old->mm; new->start = old->start; @@ -699,8 +699,8 @@ int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm) entry->size); total_used += entry->size; if (entry->hole_follows) { - hole_start = drm_mm_hole_node_start(&mm->head_node); - hole_end = drm_mm_hole_node_end(&mm->head_node); + hole_start = drm_mm_hole_node_start(entry); + hole_end = drm_mm_hole_node_end(entry); hole_size = hole_end - hole_start; seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n", hole_start, hole_end, hole_size); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 72730377a01b..12876f2795d2 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2207,7 +2207,7 @@ void i915_driver_lastclose(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { - drm_fb_helper_restore(); + intel_fb_restore_mode(dev); vga_switcheroo_process_delayed_switch(); return; } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c34a8dd31d02..32d1b3e829c8 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -49,7 +49,7 @@ module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); unsigned int i915_powersave = 1; module_param_named(powersave, i915_powersave, int, 0600); -unsigned int i915_semaphores = 1; +unsigned int i915_semaphores = 0; module_param_named(semaphores, i915_semaphores, int, 0600); unsigned int i915_enable_rc6 = 0; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 432fc04c6bff..2166ee071ddb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3771,8 +3771,11 @@ static bool g4x_compute_wm0(struct drm_device *dev, int entries, tlb_miss; crtc = intel_get_crtc_for_plane(dev, plane); - if (crtc->fb == NULL || !crtc->enabled) + if (crtc->fb == NULL || !crtc->enabled) { + *cursor_wm = cursor->guard_size; + *plane_wm = display->guard_size; return false; + } htotal = crtc->mode.htotal; hdisplay = crtc->mode.hdisplay; @@ -5602,9 +5605,9 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) intel_clock_t clock; if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) - fp = FP0(pipe); + fp = I915_READ(FP0(pipe)); else - fp = FP1(pipe); + fp = I915_READ(FP1(pipe)); clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; if (IS_PINEVIEW(dev)) { @@ -6215,36 +6218,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, return ret; } -static void intel_crtc_reset(struct drm_crtc *crtc) -{ - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - /* Reset flags back to the 'unknown' status so that they - * will be correctly set on the initial modeset. - */ - intel_crtc->dpms_mode = -1; -} - -static struct drm_crtc_helper_funcs intel_helper_funcs = { - .dpms = intel_crtc_dpms, - .mode_fixup = intel_crtc_mode_fixup, - .mode_set = intel_crtc_mode_set, - .mode_set_base = intel_pipe_set_base, - .mode_set_base_atomic = intel_pipe_set_base_atomic, - .load_lut = intel_crtc_load_lut, - .disable = intel_crtc_disable, -}; - -static const struct drm_crtc_funcs intel_crtc_funcs = { - .reset = intel_crtc_reset, - .cursor_set = intel_crtc_cursor_set, - .cursor_move = intel_crtc_cursor_move, - .gamma_set = intel_crtc_gamma_set, - .set_config = drm_crtc_helper_set_config, - .destroy = intel_crtc_destroy, - .page_flip = intel_crtc_page_flip, -}; - static void intel_sanitize_modesetting(struct drm_device *dev, int pipe, int plane) { @@ -6281,6 +6254,42 @@ static void intel_sanitize_modesetting(struct drm_device *dev, intel_disable_pipe(dev_priv, pipe); } +static void intel_crtc_reset(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + /* Reset flags back to the 'unknown' status so that they + * will be correctly set on the initial modeset. + */ + intel_crtc->dpms_mode = -1; + + /* We need to fix up any BIOS configuration that conflicts with + * our expectations. + */ + intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane); +} + +static struct drm_crtc_helper_funcs intel_helper_funcs = { + .dpms = intel_crtc_dpms, + .mode_fixup = intel_crtc_mode_fixup, + .mode_set = intel_crtc_mode_set, + .mode_set_base = intel_pipe_set_base, + .mode_set_base_atomic = intel_pipe_set_base_atomic, + .load_lut = intel_crtc_load_lut, + .disable = intel_crtc_disable, +}; + +static const struct drm_crtc_funcs intel_crtc_funcs = { + .reset = intel_crtc_reset, + .cursor_set = intel_crtc_cursor_set, + .cursor_move = intel_crtc_cursor_move, + .gamma_set = intel_crtc_gamma_set, + .set_config = drm_crtc_helper_set_config, + .destroy = intel_crtc_destroy, + .page_flip = intel_crtc_page_flip, +}; + static void intel_crtc_init(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -6330,8 +6339,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer, (unsigned long)intel_crtc); - - intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane); } int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, @@ -6572,8 +6579,10 @@ intel_user_framebuffer_create(struct drm_device *dev, return ERR_PTR(-ENOENT); intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); - if (!intel_fb) + if (!intel_fb) { + drm_gem_object_unreference_unlocked(&obj->base); return ERR_PTR(-ENOMEM); + } ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj); if (ret) { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index cb8578b7e443..a4d80314e7f8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1470,7 +1470,8 @@ intel_dp_link_down(struct intel_dp *intel_dp) if (!HAS_PCH_CPT(dev) && I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) { - struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc); + struct drm_crtc *crtc = intel_dp->base.base.crtc; + /* Hardware workaround: leaving our transcoder select * set to transcoder B while it's off will prevent the * corresponding HDMI output on transcoder A. @@ -1485,7 +1486,19 @@ intel_dp_link_down(struct intel_dp *intel_dp) /* Changes to enable or select take place the vblank * after being written. */ - intel_wait_for_vblank(dev, intel_crtc->pipe); + if (crtc == NULL) { + /* We can arrive here never having been attached + * to a CRTC, for instance, due to inheriting + * random state from the BIOS. + * + * If the pipe is not running, play safe and + * wait for the clocks to stabilise before + * continuing. + */ + POSTING_READ(intel_dp->output_reg); + msleep(50); + } else + intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); } I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f5b0d8306d83..1d20712d527f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -338,4 +338,5 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void intel_fb_output_poll_changed(struct drm_device *dev); +extern void intel_fb_restore_mode(struct drm_device *dev); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 512782728e51..ec49bae73382 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -264,3 +264,13 @@ void intel_fb_output_poll_changed(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); } + +void intel_fb_restore_mode(struct drm_device *dev) +{ + int ret; + drm_i915_private_t *dev_priv = dev->dev_private; + + ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); + if (ret) + DRM_DEBUG("failed to restore crtc mode\n"); +} diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index a562bd2648c7..67cb076d271b 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -539,6 +539,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, struct drm_device *dev = dev_priv->dev; struct drm_connector *connector = dev_priv->int_lvds_connector; + if (dev->switch_power_state != DRM_SWITCH_POWER_ON) + return NOTIFY_OK; + /* * check and update the status of LVDS connector after receiving * the LID nofication event. diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 4256b8ef3947..6b22c1dcc015 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1151,10 +1151,10 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); { int pipeconf_reg = PIPECONF(pipe); - int dspcntr_reg = DSPCNTR(pipe); + int dspcntr_reg = DSPCNTR(intel_crtc->plane); int pipeconf = I915_READ(pipeconf_reg); int dspcntr = I915_READ(dspcntr_reg); - int dspbase_reg = DSPADDR(pipe); + int dspbase_reg = DSPADDR(intel_crtc->plane); int xpos = 0x0, ypos = 0x0; unsigned int xsize, ysize; /* Pipe must be off here */ @@ -1378,7 +1378,9 @@ intel_tv_detect(struct drm_connector *connector, bool force) if (type < 0) return connector_status_disconnected; + intel_tv->type = type; intel_tv_find_better_format(connector); + return connector_status_connected; } @@ -1670,8 +1672,7 @@ intel_tv_init(struct drm_device *dev) * * More recent chipsets favour HDMI rather than integrated S-Video. */ - connector->polled = - DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + connector->polled = DRM_CONNECTOR_POLL_CONNECT; drm_connector_init(dev, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_SVIDEO); diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index ce38e97b9428..568caedd7216 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -83,7 +83,7 @@ nouveau_dma_init(struct nouveau_channel *chan) return ret; /* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier object */ - ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfd0, 0x1000, + ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000, &chan->m2mf_ntfy); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 856d56a98d1e..a76514a209b3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -682,6 +682,9 @@ struct drm_nouveau_private { /* For PFIFO and PGRAPH. */ spinlock_t context_switch_lock; + /* VM/PRAMIN flush, legacy PRAMIN aperture */ + spinlock_t vm_lock; + /* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */ struct nouveau_ramht *ramht; struct nouveau_gpuobj *ramfc; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 889c4454682e..39aee6d4daf8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -181,13 +181,13 @@ nouveau_fbcon_sync(struct fb_info *info) OUT_RING (chan, 0); } - nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff); + nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy/4 + 3, 0xffffffff); FIRE_RING(chan); mutex_unlock(&chan->mutex); ret = -EBUSY; for (i = 0; i < 100000; i++) { - if (!nouveau_bo_rd32(chan->notifier_bo, chan->m2mf_ntfy + 3)) { + if (!nouveau_bo_rd32(chan->notifier_bo, chan->m2mf_ntfy/4 + 3)) { ret = 0; break; } diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 78f467fe30be..c3e953b08992 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -152,8 +152,6 @@ nouveau_mem_vram_fini(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - nouveau_bo_ref(NULL, &dev_priv->vga_ram); - ttm_bo_device_release(&dev_priv->ttm.bdev); nouveau_ttm_global_release(dev_priv); @@ -398,7 +396,7 @@ nouveau_mem_vram_init(struct drm_device *dev) dma_bits = 40; } else if (drm_pci_device_is_pcie(dev) && - dev_priv->chipset != 0x40 && + dev_priv->chipset > 0x40 && dev_priv->chipset != 0x45) { if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(39))) dma_bits = 39; diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c index 7ba3fc0b30c1..5b39718ae1f8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_notifier.c +++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c @@ -35,19 +35,22 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct nouveau_bo *ntfy = NULL; - uint32_t flags; + uint32_t flags, ttmpl; int ret; - if (nouveau_vram_notify) + if (nouveau_vram_notify) { flags = NOUVEAU_GEM_DOMAIN_VRAM; - else + ttmpl = TTM_PL_FLAG_VRAM; + } else { flags = NOUVEAU_GEM_DOMAIN_GART; + ttmpl = TTM_PL_FLAG_TT; + } ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags, 0, 0, &ntfy); if (ret) return ret; - ret = nouveau_bo_pin(ntfy, flags); + ret = nouveau_bo_pin(ntfy, ttmpl); if (ret) goto out_err; diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 4f00c87ed86e..67a16e01ffa6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -1039,19 +1039,20 @@ nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset) { struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; struct drm_device *dev = gpuobj->dev; + unsigned long flags; if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) { u64 ptr = gpuobj->vinst + offset; u32 base = ptr >> 16; u32 val; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); if (dev_priv->ramin_base != base) { dev_priv->ramin_base = base; nv_wr32(dev, 0x001700, dev_priv->ramin_base); } val = nv_rd32(dev, 0x700000 + (ptr & 0xffff)); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); return val; } @@ -1063,18 +1064,19 @@ nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val) { struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; struct drm_device *dev = gpuobj->dev; + unsigned long flags; if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) { u64 ptr = gpuobj->vinst + offset; u32 base = ptr >> 16; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); if (dev_priv->ramin_base != base) { dev_priv->ramin_base = base; nv_wr32(dev, 0x001700, dev_priv->ramin_base); } nv_wr32(dev, 0x700000 + (ptr & 0xffff), val); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); return; } diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index a33fe4019286..c77111eca6ac 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -42,7 +42,8 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages, nvbe->nr_pages = 0; while (num_pages--) { - if (dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE) { + /* this code path isn't called and is incorrect anyways */ + if (0) { /*dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE)*/ nvbe->pages[nvbe->nr_pages] = dma_addrs[nvbe->nr_pages]; nvbe->ttm_alloced[nvbe->nr_pages] = true; @@ -55,6 +56,7 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages, be->func->clear(be); return -EFAULT; } + nvbe->ttm_alloced[nvbe->nr_pages] = false; } nvbe->nr_pages++; @@ -427,7 +429,7 @@ nouveau_sgdma_init(struct drm_device *dev) u32 aper_size, align; int ret; - if (dev_priv->card_type >= NV_50 || drm_pci_device_is_pcie(dev)) + if (dev_priv->card_type >= NV_40 && drm_pci_device_is_pcie(dev)) aper_size = 512 * 1024 * 1024; else aper_size = 64 * 1024 * 1024; @@ -457,7 +459,7 @@ nouveau_sgdma_init(struct drm_device *dev) dev_priv->gart_info.func = &nv50_sgdma_backend; } else if (drm_pci_device_is_pcie(dev) && - dev_priv->chipset != 0x40 && dev_priv->chipset != 0x45) { + dev_priv->chipset > 0x40 && dev_priv->chipset != 0x45) { if (nv44_graph_class(dev)) { dev_priv->gart_info.func = &nv44_sgdma_backend; align = 512 * 1024; diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 6e2b1a6caa2d..915fbce89595 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -608,6 +608,7 @@ nouveau_card_init(struct drm_device *dev) spin_lock_init(&dev_priv->channels.lock); spin_lock_init(&dev_priv->tile.lock); spin_lock_init(&dev_priv->context_switch_lock); + spin_lock_init(&dev_priv->vm_lock); /* Make the CRTCs and I2C buses accessible */ ret = engine->display.early_init(dev); @@ -767,6 +768,11 @@ static void nouveau_card_takedown(struct drm_device *dev) engine->mc.takedown(dev); engine->display.late_takedown(dev); + if (dev_priv->vga_ram) { + nouveau_bo_unpin(dev_priv->vga_ram); + nouveau_bo_ref(NULL, &dev_priv->vga_ram); + } + mutex_lock(&dev->struct_mutex); ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index a6f8aa651fc6..4f95a1e5822e 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -404,23 +404,25 @@ void nv50_instmem_flush(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); nv_wr32(dev, 0x00330c, 0x00000001); if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000)) NV_ERROR(dev, "PRAMIN flush timeout\n"); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); } void nv84_instmem_flush(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); nv_wr32(dev, 0x070000, 0x00000001); if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000)) NV_ERROR(dev, "PRAMIN flush timeout\n"); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); } diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c index 4fd3432b5b8d..6c2694490741 100644 --- a/drivers/gpu/drm/nouveau/nv50_vm.c +++ b/drivers/gpu/drm/nouveau/nv50_vm.c @@ -174,10 +174,11 @@ void nv50_vm_flush_engine(struct drm_device *dev, int engine) { struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); nv_wr32(dev, 0x100c80, (engine << 16) | 1); if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000)) NV_ERROR(dev, "vm flush timeout: engine %d\n", engine); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); } diff --git a/drivers/gpu/drm/nouveau/nvc0_vm.c b/drivers/gpu/drm/nouveau/nvc0_vm.c index a0a2a0277f73..a179e6c55afb 100644 --- a/drivers/gpu/drm/nouveau/nvc0_vm.c +++ b/drivers/gpu/drm/nouveau/nvc0_vm.c @@ -104,11 +104,12 @@ nvc0_vm_flush(struct nouveau_vm *vm) struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; struct drm_device *dev = vm->dev; struct nouveau_vm_pgd *vpgd; + unsigned long flags; u32 engine = (dev_priv->chan_vm == vm) ? 1 : 5; pinstmem->flush(vm->dev); - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); list_for_each_entry(vpgd, &vm->pgd_list, head) { /* looks like maybe a "free flush slots" counter, the * faster you write to 0x100cbc to more it decreases @@ -125,5 +126,5 @@ nvc0_vm_flush(struct nouveau_vm *vm) nv_rd32(dev, 0x100c80), engine); } } - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); } diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index d71d375149f8..7bd745689097 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -135,7 +135,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, case ATOM_IIO_MOVE_INDEX: temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << - CU8(base + 2)); + CU8(base + 3)); temp |= ((index >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + @@ -145,7 +145,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, case ATOM_IIO_MOVE_DATA: temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << - CU8(base + 2)); + CU8(base + 3)); temp |= ((data >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + @@ -155,7 +155,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, case ATOM_IIO_MOVE_ATTR: temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << - CU8(base + 2)); + CU8(base + 3)); temp |= ((ctx-> io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 9d516a8c4dfa..529a3a704731 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -532,10 +532,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, else pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; - if ((rdev->family == CHIP_R600) || - (rdev->family == CHIP_RV610) || - (rdev->family == CHIP_RV630) || - (rdev->family == CHIP_RV670)) + if (rdev->family < CHIP_RV770) pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; } else { pll->flags |= RADEON_PLL_LEGACY; @@ -565,7 +562,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { if (ss_enabled) { if (ss->refdiv) { - pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; pll->flags |= RADEON_PLL_USE_REF_DIV; pll->reference_div = ss->refdiv; if (ASIC_IS_AVIVO(rdev)) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 3453910ee0f3..9073e3bfb08c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -353,7 +353,7 @@ static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev, struct drm_display_mode *mode, struct drm_display_mode *other_mode) { - u32 tmp = 0; + u32 tmp; /* * Line Buffer Setup * There are 3 line buffers, each one shared by 2 display controllers. @@ -363,64 +363,63 @@ static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev, * first display controller * 0 - first half of lb (3840 * 2) * 1 - first 3/4 of lb (5760 * 2) - * 2 - whole lb (7680 * 2) + * 2 - whole lb (7680 * 2), other crtc must be disabled * 3 - first 1/4 of lb (1920 * 2) * second display controller * 4 - second half of lb (3840 * 2) * 5 - second 3/4 of lb (5760 * 2) - * 6 - whole lb (7680 * 2) + * 6 - whole lb (7680 * 2), other crtc must be disabled * 7 - last 1/4 of lb (1920 * 2) */ - if (mode && other_mode) { - if (mode->hdisplay > other_mode->hdisplay) { - if (mode->hdisplay > 2560) - tmp = 1; /* 3/4 */ - else - tmp = 0; /* 1/2 */ - } else if (other_mode->hdisplay > mode->hdisplay) { - if (other_mode->hdisplay > 2560) - tmp = 3; /* 1/4 */ - else - tmp = 0; /* 1/2 */ - } else + /* this can get tricky if we have two large displays on a paired group + * of crtcs. Ideally for multiple large displays we'd assign them to + * non-linked crtcs for maximum line buffer allocation. + */ + if (radeon_crtc->base.enabled && mode) { + if (other_mode) tmp = 0; /* 1/2 */ - } else if (mode) - tmp = 2; /* whole */ - else if (other_mode) - tmp = 3; /* 1/4 */ + else + tmp = 2; /* whole */ + } else + tmp = 0; /* second controller of the pair uses second half of the lb */ if (radeon_crtc->crtc_id % 2) tmp += 4; WREG32(DC_LB_MEMORY_SPLIT + radeon_crtc->crtc_offset, tmp); - switch (tmp) { - case 0: - case 4: - default: - if (ASIC_IS_DCE5(rdev)) - return 4096 * 2; - else - return 3840 * 2; - case 1: - case 5: - if (ASIC_IS_DCE5(rdev)) - return 6144 * 2; - else - return 5760 * 2; - case 2: - case 6: - if (ASIC_IS_DCE5(rdev)) - return 8192 * 2; - else - return 7680 * 2; - case 3: - case 7: - if (ASIC_IS_DCE5(rdev)) - return 2048 * 2; - else - return 1920 * 2; + if (radeon_crtc->base.enabled && mode) { + switch (tmp) { + case 0: + case 4: + default: + if (ASIC_IS_DCE5(rdev)) + return 4096 * 2; + else + return 3840 * 2; + case 1: + case 5: + if (ASIC_IS_DCE5(rdev)) + return 6144 * 2; + else + return 5760 * 2; + case 2: + case 6: + if (ASIC_IS_DCE5(rdev)) + return 8192 * 2; + else + return 7680 * 2; + case 3: + case 7: + if (ASIC_IS_DCE5(rdev)) + return 2048 * 2; + else + return 1920 * 2; + } } + + /* controller not enabled, so no lb used */ + return 0; } static u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev) @@ -863,9 +862,15 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) SYSTEM_ACCESS_MODE_NOT_IN_SYS | SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU | EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5); - WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); - WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); - WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); + if (rdev->flags & RADEON_IS_IGP) { + WREG32(FUS_MC_VM_MD_L1_TLB0_CNTL, tmp); + WREG32(FUS_MC_VM_MD_L1_TLB1_CNTL, tmp); + WREG32(FUS_MC_VM_MD_L1_TLB2_CNTL, tmp); + } else { + WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); + WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); + WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); + } WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); @@ -1775,7 +1780,10 @@ static void evergreen_gpu_init(struct radeon_device *rdev) mc_shared_chmap = RREG32(MC_SHARED_CHMAP); - mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); + if (rdev->flags & RADEON_IS_IGP) + mc_arb_ramcfg = RREG32(FUS_MC_ARB_RAMCFG); + else + mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); switch (rdev->config.evergreen.max_tile_pipes) { case 1: @@ -2581,7 +2589,7 @@ static inline u32 evergreen_get_ih_wptr(struct radeon_device *rdev) u32 wptr, tmp; if (rdev->wb.enabled) - wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]; + wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]); else wptr = RREG32(IH_RB_WPTR); @@ -2924,11 +2932,6 @@ static int evergreen_startup(struct radeon_device *rdev) rdev->asic->copy = NULL; dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); } - /* XXX: ontario has problems blitting to gart at the moment */ - if (rdev->family == CHIP_PALM) { - rdev->asic->copy = NULL; - radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); - } /* allocate wb buffer */ r = radeon_wb_init(rdev); diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 9aaa3f0c9372..fc40e0cc3451 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -200,6 +200,7 @@ #define BURSTLENGTH_SHIFT 9 #define BURSTLENGTH_MASK 0x00000200 #define CHANSIZE_OVERRIDE (1 << 11) +#define FUS_MC_ARB_RAMCFG 0x2768 #define MC_VM_AGP_TOP 0x2028 #define MC_VM_AGP_BOT 0x202C #define MC_VM_AGP_BASE 0x2030 @@ -221,6 +222,11 @@ #define MC_VM_MD_L1_TLB0_CNTL 0x2654 #define MC_VM_MD_L1_TLB1_CNTL 0x2658 #define MC_VM_MD_L1_TLB2_CNTL 0x265C + +#define FUS_MC_VM_MD_L1_TLB0_CNTL 0x265C +#define FUS_MC_VM_MD_L1_TLB1_CNTL 0x2660 +#define FUS_MC_VM_MD_L1_TLB2_CNTL 0x2664 + #define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203C #define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038 #define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034 diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 7aade20f63a8..3d8a7634bbe9 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -674,7 +674,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE); cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG); - cgts_tcc_disable = RREG32(CGTS_TCC_DISABLE); + cgts_tcc_disable = 0xff000000; gc_user_rb_backend_disable = RREG32(GC_USER_RB_BACKEND_DISABLE); gc_user_shader_pipe_config = RREG32(GC_USER_SHADER_PIPE_CONFIG); cgts_user_tcc_disable = RREG32(CGTS_USER_TCC_DISABLE); @@ -871,7 +871,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) smx_dc_ctl0 = RREG32(SMX_DC_CTL0); smx_dc_ctl0 &= ~NUMBER_OF_SETS(0x1ff); - smx_dc_ctl0 |= NUMBER_OF_SETS(rdev->config.evergreen.sx_num_of_sets); + smx_dc_ctl0 |= NUMBER_OF_SETS(rdev->config.cayman.sx_num_of_sets); WREG32(SMX_DC_CTL0, smx_dc_ctl0); WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4) | CRC_SIMD_ID_WADDR_DISABLE); @@ -887,20 +887,20 @@ static void cayman_gpu_init(struct radeon_device *rdev) WREG32(TA_CNTL_AUX, DISABLE_CUBE_ANISO); - WREG32(SX_EXPORT_BUFFER_SIZES, (COLOR_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_size / 4) - 1) | - POSITION_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_pos_size / 4) - 1) | - SMX_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_smx_size / 4) - 1))); + WREG32(SX_EXPORT_BUFFER_SIZES, (COLOR_BUFFER_SIZE((rdev->config.cayman.sx_max_export_size / 4) - 1) | + POSITION_BUFFER_SIZE((rdev->config.cayman.sx_max_export_pos_size / 4) - 1) | + SMX_BUFFER_SIZE((rdev->config.cayman.sx_max_export_smx_size / 4) - 1))); - WREG32(PA_SC_FIFO_SIZE, (SC_PRIM_FIFO_SIZE(rdev->config.evergreen.sc_prim_fifo_size) | - SC_HIZ_TILE_FIFO_SIZE(rdev->config.evergreen.sc_hiz_tile_fifo_size) | - SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.evergreen.sc_earlyz_tile_fifo_size))); + WREG32(PA_SC_FIFO_SIZE, (SC_PRIM_FIFO_SIZE(rdev->config.cayman.sc_prim_fifo_size) | + SC_HIZ_TILE_FIFO_SIZE(rdev->config.cayman.sc_hiz_tile_fifo_size) | + SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.cayman.sc_earlyz_tile_fifo_size))); WREG32(VGT_NUM_INSTANCES, 1); WREG32(CP_PERFMON_CNTL, 0); - WREG32(SQ_MS_FIFO_SIZES, (CACHE_FIFO_SIZE(16 * rdev->config.evergreen.sq_num_cf_insts) | + WREG32(SQ_MS_FIFO_SIZES, (CACHE_FIFO_SIZE(16 * rdev->config.cayman.sq_num_cf_insts) | FETCH_FIFO_HIWATER(0x4) | DONE_FIFO_HIWATER(0xe0) | ALU_UPDATE_FIFO_HIWATER(0x8))); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 15d58292677a..6f27593901c7 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3231,7 +3231,7 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev) u32 wptr, tmp; if (rdev->wb.enabled) - wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]; + wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]); else wptr = RREG32(IH_RB_WPTR); diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index f5d12fb103fa..90dfb2b8cf03 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -431,7 +431,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } } - /* Acer laptop (Acer TravelMate 5730G) has an HDMI port + /* Acer laptop (Acer TravelMate 5730/5730G) has an HDMI port * on the laptop and a DVI port on the docking station and * both share the same encoder, hpd pin, and ddc line. * So while the bios table is technically correct, @@ -440,7 +440,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, * with different crtcs which isn't possible on the hardware * side and leaves no crtcs for LVDS or VGA. */ - if ((dev->pdev->device == 0x95c4) && + if (((dev->pdev->device == 0x95c4) || (dev->pdev->device == 0x9591)) && (dev->pdev->subsystem_vendor == 0x1025) && (dev->pdev->subsystem_device == 0x013c)) { if ((*connector_type == DRM_MODE_CONNECTOR_DVII) && @@ -1574,9 +1574,17 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; bool bad_record = false; - u8 *record = (u8 *)(mode_info->atom_context->bios + - data_offset + - le16_to_cpu(lvds_info->info.usModePatchTableOffset)); + u8 *record; + + if ((frev == 1) && (crev < 2)) + /* absolute */ + record = (u8 *)(mode_info->atom_context->bios + + le16_to_cpu(lvds_info->info.usModePatchTableOffset)); + else + /* relative */ + record = (u8 *)(mode_info->atom_context->bios + + data_offset + + le16_to_cpu(lvds_info->info.usModePatchTableOffset)); while (*record != ATOM_RECORD_END_TYPE) { switch (*record) { case LCD_MODE_PATCH_RECORD_MODE_TYPE: @@ -1599,9 +1607,10 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0], fake_edid_record->ucFakeEDIDLength); - if (drm_edid_is_valid(edid)) + if (drm_edid_is_valid(edid)) { rdev->mode_info.bios_hardcoded_edid = edid; - else + rdev->mode_info.bios_hardcoded_edid_size = edid_size; + } else kfree(edid); } } diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index ed5dfe58f29c..9d95792bea3e 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -15,6 +15,9 @@ #define ATPX_VERSION 0 #define ATPX_GPU_PWR 2 #define ATPX_MUX_SELECT 3 +#define ATPX_I2C_MUX_SELECT 4 +#define ATPX_SWITCH_START 5 +#define ATPX_SWITCH_END 6 #define ATPX_INTEGRATED 0 #define ATPX_DISCRETE 1 @@ -149,13 +152,35 @@ static int radeon_atpx_switch_mux(acpi_handle handle, int mux_id) return radeon_atpx_execute(handle, ATPX_MUX_SELECT, mux_id); } +static int radeon_atpx_switch_i2c_mux(acpi_handle handle, int mux_id) +{ + return radeon_atpx_execute(handle, ATPX_I2C_MUX_SELECT, mux_id); +} + +static int radeon_atpx_switch_start(acpi_handle handle, int gpu_id) +{ + return radeon_atpx_execute(handle, ATPX_SWITCH_START, gpu_id); +} + +static int radeon_atpx_switch_end(acpi_handle handle, int gpu_id) +{ + return radeon_atpx_execute(handle, ATPX_SWITCH_END, gpu_id); +} static int radeon_atpx_switchto(enum vga_switcheroo_client_id id) { + int gpu_id; + if (id == VGA_SWITCHEROO_IGD) - radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 0); + gpu_id = ATPX_INTEGRATED; else - radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 1); + gpu_id = ATPX_DISCRETE; + + radeon_atpx_switch_start(radeon_atpx_priv.atpx_handle, gpu_id); + radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, gpu_id); + radeon_atpx_switch_i2c_mux(radeon_atpx_priv.atpx_handle, gpu_id); + radeon_atpx_switch_end(radeon_atpx_priv.atpx_handle, gpu_id); + return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 2ef6d5135064..5f45fa12bb8b 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1199,7 +1199,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (router->ddc_valid || router->cd_valid) { radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info); if (!radeon_connector->router_bus) - goto failed; + DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n"); } switch (connector_type) { case DRM_MODE_CONNECTOR_VGA: @@ -1208,7 +1208,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1226,7 +1226,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1249,7 +1249,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } subpixel_order = SubPixelHorizontalRGB; drm_connector_attach_property(&radeon_connector->base, @@ -1290,7 +1290,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.coherent_mode_property, @@ -1329,10 +1329,10 @@ radeon_add_atom_connector(struct drm_device *dev, else radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); if (!radeon_dig_connector->dp_i2c_bus) - goto failed; + DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } subpixel_order = SubPixelHorizontalRGB; drm_connector_attach_property(&radeon_connector->base, @@ -1381,7 +1381,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } drm_connector_attach_property(&radeon_connector->base, dev->mode_config.scaling_mode_property, @@ -1457,7 +1457,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1475,7 +1475,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1493,7 +1493,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } if (connector_type == DRM_MODE_CONNECTOR_DVII) { radeon_connector->dac_load_detect = true; @@ -1538,7 +1538,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } drm_connector_attach_property(&radeon_connector->base, dev->mode_config.scaling_mode_property, @@ -1567,9 +1567,4 @@ radeon_add_legacy_connector(struct drm_device *dev, radeon_legacy_backlight_init(radeon_encoder, connector); } } - return; - -failed: - drm_connector_cleanup(connector); - kfree(connector); } diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index bdf2fa1189ae..3189a7efb2e9 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -167,9 +167,6 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, return -EINVAL; } - radeon_crtc->cursor_width = width; - radeon_crtc->cursor_height = height; - obj = drm_gem_object_lookup(crtc->dev, file_priv, handle); if (!obj) { DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id); @@ -180,6 +177,9 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, if (ret) goto fail; + radeon_crtc->cursor_width = width; + radeon_crtc->cursor_height = height; + radeon_lock_cursor(crtc, true); /* XXX only 27 bit offset for legacy cursor */ radeon_set_cursor(crtc, obj, gpu_addr); diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 8a955bbdb608..a533f52fd163 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -181,9 +181,9 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); for (i = 0; i < pages; i++, p++) { - /* On TTM path, we only use the DMA API if TTM_PAGE_FLAG_DMA32 - * is requested. */ - if (dma_addr[i] != DMA_ERROR_CODE) { + /* we reverted the patch using dma_addr in TTM for now but this + * code stops building on alpha so just comment it out for now */ + if (0) { /*dma_addr[i] != DMA_ERROR_CODE) */ rdev->gart.ttm_alloced[p] = true; rdev->gart.pages_addr[p] = dma_addr[i]; } else { diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index ccbabf734a61..983cbac75af0 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -1096,6 +1096,9 @@ void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector) if (!radeon_connector->router.ddc_valid) return; + if (!radeon_connector->router_bus) + return; + radeon_i2c_get_byte(radeon_connector->router_bus, radeon_connector->router.i2c_addr, 0x3, &val); @@ -1121,6 +1124,9 @@ void radeon_router_select_cd_port(struct radeon_connector *radeon_connector) if (!radeon_connector->router.cd_valid) return; + if (!radeon_connector->router_bus) + return; + radeon_i2c_get_byte(radeon_connector->router_bus, radeon_connector->router.i2c_addr, 0x3, &val); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index bf7d4c061451..bd58af658581 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -221,6 +221,22 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) return -EINVAL; } break; + case RADEON_INFO_NUM_TILE_PIPES: + if (rdev->family >= CHIP_CAYMAN) + value = rdev->config.cayman.max_tile_pipes; + else if (rdev->family >= CHIP_CEDAR) + value = rdev->config.evergreen.max_tile_pipes; + else if (rdev->family >= CHIP_RV770) + value = rdev->config.rv770.max_tile_pipes; + else if (rdev->family >= CHIP_R600) + value = rdev->config.r600.max_tile_pipes; + else { + return -EINVAL; + } + break; + case RADEON_INFO_FUSION_GART_WORKING: + value = 1; + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; diff --git a/drivers/gpu/drm/radeon/reg_srcs/cayman b/drivers/gpu/drm/radeon/reg_srcs/cayman index 6334f8ac1209..0aa8e85a9457 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/cayman +++ b/drivers/gpu/drm/radeon/reg_srcs/cayman @@ -33,6 +33,7 @@ cayman 0x9400 0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS 0x00009100 SPI_CONFIG_CNTL 0x0000913C SPI_CONFIG_CNTL_1 +0x00009508 TA_CNTL_AUX 0x00009830 DB_DEBUG 0x00009834 DB_DEBUG2 0x00009838 DB_DEBUG3 diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen index 7e1637176e08..0e28cae7ea43 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/evergreen +++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen @@ -46,6 +46,7 @@ evergreen 0x9400 0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS 0x00009100 SPI_CONFIG_CNTL 0x0000913C SPI_CONFIG_CNTL_1 +0x00009508 TA_CNTL_AUX 0x00009700 VC_CNTL 0x00009714 VC_ENHANCE 0x00009830 DB_DEBUG diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600 index af0da4ae3f55..92f1900dc7ca 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r600 +++ b/drivers/gpu/drm/radeon/reg_srcs/r600 @@ -708,6 +708,7 @@ r600 0x9400 0x00028D0C DB_RENDER_CONTROL 0x00028D10 DB_RENDER_OVERRIDE 0x0002880C DB_SHADER_CONTROL +0x00028D28 DB_SRESULTS_COMPARE_STATE0 0x00028D2C DB_SRESULTS_COMPARE_STATE1 0x00028430 DB_STENCILREFMASK 0x00028434 DB_STENCILREFMASK_BF diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index e01cacba685f..498b284e5ef9 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -219,9 +219,6 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) int i; struct vga_switcheroo_client *active = NULL; - if (new_client->active == true) - return 0; - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { if (vgasr_priv.clients[i].active == true) { active = &vgasr_priv.clients[i]; @@ -372,6 +369,9 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, goto out; } + if (client->active == true) + goto out; + /* okay we want a switch - test if devices are willing to switch */ can_switch = true; for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 060ef6327876..50e40dbd8bb6 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -110,8 +110,7 @@ config SENSORS_ADM1021 help If you say yes here you get support for Analog Devices ADM1021 and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, - Genesys Logic GL523SM, National Semiconductor LM84, TI THMC10, - and the XEON processor built-in sensor. + Genesys Logic GL523SM, National Semiconductor LM84 and TI THMC10. This driver can also be built as a module. If so, the module will be called adm1021. @@ -618,10 +617,10 @@ config SENSORS_LM90 depends on I2C help If you say yes here you get support for National Semiconductor LM90, - LM86, LM89 and LM99, Analog Devices ADM1032 and ADT7461, Maxim - MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659, - MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, and Winbond/Nuvoton - W83L771W/G/AWG/ASG sensor chips. + LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A, + Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659, + MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008, + and Winbond/Nuvoton W83L771W/G/AWG/ASG sensor chips. This driver can also be built as a module. If so, the module will be called lm90. diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 250d099ca398..da72dc12068c 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1094,6 +1094,7 @@ static struct attribute *lm85_attributes_minctl[] = { &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr, &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr, &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr, + NULL }; static const struct attribute_group lm85_group_minctl = { @@ -1104,6 +1105,7 @@ static struct attribute *lm85_attributes_temp_off[] = { &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr, &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr, &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr, + NULL }; static const struct attribute_group lm85_group_temp_off = { @@ -1329,11 +1331,11 @@ static int lm85_probe(struct i2c_client *client, if (data->type != emc6d103s) { err = sysfs_create_group(&client->dev.kobj, &lm85_group_minctl); if (err) - goto err_kfree; + goto err_remove_files; err = sysfs_create_group(&client->dev.kobj, &lm85_group_temp_off); if (err) - goto err_kfree; + goto err_remove_files; } /* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index c43b4e9f96a9..2f94f9504804 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -49,10 +49,10 @@ * chips, but support three temperature sensors instead of two. MAX6695 * and MAX6696 only differ in the pinout so they can be treated identically. * - * This driver also supports the ADT7461 chip from Analog Devices. - * It's supported in both compatibility and extended mode. It is mostly - * compatible with LM90 except for a data format difference for the - * temperature value registers. + * This driver also supports ADT7461 and ADT7461A from Analog Devices as well as + * NCT1008 from ON Semiconductor. The chips are supported in both compatibility + * and extended mode. They are mostly compatible with LM90 except for a data + * format difference for the temperature value registers. * * Since the LM90 was the first chipset supported by this driver, most * comments will refer to this chipset, but are actually general and @@ -88,9 +88,10 @@ * Addresses to scan * Address is fully defined internally and cannot be changed except for * MAX6659, MAX6680 and MAX6681. - * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6649, MAX6657, - * MAX6658 and W83L771 have address 0x4c. - * ADM1032-2, ADT7461-2, LM89-1, LM99-1 and MAX6646 have address 0x4d. + * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, ADT7461A, MAX6649, + * MAX6657, MAX6658, NCT1008 and W83L771 have address 0x4c. + * ADM1032-2, ADT7461-2, ADT7461A-2, LM89-1, LM99-1, MAX6646, and NCT1008D + * have address 0x4d. * MAX6647 has address 0x4e. * MAX6659 can have address 0x4c, 0x4d or 0x4e. * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, @@ -174,6 +175,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680, static const struct i2c_device_id lm90_id[] = { { "adm1032", adm1032 }, { "adt7461", adt7461 }, + { "adt7461a", adt7461 }, { "lm90", lm90 }, { "lm86", lm86 }, { "lm89", lm86 }, @@ -188,6 +190,7 @@ static const struct i2c_device_id lm90_id[] = { { "max6681", max6680 }, { "max6695", max6696 }, { "max6696", max6696 }, + { "nct1008", adt7461 }, { "w83l771", w83l771 }, { } }; @@ -1153,6 +1156,11 @@ static int lm90_detect(struct i2c_client *new_client, && (reg_config1 & 0x1B) == 0x00 && reg_convrate <= 0x0A) { name = "adt7461"; + } else + if (chip_id == 0x57 /* ADT7461A, NCT1008 */ + && (reg_config1 & 0x1B) == 0x00 + && reg_convrate <= 0x0A) { + name = "adt7461a"; } } else if (man_id == 0x4D) { /* Maxim */ diff --git a/drivers/hwmon/pmbus_core.c b/drivers/hwmon/pmbus_core.c index edfb92e41735..196ffafafd88 100644 --- a/drivers/hwmon/pmbus_core.c +++ b/drivers/hwmon/pmbus_core.c @@ -139,7 +139,6 @@ struct pmbus_data { * A single status register covers multiple attributes, * so we keep them all together. */ - u8 status_bits; u8 status[PB_NUM_STATUS_REG]; u8 currpage; diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c index de5819199e2e..57240740b161 100644 --- a/drivers/hwmon/twl4030-madc-hwmon.c +++ b/drivers/hwmon/twl4030-madc-hwmon.c @@ -98,7 +98,6 @@ static const struct attribute_group twl4030_madc_group = { static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev) { int ret; - int status; struct device *hwmon; ret = sysfs_create_group(&pdev->dev.kobj, &twl4030_madc_group); @@ -107,7 +106,7 @@ static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev) hwmon = hwmon_device_register(&pdev->dev); if (IS_ERR(hwmon)) { dev_err(&pdev->dev, "hwmon_device_register failed.\n"); - status = PTR_ERR(hwmon); + ret = PTR_ERR(hwmon); goto err_reg; } diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 72c0415f6f94..455e909bc768 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -134,10 +134,15 @@ SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \ SMBHSTSTS_INTR) +/* Older devices have their ID defined in */ +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */ #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72 +#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 +#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 struct i801_priv { struct i2c_adapter adapter; diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 75b984c519ac..107397a606b4 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -560,15 +560,18 @@ static struct i2c_adapter mpc_ops = { .timeout = HZ, }; +static const struct of_device_id mpc_i2c_of_match[]; static int __devinit fsl_i2c_probe(struct platform_device *op) { + const struct of_device_id *match; struct mpc_i2c *i2c; const u32 *prop; u32 clock = MPC_I2C_CLOCK_LEGACY; int result = 0; int plen; - if (!op->dev.of_match) + match = of_match_device(mpc_i2c_of_match, &op->dev); + if (!match) return -EINVAL; i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); @@ -605,8 +608,8 @@ static int __devinit fsl_i2c_probe(struct platform_device *op) clock = *prop; } - if (op->dev.of_match->data) { - struct mpc_i2c_data *data = op->dev.of_match->data; + if (match->data) { + struct mpc_i2c_data *data = match->data; data->setup(op->dev.of_node, i2c, clock, data->prescaler); } else { /* Backwards compatibility */ diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 0eb1515541e7..2dbba163b102 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * * i2c-parport.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2010 Jean Delvare + Copyright (C) 2003-2011 Jean Delvare Based on older i2c-philips-par.c driver Copyright (C) 1995-2000 Simon G. Vogl @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "i2c-parport.h" /* ----- Device list ------------------------------------------------------ */ @@ -43,10 +45,11 @@ struct i2c_par { struct i2c_algo_bit_data algo_data; struct i2c_smbus_alert_setup alert_data; struct i2c_client *ara; - struct i2c_par *next; + struct list_head node; }; -static struct i2c_par *adapter_list; +static LIST_HEAD(adapter_list); +static DEFINE_MUTEX(adapter_list_lock); /* ----- Low-level parallel port access ----------------------------------- */ @@ -228,8 +231,9 @@ static void i2c_parport_attach (struct parport *port) } /* Add the new adapter to the list */ - adapter->next = adapter_list; - adapter_list = adapter; + mutex_lock(&adapter_list_lock); + list_add_tail(&adapter->node, &adapter_list); + mutex_unlock(&adapter_list_lock); return; ERROR1: @@ -241,11 +245,11 @@ static void i2c_parport_attach (struct parport *port) static void i2c_parport_detach (struct parport *port) { - struct i2c_par *adapter, *prev; + struct i2c_par *adapter, *_n; /* Walk the list */ - for (prev = NULL, adapter = adapter_list; adapter; - prev = adapter, adapter = adapter->next) { + mutex_lock(&adapter_list_lock); + list_for_each_entry_safe(adapter, _n, &adapter_list, node) { if (adapter->pdev->port == port) { if (adapter->ara) { parport_disable_irq(port); @@ -259,14 +263,11 @@ static void i2c_parport_detach (struct parport *port) parport_release(adapter->pdev); parport_unregister_device(adapter->pdev); - if (prev) - prev->next = adapter->next; - else - adapter_list = adapter->next; + list_del(&adapter->node); kfree(adapter); - return; } } + mutex_unlock(&adapter_list_lock); } static struct parport_driver i2c_parport_driver = { diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index a97e3fec8148..04be9f82e14b 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -65,7 +65,7 @@ static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) jiffies, expires); timer->expires = jiffies + expires; - timer->data = (unsigned long)&alg_data; + timer->data = (unsigned long)alg_data; add_timer(timer); } diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index fd1e11799137..a5ec5a7cb381 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1782,7 +1782,6 @@ static int ide_cd_probe(ide_drive_t *drive) ide_cd_read_toc(drive, &sense); g->fops = &idecd_ops; g->flags |= GENHD_FL_REMOVABLE; - g->events = DISK_EVENT_MEDIA_CHANGE; add_disk(g); return 0; diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c index 2a6bc50e8a41..02caa7dd51c8 100644 --- a/drivers/ide/ide-cd_ioctl.c +++ b/drivers/ide/ide-cd_ioctl.c @@ -79,6 +79,12 @@ int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr) return CDS_DRIVE_NOT_READY; } +/* + * ide-cd always generates media changed event if media is missing, which + * makes it impossible to use for proper event reporting, so disk->events + * is cleared to 0 and the following function is used only to trigger + * revalidation and never propagated to userland. + */ unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *cdi, unsigned int clearing, int slot_nr) { diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c index c4ffd4888939..70ea8763567d 100644 --- a/drivers/ide/ide-gd.c +++ b/drivers/ide/ide-gd.c @@ -298,6 +298,12 @@ static unsigned int ide_gd_check_events(struct gendisk *disk, return 0; } + /* + * The following is used to force revalidation on the first open on + * removeable devices, and never gets reported to userland as + * genhd->events is 0. This is intended as removeable ide disk + * can't really detect MEDIA_CHANGE events. + */ ret = drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED; drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED; @@ -413,7 +419,6 @@ static int ide_gd_probe(ide_drive_t *drive) if (drive->dev_flags & IDE_DFLAG_REMOVABLE) g->flags = GENHD_FL_REMOVABLE; g->fops = &ide_gd_ops; - g->events = DISK_EVENT_MEDIA_CHANGE; add_disk(g); return 0; diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index d9d0e13efe47..a5a49a1baae7 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -393,16 +393,6 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev) priv = netdev_priv(dev); priv->phy = phy; - /* - * If the name is a format string the caller wants us to do a - * name allocation. - */ - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto out; - } - wpan_phy_set_dev(phy, &pdev->dev); SET_NETDEV_DEV(dev, &phy->dev); diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 4ffc224faa7f..8e21d457b899 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -185,15 +185,20 @@ static int addr4_resolve(struct sockaddr_in *src_in, __be32 dst_ip = dst_in->sin_addr.s_addr; struct rtable *rt; struct neighbour *neigh; + struct flowi4 fl4; int ret; - rt = ip_route_output(&init_net, dst_ip, src_ip, 0, addr->bound_dev_if); + memset(&fl4, 0, sizeof(fl4)); + fl4.daddr = dst_ip; + fl4.saddr = src_ip; + fl4.flowi4_oif = addr->bound_dev_if; + rt = ip_route_output_key(&init_net, &fl4); if (IS_ERR(rt)) { ret = PTR_ERR(rt); goto out; } src_in->sin_family = AF_INET; - src_in->sin_addr.s_addr = rt->rt_src; + src_in->sin_addr.s_addr = fl4.saddr; if (rt->dst.dev->flags & IFF_LOOPBACK) { ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 5ed9d25d021a..99dde874fbbd 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -148,6 +148,7 @@ struct rdma_id_private { u32 qp_num; u8 srq; u8 tos; + u8 reuseaddr; }; struct cma_multicast { @@ -712,6 +713,21 @@ static inline int cma_any_addr(struct sockaddr *addr) return cma_zero_addr(addr) || cma_loopback_addr(addr); } +static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst) +{ + if (src->sa_family != dst->sa_family) + return -1; + + switch (src->sa_family) { + case AF_INET: + return ((struct sockaddr_in *) src)->sin_addr.s_addr != + ((struct sockaddr_in *) dst)->sin_addr.s_addr; + default: + return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr, + &((struct sockaddr_in6 *) dst)->sin6_addr); + } +} + static inline __be16 cma_port(struct sockaddr *addr) { if (addr->sa_family == AF_INET) @@ -1564,50 +1580,6 @@ static void cma_listen_on_all(struct rdma_id_private *id_priv) mutex_unlock(&lock); } -int rdma_listen(struct rdma_cm_id *id, int backlog) -{ - struct rdma_id_private *id_priv; - int ret; - - id_priv = container_of(id, struct rdma_id_private, id); - if (id_priv->state == CMA_IDLE) { - ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET; - ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr); - if (ret) - return ret; - } - - if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN)) - return -EINVAL; - - id_priv->backlog = backlog; - if (id->device) { - switch (rdma_node_get_transport(id->device->node_type)) { - case RDMA_TRANSPORT_IB: - ret = cma_ib_listen(id_priv); - if (ret) - goto err; - break; - case RDMA_TRANSPORT_IWARP: - ret = cma_iw_listen(id_priv, backlog); - if (ret) - goto err; - break; - default: - ret = -ENOSYS; - goto err; - } - } else - cma_listen_on_all(id_priv); - - return 0; -err: - id_priv->backlog = 0; - cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND); - return ret; -} -EXPORT_SYMBOL(rdma_listen); - void rdma_set_service_type(struct rdma_cm_id *id, int tos) { struct rdma_id_private *id_priv; @@ -2090,6 +2062,25 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, } EXPORT_SYMBOL(rdma_resolve_addr); +int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse) +{ + struct rdma_id_private *id_priv; + unsigned long flags; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + spin_lock_irqsave(&id_priv->lock, flags); + if (id_priv->state == CMA_IDLE) { + id_priv->reuseaddr = reuse; + ret = 0; + } else { + ret = -EINVAL; + } + spin_unlock_irqrestore(&id_priv->lock, flags); + return ret; +} +EXPORT_SYMBOL(rdma_set_reuseaddr); + static void cma_bind_port(struct rdma_bind_list *bind_list, struct rdma_id_private *id_priv) { @@ -2165,41 +2156,71 @@ static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) return -EADDRNOTAVAIL; } -static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) +/* + * Check that the requested port is available. This is called when trying to + * bind to a specific port, or when trying to listen on a bound port. In + * the latter case, the provided id_priv may already be on the bind_list, but + * we still need to check that it's okay to start listening. + */ +static int cma_check_port(struct rdma_bind_list *bind_list, + struct rdma_id_private *id_priv, uint8_t reuseaddr) { struct rdma_id_private *cur_id; - struct sockaddr_in *sin, *cur_sin; - struct rdma_bind_list *bind_list; + struct sockaddr *addr, *cur_addr; struct hlist_node *node; - unsigned short snum; - sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; - snum = ntohs(sin->sin_port); + addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; + if (cma_any_addr(addr) && !reuseaddr) + return -EADDRNOTAVAIL; + + hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { + if (id_priv == cur_id) + continue; + + if ((cur_id->state == CMA_LISTEN) || + !reuseaddr || !cur_id->reuseaddr) { + cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr; + if (cma_any_addr(cur_addr)) + return -EADDRNOTAVAIL; + + if (!cma_addr_cmp(addr, cur_addr)) + return -EADDRINUSE; + } + } + return 0; +} + +static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) +{ + struct rdma_bind_list *bind_list; + unsigned short snum; + int ret; + + snum = ntohs(cma_port((struct sockaddr *) &id_priv->id.route.addr.src_addr)); if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) return -EACCES; bind_list = idr_find(ps, snum); - if (!bind_list) - return cma_alloc_port(ps, id_priv, snum); - - /* - * We don't support binding to any address if anyone is bound to - * a specific address on the same port. - */ - if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)) - return -EADDRNOTAVAIL; - - hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { - if (cma_any_addr((struct sockaddr *) &cur_id->id.route.addr.src_addr)) - return -EADDRNOTAVAIL; - - cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr; - if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr) - return -EADDRINUSE; + if (!bind_list) { + ret = cma_alloc_port(ps, id_priv, snum); + } else { + ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr); + if (!ret) + cma_bind_port(bind_list, id_priv); } + return ret; +} - cma_bind_port(bind_list, id_priv); - return 0; +static int cma_bind_listen(struct rdma_id_private *id_priv) +{ + struct rdma_bind_list *bind_list = id_priv->bind_list; + int ret = 0; + + mutex_lock(&lock); + if (bind_list->owners.first->next) + ret = cma_check_port(bind_list, id_priv, 0); + mutex_unlock(&lock); + return ret; } static int cma_get_port(struct rdma_id_private *id_priv) @@ -2253,6 +2274,56 @@ static int cma_check_linklocal(struct rdma_dev_addr *dev_addr, return 0; } +int rdma_listen(struct rdma_cm_id *id, int backlog) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (id_priv->state == CMA_IDLE) { + ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET; + ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr); + if (ret) + return ret; + } + + if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN)) + return -EINVAL; + + if (id_priv->reuseaddr) { + ret = cma_bind_listen(id_priv); + if (ret) + goto err; + } + + id_priv->backlog = backlog; + if (id->device) { + switch (rdma_node_get_transport(id->device->node_type)) { + case RDMA_TRANSPORT_IB: + ret = cma_ib_listen(id_priv); + if (ret) + goto err; + break; + case RDMA_TRANSPORT_IWARP: + ret = cma_iw_listen(id_priv, backlog); + if (ret) + goto err; + break; + default: + ret = -ENOSYS; + goto err; + } + } else + cma_listen_on_all(id_priv); + + return 0; +err: + id_priv->backlog = 0; + cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND); + return ret; +} +EXPORT_SYMBOL(rdma_listen); + int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) { struct rdma_id_private *id_priv; diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index 2a1e9ae134b4..a9c042345c6f 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -725,7 +725,7 @@ static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv, */ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT); - if (iw_event->status == IW_CM_EVENT_STATUS_ACCEPTED) { + if (iw_event->status == 0) { cm_id_priv->id.local_addr = iw_event->local_addr; cm_id_priv->id.remote_addr = iw_event->remote_addr; cm_id_priv->state = IW_CM_STATE_ESTABLISHED; diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index ec1e9da1488b..b3fa798525b2 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -883,6 +883,13 @@ static int ucma_set_option_id(struct ucma_context *ctx, int optname, } rdma_set_service_type(ctx->cm_id, *((u8 *) optval)); break; + case RDMA_OPTION_ID_REUSEADDR: + if (optlen != sizeof(int)) { + ret = -EINVAL; + break; + } + ret = rdma_set_reuseaddr(ctx->cm_id, *((int *) optval) ? 1 : 0); + break; default: ret = -ENOSYS; } diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 3216bcad7e82..239184138994 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -338,8 +338,9 @@ static struct rtable *find_route(struct t3cdev *dev, __be32 local_ip, __be16 peer_port, u8 tos) { struct rtable *rt; + struct flowi4 fl4; - rt = ip_route_output_ports(&init_net, NULL, peer_ip, local_ip, + rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip, peer_port, local_port, IPPROTO_TCP, tos, 0); if (IS_ERR(rt)) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 9d8dcfab2b38..f660cd04ec2f 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -315,8 +315,9 @@ static struct rtable *find_route(struct c4iw_dev *dev, __be32 local_ip, __be16 peer_port, u8 tos) { struct rtable *rt; + struct flowi4 fl4; - rt = ip_route_output_ports(&init_net, NULL, peer_ip, local_ip, + rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip, peer_port, local_port, IPPROTO_TCP, tos, 0); if (IS_ERR(rt)) @@ -1198,9 +1199,7 @@ static int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) } PDBG("%s ep %p status %d error %d\n", __func__, ep, rpl->status, status2errno(rpl->status)); - ep->com.wr_wait.ret = status2errno(rpl->status); - ep->com.wr_wait.done = 1; - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status)); return 0; } @@ -1234,9 +1233,7 @@ static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb) struct c4iw_listen_ep *ep = lookup_stid(t, stid); PDBG("%s ep %p\n", __func__, ep); - ep->com.wr_wait.ret = status2errno(rpl->status); - ep->com.wr_wait.done = 1; - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status)); return 0; } @@ -1466,7 +1463,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) struct c4iw_qp_attributes attrs; int disconnect = 1; int release = 0; - int closing = 0; + int abort = 0; struct tid_info *t = dev->rdev.lldi.tids; unsigned int tid = GET_TID(hdr); @@ -1492,23 +1489,22 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) * in rdma connection migration (see c4iw_accept_cr()). */ __state_set(&ep->com, CLOSING); - ep->com.wr_wait.done = 1; - ep->com.wr_wait.ret = -ECONNRESET; PDBG("waking up ep %p tid %u\n", ep, ep->hwtid); - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); break; case MPA_REP_SENT: __state_set(&ep->com, CLOSING); - ep->com.wr_wait.done = 1; - ep->com.wr_wait.ret = -ECONNRESET; PDBG("waking up ep %p tid %u\n", ep, ep->hwtid); - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); break; case FPDU_MODE: start_ep_timer(ep); __state_set(&ep->com, CLOSING); - closing = 1; + attrs.next_state = C4IW_QP_STATE_CLOSING; + abort = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, + C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); peer_close_upcall(ep); + disconnect = 1; break; case ABORTING: disconnect = 0; @@ -1536,11 +1532,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) BUG_ON(1); } mutex_unlock(&ep->com.mutex); - if (closing) { - attrs.next_state = C4IW_QP_STATE_CLOSING; - c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, - C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); - } if (disconnect) c4iw_ep_disconnect(ep, 0, GFP_KERNEL); if (release) @@ -1581,9 +1572,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb) /* * Wake up any threads in rdma_init() or rdma_fini(). */ - ep->com.wr_wait.done = 1; - ep->com.wr_wait.ret = -ECONNRESET; - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); mutex_lock(&ep->com.mutex); switch (ep->com.state) { @@ -1710,14 +1699,14 @@ static int terminate(struct c4iw_dev *dev, struct sk_buff *skb) ep = lookup_tid(t, tid); BUG_ON(!ep); - if (ep->com.qp) { + if (ep && ep->com.qp) { printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid, ep->com.qp->wq.sq.qid); attrs.next_state = C4IW_QP_STATE_TERMINATE; c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); } else - printk(KERN_WARNING MOD "TERM received tid %u no qp\n", tid); + printk(KERN_WARNING MOD "TERM received tid %u no ep/qp\n", tid); return 0; } @@ -2296,14 +2285,8 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb) ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff); wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1]; PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret); - if (wr_waitp) { - if (ret) - wr_waitp->ret = -ret; - else - wr_waitp->ret = 0; - wr_waitp->done = 1; - wake_up(&wr_waitp->wait); - } + if (wr_waitp) + c4iw_wake_up(wr_waitp, ret ? -ret : 0); kfree_skb(skb); break; case 2: diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index e29172c2afcb..40a13cc633a3 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -44,7 +44,7 @@ MODULE_DESCRIPTION("Chelsio T4 RDMA Driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRV_VERSION); -static LIST_HEAD(dev_list); +static LIST_HEAD(uld_ctx_list); static DEFINE_MUTEX(dev_mutex); static struct dentry *c4iw_debugfs_root; @@ -370,18 +370,23 @@ static void c4iw_rdev_close(struct c4iw_rdev *rdev) c4iw_destroy_resource(&rdev->resource); } -static void c4iw_remove(struct c4iw_dev *dev) +struct uld_ctx { + struct list_head entry; + struct cxgb4_lld_info lldi; + struct c4iw_dev *dev; +}; + +static void c4iw_remove(struct uld_ctx *ctx) { - PDBG("%s c4iw_dev %p\n", __func__, dev); - list_del(&dev->entry); - if (dev->registered) - c4iw_unregister_device(dev); - c4iw_rdev_close(&dev->rdev); - idr_destroy(&dev->cqidr); - idr_destroy(&dev->qpidr); - idr_destroy(&dev->mmidr); - iounmap(dev->rdev.oc_mw_kva); - ib_dealloc_device(&dev->ibdev); + PDBG("%s c4iw_dev %p\n", __func__, ctx->dev); + c4iw_unregister_device(ctx->dev); + c4iw_rdev_close(&ctx->dev->rdev); + idr_destroy(&ctx->dev->cqidr); + idr_destroy(&ctx->dev->qpidr); + idr_destroy(&ctx->dev->mmidr); + iounmap(ctx->dev->rdev.oc_mw_kva); + ib_dealloc_device(&ctx->dev->ibdev); + ctx->dev = NULL; } static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) @@ -392,7 +397,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) devp = (struct c4iw_dev *)ib_alloc_device(sizeof(*devp)); if (!devp) { printk(KERN_ERR MOD "Cannot allocate ib device\n"); - return NULL; + return ERR_PTR(-ENOMEM); } devp->rdev.lldi = *infop; @@ -402,27 +407,23 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) devp->rdev.oc_mw_kva = ioremap_wc(devp->rdev.oc_mw_pa, devp->rdev.lldi.vr->ocq.size); - printk(KERN_INFO MOD "ocq memory: " + PDBG(KERN_INFO MOD "ocq memory: " "hw_start 0x%x size %u mw_pa 0x%lx mw_kva %p\n", devp->rdev.lldi.vr->ocq.start, devp->rdev.lldi.vr->ocq.size, devp->rdev.oc_mw_pa, devp->rdev.oc_mw_kva); - mutex_lock(&dev_mutex); - ret = c4iw_rdev_open(&devp->rdev); if (ret) { mutex_unlock(&dev_mutex); printk(KERN_ERR MOD "Unable to open CXIO rdev err %d\n", ret); ib_dealloc_device(&devp->ibdev); - return NULL; + return ERR_PTR(ret); } idr_init(&devp->cqidr); idr_init(&devp->qpidr); idr_init(&devp->mmidr); spin_lock_init(&devp->lock); - list_add_tail(&devp->entry, &dev_list); - mutex_unlock(&dev_mutex); if (c4iw_debugfs_root) { devp->debugfs_root = debugfs_create_dir( @@ -435,7 +436,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) static void *c4iw_uld_add(const struct cxgb4_lld_info *infop) { - struct c4iw_dev *dev; + struct uld_ctx *ctx; static int vers_printed; int i; @@ -443,25 +444,33 @@ static void *c4iw_uld_add(const struct cxgb4_lld_info *infop) printk(KERN_INFO MOD "Chelsio T4 RDMA Driver - version %s\n", DRV_VERSION); - dev = c4iw_alloc(infop); - if (!dev) + ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + if (!ctx) { + ctx = ERR_PTR(-ENOMEM); goto out; + } + ctx->lldi = *infop; PDBG("%s found device %s nchan %u nrxq %u ntxq %u nports %u\n", - __func__, pci_name(dev->rdev.lldi.pdev), - dev->rdev.lldi.nchan, dev->rdev.lldi.nrxq, - dev->rdev.lldi.ntxq, dev->rdev.lldi.nports); + __func__, pci_name(ctx->lldi.pdev), + ctx->lldi.nchan, ctx->lldi.nrxq, + ctx->lldi.ntxq, ctx->lldi.nports); - for (i = 0; i < dev->rdev.lldi.nrxq; i++) - PDBG("rxqid[%u] %u\n", i, dev->rdev.lldi.rxq_ids[i]); + mutex_lock(&dev_mutex); + list_add_tail(&ctx->entry, &uld_ctx_list); + mutex_unlock(&dev_mutex); + + for (i = 0; i < ctx->lldi.nrxq; i++) + PDBG("rxqid[%u] %u\n", i, ctx->lldi.rxq_ids[i]); out: - return dev; + return ctx; } static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp, const struct pkt_gl *gl) { - struct c4iw_dev *dev = handle; + struct uld_ctx *ctx = handle; + struct c4iw_dev *dev = ctx->dev; struct sk_buff *skb; const struct cpl_act_establish *rpl; unsigned int opcode; @@ -503,47 +512,49 @@ static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp, static int c4iw_uld_state_change(void *handle, enum cxgb4_state new_state) { - struct c4iw_dev *dev = handle; + struct uld_ctx *ctx = handle; PDBG("%s new_state %u\n", __func__, new_state); switch (new_state) { case CXGB4_STATE_UP: - printk(KERN_INFO MOD "%s: Up\n", pci_name(dev->rdev.lldi.pdev)); - if (!dev->registered) { - int ret; - ret = c4iw_register_device(dev); - if (ret) + printk(KERN_INFO MOD "%s: Up\n", pci_name(ctx->lldi.pdev)); + if (!ctx->dev) { + int ret = 0; + + ctx->dev = c4iw_alloc(&ctx->lldi); + if (!IS_ERR(ctx->dev)) + ret = c4iw_register_device(ctx->dev); + if (IS_ERR(ctx->dev) || ret) printk(KERN_ERR MOD "%s: RDMA registration failed: %d\n", - pci_name(dev->rdev.lldi.pdev), ret); + pci_name(ctx->lldi.pdev), ret); } break; case CXGB4_STATE_DOWN: printk(KERN_INFO MOD "%s: Down\n", - pci_name(dev->rdev.lldi.pdev)); - if (dev->registered) - c4iw_unregister_device(dev); + pci_name(ctx->lldi.pdev)); + if (ctx->dev) + c4iw_remove(ctx); break; case CXGB4_STATE_START_RECOVERY: printk(KERN_INFO MOD "%s: Fatal Error\n", - pci_name(dev->rdev.lldi.pdev)); - dev->rdev.flags |= T4_FATAL_ERROR; - if (dev->registered) { + pci_name(ctx->lldi.pdev)); + if (ctx->dev) { struct ib_event event; + ctx->dev->rdev.flags |= T4_FATAL_ERROR; memset(&event, 0, sizeof event); event.event = IB_EVENT_DEVICE_FATAL; - event.device = &dev->ibdev; + event.device = &ctx->dev->ibdev; ib_dispatch_event(&event); - c4iw_unregister_device(dev); + c4iw_remove(ctx); } break; case CXGB4_STATE_DETACH: printk(KERN_INFO MOD "%s: Detach\n", - pci_name(dev->rdev.lldi.pdev)); - mutex_lock(&dev_mutex); - c4iw_remove(dev); - mutex_unlock(&dev_mutex); + pci_name(ctx->lldi.pdev)); + if (ctx->dev) + c4iw_remove(ctx); break; } return 0; @@ -576,11 +587,13 @@ static int __init c4iw_init_module(void) static void __exit c4iw_exit_module(void) { - struct c4iw_dev *dev, *tmp; + struct uld_ctx *ctx, *tmp; mutex_lock(&dev_mutex); - list_for_each_entry_safe(dev, tmp, &dev_list, entry) { - c4iw_remove(dev); + list_for_each_entry_safe(ctx, tmp, &uld_ctx_list, entry) { + if (ctx->dev) + c4iw_remove(ctx); + kfree(ctx); } mutex_unlock(&dev_mutex); cxgb4_unregister_uld(CXGB4_ULD_RDMA); diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 9f6166f59268..35d2a5dd9bb4 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -131,42 +131,58 @@ static inline int c4iw_num_stags(struct c4iw_rdev *rdev) #define C4IW_WR_TO (10*HZ) +enum { + REPLY_READY = 0, +}; + struct c4iw_wr_wait { wait_queue_head_t wait; - int done; + unsigned long status; int ret; }; static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp) { wr_waitp->ret = 0; - wr_waitp->done = 0; + wr_waitp->status = 0; init_waitqueue_head(&wr_waitp->wait); } +static inline void c4iw_wake_up(struct c4iw_wr_wait *wr_waitp, int ret) +{ + wr_waitp->ret = ret; + set_bit(REPLY_READY, &wr_waitp->status); + wake_up(&wr_waitp->wait); +} + static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev, struct c4iw_wr_wait *wr_waitp, u32 hwtid, u32 qpid, const char *func) { unsigned to = C4IW_WR_TO; - do { + int ret; - wait_event_timeout(wr_waitp->wait, wr_waitp->done, to); - if (!wr_waitp->done) { + do { + ret = wait_event_timeout(wr_waitp->wait, + test_and_clear_bit(REPLY_READY, &wr_waitp->status), to); + if (!ret) { printk(KERN_ERR MOD "%s - Device %s not responding - " "tid %u qpid %u\n", func, pci_name(rdev->lldi.pdev), hwtid, qpid); + if (c4iw_fatal_error(rdev)) { + wr_waitp->ret = -EIO; + break; + } to = to << 2; } - } while (!wr_waitp->done); + } while (!ret); if (wr_waitp->ret) - printk(KERN_WARNING MOD "%s: FW reply %d tid %u qpid %u\n", - pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid); + PDBG("%s: FW reply %d tid %u qpid %u\n", + pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid); return wr_waitp->ret; } - struct c4iw_dev { struct ib_device ibdev; struct c4iw_rdev rdev; @@ -175,9 +191,7 @@ struct c4iw_dev { struct idr qpidr; struct idr mmidr; spinlock_t lock; - struct list_head entry; struct dentry *debugfs_root; - u8 registered; }; static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev) diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index f66dd8bf5128..5b9e4220ca08 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -516,7 +516,6 @@ int c4iw_register_device(struct c4iw_dev *dev) if (ret) goto bail2; } - dev->registered = 1; return 0; bail2: ib_unregister_device(&dev->ibdev); @@ -535,6 +534,5 @@ void c4iw_unregister_device(struct c4iw_dev *dev) c4iw_class_attributes[i]); ib_unregister_device(&dev->ibdev); kfree(dev->ibdev.iwcm); - dev->registered = 0; return; } diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 70a5a3c646da..3b773b05a898 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -214,7 +214,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, V_FW_RI_RES_WR_HOSTFCMODE(0) | /* no host cidx updates */ V_FW_RI_RES_WR_CPRIO(0) | /* don't keep in chip cache */ V_FW_RI_RES_WR_PCIECHN(0) | /* set by uP at ri_init time */ - t4_sq_onchip(&wq->sq) ? F_FW_RI_RES_WR_ONCHIP : 0 | + (t4_sq_onchip(&wq->sq) ? F_FW_RI_RES_WR_ONCHIP : 0) | V_FW_RI_RES_WR_IQID(scq->cqid)); res->u.sqrq.dcaen_to_eqsize = cpu_to_be32( V_FW_RI_RES_WR_DCAEN(0) | @@ -1210,7 +1210,6 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, if (ret) { if (internal) c4iw_get_ep(&qhp->ep->com); - disconnect = abort = 1; goto err; } break; diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index 24af12fc8228..c0221eec8817 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -269,11 +269,8 @@ struct t4_swsqe { static inline pgprot_t t4_pgprot_wc(pgprot_t prot) { -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) || defined(CONFIG_PPC64) return pgprot_writecombine(prot); -#elif defined(CONFIG_PPC64) - return __pgprot((pgprot_val(prot) | _PAGE_NO_CACHE) & - ~(pgprot_t)_PAGE_GUARDED); #else return pgprot_noncached(prot); #endif diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 58c0e417bc30..be24ac726114 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -398,7 +398,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, struct ipath_devdata *dd; unsigned long long addr; u32 bar0 = 0, bar1 = 0; - u8 rev; dd = ipath_alloc_devdata(pdev); if (IS_ERR(dd)) { @@ -540,13 +539,7 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, goto bail_regions; } - ret = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); - if (ret) { - ipath_dev_err(dd, "Failed to read PCI revision ID unit " - "%u: err %d\n", dd->ipath_unit, -ret); - goto bail_regions; /* shouldn't ever happen */ - } - dd->ipath_pcirev = rev; + dd->ipath_pcirev = pdev->revision; #if defined(__powerpc__) /* There isn't a generic way to specify writethrough mappings */ diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 33c7eedaba6c..e74cdf9ef471 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -2563,7 +2563,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) u16 last_ae; u8 original_hw_tcp_state; u8 original_ibqp_state; - enum iw_cm_event_status disconn_status = IW_CM_EVENT_STATUS_OK; + int disconn_status = 0; int issue_disconn = 0; int issue_close = 0; int issue_flush = 0; @@ -2605,7 +2605,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { issue_disconn = 1; if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) - disconn_status = IW_CM_EVENT_STATUS_RESET; + disconn_status = -ECONNRESET; } if (((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) || @@ -2666,7 +2666,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) cm_id->provider_data = nesqp; /* Send up the close complete event */ cm_event.event = IW_CM_EVENT_CLOSE; - cm_event.status = IW_CM_EVENT_STATUS_OK; + cm_event.status = 0; cm_event.provider_data = cm_id->provider_data; cm_event.local_addr = cm_id->local_addr; cm_event.remote_addr = cm_id->remote_addr; @@ -2966,7 +2966,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) nes_add_ref(&nesqp->ibqp); cm_event.event = IW_CM_EVENT_ESTABLISHED; - cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED; + cm_event.status = 0; cm_event.provider_data = (void *)nesqp; cm_event.local_addr = cm_id->local_addr; cm_event.remote_addr = cm_id->remote_addr; @@ -3377,7 +3377,7 @@ static void cm_event_connected(struct nes_cm_event *event) /* notify OF layer we successfully created the requested connection */ cm_event.event = IW_CM_EVENT_CONNECT_REPLY; - cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED; + cm_event.status = 0; cm_event.provider_data = cm_id->provider_data; cm_event.local_addr.sin_family = AF_INET; cm_event.local_addr.sin_port = cm_id->local_addr.sin_port; @@ -3484,7 +3484,7 @@ static void cm_event_reset(struct nes_cm_event *event) nesqp->cm_id = NULL; /* cm_id->provider_data = NULL; */ cm_event.event = IW_CM_EVENT_DISCONNECT; - cm_event.status = IW_CM_EVENT_STATUS_RESET; + cm_event.status = -ECONNRESET; cm_event.provider_data = cm_id->provider_data; cm_event.local_addr = cm_id->local_addr; cm_event.remote_addr = cm_id->remote_addr; @@ -3495,7 +3495,7 @@ static void cm_event_reset(struct nes_cm_event *event) ret = cm_id->event_handler(cm_id, &cm_event); atomic_inc(&cm_closes); cm_event.event = IW_CM_EVENT_CLOSE; - cm_event.status = IW_CM_EVENT_STATUS_OK; + cm_event.status = 0; cm_event.provider_data = cm_id->provider_data; cm_event.local_addr = cm_id->local_addr; cm_event.remote_addr = cm_id->remote_addr; @@ -3534,7 +3534,7 @@ static void cm_event_mpa_req(struct nes_cm_event *event) cm_node, cm_id, jiffies); cm_event.event = IW_CM_EVENT_CONNECT_REQUEST; - cm_event.status = IW_CM_EVENT_STATUS_OK; + cm_event.status = 0; cm_event.provider_data = (void *)cm_node; cm_event.local_addr.sin_family = AF_INET; diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 10d0a5ec9add..96fa9a4cafdf 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2885,9 +2885,8 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) if ((cqe_errv & (NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR | NES_NIC_ERRV_BITS_IPH_ERR | NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) { - if (nesvnic->rx_checksum_disabled == 0) { + if (nesvnic->netdev->features & NETIF_F_RXCSUM) rx_skb->ip_summed = CHECKSUM_UNNECESSARY; - } } else nes_debug(NES_DBG_CQ, "%s: unsuccessfully checksummed TCP or UDP packet." " errv = 0x%X, pkt_type = 0x%X.\n", @@ -2897,7 +2896,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) if ((cqe_errv & (NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_IPH_ERR | NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) { - if (nesvnic->rx_checksum_disabled == 0) { + if (nesvnic->netdev->features & NETIF_F_RXCSUM) { rx_skb->ip_summed = CHECKSUM_UNNECESSARY; /* nes_debug(NES_DBG_CQ, "%s: Reporting successfully checksummed IPv4 packet.\n", nesvnic->netdev->name); */ diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index d2abe07133a5..91594116f947 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -1245,7 +1245,6 @@ struct nes_vnic { u8 next_qp_nic_index; u8 of_device_registered; u8 rdma_enabled; - u8 rx_checksum_disabled; u32 lro_max_aggr; struct net_lro_mgr lro_mgr; struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS]; diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index e96b8fb5d44c..d3a1c41cfd27 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1093,34 +1093,6 @@ static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = { }; #define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset) -/** - * nes_netdev_get_rx_csum - */ -static u32 nes_netdev_get_rx_csum (struct net_device *netdev) -{ - struct nes_vnic *nesvnic = netdev_priv(netdev); - - if (nesvnic->rx_checksum_disabled) - return 0; - else - return 1; -} - - -/** - * nes_netdev_set_rc_csum - */ -static int nes_netdev_set_rx_csum(struct net_device *netdev, u32 enable) -{ - struct nes_vnic *nesvnic = netdev_priv(netdev); - - if (enable) - nesvnic->rx_checksum_disabled = 0; - else - nesvnic->rx_checksum_disabled = 1; - return 0; -} - /** * nes_netdev_get_sset_count @@ -1521,7 +1493,7 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd et_cmd->maxrxpkt = 511; if (nesadapter->OneG_Mode) { - et_cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(et_cmd, SPEED_1000); if (phy_type == NES_PHY_TYPE_PUMA_1G) { et_cmd->supported = SUPPORTED_1000baseT_Full; et_cmd->advertising = ADVERTISED_1000baseT_Full; @@ -1560,7 +1532,7 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd et_cmd->advertising = ADVERTISED_10000baseT_Full; et_cmd->phy_address = mac_index; } - et_cmd->speed = SPEED_10000; + ethtool_cmd_speed_set(et_cmd, SPEED_10000); et_cmd->autoneg = AUTONEG_DISABLE; return 0; } @@ -1598,19 +1570,10 @@ static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd } -static int nes_netdev_set_flags(struct net_device *netdev, u32 flags) -{ - return ethtool_op_set_flags(netdev, flags, ETH_FLAG_LRO); -} - - static const struct ethtool_ops nes_ethtool_ops = { .get_link = ethtool_op_get_link, .get_settings = nes_netdev_get_settings, .set_settings = nes_netdev_set_settings, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_rx_csum = nes_netdev_get_rx_csum, - .get_sg = ethtool_op_get_sg, .get_strings = nes_netdev_get_strings, .get_sset_count = nes_netdev_get_sset_count, .get_ethtool_stats = nes_netdev_get_ethtool_stats, @@ -1619,13 +1582,6 @@ static const struct ethtool_ops nes_ethtool_ops = { .set_coalesce = nes_netdev_set_coalesce, .get_pauseparam = nes_netdev_get_pauseparam, .set_pauseparam = nes_netdev_set_pauseparam, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_rx_csum = nes_netdev_set_rx_csum, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, - .get_flags = ethtool_op_get_flags, - .set_flags = nes_netdev_set_flags, }; @@ -1727,12 +1683,11 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, netdev->dev_addr[5] = (u8)u64temp; memcpy(netdev->perm_addr, netdev->dev_addr, 6); - if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV)) { - netdev->features |= NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM; - netdev->features |= NETIF_F_GSO | NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM; - } else { - netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - } + netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM; + if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV)) + netdev->hw_features |= NETIF_F_TSO; + netdev->features |= netdev->hw_features; + netdev->hw_features |= NETIF_F_LRO; nes_debug(NES_DBG_INIT, "nesvnic = %p, reported features = 0x%lX, QPid = %d," " nic_index = %d, logical_port = %d, mac_index = %d.\n", diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 26d8018c0a7c..95ca93ceedac 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1484,7 +1484,7 @@ static int nes_destroy_qp(struct ib_qp *ibqp) (nesqp->ibqp_state == IB_QPS_RTR)) && (nesqp->cm_id)) { cm_id = nesqp->cm_id; cm_event.event = IW_CM_EVENT_CONNECT_REPLY; - cm_event.status = IW_CM_EVENT_STATUS_TIMEOUT; + cm_event.status = -ETIMEDOUT; cm_event.local_addr = cm_id->local_addr; cm_event.remote_addr = cm_id->remote_addr; cm_event.private_data = NULL; diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index 7de4b7ebffc5..d8ca0a0b970d 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -1799,7 +1799,7 @@ static int qib_6120_setup_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isn't' set. + * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT); dd->int_counter = 0; /* so we check interrupts work again */ diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 74fe0360bec7..c765a2eb04cf 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -2111,7 +2111,7 @@ static int qib_setup_7220_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isn't' set. + * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT); dd->int_counter = 0; /* so we check interrupts work again */ diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 55de3cf3441c..9f53e68a096a 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -3299,7 +3299,7 @@ static int qib_do_7322_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isn't' set. + * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT | QIB_BADINTR); dd->flags |= QIB_DOING_RESET; @@ -7534,7 +7534,8 @@ static int serdes_7322_init_new(struct qib_pportdata *ppd) ibsd_wr_allchans(ppd, 4, (1 << 10), BMASK(10, 10)); tstart = get_jiffies_64(); while (chan_done && - !time_after64(tstart, tstart + msecs_to_jiffies(500))) { + !time_after64(get_jiffies_64(), + tstart + msecs_to_jiffies(500))) { msleep(20); for (chan = 0; chan < SERDES_CHANS; ++chan) { rxcaldone = ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c index 48b6674cbc49..891cc2ff5f00 100644 --- a/drivers/infiniband/hw/qib/qib_pcie.c +++ b/drivers/infiniband/hw/qib/qib_pcie.c @@ -526,11 +526,8 @@ static int qib_tune_pcie_coalesce(struct qib_devdata *dd) */ devid = parent->device; if (devid >= 0x25e2 && devid <= 0x25fa) { - u8 rev; - /* 5000 P/V/X/Z */ - pci_read_config_byte(parent, PCI_REVISION_ID, &rev); - if (rev <= 0xb2) + if (parent->revision <= 0xb2) bits = 1U << 10; else bits = 7U << 10; diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index ab97f92fc257..7b6985a2e652 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -91,7 +91,6 @@ enum { IPOIB_STOP_REAPER = 7, IPOIB_FLAG_ADMIN_CM = 9, IPOIB_FLAG_UMCAST = 10, - IPOIB_FLAG_CSUM = 11, IPOIB_MAX_BACKOFF_SECONDS = 16, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 93d55806b967..39913a065f99 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1463,8 +1463,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); ipoib_warn(priv, "enabling connected mode " "will cause multicast packet drops\n"); - - dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO); + netdev_update_features(dev); rtnl_unlock(); priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM; @@ -1474,13 +1473,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, if (!strcmp(buf, "datagram\n")) { clear_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); - - if (test_bit(IPOIB_FLAG_CSUM, &priv->flags)) { - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - priv->dev->features |= NETIF_F_GRO; - if (priv->hca_caps & IB_DEVICE_UD_TSO) - dev->features |= NETIF_F_TSO; - } + netdev_update_features(dev); dev_set_mtu(dev, min(priv->mcast_mtu, dev->mtu)); rtnl_unlock(); ipoib_flush_paths(dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c index 19f7f5206f78..29bc7b5724ac 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c @@ -42,32 +42,6 @@ static void ipoib_get_drvinfo(struct net_device *netdev, strncpy(drvinfo->driver, "ipoib", sizeof(drvinfo->driver) - 1); } -static u32 ipoib_get_rx_csum(struct net_device *dev) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - return test_bit(IPOIB_FLAG_CSUM, &priv->flags) && - !test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); -} - -static int ipoib_set_tso(struct net_device *dev, u32 data) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - - if (data) { - if (!test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags) && - (dev->features & NETIF_F_SG) && - (priv->hca_caps & IB_DEVICE_UD_TSO)) { - dev->features |= NETIF_F_TSO; - } else { - ipoib_warn(priv, "can't set TSO on\n"); - return -EOPNOTSUPP; - } - } else - dev->features &= ~NETIF_F_TSO; - - return 0; -} - static int ipoib_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) { @@ -108,8 +82,6 @@ static int ipoib_set_coalesce(struct net_device *dev, static const struct ethtool_ops ipoib_ethtool_ops = { .get_drvinfo = ipoib_get_drvinfo, - .get_rx_csum = ipoib_get_rx_csum, - .set_tso = ipoib_set_tso, .get_coalesce = ipoib_get_coalesce, .set_coalesce = ipoib_set_coalesce, }; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 806d0292dc39..81ae61d68a22 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -292,7 +292,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) dev->stats.rx_bytes += skb->len; skb->dev = dev; - if (test_bit(IPOIB_FLAG_CSUM, &priv->flags) && likely(wc->csum_ok)) + if ((dev->features & NETIF_F_RXCSUM) && likely(wc->csum_ok)) skb->ip_summed = CHECKSUM_UNNECESSARY; napi_gro_receive(&priv->napi, skb); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index aca3b44f7aed..86addca9ddf6 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -171,6 +171,16 @@ static int ipoib_stop(struct net_device *dev) return 0; } +static u32 ipoib_fix_features(struct net_device *dev, u32 features) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + + if (test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags)) + features &= ~(NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + + return features; +} + static int ipoib_change_mtu(struct net_device *dev, int new_mtu) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -970,6 +980,7 @@ static const struct net_device_ops ipoib_netdev_ops = { .ndo_open = ipoib_open, .ndo_stop = ipoib_stop, .ndo_change_mtu = ipoib_change_mtu, + .ndo_fix_features = ipoib_fix_features, .ndo_start_xmit = ipoib_start_xmit, .ndo_tx_timeout = ipoib_timeout, .ndo_set_multicast_list = ipoib_set_mcast_list, @@ -1154,19 +1165,18 @@ int ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca) kfree(device_attr); if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) { - set_bit(IPOIB_FLAG_CSUM, &priv->flags); - priv->dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + priv->dev->hw_features = NETIF_F_SG | + NETIF_F_IP_CSUM | NETIF_F_RXCSUM; + + if (priv->hca_caps & IB_DEVICE_UD_TSO) + priv->dev->hw_features |= NETIF_F_TSO; + + priv->dev->features |= priv->dev->hw_features; } - priv->dev->features |= NETIF_F_GRO; - - if (priv->dev->features & NETIF_F_SG && priv->hca_caps & IB_DEVICE_UD_TSO) - priv->dev->features |= NETIF_F_TSO; - return 0; } - static struct net_device *ipoib_add_port(const char *format, struct ib_device *hca, u8 port) { diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 7f42d3a454d2..88d8e4cb419a 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -39,13 +39,13 @@ struct evdev { }; struct evdev_client { - int head; - int tail; + unsigned int head; + unsigned int tail; spinlock_t buffer_lock; /* protects access to buffer, head and tail */ struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; - int bufsize; + unsigned int bufsize; struct input_event buffer[]; }; @@ -55,16 +55,25 @@ static DEFINE_MUTEX(evdev_table_mutex); static void evdev_pass_event(struct evdev_client *client, struct input_event *event) { - /* - * Interrupts are disabled, just acquire the lock. - * Make sure we don't leave with the client buffer - * "empty" by having client->head == client->tail. - */ + /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); - do { - client->buffer[client->head++] = *event; - client->head &= client->bufsize - 1; - } while (client->head == client->tail); + + client->buffer[client->head++] = *event; + client->head &= client->bufsize - 1; + + if (unlikely(client->head == client->tail)) { + /* + * This effectively "drops" all unconsumed events, leaving + * EV_SYN/SYN_DROPPED plus the newest event in the queue. + */ + client->tail = (client->head - 2) & (client->bufsize - 1); + + client->buffer[client->tail].time = event->time; + client->buffer[client->tail].type = EV_SYN; + client->buffer[client->tail].code = SYN_DROPPED; + client->buffer[client->tail].value = 0; + } + spin_unlock(&client->buffer_lock); if (event->type == EV_SYN) diff --git a/drivers/input/input.c b/drivers/input/input.c index d6e8bd8a851c..ebbceedc92f4 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1746,6 +1746,42 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int } EXPORT_SYMBOL(input_set_capability); +static unsigned int input_estimate_events_per_packet(struct input_dev *dev) +{ + int mt_slots; + int i; + unsigned int events; + + if (dev->mtsize) { + mt_slots = dev->mtsize; + } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) { + mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum - + dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1, + clamp(mt_slots, 2, 32); + } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { + mt_slots = 2; + } else { + mt_slots = 0; + } + + events = mt_slots + 1; /* count SYN_MT_REPORT and SYN_REPORT */ + + for (i = 0; i < ABS_CNT; i++) { + if (test_bit(i, dev->absbit)) { + if (input_is_mt_axis(i)) + events += mt_slots; + else + events++; + } + } + + for (i = 0; i < REL_CNT; i++) + if (test_bit(i, dev->relbit)) + events++; + + return events; +} + #define INPUT_CLEANSE_BITMASK(dev, type, bits) \ do { \ if (!test_bit(EV_##type, dev->evbit)) \ @@ -1793,6 +1829,10 @@ int input_register_device(struct input_dev *dev) /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ input_cleanse_bitmasks(dev); + if (!dev->hint_events_per_packet) + dev->hint_events_per_packet = + input_estimate_events_per_packet(dev); + /* * If delay and period are pre-set by the driver, then autorepeating * is handled by the driver itself and we don't do it in input.c. diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c index 1839194ea987..10bcd4ae5402 100644 --- a/drivers/input/keyboard/atakbd.c +++ b/drivers/input/keyboard/atakbd.c @@ -223,8 +223,9 @@ static int __init atakbd_init(void) return -ENODEV; // need to init core driver if not already done so - if (atari_keyb_init()) - return -ENODEV; + error = atari_keyb_init(); + if (error) + return error; atakbd_dev = input_allocate_device(); if (!atakbd_dev) diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 09bef79d9da1..a26922cf0e84 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -332,18 +332,20 @@ static int __devinit twl4030_kp_program(struct twl4030_keypad *kp) static int __devinit twl4030_kp_probe(struct platform_device *pdev) { struct twl4030_keypad_data *pdata = pdev->dev.platform_data; - const struct matrix_keymap_data *keymap_data = pdata->keymap_data; + const struct matrix_keymap_data *keymap_data; struct twl4030_keypad *kp; struct input_dev *input; u8 reg; int error; - if (!pdata || !pdata->rows || !pdata->cols || + if (!pdata || !pdata->rows || !pdata->cols || !pdata->keymap_data || pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) { dev_err(&pdev->dev, "Invalid platform_data\n"); return -EINVAL; } + keymap_data = pdata->keymap_data; + kp = kzalloc(sizeof(*kp), GFP_KERNEL); input = input_allocate_device(); if (!kp || !input) { diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 7077f9bf5ead..62bae99424e6 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -303,7 +303,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - int val; + int ret, val; switch (backend_state) { case XenbusStateInitialising: @@ -316,6 +316,17 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, case XenbusStateInitWait: InitWait: + ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "feature-abs-pointer", "%d", &val); + if (ret < 0) + val = 0; + if (val) { + ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, + "request-abs-pointer", "1"); + if (ret) + pr_warning("xenkbd: can't request abs-pointer"); + } + xenbus_switch_state(dev, XenbusStateConnected); break; diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c index adf45b3040e9..5c4a692bf73a 100644 --- a/drivers/input/mouse/atarimouse.c +++ b/drivers/input/mouse/atarimouse.c @@ -77,15 +77,15 @@ static void atamouse_interrupt(char *buf) #endif /* only relative events get here */ - dx = buf[1]; - dy = -buf[2]; + dx = buf[1]; + dy = buf[2]; input_report_rel(atamouse_dev, REL_X, dx); input_report_rel(atamouse_dev, REL_Y, dy); - input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x1); + input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x4); input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2); - input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x4); + input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x1); input_sync(atamouse_dev); @@ -108,7 +108,7 @@ static int atamouse_open(struct input_dev *dev) static void atamouse_close(struct input_dev *dev) { ikbd_mouse_disable(); - atari_mouse_interrupt_hook = NULL; + atari_input_mouse_interrupt_hook = NULL; } static int __init atamouse_init(void) @@ -118,8 +118,9 @@ static int __init atamouse_init(void) if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) return -ENODEV; - if (!atari_keyb_init()) - return -ENODEV; + error = atari_keyb_init(); + if (error) + return error; atamouse_dev = input_allocate_device(); if (!atamouse_dev) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index c24946f51256..1de1c19dad30 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -281,17 +281,24 @@ struct ser_req { u8 command; u8 ref_off; u16 scratch; - __be16 sample; struct spi_message msg; struct spi_transfer xfer[6]; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + __be16 sample ____cacheline_aligned; }; struct ads7845_ser_req { u8 command[3]; - u8 pwrdown[3]; - u8 sample[3]; struct spi_message msg; struct spi_transfer xfer[2]; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + u8 sample[3] ____cacheline_aligned; }; static int ads7846_read12_ser(struct device *dev, unsigned command) diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index efa06882de00..45f93d0f5592 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -399,31 +399,34 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv) IRQF_SHARED | IRQF_DISABLED, "h3600_action", &ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n"); err = -EBUSY; - goto fail2; + goto fail1; } if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler, IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", &ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n"); err = -EBUSY; - goto fail3; + goto fail2; } serio_set_drvdata(serio, ts); err = serio_open(serio, drv); if (err) - return err; + goto fail3; //h3600_flite_control(1, 25); /* default brightness */ - input_register_device(ts->dev); + err = input_register_device(ts->dev); + if (err) + goto fail4; return 0; -fail3: free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev); +fail4: serio_close(serio); +fail3: serio_set_drvdata(serio, NULL); + free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev); fail2: free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev); -fail1: serio_set_drvdata(serio, NULL); - input_free_device(input_dev); +fail1: input_free_device(input_dev); kfree(ts); return err; } diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 6ae054f8e0aa..9175d49d2546 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -68,8 +68,23 @@ struct wm831x_ts { unsigned int pd_irq; bool pressure; bool pen_down; + struct work_struct pd_data_work; }; +static void wm831x_pd_data_work(struct work_struct *work) +{ + struct wm831x_ts *wm831x_ts = + container_of(work, struct wm831x_ts, pd_data_work); + + if (wm831x_ts->pen_down) { + enable_irq(wm831x_ts->data_irq); + dev_dbg(wm831x_ts->wm831x->dev, "IRQ PD->DATA done\n"); + } else { + enable_irq(wm831x_ts->pd_irq); + dev_dbg(wm831x_ts->wm831x->dev, "IRQ DATA->PD done\n"); + } +} + static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) { struct wm831x_ts *wm831x_ts = irq_data; @@ -110,6 +125,9 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) } if (!wm831x_ts->pen_down) { + /* Switch from data to pen down */ + dev_dbg(wm831x->dev, "IRQ DATA->PD\n"); + disable_irq_nosync(wm831x_ts->data_irq); /* Don't need data any more */ @@ -128,6 +146,10 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) ABS_PRESSURE, 0); input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0); + + schedule_work(&wm831x_ts->pd_data_work); + } else { + input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); } input_sync(wm831x_ts->input_dev); @@ -141,6 +163,11 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) struct wm831x *wm831x = wm831x_ts->wm831x; int ena = 0; + if (wm831x_ts->pen_down) + return IRQ_HANDLED; + + disable_irq_nosync(wm831x_ts->pd_irq); + /* Start collecting data */ if (wm831x_ts->pressure) ena |= WM831X_TCH_Z_ENA; @@ -149,14 +176,14 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena); - input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); - input_sync(wm831x_ts->input_dev); - wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); wm831x_ts->pen_down = true; - enable_irq(wm831x_ts->data_irq); + + /* Switch from pen down to data */ + dev_dbg(wm831x->dev, "IRQ PD->DATA\n"); + schedule_work(&wm831x_ts->pd_data_work); return IRQ_HANDLED; } @@ -182,13 +209,28 @@ static void wm831x_ts_input_close(struct input_dev *idev) struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); struct wm831x *wm831x = wm831x_ts->wm831x; + /* Shut the controller down, disabling all other functionality too */ wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, - WM831X_TCH_ENA | WM831X_TCH_CVT_ENA | - WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | - WM831X_TCH_Z_ENA, 0); + WM831X_TCH_ENA | WM831X_TCH_X_ENA | + WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 0); - if (wm831x_ts->pen_down) + /* Make sure any pending IRQs are done, the above will prevent + * new ones firing. + */ + synchronize_irq(wm831x_ts->data_irq); + synchronize_irq(wm831x_ts->pd_irq); + + /* Make sure the IRQ completion work is quiesced */ + flush_work_sync(&wm831x_ts->pd_data_work); + + /* If we ended up with the pen down then make sure we revert back + * to pen detection state for the next time we start up. + */ + if (wm831x_ts->pen_down) { disable_irq(wm831x_ts->data_irq); + enable_irq(wm831x_ts->pd_irq); + wm831x_ts->pen_down = false; + } } static __devinit int wm831x_ts_probe(struct platform_device *pdev) @@ -198,7 +240,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent); struct wm831x_touch_pdata *pdata = NULL; struct input_dev *input_dev; - int error; + int error, irqf; if (core_pdata) pdata = core_pdata->touch; @@ -212,6 +254,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) wm831x_ts->wm831x = wm831x; wm831x_ts->input_dev = input_dev; + INIT_WORK(&wm831x_ts->pd_data_work, wm831x_pd_data_work); /* * If we have a direct IRQ use it, otherwise use the interrupt @@ -270,9 +313,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, WM831X_TCH_RATE_MASK, 6); + if (pdata && pdata->data_irqf) + irqf = pdata->data_irqf; + else + irqf = IRQF_TRIGGER_HIGH; + error = request_threaded_irq(wm831x_ts->data_irq, NULL, wm831x_ts_data_irq, - IRQF_ONESHOT, + irqf | IRQF_ONESHOT, "Touchscreen data", wm831x_ts); if (error) { dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n", @@ -281,9 +329,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) } disable_irq(wm831x_ts->data_irq); + if (pdata && pdata->pd_irqf) + irqf = pdata->pd_irqf; + else + irqf = IRQF_TRIGGER_HIGH; + error = request_threaded_irq(wm831x_ts->pd_irq, NULL, wm831x_ts_pen_down_irq, - IRQF_ONESHOT, + irqf | IRQF_ONESHOT, "Touchscreen pen down", wm831x_ts); if (error) { dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n", diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig index a168e8a891be..15c3ffd9d860 100644 --- a/drivers/isdn/capi/Kconfig +++ b/drivers/isdn/capi/Kconfig @@ -33,21 +33,6 @@ config ISDN_CAPI_CAPI20 standardized libcapi20 to access this functionality. You should say Y/M here. -config ISDN_CAPI_CAPIFS_BOOL - bool "CAPI2.0 filesystem support (DEPRECATED)" - depends on ISDN_CAPI_MIDDLEWARE && ISDN_CAPI_CAPI20 - help - This option provides a special file system, similar to /dev/pts with - device nodes for the special ttys established by using the - middleware extension above. - You no longer need this, udev fully replaces it. This feature is - scheduled for removal. - -config ISDN_CAPI_CAPIFS - tristate - depends on ISDN_CAPI_CAPIFS_BOOL - default ISDN_CAPI_CAPI20 - config ISDN_CAPI_CAPIDRV tristate "CAPI2.0 capidrv interface support" depends on ISDN_I4L diff --git a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile index 57123e3e4978..4d5b4b71db1e 100644 --- a/drivers/isdn/capi/Makefile +++ b/drivers/isdn/capi/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_ISDN_CAPI) += kernelcapi.o obj-$(CONFIG_ISDN_CAPI_CAPI20) += capi.o obj-$(CONFIG_ISDN_CAPI_CAPIDRV) += capidrv.o -obj-$(CONFIG_ISDN_CAPI_CAPIFS) += capifs.o # Multipart objects. diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 0d7088367038..e44933d58790 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -38,15 +38,10 @@ #include #include -#include "capifs.h" - MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); -#undef _DEBUG_TTYFUNCS /* call to tty_driver */ -#undef _DEBUG_DATAFLOW /* data flow */ - /* -------- driver information -------------------------------------- */ static DEFINE_MUTEX(capi_mutex); @@ -85,7 +80,6 @@ struct capiminor { struct kref kref; unsigned int minor; - struct dentry *capifs_dentry; struct capi20_appl *ap; u32 ncci; @@ -300,17 +294,8 @@ static void capiminor_free(struct capiminor *mp) static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np) { - struct capiminor *mp; - dev_t device; - - if (!(cdev->userflags & CAPIFLAG_HIGHJACKING)) - return; - - mp = np->minorp = capiminor_alloc(&cdev->ap, np->ncci); - if (mp) { - device = MKDEV(capinc_tty_driver->major, mp->minor); - mp->capifs_dentry = capifs_new_ncci(mp->minor, device); - } + if (cdev->userflags & CAPIFLAG_HIGHJACKING) + np->minorp = capiminor_alloc(&cdev->ap, np->ncci); } static void capincci_free_minor(struct capincci *np) @@ -319,8 +304,6 @@ static void capincci_free_minor(struct capincci *np) struct tty_struct *tty; if (mp) { - capifs_free_ncci(mp->capifs_dentry); - tty = tty_port_tty_get(&mp->port); if (tty) { tty_vhangup(tty); @@ -432,9 +415,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) tty = tty_port_tty_get(&mp->port); if (!tty) { -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: currently no receiver\n"); -#endif + pr_debug("capi: currently no receiver\n"); return -1; } @@ -447,23 +428,17 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) } if (ld->ops->receive_buf == NULL) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n"); -#endif + pr_debug("capi: ldisc has no receive_buf function\n"); /* fatal error, do not requeue */ goto free_skb; } if (mp->ttyinstop) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: recv tty throttled\n"); -#endif + pr_debug("capi: recv tty throttled\n"); goto deref_ldisc; } if (tty->receive_room < datalen) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: no room in tty\n"); -#endif + pr_debug("capi: no room in tty\n"); goto deref_ldisc; } @@ -479,10 +454,8 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) if (errcode == CAPI_NOERROR) { skb_pull(skb, CAPIMSG_LEN(skb->data)); -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", - datahandle, skb->len); -#endif + pr_debug("capi: DATA_B3_RESP %u len=%d => ldisc\n", + datahandle, skb->len); ld->ops->receive_buf(tty, skb->data, NULL, skb->len); } else { printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", @@ -529,9 +502,7 @@ static void handle_minor_send(struct capiminor *mp) return; if (mp->ttyoutstop) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: send: tty stopped\n"); -#endif + pr_debug("capi: send: tty stopped\n"); tty_kref_put(tty); return; } @@ -573,10 +544,8 @@ static void handle_minor_send(struct capiminor *mp) } errcode = capi20_put_message(mp->ap, skb); if (errcode == CAPI_NOERROR) { -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n", - datahandle, len); -#endif + pr_debug("capi: DATA_B3_REQ %u len=%u\n", + datahandle, len); continue; } capiminor_del_ack(mp, datahandle); @@ -650,10 +619,8 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) } if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2); -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n", - datahandle, skb->len-CAPIMSG_LEN(skb->data)); -#endif + pr_debug("capi_signal: DATA_B3_IND %u len=%d\n", + datahandle, skb->len-CAPIMSG_LEN(skb->data)); skb_queue_tail(&mp->inqueue, skb); handle_minor_recv(mp); @@ -661,11 +628,9 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) } else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) { datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4); -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi_signal: DATA_B3_CONF %u 0x%x\n", - datahandle, - CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2)); -#endif + pr_debug("capi_signal: DATA_B3_CONF %u 0x%x\n", + datahandle, + CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2)); kfree_skb(skb); capiminor_del_ack(mp, datahandle); tty = tty_port_tty_get(&mp->port); @@ -1095,9 +1060,7 @@ static int capinc_tty_write(struct tty_struct *tty, struct capiminor *mp = tty->driver_data; struct sk_buff *skb; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count); -#endif + pr_debug("capinc_tty_write(count=%d)\n", count); spin_lock_bh(&mp->outlock); skb = mp->outskb; @@ -1133,9 +1096,7 @@ static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) struct sk_buff *skb; int ret = 1; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_put_char(%u)\n", ch); -#endif + pr_debug("capinc_put_char(%u)\n", ch); spin_lock_bh(&mp->outlock); skb = mp->outskb; @@ -1174,9 +1135,7 @@ static void capinc_tty_flush_chars(struct tty_struct *tty) struct capiminor *mp = tty->driver_data; struct sk_buff *skb; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_flush_chars\n"); -#endif + pr_debug("capinc_tty_flush_chars\n"); spin_lock_bh(&mp->outlock); skb = mp->outskb; @@ -1200,9 +1159,7 @@ static int capinc_tty_write_room(struct tty_struct *tty) room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue); room *= CAPI_MAX_BLKSIZE; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_write_room = %d\n", room); -#endif + pr_debug("capinc_tty_write_room = %d\n", room); return room; } @@ -1210,12 +1167,10 @@ static int capinc_tty_chars_in_buffer(struct tty_struct *tty) { struct capiminor *mp = tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n", - mp->outbytes, mp->nack, - skb_queue_len(&mp->outqueue), - skb_queue_len(&mp->inqueue)); -#endif + pr_debug("capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n", + mp->outbytes, mp->nack, + skb_queue_len(&mp->outqueue), + skb_queue_len(&mp->inqueue)); return mp->outbytes; } @@ -1227,17 +1182,13 @@ static int capinc_tty_ioctl(struct tty_struct *tty, static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios * old) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_set_termios\n"); -#endif + pr_debug("capinc_tty_set_termios\n"); } static void capinc_tty_throttle(struct tty_struct *tty) { struct capiminor *mp = tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_throttle\n"); -#endif + pr_debug("capinc_tty_throttle\n"); mp->ttyinstop = 1; } @@ -1245,9 +1196,7 @@ static void capinc_tty_unthrottle(struct tty_struct *tty) { struct capiminor *mp = tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_unthrottle\n"); -#endif + pr_debug("capinc_tty_unthrottle\n"); mp->ttyinstop = 0; handle_minor_recv(mp); } @@ -1256,9 +1205,7 @@ static void capinc_tty_stop(struct tty_struct *tty) { struct capiminor *mp = tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_stop\n"); -#endif + pr_debug("capinc_tty_stop\n"); mp->ttyoutstop = 1; } @@ -1266,9 +1213,7 @@ static void capinc_tty_start(struct tty_struct *tty) { struct capiminor *mp = tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_start\n"); -#endif + pr_debug("capinc_tty_start\n"); mp->ttyoutstop = 0; handle_minor_send(mp); } @@ -1277,39 +1222,29 @@ static void capinc_tty_hangup(struct tty_struct *tty) { struct capiminor *mp = tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_hangup\n"); -#endif + pr_debug("capinc_tty_hangup\n"); tty_port_hangup(&mp->port); } static int capinc_tty_break_ctl(struct tty_struct *tty, int state) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state); -#endif + pr_debug("capinc_tty_break_ctl(%d)\n", state); return 0; } static void capinc_tty_flush_buffer(struct tty_struct *tty) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_flush_buffer\n"); -#endif + pr_debug("capinc_tty_flush_buffer\n"); } static void capinc_tty_set_ldisc(struct tty_struct *tty) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_set_ldisc\n"); -#endif + pr_debug("capinc_tty_set_ldisc\n"); } static void capinc_tty_send_xchar(struct tty_struct *tty, char ch) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch); -#endif + pr_debug("capinc_tty_send_xchar(%d)\n", ch); } static const struct tty_operations capinc_ops = { @@ -1514,10 +1449,8 @@ static int __init capi_init(void) proc_init(); -#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) - compileinfo = " (middleware+capifs)"; -#elif defined(CONFIG_ISDN_CAPI_MIDDLEWARE) - compileinfo = " (no capifs)"; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + compileinfo = " (middleware)"; #else compileinfo = " (no middleware)"; #endif diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c deleted file mode 100644 index b4faed7fe0d3..000000000000 --- a/drivers/isdn/capi/capifs.c +++ /dev/null @@ -1,239 +0,0 @@ -/* $Id: capifs.c,v 1.1.2.3 2004/01/16 21:09:26 keil Exp $ - * - * Copyright 2000 by Carsten Paeth - * - * Heavily based on devpts filesystem from H. Peter Anvin - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include /* current */ - -#include "capifs.h" - -MODULE_DESCRIPTION("CAPI4Linux: /dev/capi/ filesystem"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------------ */ - -#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N') - -static struct vfsmount *capifs_mnt; -static int capifs_mnt_count; - -static struct { - int setuid; - int setgid; - uid_t uid; - gid_t gid; - umode_t mode; -} config = {.mode = 0600}; - -/* ------------------------------------------------------------------ */ - -static int capifs_remount(struct super_block *s, int *flags, char *data) -{ - int setuid = 0; - int setgid = 0; - uid_t uid = 0; - gid_t gid = 0; - umode_t mode = 0600; - char *this_char; - char *new_opt = kstrdup(data, GFP_KERNEL); - - this_char = NULL; - while ((this_char = strsep(&data, ",")) != NULL) { - int n; - char dummy; - if (!*this_char) - continue; - if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) { - setuid = 1; - uid = n; - } else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) { - setgid = 1; - gid = n; - } else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1) - mode = n & ~S_IFMT; - else { - kfree(new_opt); - printk("capifs: called with bogus options\n"); - return -EINVAL; - } - } - - mutex_lock(&s->s_root->d_inode->i_mutex); - - replace_mount_options(s, new_opt); - config.setuid = setuid; - config.setgid = setgid; - config.uid = uid; - config.gid = gid; - config.mode = mode; - - mutex_unlock(&s->s_root->d_inode->i_mutex); - - return 0; -} - -static const struct super_operations capifs_sops = -{ - .statfs = simple_statfs, - .remount_fs = capifs_remount, - .show_options = generic_show_options, -}; - - -static int -capifs_fill_super(struct super_block *s, void *data, int silent) -{ - struct inode * inode; - - s->s_blocksize = 1024; - s->s_blocksize_bits = 10; - s->s_magic = CAPIFS_SUPER_MAGIC; - s->s_op = &capifs_sops; - s->s_time_gran = 1; - - inode = new_inode(s); - if (!inode) - goto fail; - inode->i_ino = 1; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - inode->i_nlink = 2; - - s->s_root = d_alloc_root(inode); - if (s->s_root) - return 0; - - printk("capifs: get root dentry failed\n"); - iput(inode); -fail: - return -ENOMEM; -} - -static struct dentry *capifs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_single(fs_type, flags, data, capifs_fill_super); -} - -static struct file_system_type capifs_fs_type = { - .owner = THIS_MODULE, - .name = "capifs", - .mount = capifs_mount, - .kill_sb = kill_anon_super, -}; - -static struct dentry *new_ncci(unsigned int number, dev_t device) -{ - struct super_block *s = capifs_mnt->mnt_sb; - struct dentry *root = s->s_root; - struct dentry *dentry; - struct inode *inode; - char name[10]; - int namelen; - - mutex_lock(&root->d_inode->i_mutex); - - namelen = sprintf(name, "%d", number); - dentry = lookup_one_len(name, root, namelen); - if (IS_ERR(dentry)) { - dentry = NULL; - goto unlock_out; - } - - if (dentry->d_inode) { - dput(dentry); - dentry = NULL; - goto unlock_out; - } - - inode = new_inode(s); - if (!inode) { - dput(dentry); - dentry = NULL; - goto unlock_out; - } - - /* config contents is protected by root's i_mutex */ - inode->i_uid = config.setuid ? config.uid : current_fsuid(); - inode->i_gid = config.setgid ? config.gid : current_fsgid(); - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_ino = number + 2; - init_special_inode(inode, S_IFCHR|config.mode, device); - - d_instantiate(dentry, inode); - dget(dentry); - -unlock_out: - mutex_unlock(&root->d_inode->i_mutex); - - return dentry; -} - -struct dentry *capifs_new_ncci(unsigned int number, dev_t device) -{ - struct dentry *dentry; - - if (simple_pin_fs(&capifs_fs_type, &capifs_mnt, &capifs_mnt_count) < 0) - return NULL; - - dentry = new_ncci(number, device); - if (!dentry) - simple_release_fs(&capifs_mnt, &capifs_mnt_count); - - return dentry; -} - -void capifs_free_ncci(struct dentry *dentry) -{ - struct dentry *root = capifs_mnt->mnt_sb->s_root; - struct inode *inode; - - if (!dentry) - return; - - mutex_lock(&root->d_inode->i_mutex); - - inode = dentry->d_inode; - if (inode) { - drop_nlink(inode); - d_delete(dentry); - dput(dentry); - } - dput(dentry); - - mutex_unlock(&root->d_inode->i_mutex); - - simple_release_fs(&capifs_mnt, &capifs_mnt_count); -} - -static int __init capifs_init(void) -{ - return register_filesystem(&capifs_fs_type); -} - -static void __exit capifs_exit(void) -{ - unregister_filesystem(&capifs_fs_type); -} - -EXPORT_SYMBOL(capifs_new_ncci); -EXPORT_SYMBOL(capifs_free_ncci); - -module_init(capifs_init); -module_exit(capifs_exit); diff --git a/drivers/isdn/capi/capifs.h b/drivers/isdn/capi/capifs.h deleted file mode 100644 index e193d1189531..000000000000 --- a/drivers/isdn/capi/capifs.h +++ /dev/null @@ -1,28 +0,0 @@ -/* $Id: capifs.h,v 1.1.2.2 2004/01/16 21:09:26 keil Exp $ - * - * Copyright 2000 by Carsten Paeth - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include - -#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) - -struct dentry *capifs_new_ncci(unsigned int num, dev_t device); -void capifs_free_ncci(struct dentry *dentry); - -#else - -static inline struct dentry *capifs_new_ncci(unsigned int num, dev_t device) -{ - return NULL; -} - -static inline void capifs_free_ncci(struct dentry *dentry) -{ -} - -#endif diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 8a3c5cfc4fea..3913f47ef86d 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -1157,7 +1157,6 @@ static void write_iso_tasklet(unsigned long data) struct urb *urb; int status; struct usb_iso_packet_descriptor *ifd; - int offset; unsigned long flags; int i; struct sk_buff *skb; @@ -1225,7 +1224,6 @@ static void write_iso_tasklet(unsigned long data) * successfully sent * - all following frames are not sent at all */ - offset = done->limit; /* default (no error) */ for (i = 0; i < BAS_NUMFRAMES; i++) { ifd = &urb->iso_frame_desc[i]; if (ifd->status || @@ -1235,9 +1233,6 @@ static void write_iso_tasklet(unsigned long data) i, ifd->actual_length, ifd->length, get_usb_statmsg(ifd->status)); - offset = (ifd->offset + - ifd->actual_length) - % BAS_OUTBUFSIZE; break; } } diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index a14187605f5e..ba74646cf0e4 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -390,12 +390,12 @@ static const struct zsau_resp_t { */ static int cid_of_response(char *s) { - unsigned long cid; + int cid; int rc; if (s[-1] != ';') return 0; /* no CID separator */ - rc = strict_strtoul(s, 10, &cid); + rc = kstrtoint(s, 10, &cid); if (rc) return 0; /* CID not numeric */ if (cid < 1 || cid > 65535) @@ -566,27 +566,19 @@ void gigaset_handle_modem_response(struct cardstate *cs) case RT_ZCAU: event->parameter = -1; if (curarg + 1 < params) { - unsigned long type, value; + u8 type, value; - i = strict_strtoul(argv[curarg++], 16, &type); - j = strict_strtoul(argv[curarg++], 16, &value); - - if (i == 0 && type < 256 && - j == 0 && value < 256) + i = kstrtou8(argv[curarg++], 16, &type); + j = kstrtou8(argv[curarg++], 16, &value); + if (i == 0 && j == 0) event->parameter = (type << 8) | value; } else curarg = params - 1; break; case RT_NUMBER: - event->parameter = -1; - if (curarg < params) { - unsigned long res; - int rc; - - rc = strict_strtoul(argv[curarg++], 10, &res); - if (rc == 0) - event->parameter = res; - } + if (curarg >= params || + kstrtoint(argv[curarg++], 10, &event->parameter)) + event->parameter = -1; gig_dbg(DEBUG_EVENT, "parameter==%d", event->parameter); break; } diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c index 362640120886..7a9894cb4557 100644 --- a/drivers/isdn/hardware/eicon/debug.c +++ b/drivers/isdn/hardware/eicon/debug.c @@ -861,7 +861,7 @@ static int diva_get_idi_adapter_info (IDI_CALL request, dword* serial, dword* lo void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) { diva_os_spin_lock_magic_t old_irql, old_irql1; dword sec, usec, logical, serial, org_mask; - int id, best_id = 0, free_id = -1; + int id, free_id = -1; char tmp[128]; diva_dbg_entry_head_t* pmsg = NULL; int len; @@ -906,7 +906,6 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) { and slot is still free - reuse it */ free_id = id; - best_id = 1; break; } } diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 8c5c563c4f12..a3395986df3d 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -1198,7 +1198,6 @@ static byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, word ch; word i; word Info; - word CIP; byte LinkLayer; API_PARSE * ai; API_PARSE * bp; @@ -1340,7 +1339,6 @@ static byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, add_s(plci,BC,&parms[6]); add_s(plci,LLC,&parms[7]); add_s(plci,HLC,&parms[8]); - CIP = GET_WORD(parms[0].info); if (a->Info_Mask[appl->Id-1] & 0x200) { /* early B3 connect (CIP mask bit 9) no release after a disc */ @@ -4830,7 +4828,6 @@ static void sig_ind(PLCI *plci) dword x_Id; dword Id; dword rId; - word Number = 0; word i; word cip; dword cip_mask; @@ -5106,7 +5103,7 @@ static void sig_ind(PLCI *plci) } } - if(plci->appl) Number = plci->appl->Number++; + if(plci->appl) plci->appl->Number++; switch(plci->Sig.Ind) { /* Response to Get_Supported_Services request */ @@ -5894,7 +5891,6 @@ static void sig_ind(PLCI *plci) break; case TEL_CTRL: - Number = 0; ie = multi_fac_parms[0]; /* inspect the facility hook indications */ if(plci->State==ADVANCED_VOICE_SIG && ie[0]){ switch (ie[1]&0x91) { @@ -10119,14 +10115,12 @@ static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI static void dtmf_confirmation (dword Id, PLCI *plci) { - word Info; word i; byte result[4]; dbug (1, dprintf ("[%06lx] %s,%d: dtmf_confirmation", UnMapId (Id), (char *)(FILE_), __LINE__)); - Info = GOOD; result[0] = 2; PUT_WORD (&result[1], DTMF_SUCCESS); if (plci->dtmf_send_requests != 0) @@ -11520,13 +11514,12 @@ static word mixer_restore_config (dword Id, PLCI *plci, byte Rc) static void mixer_command (dword Id, PLCI *plci, byte Rc) { DIVA_CAPI_ADAPTER *a; - word i, internal_command, Info; + word i, internal_command; dbug (1, dprintf ("[%06lx] %s,%d: mixer_command %02x %04x %04x", UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command, plci->li_cmd)); - Info = GOOD; a = plci->adapter; internal_command = plci->internal_command; plci->internal_command = 0; @@ -11550,7 +11543,6 @@ static void mixer_command (dword Id, PLCI *plci, byte Rc) { dbug (1, dprintf ("[%06lx] %s,%d: Load mixer failed", UnMapId (Id), (char *)(FILE_), __LINE__)); - Info = _FACILITY_NOT_SUPPORTED; break; } if (plci->internal_command) @@ -11592,7 +11584,6 @@ static void mixer_command (dword Id, PLCI *plci, byte Rc) } while ((plci->li_plci_b_write_pos != plci->li_plci_b_req_pos) && !(plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG)); } - Info = _FACILITY_NOT_SUPPORTED; break; } if (plci->internal_command) @@ -11610,7 +11601,6 @@ static void mixer_command (dword Id, PLCI *plci, byte Rc) { dbug (1, dprintf ("[%06lx] %s,%d: Unload mixer failed", UnMapId (Id), (char *)(FILE_), __LINE__)); - Info = _FACILITY_NOT_SUPPORTED; break; } if (plci->internal_command) @@ -12448,13 +12438,11 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI static void mixer_indication_coefs_set (dword Id, PLCI *plci) { dword d; - DIVA_CAPI_ADAPTER *a; byte result[12]; dbug (1, dprintf ("[%06lx] %s,%d: mixer_indication_coefs_set", UnMapId (Id), (char *)(FILE_), __LINE__)); - a = plci->adapter; if (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos) { do @@ -14111,13 +14099,11 @@ static void select_b_command (dword Id, PLCI *plci, byte Rc) static void fax_connect_ack_command (dword Id, PLCI *plci, byte Rc) { - word Info; word internal_command; dbug (1, dprintf ("[%06lx] %s,%d: fax_connect_ack_command %02x %04x", UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); - Info = GOOD; internal_command = plci->internal_command; plci->internal_command = 0; switch (internal_command) @@ -14160,13 +14146,11 @@ static void fax_connect_ack_command (dword Id, PLCI *plci, byte Rc) static void fax_edata_ack_command (dword Id, PLCI *plci, byte Rc) { - word Info; word internal_command; dbug (1, dprintf ("[%06lx] %s,%d: fax_edata_ack_command %02x %04x", UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); - Info = GOOD; internal_command = plci->internal_command; plci->internal_command = 0; switch (internal_command) @@ -14395,13 +14379,11 @@ static void rtp_connect_b3_req_command (dword Id, PLCI *plci, byte Rc) static void rtp_connect_b3_res_command (dword Id, PLCI *plci, byte Rc) { - word Info; word internal_command; dbug (1, dprintf ("[%06lx] %s,%d: rtp_connect_b3_res_command %02x %04x", UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); - Info = GOOD; internal_command = plci->internal_command; plci->internal_command = 0; switch (internal_command) @@ -14423,7 +14405,6 @@ static void rtp_connect_b3_res_command (dword Id, PLCI *plci, byte Rc) { dbug (1, dprintf ("[%06lx] %s,%d: RTP setting connect resp info failed %02x", UnMapId (Id), (char *)(FILE_), __LINE__, Rc)); - Info = _WRONG_STATE; break; } if (plci_nl_busy (plci)) diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 4343abac0b13..b01a7be1300f 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -405,7 +405,7 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, u_char *bdata, int count) { u_char *ptr, *ptr1, new_f2; - int total, maxlen, new_z2; + int maxlen, new_z2; struct zt *zp; if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) @@ -431,7 +431,6 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, printk(KERN_WARNING "HFCPCI: receive out of memory\n"); return; } - total = count; count -= 3; ptr = skb_put(bch->rx_skb, count); @@ -968,7 +967,6 @@ static void ph_state_nt(struct dchannel *dch) { struct hfc_pci *hc = dch->hw; - u_char val; if (dch->debug) printk(KERN_DEBUG "%s: NT newstate %x\n", @@ -982,7 +980,7 @@ ph_state_nt(struct dchannel *dch) hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); /* Clear already pending ints */ - val = Read_hfc(hc, HFCPCI_INT_S1); + (void) Read_hfc(hc, HFCPCI_INT_S1); Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); udelay(10); Write_hfc(hc, HFCPCI_STATES, 4); diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 8700474747e8..3ccbff13eaf2 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -118,14 +118,12 @@ static void ctrl_complete(struct urb *urb) { struct hfcsusb *hw = (struct hfcsusb *) urb->context; - struct ctrl_buf *buf; if (debug & DBG_HFC_CALL_TRACE) printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); urb->dev = hw->dev; if (hw->ctrl_cnt) { - buf = &hw->ctrl_buff[hw->ctrl_out_idx]; hw->ctrl_cnt--; /* decrement actual count */ if (++hw->ctrl_out_idx >= HFC_CTRL_BUFSIZE) hw->ctrl_out_idx = 0; /* pointer wrap */ @@ -1726,7 +1724,6 @@ hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel) static int setup_hfcsusb(struct hfcsusb *hw) { - int err; u_char b; if (debug & DBG_HFC_CALL_TRACE) @@ -1745,7 +1742,7 @@ setup_hfcsusb(struct hfcsusb *hw) } /* first set the needed config, interface and alternate */ - err = usb_set_interface(hw->dev, hw->if_used, hw->alt_used); + (void) usb_set_interface(hw->dev, hw->if_used, hw->alt_used); hw->led_state = 0; diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c index 85a8fd8dd0b7..21cbbe1d5563 100644 --- a/drivers/isdn/hisax/arcofi.c +++ b/drivers/isdn/hisax/arcofi.c @@ -30,8 +30,6 @@ add_arcofi_timer(struct IsdnCardState *cs) { static void send_arcofi(struct IsdnCardState *cs) { - u_char val; - add_arcofi_timer(cs); cs->dc.isac.mon_txp = 0; cs->dc.isac.mon_txc = cs->dc.isac.arcofi_list->len; @@ -45,7 +43,7 @@ send_arcofi(struct IsdnCardState *cs) { cs->dc.isac.mocr &= 0x0f; cs->dc.isac.mocr |= 0xa0; cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - val = cs->readisac(cs, ISAC_MOSR); + (void) cs->readisac(cs, ISAC_MOSR); cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); cs->dc.isac.mocr |= 0x10; cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index 496d477af0f8..9e5e87be756b 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -129,12 +129,10 @@ static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) static int __devinit elsa_cs_config(struct pcmcia_device *link) { - local_info_t *dev; int i; IsdnCard_t icard; dev_dbg(&link->dev, "elsa_config(0x%p)\n", link); - dev = link->priv; link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c index cbda3790a10d..3fa9f6171095 100644 --- a/drivers/isdn/hisax/elsa_ser.c +++ b/drivers/isdn/hisax/elsa_ser.c @@ -109,11 +109,10 @@ static void change_speed(struct IsdnCardState *cs, int baud) { int quot = 0, baud_base; unsigned cval, fcr = 0; - int bits; /* byte size and parity */ - cval = 0x03; bits = 10; + cval = 0x03; /* Determine divisor based on baud rate */ baud_base = BASE_BAUD; quot = baud_base / baud; diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index ed9527aa5f2c..f407de0e006d 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -258,11 +258,9 @@ static void ctrl_complete(struct urb *urb) { hfcusb_data *hfc = (hfcusb_data *) urb->context; - ctrl_buft *buf; urb->dev = hfc->dev; if (hfc->ctrl_cnt) { - buf = &hfc->ctrl_buff[hfc->ctrl_out_idx]; hfc->ctrl_cnt--; /* decrement actual count */ if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE) hfc->ctrl_out_idx = 0; /* pointer wrap */ @@ -1097,7 +1095,7 @@ static int hfc_usb_init(hfcusb_data * hfc) { usb_fifo *fifo; - int i, err; + int i; u_char b; struct hisax_b_if *p_b_if[2]; @@ -1112,7 +1110,7 @@ hfc_usb_init(hfcusb_data * hfc) } /* first set the needed config, interface and alternate */ - err = usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used); + usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used); /* do Chip reset */ write_usb(hfc, HFCUSB_CIRM, 8); diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c index 332104103e18..690840444184 100644 --- a/drivers/isdn/hisax/ipacx.c +++ b/drivers/isdn/hisax/ipacx.c @@ -96,7 +96,7 @@ dch_l2l1(struct PStack *st, int pr, void *arg) { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; - u_char cda1_cr, cda2_cr; + u_char cda1_cr; switch (pr) { case (PH_DATA |REQUEST): @@ -163,7 +163,7 @@ dch_l2l1(struct PStack *st, int pr, void *arg) cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1 cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1 cda1_cr = cs->readisac(cs, IPACX_CDA1_CR); - cda2_cr = cs->readisac(cs, IPACX_CDA2_CR); + (void) cs->readisac(cs, IPACX_CDA2_CR); if ((long)arg &1) { // loop B1 cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x0a); } diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c index ea8f840871d0..a06cea09158b 100644 --- a/drivers/isdn/hisax/jade.c +++ b/drivers/isdn/hisax/jade.c @@ -23,10 +23,9 @@ int JadeVersion(struct IsdnCardState *cs, char *s) { - int ver,i; + int ver; int to = 50; cs->BC_Write_Reg(cs, -1, 0x50, 0x19); - i=0; while (to) { udelay(1); ver = cs->BC_Read_Reg(cs, -1, 0x60); diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index 8e2fd02ecce0..b0d9ab1f21c0 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -2943,7 +2943,7 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb) static void dss1up(struct PStack *st, int pr, void *arg) { - int i, mt, cr, cause, callState; + int i, mt, cr, callState; char *ptr; u_char *p; struct sk_buff *skb = arg; @@ -3034,12 +3034,10 @@ dss1up(struct PStack *st, int pr, void *arg) return; } } else if (mt == MT_STATUS) { - cause = 0; if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { ptr++; if (*ptr++ == 2) ptr++; - cause = *ptr & 0x7f; } callState = 0; if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c index 7b229c0ce115..092dcbb39d94 100644 --- a/drivers/isdn/hisax/l3ni1.c +++ b/drivers/isdn/hisax/l3ni1.c @@ -2883,7 +2883,7 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb) static void ni1up(struct PStack *st, int pr, void *arg) { - int i, mt, cr, cause, callState; + int i, mt, cr, callState; char *ptr; u_char *p; struct sk_buff *skb = arg; @@ -2986,12 +2986,10 @@ ni1up(struct PStack *st, int pr, void *arg) return; } } else if (mt == MT_STATUS) { - cause = 0; if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { ptr++; if (*ptr++ == 2) ptr++; - cause = *ptr & 0x7f; } callState = 0; if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h index 64f78a8c28c5..b9054cb7a0da 100644 --- a/drivers/isdn/hisax/st5481.h +++ b/drivers/isdn/hisax/st5481.h @@ -377,7 +377,6 @@ struct st5481_bcs { }; struct st5481_adapter { - struct list_head list; int number_of_leds; struct usb_device *usb_dev; struct hisax_d_if hisax_d_if; diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c index 13751237bfcd..9f7fd18ff773 100644 --- a/drivers/isdn/hisax/st5481_init.c +++ b/drivers/isdn/hisax/st5481_init.c @@ -46,8 +46,6 @@ module_param(debug, int, 0); #endif int st5481_debug; -static LIST_HEAD(adapter_list); - /* ====================================================================== * registration/deregistration with the USB layer */ @@ -86,7 +84,6 @@ static int probe_st5481(struct usb_interface *intf, adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; adapter->bcs[i].b_if.ifc.l2l1 = st5481_b_l2l1; } - list_add(&adapter->list, &adapter_list); retval = st5481_setup_usb(adapter); if (retval < 0) @@ -125,6 +122,7 @@ static int probe_st5481(struct usb_interface *intf, err_usb: st5481_release_usb(adapter); err: + kfree(adapter); return -EIO; } @@ -142,8 +140,6 @@ static void disconnect_st5481(struct usb_interface *intf) if (!adapter) return; - list_del(&adapter->list); - st5481_stop(adapter); st5481_release_b(&adapter->bcs[1]); st5481_release_b(&adapter->bcs[0]); diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index aa25e183bf79..360f9ec7c802 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -111,12 +111,10 @@ static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) static int __devinit teles_cs_config(struct pcmcia_device *link) { - local_info_t *dev; int i; IsdnCard_t icard; dev_dbg(&link->dev, "teles_config(0x%p)\n", link); - dev = link->priv; i = pcmcia_loop_config(link, teles_cs_configcheck, NULL); if (i != 0) diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index 2ee93d04b2dd..236cc7dadfd0 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -155,7 +155,6 @@ put_log_buffer(hysdn_card * card, char *cp) static ssize_t hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t * off) { - unsigned long u = 0; int rc; unsigned char valbuf[128]; hysdn_card *card = file->private_data; @@ -167,12 +166,10 @@ hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t valbuf[count] = 0; /* terminating 0 */ - rc = strict_strtoul(valbuf, 0, &u); - - if (rc == 0) { - card->debug_flags = u; /* remember debug flags */ - hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags); - } + rc = kstrtoul(valbuf, 0, &card->debug_flags); + if (rc < 0) + return rc; + hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags); return (count); } /* hysdn_log_write */ diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 15632bd2f643..6ed82add6ffa 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -399,13 +399,8 @@ isdn_all_eaz(int di, int ch) #include static int -isdn_capi_rec_hl_msg(capi_msg *cm) { - - int di; - int ch; - - di = (cm->adr.Controller & 0x7f) -1; - ch = isdn_dc2minor(di, (cm->adr.Controller>>8)& 0x7f); +isdn_capi_rec_hl_msg(capi_msg *cm) +{ switch(cm->Command) { case CAPI_FACILITY: /* in the moment only handled in tty */ @@ -1278,7 +1273,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) uint minor = iminor(file->f_path.dentry->d_inode); isdn_ctrl c; int drvidx; - int chidx; int ret; int i; char __user *p; @@ -1340,7 +1334,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) drvidx = isdn_minor2drv(minor); if (drvidx < 0) return -ENODEV; - chidx = isdn_minor2chan(minor); if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; return 0; diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 2a7d17c19489..97988111e45a 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1678,7 +1678,6 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) u32 your_seq; __be32 local; __be32 *addr, *mask; - u16 unused; if (skb->len < 14) return; @@ -1722,7 +1721,6 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) lp->cisco_last_slarp_in = jiffies; my_seq = be32_to_cpup((__be32 *)(p + 0)); your_seq = be32_to_cpup((__be32 *)(p + 4)); - unused = be16_to_cpup((__be16 *)(p + 8)); p += 10; lp->cisco_yourseq = my_seq; lp->cisco_mineseen = your_seq; diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 607d846ae063..d8504279e502 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -998,7 +998,6 @@ isdn_tty_change_speed(modem_info * info) { uint cflag, cval, - fcr, quot; int i; @@ -1037,7 +1036,6 @@ isdn_tty_change_speed(modem_info * info) cval |= UART_LCR_PARITY; if (!(cflag & PARODD)) cval |= UART_LCR_EPAR; - fcr = 0; /* CTS flow control flag and modem status interrupts */ if (cflag & CRTSCTS) { diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index d0aeb44ee7c0..5bc00156315e 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -1640,7 +1640,7 @@ l2_tei_remove(struct FsmInst *fi, int event, void *arg) } static void -l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_st14_persistent_da(struct FsmInst *fi, int event, void *arg) { struct layer2 *l2 = fi->userdata; struct sk_buff *skb = arg; @@ -1654,7 +1654,7 @@ l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg) } static void -l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_st5_persistent_da(struct FsmInst *fi, int event, void *arg) { struct layer2 *l2 = fi->userdata; struct sk_buff *skb = arg; @@ -1671,7 +1671,7 @@ l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) } static void -l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_st6_persistent_da(struct FsmInst *fi, int event, void *arg) { struct layer2 *l2 = fi->userdata; struct sk_buff *skb = arg; @@ -1685,7 +1685,7 @@ l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) } static void -l2_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_persistent_da(struct FsmInst *fi, int event, void *arg) { struct layer2 *l2 = fi->userdata; struct sk_buff *skb = arg; @@ -1829,14 +1829,14 @@ static struct FsmNode L2FnList[] = {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error}, {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest}, {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest}, - {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da}, + {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da}, {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove}, {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove}, - {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da}, - {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da}, - {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da}, - {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da}, - {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, + {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da}, + {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da}, + {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da}, + {ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da}, + {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da}, }; static int diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 7446d8b4282d..8e325227b4c0 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -457,6 +457,9 @@ static int data_sock_getsockopt(struct socket *sock, int level, int optname, if (get_user(len, optlen)) return -EFAULT; + if (len != sizeof(char)) + return -EINVAL; + switch (optname) { case MISDN_TIME_STAMP: if (_pms(sk)->cmask & MISDN_TIME_STAMP) diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c index e7089a1f6cb6..b37e6186d0fa 100644 --- a/drivers/leds/leds-lm3530.c +++ b/drivers/leds/leds-lm3530.c @@ -349,6 +349,7 @@ static const struct i2c_device_id lm3530_id[] = { {LM3530_NAME, 0}, {} }; +MODULE_DEVICE_TABLE(i2c, lm3530_id); static struct i2c_driver lm3530_i2c_driver = { .probe = lm3530_probe, diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig index 0aaa0597a622..34ae49dc557c 100644 --- a/drivers/lguest/Kconfig +++ b/drivers/lguest/Kconfig @@ -5,8 +5,10 @@ config LGUEST ---help--- This is a very simple module which allows you to run multiple instances of the same Linux kernel, using the - "lguest" command found in the Documentation/lguest directory. + "lguest" command found in the Documentation/virtual/lguest + directory. + Note that "lguest" is pronounced to rhyme with "fell quest", - not "rustyvisor". See Documentation/lguest/lguest.txt. + not "rustyvisor". See Documentation/virtual/lguest/lguest.txt. If unsure, say N. If curious, say M. If masochistic, say Y. diff --git a/drivers/lguest/Makefile b/drivers/lguest/Makefile index 7d463c26124f..8ac947c7e7c7 100644 --- a/drivers/lguest/Makefile +++ b/drivers/lguest/Makefile @@ -18,7 +18,7 @@ Mastery: PREFIX=M Beer: @for f in Preparation Guest Drivers Launcher Host Switcher Mastery; do echo "{==- $$f -==}"; make -s $$f; done; echo "{==-==}" Preparation Preparation! Guest Drivers Launcher Host Switcher Mastery: - @sh ../../Documentation/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'` + @sh ../../Documentation/virtual/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'` Puppy: @clear @printf " __ \n (___()'\`;\n /, /\`\n \\\\\\\"--\\\\\\ \n" diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 8b021eb0d48c..6cccd60c594e 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include @@ -2527,12 +2527,9 @@ void pmu_blink(int n) #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) int pmu_sys_suspended; -static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state) +static int pmu_syscore_suspend(void) { - if (state.event != PM_EVENT_SUSPEND || pmu_sys_suspended) - return 0; - - /* Suspend PMU event interrupts */\ + /* Suspend PMU event interrupts */ pmu_suspend(); pmu_sys_suspended = 1; @@ -2544,12 +2541,12 @@ static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state) return 0; } -static int pmu_sys_resume(struct sys_device *sysdev) +static void pmu_syscore_resume(void) { struct adb_request req; if (!pmu_sys_suspended) - return 0; + return; /* Tell PMU we are ready */ pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); @@ -2562,50 +2559,21 @@ static int pmu_sys_resume(struct sys_device *sysdev) /* Resume PMU event interrupts */ pmu_resume(); pmu_sys_suspended = 0; - - return 0; } -#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ - -static struct sysdev_class pmu_sysclass = { - .name = "pmu", +static struct syscore_ops pmu_syscore_ops = { + .suspend = pmu_syscore_suspend, + .resume = pmu_syscore_resume, }; -static struct sys_device device_pmu = { - .cls = &pmu_sysclass, -}; - -static struct sysdev_driver driver_pmu = { -#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) - .suspend = &pmu_sys_suspend, - .resume = &pmu_sys_resume, -#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ -}; - -static int __init init_pmu_sysfs(void) +static int pmu_syscore_register(void) { - int rc; + register_syscore_ops(&pmu_syscore_ops); - rc = sysdev_class_register(&pmu_sysclass); - if (rc) { - printk(KERN_ERR "Failed registering PMU sys class\n"); - return -ENODEV; - } - rc = sysdev_register(&device_pmu); - if (rc) { - printk(KERN_ERR "Failed registering PMU sys device\n"); - return -ENODEV; - } - rc = sysdev_driver_register(&pmu_sysclass, &driver_pmu); - if (rc) { - printk(KERN_ERR "Failed registering PMU sys driver\n"); - return -ENODEV; - } return 0; } - -subsys_initcall(init_pmu_sysfs); +subsys_initcall(pmu_syscore_register); +#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ EXPORT_SYMBOL(pmu_request); EXPORT_SYMBOL(pmu_queue_request); diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 5ef136cdba91..e5d8904fc8f6 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -390,13 +390,6 @@ static int raid_is_congested(struct dm_target_callbacks *cb, int bits) return md_raid5_congested(&rs->md, bits); } -static void raid_unplug(struct dm_target_callbacks *cb) -{ - struct raid_set *rs = container_of(cb, struct raid_set, callbacks); - - md_raid5_kick_device(rs->md.private); -} - /* * Construct a RAID4/5/6 mapping: * Args: @@ -487,7 +480,6 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) } rs->callbacks.congested_fn = raid_is_congested; - rs->callbacks.unplug_fn = raid_unplug; dm_table_add_target_callbacks(ti->table, &rs->callbacks); return 0; diff --git a/drivers/md/md.c b/drivers/md/md.c index b12b3776c0c0..7d6f7f18a920 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -447,48 +447,59 @@ EXPORT_SYMBOL(md_flush_request); /* Support for plugging. * This mirrors the plugging support in request_queue, but does not - * require having a whole queue + * require having a whole queue or request structures. + * We allocate an md_plug_cb for each md device and each thread it gets + * plugged on. This links tot the private plug_handle structure in the + * personality data where we keep a count of the number of outstanding + * plugs so other code can see if a plug is active. */ -static void plugger_work(struct work_struct *work) -{ - struct plug_handle *plug = - container_of(work, struct plug_handle, unplug_work); - plug->unplug_fn(plug); -} -static void plugger_timeout(unsigned long data) -{ - struct plug_handle *plug = (void *)data; - kblockd_schedule_work(NULL, &plug->unplug_work); -} -void plugger_init(struct plug_handle *plug, - void (*unplug_fn)(struct plug_handle *)) -{ - plug->unplug_flag = 0; - plug->unplug_fn = unplug_fn; - init_timer(&plug->unplug_timer); - plug->unplug_timer.function = plugger_timeout; - plug->unplug_timer.data = (unsigned long)plug; - INIT_WORK(&plug->unplug_work, plugger_work); -} -EXPORT_SYMBOL_GPL(plugger_init); +struct md_plug_cb { + struct blk_plug_cb cb; + mddev_t *mddev; +}; -void plugger_set_plug(struct plug_handle *plug) +static void plugger_unplug(struct blk_plug_cb *cb) { - if (!test_and_set_bit(PLUGGED_FLAG, &plug->unplug_flag)) - mod_timer(&plug->unplug_timer, jiffies + msecs_to_jiffies(3)+1); + struct md_plug_cb *mdcb = container_of(cb, struct md_plug_cb, cb); + if (atomic_dec_and_test(&mdcb->mddev->plug_cnt)) + md_wakeup_thread(mdcb->mddev->thread); + kfree(mdcb); } -EXPORT_SYMBOL_GPL(plugger_set_plug); -int plugger_remove_plug(struct plug_handle *plug) +/* Check that an unplug wakeup will come shortly. + * If not, wakeup the md thread immediately + */ +int mddev_check_plugged(mddev_t *mddev) { - if (test_and_clear_bit(PLUGGED_FLAG, &plug->unplug_flag)) { - del_timer(&plug->unplug_timer); - return 1; - } else + struct blk_plug *plug = current->plug; + struct md_plug_cb *mdcb; + + if (!plug) return 0; -} -EXPORT_SYMBOL_GPL(plugger_remove_plug); + list_for_each_entry(mdcb, &plug->cb_list, cb.list) { + if (mdcb->cb.callback == plugger_unplug && + mdcb->mddev == mddev) { + /* Already on the list, move to top */ + if (mdcb != list_first_entry(&plug->cb_list, + struct md_plug_cb, + cb.list)) + list_move(&mdcb->cb.list, &plug->cb_list); + return 1; + } + } + /* Not currently on the callback list */ + mdcb = kmalloc(sizeof(*mdcb), GFP_ATOMIC); + if (!mdcb) + return 0; + + mdcb->mddev = mddev; + mdcb->cb.callback = plugger_unplug; + atomic_inc(&mddev->plug_cnt); + list_add(&mdcb->cb.list, &plug->cb_list); + return 1; +} +EXPORT_SYMBOL_GPL(mddev_check_plugged); static inline mddev_t *mddev_get(mddev_t *mddev) { @@ -538,6 +549,7 @@ void mddev_init(mddev_t *mddev) atomic_set(&mddev->active, 1); atomic_set(&mddev->openers, 0); atomic_set(&mddev->active_io, 0); + atomic_set(&mddev->plug_cnt, 0); spin_lock_init(&mddev->write_lock); atomic_set(&mddev->flush_pending, 0); init_waitqueue_head(&mddev->sb_wait); @@ -3158,6 +3170,7 @@ level_store(mddev_t *mddev, const char *buf, size_t len) mddev->layout = mddev->new_layout; mddev->chunk_sectors = mddev->new_chunk_sectors; mddev->delta_disks = 0; + mddev->degraded = 0; if (mddev->pers->sync_request == NULL) { /* this is now an array without redundancy, so * it must always be in_sync @@ -4723,7 +4736,6 @@ static void md_clean(mddev_t *mddev) mddev->bitmap_info.chunksize = 0; mddev->bitmap_info.daemon_sleep = 0; mddev->bitmap_info.max_write_behind = 0; - mddev->plug = NULL; } static void __md_stop_writes(mddev_t *mddev) @@ -6688,12 +6700,6 @@ int md_allow_write(mddev_t *mddev) } EXPORT_SYMBOL_GPL(md_allow_write); -void md_unplug(mddev_t *mddev) -{ - if (mddev->plug) - mddev->plug->unplug_fn(mddev->plug); -} - #define SYNC_MARKS 10 #define SYNC_MARK_STEP (3*HZ) void md_do_sync(mddev_t *mddev) diff --git a/drivers/md/md.h b/drivers/md/md.h index 52b407369e13..0b1fd3f1d85b 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -29,26 +29,6 @@ typedef struct mddev_s mddev_t; typedef struct mdk_rdev_s mdk_rdev_t; -/* generic plugging support - like that provided with request_queue, - * but does not require a request_queue - */ -struct plug_handle { - void (*unplug_fn)(struct plug_handle *); - struct timer_list unplug_timer; - struct work_struct unplug_work; - unsigned long unplug_flag; -}; -#define PLUGGED_FLAG 1 -void plugger_init(struct plug_handle *plug, - void (*unplug_fn)(struct plug_handle *)); -void plugger_set_plug(struct plug_handle *plug); -int plugger_remove_plug(struct plug_handle *plug); -static inline void plugger_flush(struct plug_handle *plug) -{ - del_timer_sync(&plug->unplug_timer); - cancel_work_sync(&plug->unplug_work); -} - /* * MD's 'extended' device */ @@ -199,6 +179,9 @@ struct mddev_s int delta_disks, new_level, new_layout; int new_chunk_sectors; + atomic_t plug_cnt; /* If device is expecting + * more bios soon. + */ struct mdk_thread_s *thread; /* management thread */ struct mdk_thread_s *sync_thread; /* doing resync or reconstruct */ sector_t curr_resync; /* last block scheduled */ @@ -336,7 +319,6 @@ struct mddev_s struct list_head all_mddevs; struct attribute_group *to_remove; - struct plug_handle *plug; /* if used by personality */ struct bio_set *bio_set; @@ -516,7 +498,6 @@ extern int md_integrity_register(mddev_t *mddev); extern void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev); extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); extern void restore_bitmap_write_access(struct file *file); -extern void md_unplug(mddev_t *mddev); extern void mddev_init(mddev_t *mddev); extern int md_run(mddev_t *mddev); @@ -530,4 +511,5 @@ extern struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask, mddev_t *mddev); extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, mddev_t *mddev); +extern int mddev_check_plugged(mddev_t *mddev); #endif /* _MD_MD_H */ diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index c2a21ae56d97..2b7a7ff401dc 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -565,12 +565,6 @@ static void flush_pending_writes(conf_t *conf) spin_unlock_irq(&conf->device_lock); } -static void md_kick_device(mddev_t *mddev) -{ - blk_flush_plug(current); - md_wakeup_thread(mddev->thread); -} - /* Barriers.... * Sometimes we need to suspend IO while we do something else, * either some resync/recovery, or reconfigure the array. @@ -600,7 +594,7 @@ static void raise_barrier(conf_t *conf) /* Wait until no block IO is waiting */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_waiting, - conf->resync_lock, md_kick_device(conf->mddev)); + conf->resync_lock, ); /* block any new IO from starting */ conf->barrier++; @@ -608,7 +602,7 @@ static void raise_barrier(conf_t *conf) /* Now wait for all pending IO to complete */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_pending && conf->barrier < RESYNC_DEPTH, - conf->resync_lock, md_kick_device(conf->mddev)); + conf->resync_lock, ); spin_unlock_irq(&conf->resync_lock); } @@ -630,7 +624,7 @@ static void wait_barrier(conf_t *conf) conf->nr_waiting++; wait_event_lock_irq(conf->wait_barrier, !conf->barrier, conf->resync_lock, - md_kick_device(conf->mddev)); + ); conf->nr_waiting--; } conf->nr_pending++; @@ -666,8 +660,7 @@ static void freeze_array(conf_t *conf) wait_event_lock_irq(conf->wait_barrier, conf->nr_pending == conf->nr_queued+1, conf->resync_lock, - ({ flush_pending_writes(conf); - md_kick_device(conf->mddev); })); + flush_pending_writes(conf)); spin_unlock_irq(&conf->resync_lock); } static void unfreeze_array(conf_t *conf) @@ -729,6 +722,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA)); mdk_rdev_t *blocked_rdev; + int plugged; /* * Register the new request and wait if the reconstruction @@ -820,6 +814,8 @@ static int make_request(mddev_t *mddev, struct bio * bio) * inc refcount on their rdev. Record them by setting * bios[x] to bio */ + plugged = mddev_check_plugged(mddev); + disks = conf->raid_disks; retry_write: blocked_rdev = NULL; @@ -925,7 +921,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) /* In case raid1d snuck in to freeze_array */ wake_up(&conf->wait_barrier); - if (do_sync || !bitmap) + if (do_sync || !bitmap || !plugged) md_wakeup_thread(mddev->thread); return 0; @@ -1516,13 +1512,16 @@ static void raid1d(mddev_t *mddev) conf_t *conf = mddev->private; struct list_head *head = &conf->retry_list; mdk_rdev_t *rdev; + struct blk_plug plug; md_check_recovery(mddev); - + + blk_start_plug(&plug); for (;;) { char b[BDEVNAME_SIZE]; - flush_pending_writes(conf); + if (atomic_read(&mddev->plug_cnt) == 0) + flush_pending_writes(conf); spin_lock_irqsave(&conf->device_lock, flags); if (list_empty(head)) { @@ -1593,6 +1592,7 @@ static void raid1d(mddev_t *mddev) } cond_resched(); } + blk_finish_plug(&plug); } @@ -2039,7 +2039,6 @@ static int stop(mddev_t *mddev) md_unregister_thread(mddev->thread); mddev->thread = NULL; - blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ if (conf->r1bio_pool) mempool_destroy(conf->r1bio_pool); kfree(conf->mirrors); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 2da83d566592..8e9462626ec5 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -634,12 +634,6 @@ static void flush_pending_writes(conf_t *conf) spin_unlock_irq(&conf->device_lock); } -static void md_kick_device(mddev_t *mddev) -{ - blk_flush_plug(current); - md_wakeup_thread(mddev->thread); -} - /* Barriers.... * Sometimes we need to suspend IO while we do something else, * either some resync/recovery, or reconfigure the array. @@ -669,15 +663,15 @@ static void raise_barrier(conf_t *conf, int force) /* Wait until no block IO is waiting (unless 'force') */ wait_event_lock_irq(conf->wait_barrier, force || !conf->nr_waiting, - conf->resync_lock, md_kick_device(conf->mddev)); + conf->resync_lock, ); /* block any new IO from starting */ conf->barrier++; - /* No wait for all pending IO to complete */ + /* Now wait for all pending IO to complete */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_pending && conf->barrier < RESYNC_DEPTH, - conf->resync_lock, md_kick_device(conf->mddev)); + conf->resync_lock, ); spin_unlock_irq(&conf->resync_lock); } @@ -698,7 +692,7 @@ static void wait_barrier(conf_t *conf) conf->nr_waiting++; wait_event_lock_irq(conf->wait_barrier, !conf->barrier, conf->resync_lock, - md_kick_device(conf->mddev)); + ); conf->nr_waiting--; } conf->nr_pending++; @@ -734,8 +728,8 @@ static void freeze_array(conf_t *conf) wait_event_lock_irq(conf->wait_barrier, conf->nr_pending == conf->nr_queued+1, conf->resync_lock, - ({ flush_pending_writes(conf); - md_kick_device(conf->mddev); })); + flush_pending_writes(conf)); + spin_unlock_irq(&conf->resync_lock); } @@ -762,6 +756,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) const unsigned long do_fua = (bio->bi_rw & REQ_FUA); unsigned long flags; mdk_rdev_t *blocked_rdev; + int plugged; if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); @@ -870,6 +865,8 @@ static int make_request(mddev_t *mddev, struct bio * bio) * inc refcount on their rdev. Record them by setting * bios[x] to bio */ + plugged = mddev_check_plugged(mddev); + raid10_find_phys(conf, r10_bio); retry_write: blocked_rdev = NULL; @@ -946,9 +943,8 @@ static int make_request(mddev_t *mddev, struct bio * bio) /* In case raid10d snuck in to freeze_array */ wake_up(&conf->wait_barrier); - if (do_sync || !mddev->bitmap) + if (do_sync || !mddev->bitmap || !plugged) md_wakeup_thread(mddev->thread); - return 0; } @@ -1640,9 +1636,11 @@ static void raid10d(mddev_t *mddev) conf_t *conf = mddev->private; struct list_head *head = &conf->retry_list; mdk_rdev_t *rdev; + struct blk_plug plug; md_check_recovery(mddev); + blk_start_plug(&plug); for (;;) { char b[BDEVNAME_SIZE]; @@ -1716,6 +1714,7 @@ static void raid10d(mddev_t *mddev) } cond_resched(); } + blk_finish_plug(&plug); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e867ee42b152..49bf5f891435 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -27,12 +27,12 @@ * * We group bitmap updates into batches. Each batch has a number. * We may write out several batches at once, but that isn't very important. - * conf->bm_write is the number of the last batch successfully written. - * conf->bm_flush is the number of the last batch that was closed to + * conf->seq_write is the number of the last batch successfully written. + * conf->seq_flush is the number of the last batch that was closed to * new additions. * When we discover that we will need to write to any block in a stripe * (in add_stripe_bio) we update the in-memory bitmap and record in sh->bm_seq - * the number of the batch it will be in. This is bm_flush+1. + * the number of the batch it will be in. This is seq_flush+1. * When we are ready to do a write, if that batch hasn't been written yet, * we plug the array and queue the stripe for later. * When an unplug happens, we increment bm_flush, thus closing the current @@ -199,14 +199,12 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) BUG_ON(!list_empty(&sh->lru)); BUG_ON(atomic_read(&conf->active_stripes)==0); if (test_bit(STRIPE_HANDLE, &sh->state)) { - if (test_bit(STRIPE_DELAYED, &sh->state)) { + if (test_bit(STRIPE_DELAYED, &sh->state)) list_add_tail(&sh->lru, &conf->delayed_list); - plugger_set_plug(&conf->plug); - } else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && - sh->bm_seq - conf->seq_write > 0) { + else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && + sh->bm_seq - conf->seq_write > 0) list_add_tail(&sh->lru, &conf->bitmap_list); - plugger_set_plug(&conf->plug); - } else { + else { clear_bit(STRIPE_BIT_DELAY, &sh->state); list_add_tail(&sh->lru, &conf->handle_list); } @@ -461,7 +459,7 @@ get_active_stripe(raid5_conf_t *conf, sector_t sector, < (conf->max_nr_stripes *3/4) || !conf->inactive_blocked), conf->device_lock, - md_raid5_kick_device(conf)); + ); conf->inactive_blocked = 0; } else init_stripe(sh, sector, previous); @@ -1470,7 +1468,7 @@ static int resize_stripes(raid5_conf_t *conf, int newsize) wait_event_lock_irq(conf->wait_for_stripe, !list_empty(&conf->inactive_list), conf->device_lock, - blk_flush_plug(current)); + ); osh = get_free_stripe(conf); spin_unlock_irq(&conf->device_lock); atomic_set(&nsh->count, 1); @@ -3623,8 +3621,7 @@ static void raid5_activate_delayed(raid5_conf_t *conf) atomic_inc(&conf->preread_active_stripes); list_add_tail(&sh->lru, &conf->hold_list); } - } else - plugger_set_plug(&conf->plug); + } } static void activate_bit_delay(raid5_conf_t *conf) @@ -3641,21 +3638,6 @@ static void activate_bit_delay(raid5_conf_t *conf) } } -void md_raid5_kick_device(raid5_conf_t *conf) -{ - blk_flush_plug(current); - raid5_activate_delayed(conf); - md_wakeup_thread(conf->mddev->thread); -} -EXPORT_SYMBOL_GPL(md_raid5_kick_device); - -static void raid5_unplug(struct plug_handle *plug) -{ - raid5_conf_t *conf = container_of(plug, raid5_conf_t, plug); - - md_raid5_kick_device(conf); -} - int md_raid5_congested(mddev_t *mddev, int bits) { raid5_conf_t *conf = mddev->private; @@ -3945,6 +3927,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) struct stripe_head *sh; const int rw = bio_data_dir(bi); int remaining; + int plugged; if (unlikely(bi->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bi); @@ -3963,6 +3946,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) bi->bi_next = NULL; bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ + plugged = mddev_check_plugged(mddev); for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { DEFINE_WAIT(w); int disks, data_disks; @@ -4057,7 +4041,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) * add failed due to overlap. Flush everything * and wait a while */ - md_raid5_kick_device(conf); + md_wakeup_thread(mddev->thread); release_stripe(sh); schedule(); goto retry; @@ -4077,6 +4061,9 @@ static int make_request(mddev_t *mddev, struct bio * bi) } } + if (!plugged) + md_wakeup_thread(mddev->thread); + spin_lock_irq(&conf->device_lock); remaining = raid5_dec_bi_phys_segments(bi); spin_unlock_irq(&conf->device_lock); @@ -4478,24 +4465,30 @@ static void raid5d(mddev_t *mddev) struct stripe_head *sh; raid5_conf_t *conf = mddev->private; int handled; + struct blk_plug plug; pr_debug("+++ raid5d active\n"); md_check_recovery(mddev); + blk_start_plug(&plug); handled = 0; spin_lock_irq(&conf->device_lock); while (1) { struct bio *bio; - if (conf->seq_flush != conf->seq_write) { - int seq = conf->seq_flush; + if (atomic_read(&mddev->plug_cnt) == 0 && + !list_empty(&conf->bitmap_list)) { + /* Now is a good time to flush some bitmap updates */ + conf->seq_flush++; spin_unlock_irq(&conf->device_lock); bitmap_unplug(mddev->bitmap); spin_lock_irq(&conf->device_lock); - conf->seq_write = seq; + conf->seq_write = conf->seq_flush; activate_bit_delay(conf); } + if (atomic_read(&mddev->plug_cnt) == 0) + raid5_activate_delayed(conf); while ((bio = remove_bio_from_retry(conf))) { int ok; @@ -4525,6 +4518,7 @@ static void raid5d(mddev_t *mddev) spin_unlock_irq(&conf->device_lock); async_tx_issue_pending_all(); + blk_finish_plug(&plug); pr_debug("--- raid5d inactive\n"); } @@ -5141,8 +5135,6 @@ static int run(mddev_t *mddev) mdname(mddev)); md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); - plugger_init(&conf->plug, raid5_unplug); - mddev->plug = &conf->plug; if (mddev->queue) { int chunk_size; /* read-ahead size must cover two whole stripes, which @@ -5159,7 +5151,6 @@ static int run(mddev_t *mddev) mddev->queue->backing_dev_info.congested_data = mddev; mddev->queue->backing_dev_info.congested_fn = raid5_congested; - mddev->queue->queue_lock = &conf->device_lock; chunk_size = mddev->chunk_sectors << 9; blk_queue_io_min(mddev->queue, chunk_size); @@ -5192,7 +5183,6 @@ static int stop(mddev_t *mddev) mddev->thread = NULL; if (mddev->queue) mddev->queue->backing_dev_info.congested_fn = NULL; - plugger_flush(&conf->plug); /* the unplug fn references 'conf'*/ free_conf(conf); mddev->private = NULL; mddev->to_remove = &raid5_attrs_group; @@ -5688,6 +5678,7 @@ static void raid5_quiesce(mddev_t *mddev, int state) static void *raid45_takeover_raid0(mddev_t *mddev, int level) { struct raid0_private_data *raid0_priv = mddev->private; + sector_t sectors; /* for raid0 takeover only one zone is supported */ if (raid0_priv->nr_strip_zones > 1) { @@ -5696,6 +5687,9 @@ static void *raid45_takeover_raid0(mddev_t *mddev, int level) return ERR_PTR(-EINVAL); } + sectors = raid0_priv->strip_zone[0].zone_end; + sector_div(sectors, raid0_priv->strip_zone[0].nb_dev); + mddev->dev_sectors = sectors; mddev->new_level = level; mddev->new_layout = ALGORITHM_PARITY_N; mddev->new_chunk_sectors = mddev->chunk_sectors; diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 8d563a4f022a..3ca77a2613ba 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -400,8 +400,6 @@ struct raid5_private_data { * Cleared when a sync completes. */ - struct plug_handle plug; - /* per cpu variables */ struct raid5_percpu { struct page *spare_page; /* Used when checking P/Q in raid6 */ diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c index 5466d47db899..aae40e52af5b 100644 --- a/drivers/media/common/tuners/tda18271-common.c +++ b/drivers/media/common/tuners/tda18271-common.c @@ -533,16 +533,7 @@ int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) if (tda_fail(ret)) goto fail; - regs[R_MPD] = (0x77 & pd); - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } + regs[R_MPD] = (0x7f & pd); div = ((d * (freq / 1000)) << 7) / 125; diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index 9ad4454a148d..d884f5eee73c 100644 --- a/drivers/media/common/tuners/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c @@ -579,8 +579,8 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) #define RF3 2 u32 rf_default[3]; u32 rf_freq[3]; - u8 prog_cal[3]; - u8 prog_tab[3]; + s32 prog_cal[3]; + s32 prog_tab[3]; i = tda18271_lookup_rf_band(fe, &freq, NULL); @@ -602,32 +602,33 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) return bcal; tda18271_calc_rf_cal(fe, &rf_freq[rf]); - prog_tab[rf] = regs[R_EB14]; + prog_tab[rf] = (s32)regs[R_EB14]; if (1 == bcal) - prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]); + prog_cal[rf] = + (s32)tda18271_calibrate_rf(fe, rf_freq[rf]); else prog_cal[rf] = prog_tab[rf]; switch (rf) { case RF1: map[i].rf_a1 = 0; - map[i].rf_b1 = (s32)(prog_cal[RF1] - prog_tab[RF1]); + map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]); map[i].rf1 = rf_freq[RF1] / 1000; break; case RF2: - dividend = (s32)(prog_cal[RF2] - prog_tab[RF2]) - - (s32)(prog_cal[RF1] + prog_tab[RF1]); + dividend = (prog_cal[RF2] - prog_tab[RF2] - + prog_cal[RF1] + prog_tab[RF1]); divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000; map[i].rf_a1 = (dividend / divisor); map[i].rf2 = rf_freq[RF2] / 1000; break; case RF3: - dividend = (s32)(prog_cal[RF3] - prog_tab[RF3]) - - (s32)(prog_cal[RF2] + prog_tab[RF2]); + dividend = (prog_cal[RF3] - prog_tab[RF3] - + prog_cal[RF2] + prog_tab[RF2]); divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000; map[i].rf_a2 = (dividend / divisor); - map[i].rf_b2 = (s32)(prog_cal[RF2] - prog_tab[RF2]); + map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]); map[i].rf3 = rf_freq[RF3] / 1000; break; default: diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c index e7f84c705da8..3d5b6ab7e332 100644 --- a/drivers/media/common/tuners/tda18271-maps.c +++ b/drivers/media/common/tuners/tda18271-maps.c @@ -229,8 +229,7 @@ static struct tda18271_map tda18271c2_km[] = { static struct tda18271_map tda18271_rf_band[] = { { .rfmax = 47900, .val = 0x00 }, { .rfmax = 61100, .val = 0x01 }, -/* { .rfmax = 152600, .val = 0x02 }, */ - { .rfmax = 121200, .val = 0x02 }, + { .rfmax = 152600, .val = 0x02 }, { .rfmax = 164700, .val = 0x03 }, { .rfmax = 203500, .val = 0x04 }, { .rfmax = 457800, .val = 0x05 }, @@ -448,7 +447,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 150000, .val = 0xb0 }, { .rfmax = 151000, .val = 0xb1 }, { .rfmax = 152000, .val = 0xb7 }, - { .rfmax = 153000, .val = 0xbd }, + { .rfmax = 152600, .val = 0xbd }, { .rfmax = 154000, .val = 0x20 }, { .rfmax = 155000, .val = 0x22 }, { .rfmax = 156000, .val = 0x24 }, @@ -459,7 +458,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 161000, .val = 0x2d }, { .rfmax = 163000, .val = 0x2e }, { .rfmax = 164000, .val = 0x2f }, - { .rfmax = 165000, .val = 0x30 }, + { .rfmax = 164700, .val = 0x30 }, { .rfmax = 166000, .val = 0x11 }, { .rfmax = 167000, .val = 0x12 }, { .rfmax = 168000, .val = 0x13 }, @@ -510,7 +509,8 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 236000, .val = 0x1b }, { .rfmax = 237000, .val = 0x1c }, { .rfmax = 240000, .val = 0x1d }, - { .rfmax = 242000, .val = 0x1f }, + { .rfmax = 242000, .val = 0x1e }, + { .rfmax = 244000, .val = 0x1f }, { .rfmax = 247000, .val = 0x20 }, { .rfmax = 249000, .val = 0x21 }, { .rfmax = 252000, .val = 0x22 }, @@ -624,7 +624,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 453000, .val = 0x93 }, { .rfmax = 454000, .val = 0x94 }, { .rfmax = 456000, .val = 0x96 }, - { .rfmax = 457000, .val = 0x98 }, + { .rfmax = 457800, .val = 0x98 }, { .rfmax = 461000, .val = 0x11 }, { .rfmax = 468000, .val = 0x12 }, { .rfmax = 472000, .val = 0x13 }, diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 955254090a0e..03f96d6ca894 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -38,7 +38,7 @@ MODULE_PARM_DESC(debug, DEBSTATUS); #define DRIVER_VERSION "0.1" -#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" +#define DRIVER_NAME "flexcop-pci" #define DRIVER_AUTHOR "Patrick Boettcher " struct flexcop_pci { diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index fe4f894183ff..c545039287ad 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -356,13 +356,15 @@ config DVB_USB_LME2510 select DVB_TDA826X if !DVB_FE_CUSTOMISE select DVB_STV0288 if !DVB_FE_CUSTOMISE select DVB_IX2505V if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE help Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 . config DVB_USB_TECHNISAT_USB2 tristate "Technisat DVB-S/S2 USB2.0 support" depends on DVB_USB - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE help Say Y here to support the Technisat USB2 DVB-S/S2 device diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 97af266d7f1d..65214af5cd74 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -2162,7 +2162,7 @@ struct dibx000_agc_config dib7090_agc_config[2] = { .agc1_pt3 = 98, .agc1_slope1 = 0, .agc1_slope2 = 167, - .agc1_pt1 = 98, + .agc2_pt1 = 98, .agc2_pt2 = 255, .agc2_slope1 = 104, .agc2_slope2 = 0, @@ -2440,11 +2440,11 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) dib0700_set_i2c_speed(adap->dev, 340); adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); - dib7090_slave_reset(adap->fe); - if (adap->fe == NULL) return -ENODEV; + dib7090_slave_reset(adap->fe); + return 0; } diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c index fc5ccd8c923a..21c52e3b522e 100644 --- a/drivers/media/dvb/firewire/firedtv-avc.c +++ b/drivers/media/dvb/firewire/firedtv-avc.c @@ -1320,14 +1320,10 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data) { int ret; - mutex_lock(&fdtv->avc_mutex); - ret = fdtv_read(fdtv, addr, data); if (ret < 0) dev_err(fdtv->device, "CMP: read I/O error\n"); - mutex_unlock(&fdtv->avc_mutex); - return ret; } @@ -1335,18 +1331,9 @@ static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[]) { int ret; - mutex_lock(&fdtv->avc_mutex); - - /* data[] is stack-allocated and should not be DMA-mapped. */ - memcpy(fdtv->avc_data, data, 8); - - ret = fdtv_lock(fdtv, addr, fdtv->avc_data); + ret = fdtv_lock(fdtv, addr, data); if (ret < 0) dev_err(fdtv->device, "CMP: lock I/O error\n"); - else - memcpy(data, fdtv->avc_data, 8); - - mutex_unlock(&fdtv->avc_mutex); return ret; } diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c index 8022b743af91..864b6274c729 100644 --- a/drivers/media/dvb/firewire/firedtv-fw.c +++ b/drivers/media/dvb/firewire/firedtv-fw.c @@ -125,6 +125,7 @@ static void handle_iso(struct fw_iso_context *context, u32 cycle, i = (i + 1) & (N_PACKETS - 1); } + fw_iso_context_queue_flush(ctx->context); ctx->current_packet = i; } diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index ccc2d1af49d4..6927c726ce35 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -1520,6 +1520,7 @@ static int init_channel(struct ngene_channel *chan) if (dev->ci.en && (io & NGENE_IO_TSOUT)) { dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); set_transfer(chan, 1); + chan->dev->channel[2].DataFormatFlags = DF_SWAP32; set_transfer(&chan->dev->channel[2], 1); dvb_register_device(adapter, &chan->ci_dev, &ngene_dvbdev_ci, (void *) chan, diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 23640ed44d85..056138f63c7d 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -378,7 +378,6 @@ EXPORT_SYMBOL_GPL(media_entity_create_link); static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) { - const u32 mask = MEDIA_LNK_FL_ENABLED; int ret; /* Notify both entities. */ @@ -395,7 +394,7 @@ static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) return ret; } - link->flags = (link->flags & ~mask) | (flags & mask); + link->flags = flags; link->reverse->flags = link->flags; return 0; @@ -417,6 +416,7 @@ static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) */ int __media_entity_setup_link(struct media_link *link, u32 flags) { + const u32 mask = MEDIA_LNK_FL_ENABLED; struct media_device *mdev; struct media_entity *source, *sink; int ret = -EBUSY; @@ -424,6 +424,10 @@ int __media_entity_setup_link(struct media_link *link, u32 flags) if (link == NULL) return -EINVAL; + /* The non-modifiable link flags must not be modified. */ + if ((link->flags & ~mask) != (flags & ~mask)) + return -EINVAL; + if (link->flags & MEDIA_LNK_FL_IMMUTABLE) return link->flags == flags ? 0 : -EINVAL; diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index dc3f04c52d5e..87bad7678d92 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -170,7 +170,7 @@ static int fmr2_setfreq(struct fmr2 *dev) return 0; } -/* !!! not tested, in my card this does't work !!! */ +/* !!! not tested, in my card this doesn't work !!! */ static int fmr2_setvolume(struct fmr2 *dev) { int vol[16] = { 0x021, 0x084, 0x090, 0x104, diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c index 585680ffbfb6..b1193dfc5087 100644 --- a/drivers/media/radio/saa7706h.c +++ b/drivers/media/radio/saa7706h.c @@ -376,7 +376,7 @@ static int __devinit saa7706h_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%02x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct saa7706h_state), GFP_KERNEL); + state = kzalloc(sizeof(struct saa7706h_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; sd = &state->sd; diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c index 7c0d77751f6e..0991e1973678 100644 --- a/drivers/media/radio/tef6862.c +++ b/drivers/media/radio/tef6862.c @@ -176,7 +176,7 @@ static int __devinit tef6862_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%02x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct tef6862_state), GFP_KERNEL); + state = kzalloc(sizeof(struct tef6862_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; state->freq = TEF6862_LO_FREQ; diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index ebd68edf5b24..8fc0f081b470 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -46,7 +46,7 @@ #define MOD_AUTHOR "Jarod Wilson " #define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" #define MOD_NAME "imon" -#define MOD_VERSION "0.9.2" +#define MOD_VERSION "0.9.3" #define DISPLAY_MINOR_BASE 144 #define DEVICE_NAME "lcd%d" @@ -460,8 +460,9 @@ static int display_close(struct inode *inode, struct file *file) } /** - * Sends a packet to the device -- this function must be called - * with ictx->lock held. + * Sends a packet to the device -- this function must be called with + * ictx->lock held, or its unlock/lock sequence while waiting for tx + * to complete can/will lead to a deadlock. */ static int send_packet(struct imon_context *ictx) { @@ -991,12 +992,21 @@ static void imon_touch_display_timeout(unsigned long data) * the iMON remotes, and those used by the Windows MCE remotes (which is * really just RC-6), but only one or the other at a time, as the signals * are decoded onboard the receiver. + * + * This function gets called two different ways, one way is from + * rc_register_device, for initial protocol selection/setup, and the other is + * via a userspace-initiated protocol change request, either by direct sysfs + * prodding or by something like ir-keytable. In the rc_register_device case, + * the imon context lock is already held, but when initiated from userspace, + * it is not, so we must acquire it prior to calling send_packet, which + * requires that the lock is held. */ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) { int retval; struct imon_context *ictx = rc->priv; struct device *dev = ictx->dev; + bool unlock = false; unsigned char ir_proto_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; @@ -1029,6 +1039,11 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); + if (!mutex_is_locked(&ictx->lock)) { + unlock = true; + mutex_lock(&ictx->lock); + } + retval = send_packet(ictx); if (retval) goto out; @@ -1037,6 +1052,9 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) ictx->pad_mouse = false; out: + if (unlock) + mutex_unlock(&ictx->lock); + return retval; } @@ -2134,6 +2152,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) goto rdev_setup_failed; } + mutex_unlock(&ictx->lock); return ictx; rdev_setup_failed: @@ -2205,6 +2224,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, goto urb_submit_failed; } + mutex_unlock(&ictx->lock); return ictx; urb_submit_failed: @@ -2299,6 +2319,8 @@ static int __devinit imon_probe(struct usb_interface *interface, usb_set_intfdata(interface, ictx); if (ifnum == 0) { + mutex_lock(&ictx->lock); + if (product == 0xffdc && ictx->rf_device) { sysfs_err = sysfs_create_group(&interface->dev.kobj, &imon_rf_attr_group); @@ -2309,13 +2331,14 @@ static int __devinit imon_probe(struct usb_interface *interface, if (ictx->display_supported) imon_init_display(ictx, interface); + + mutex_unlock(&ictx->lock); } dev_info(dev, "iMON device (%04x:%04x, intf%d) on " "usb<%d:%d> initialized\n", vendor, product, ifnum, usbdev->bus->busnum, usbdev->devnum); - mutex_unlock(&ictx->lock); mutex_unlock(&driver_lock); return 0; diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index accaf6c9789a..43908a70bd8b 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 044fb7a382d6..0c273ec465c9 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -220,6 +220,8 @@ static struct usb_device_id mceusb_dev_table[] = { { USB_DEVICE(VENDOR_PHILIPS, 0x206c) }, /* Philips/Spinel plus IR transceiver for ASUS */ { USB_DEVICE(VENDOR_PHILIPS, 0x2088) }, + /* Philips IR transceiver (Dell branded) */ + { USB_DEVICE(VENDOR_PHILIPS, 0x2093) }, /* Realtek MCE IR Receiver and card reader */ { USB_DEVICE(VENDOR_REALTEK, 0x0161), .driver_info = MULTIFUNCTION }, diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index f53f9c68d38d..a2706648e365 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -707,7 +707,8 @@ static void ir_close(struct input_dev *idev) { struct rc_dev *rdev = input_get_drvdata(idev); - rdev->close(rdev); + if (rdev) + rdev->close(rdev); } /* class for /sys/class/rc */ @@ -733,6 +734,7 @@ static struct { { RC_TYPE_SONY, "sony" }, { RC_TYPE_RC5_SZ, "rc-5-sz" }, { RC_TYPE_LIRC, "lirc" }, + { RC_TYPE_OTHER, "other" }, }; #define PROTO_NONE "none" diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 4498b944dec8..00f51dd121f3 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -875,7 +875,7 @@ config MX3_VIDEO config VIDEO_MX3 tristate "i.MX3x Camera Sensor Interface driver" depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA - select VIDEOBUF_DMA_CONTIG + select VIDEOBUF2_DMA_CONTIG select MX3_VIDEO ---help--- This is a v4l2 driver for the i.MX3x Camera Sensor Interface diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index c6e2ca3b1149..6fbc356113c1 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -350,9 +350,17 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) /* No struct video_device, but can have buffers allocated */ if (type == CX18_ENC_STREAM_TYPE_IDX) { + /* If the module params didn't inhibit IDX ... */ if (cx->stream_buffers[type] != 0) { cx->stream_buffers[type] = 0; - cx18_stream_free(&cx->streams[type]); + /* + * Before calling cx18_stream_free(), + * check if the IDX stream was actually set up. + * Needed, since the cx18_probe() error path + * exits through here as well as normal clean up + */ + if (cx->streams[type].buffers != 0) + cx18_stream_free(&cx->streams[type]); } continue; } diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 3b6e7f28568e..caab1bfb79e2 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -22,6 +22,7 @@ config VIDEO_CX23885 select DVB_CX24116 if !DVB_FE_CUSTOMISE select DVB_STV0900 if !DVB_FE_CUSTOMISE select DVB_DS3000 if !DVB_FE_CUSTOMISE + select DVB_STV0367 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index c820e2f53527..3f442003623d 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -524,7 +524,7 @@ void cx88_ir_irq(struct cx88_core *core) for (todo = 32; todo > 0; todo -= bits) { ev.pulse = samples & 0x80000000 ? false : true; bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples)); - ev.duration = (bits * NSEC_PER_SEC) / (1000 * ir_samplerate); + ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate; ir_raw_event_store_with_filter(ir->dev, &ev); samples <<= bits; } diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 1a1169115716..0382ea752e6f 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -298,7 +298,7 @@ static unsigned long imx074_query_bus_param(struct soc_camera_device *icd) static int imx074_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { - return -1; + return -EINVAL; } static struct soc_camera_ops imx074_ops = { diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c index 5e1c9a81984c..303ffa7df4ac 100644 --- a/drivers/media/video/m52790.c +++ b/drivers/media/video/m52790.c @@ -174,7 +174,7 @@ static int m52790_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL); + state = kzalloc(sizeof(struct m52790_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 503bd7922bd6..472a69359e60 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -215,20 +215,21 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) } switch (xclksel) { - case 0: + case ISP_XCLK_A: isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, ISPTCTRL_CTRL_DIVA_MASK, divisor << ISPTCTRL_CTRL_DIVA_SHIFT); dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n", currentxclk); break; - case 1: + case ISP_XCLK_B: isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, ISPTCTRL_CTRL_DIVB_MASK, divisor << ISPTCTRL_CTRL_DIVB_SHIFT); dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n", currentxclk); break; + case ISP_XCLK_NONE: default: omap3isp_put(isp); dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested " @@ -237,13 +238,13 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) } /* Do we go from stable whatever to clock? */ - if (divisor >= 2 && isp->xclk_divisor[xclksel] < 2) + if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2) omap3isp_get(isp); /* Stopping the clock. */ - else if (divisor < 2 && isp->xclk_divisor[xclksel] >= 2) + else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2) omap3isp_put(isp); - isp->xclk_divisor[xclksel] = divisor; + isp->xclk_divisor[xclksel - 1] = divisor; omap3isp_put(isp); @@ -285,7 +286,8 @@ static void isp_power_settings(struct isp_device *isp, int idle) */ void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata) + const struct isp_parallel_platform_data *pdata, + unsigned int shift) { u32 ispctrl_val; @@ -298,9 +300,9 @@ void omap3isp_configure_bridge(struct isp_device *isp, switch (input) { case CCDC_INPUT_PARALLEL: ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; - ispctrl_val |= pdata->data_lane_shift << ISPCTRL_SHIFT_SHIFT; ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT; + shift += pdata->data_lane_shift * 2; break; case CCDC_INPUT_CSI2A: @@ -319,6 +321,8 @@ void omap3isp_configure_bridge(struct isp_device *isp, return; } + ispctrl_val |= ((shift/2) << ISPCTRL_SHIFT_SHIFT) & ISPCTRL_SHIFT_MASK; + ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK; ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE; @@ -658,6 +662,8 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use) /* Apply power change to connected non-nodes. */ ret = isp_pipeline_pm_power(entity, change); + if (ret < 0) + entity->use_count -= change; mutex_unlock(&entity->parent->graph_mutex); @@ -872,6 +878,9 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) } } + if (failure < 0) + isp->needs_reset = true; + return failure; } @@ -884,7 +893,8 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) * single-shot or continuous mode. * * Return 0 if successful, or the return value of the failed video::s_stream - * operation otherwise. + * operation otherwise. The pipeline state is not updated when the operation + * fails, except when stopping the pipeline. */ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, enum isp_pipeline_stream_state state) @@ -895,7 +905,9 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, ret = isp_pipeline_disable(pipe); else ret = isp_pipeline_enable(pipe, state); - pipe->stream_state = state; + + if (ret == 0 || state == ISP_PIPELINE_STREAM_STOPPED) + pipe->stream_state = state; return ret; } @@ -1481,6 +1493,10 @@ void omap3isp_put(struct isp_device *isp) if (--isp->ref_count == 0) { isp_disable_interrupts(isp); isp_save_ctx(isp); + if (isp->needs_reset) { + isp_reset(isp); + isp->needs_reset = false; + } isp_disable_clocks(isp); } mutex_unlock(&isp->isp_mutex); diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h index cf5214e95a92..2620c405f5e4 100644 --- a/drivers/media/video/omap3isp/isp.h +++ b/drivers/media/video/omap3isp/isp.h @@ -132,7 +132,6 @@ struct isp_reg { /** * struct isp_parallel_platform_data - Parallel interface platform data - * @width: Parallel bus width in bits (8, 10, 11 or 12) * @data_lane_shift: Data lane shifter * 0 - CAMEXT[13:0] -> CAM[13:0] * 1 - CAMEXT[13:2] -> CAM[11:0] @@ -146,7 +145,6 @@ struct isp_reg { * ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian */ struct isp_parallel_platform_data { - unsigned int width; unsigned int data_lane_shift:2; unsigned int clk_pol:1; unsigned int bridge:4; @@ -262,6 +260,7 @@ struct isp_device { /* ISP Obj */ spinlock_t stat_lock; /* common lock for statistic drivers */ struct mutex isp_mutex; /* For handling ref_count field */ + bool needs_reset; int has_context; int ref_count; unsigned int autoidle; @@ -311,11 +310,12 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, enum isp_pipeline_stream_state state); void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata); + const struct isp_parallel_platform_data *pdata, + unsigned int shift); -#define ISP_XCLK_NONE -1 -#define ISP_XCLK_A 0 -#define ISP_XCLK_B 1 +#define ISP_XCLK_NONE 0 +#define ISP_XCLK_A 1 +#define ISP_XCLK_B 2 struct isp_device *omap3isp_get(struct isp_device *isp); void omap3isp_put(struct isp_device *isp); diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 5ff9d14ce710..39d501bda636 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -43,6 +43,12 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, static const unsigned int ccdc_fmts[] = { V4L2_MBUS_FMT_Y8_1X8, + V4L2_MBUS_FMT_Y10_1X10, + V4L2_MBUS_FMT_Y12_1X12, + V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, @@ -1110,21 +1116,38 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) struct isp_parallel_platform_data *pdata = NULL; struct v4l2_subdev *sensor; struct v4l2_mbus_framefmt *format; + const struct isp_format_info *fmt_info; + struct v4l2_subdev_format fmt_src; + unsigned int depth_out; + unsigned int depth_in = 0; struct media_pad *pad; unsigned long flags; + unsigned int shift; u32 syn_mode; u32 ccdc_pattern; - if (ccdc->input == CCDC_INPUT_PARALLEL) { - pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]); - sensor = media_entity_to_v4l2_subdev(pad->entity); + pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]); + sensor = media_entity_to_v4l2_subdev(pad->entity); + if (ccdc->input == CCDC_INPUT_PARALLEL) pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) ->bus.parallel; + + /* Compute shift value for lane shifter to configure the bridge. */ + fmt_src.pad = pad->index; + fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; + if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) { + fmt_info = omap3isp_video_format_info(fmt_src.format.code); + depth_in = fmt_info->bpp; } - omap3isp_configure_bridge(isp, ccdc->input, pdata); + fmt_info = omap3isp_video_format_info + (isp->isp_ccdc.formats[CCDC_PAD_SINK].code); + depth_out = fmt_info->bpp; - ccdc->syncif.datsz = pdata ? pdata->width : 10; + shift = depth_in - depth_out; + omap3isp_configure_bridge(isp, ccdc->input, pdata, shift); + + ccdc->syncif.datsz = depth_out; ccdc_config_sync_if(ccdc, &ccdc->syncif); /* CCDC_PAD_SINK */ @@ -1338,7 +1361,7 @@ static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc, * @ccdc: Pointer to ISP CCDC device. * @event: Pointing which event trigger handler * - * Return 1 when the event and stopping request combination is satisfyied, + * Return 1 when the event and stopping request combination is satisfied, * zero otherwise. */ static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) @@ -1618,7 +1641,7 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) ccdc_set_outaddr(ccdc, buffer->isp_addr); - /* We now have a buffer queued on the output, restart the pipeline in + /* We now have a buffer queued on the output, restart the pipeline * on the next CCDC interrupt if running in continuous mode (or when * starting the stream). */ diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index 2b16988a501d..aba537af87e4 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -755,7 +755,7 @@ static struct preview_update update_attrs[] = { * @configs - pointer to update config structure. * @config - return pointer to appropriate structure field. * @bit - for which feature to return pointers. - * Return size of coresponding prev_params member + * Return size of corresponding prev_params member */ static u32 __preview_get_ptrs(struct prev_params *params, void **param, diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c index 8fddc5806b0d..9c317148205f 100644 --- a/drivers/media/video/omap3isp/ispqueue.c +++ b/drivers/media/video/omap3isp/ispqueue.c @@ -339,7 +339,7 @@ static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf) up_read(¤t->mm->mmap_sem); if (ret != buf->npages) { - buf->npages = ret; + buf->npages = ret < 0 ? 0 : ret; isp_video_buffer_cleanup(buf); return -EFAULT; } @@ -408,8 +408,8 @@ static int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf) * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address * * This function locates the VMAs for the buffer's userspace address and checks - * that their flags match. The onlflag that we need to care for at the moment is - * VM_PFNMAP. + * that their flags match. The only flag that we need to care for at the moment + * is VM_PFNMAP. * * The buffer vm_flags field is set to the first VMA flags. * diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 653f88ba56db..0bb0f8cd36f5 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -714,19 +714,50 @@ static void resizer_print_status(struct isp_res_device *res) * iw and ih are the input width and height after cropping. Those equations need * to be satisfied exactly for the resizer to work correctly. * - * Reverting the equations, we can compute the resizing ratios with + * The equations can't be easily reverted, as the >> 8 operation is not linear. + * In addition, not all input sizes can be achieved for a given output size. To + * get the highest input size lower than or equal to the requested input size, + * we need to compute the highest resizing ratio that satisfies the following + * inequality (taking the 4-tap mode width equation as an example) + * + * iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7 + * + * (where iw is the requested input width) which can be rewritten as + * + * iw - 7 >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 + * (iw - 7) << 8 >= 32 * sph + (ow - 1) * hrsz + 16 - b + * ((iw - 7) << 8) + b >= 32 * sph + (ow - 1) * hrsz + 16 + * + * where b is the value of the 8 least significant bits of the right hand side + * expression of the last inequality. The highest resizing ratio value will be + * achieved when b is equal to its maximum value of 255. That resizing ratio + * value will still satisfy the original inequality, as b will disappear when + * the expression will be shifted right by 8. + * + * The reverted the equations thus become * * - 8-phase, 4-tap mode - * hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1) - * vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1) + * hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1) + * vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1) * - 4-phase, 7-tap mode - * hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1) - * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1) + * hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1) + * vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1) * - * The ratios are integer values, and must be rounded down to ensure that the - * cropped input size is not bigger than the uncropped input size. As the ratio - * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the - * 7-tap mode equations to compute a ratio approximation. + * The ratios are integer values, and are rounded down to ensure that the + * cropped input size is not bigger than the uncropped input size. + * + * As the number of phases/taps, used to select the correct equations to compute + * the ratio, depends on the ratio, we start with the 4-tap mode equations to + * compute an approximation of the ratio, and switch to the 7-tap mode equations + * if the approximation is higher than the ratio threshold. + * + * As the 7-tap mode equations will return a ratio smaller than or equal to the + * 4-tap mode equations, the resulting ratio could become lower than or equal to + * the ratio threshold. This 'equations loop' isn't an issue as long as the + * correct equations are used to compute the final input size. Starting with the + * 4-tap mode equations ensure that, in case of values resulting in a 'ratio + * loop', the smallest of the ratio values will be used, never exceeding the + * requested input size. * * We first clamp the output size according to the hardware capabilitie to avoid * auto-cropping the input more than required to satisfy the TRM equations. The @@ -775,6 +806,8 @@ static void resizer_calc_ratios(struct isp_res_device *res, unsigned int max_width; unsigned int max_height; unsigned int width_alignment; + unsigned int width; + unsigned int height; /* * Clamp the output height based on the hardware capabilities and @@ -786,19 +819,22 @@ static void resizer_calc_ratios(struct isp_res_device *res, max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT); output->height = clamp(output->height, min_height, max_height); - ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv) + ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / (output->height - 1); + if (ratio->vert > MID_RESIZE_VALUE) + ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv) + / (output->height - 1); ratio->vert = clamp_t(unsigned int, ratio->vert, MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); if (ratio->vert <= MID_RESIZE_VALUE) { upscaled_height = (output->height - 1) * ratio->vert + 32 * spv + 16; - input->height = (upscaled_height >> 8) + 4; + height = (upscaled_height >> 8) + 4; } else { upscaled_height = (output->height - 1) * ratio->vert + 64 * spv + 32; - input->height = (upscaled_height >> 8) + 7; + height = (upscaled_height >> 8) + 7; } /* @@ -854,20 +890,29 @@ static void resizer_calc_ratios(struct isp_res_device *res, max_width & ~(width_alignment - 1)); output->width = ALIGN(output->width, width_alignment); - ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph) + ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph) / (output->width - 1); + if (ratio->horz > MID_RESIZE_VALUE) + ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph) + / (output->width - 1); ratio->horz = clamp_t(unsigned int, ratio->horz, MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); if (ratio->horz <= MID_RESIZE_VALUE) { upscaled_width = (output->width - 1) * ratio->horz + 32 * sph + 16; - input->width = (upscaled_width >> 8) + 7; + width = (upscaled_width >> 8) + 7; } else { upscaled_width = (output->width - 1) * ratio->horz + 64 * sph + 32; - input->width = (upscaled_width >> 8) + 7; + width = (upscaled_width >> 8) + 7; } + + /* Center the new crop rectangle. */ + input->left += (input->width - width) / 2; + input->top += (input->height - height) / 2; + input->width = width; + input->height = height; } /* diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h index 820950c9ef46..d86da94fa50d 100644 --- a/drivers/media/video/omap3isp/ispstat.h +++ b/drivers/media/video/omap3isp/ispstat.h @@ -131,9 +131,9 @@ struct ispstat { struct ispstat_generic_config { /* * Fields must be in the same order as in: - * - isph3a_aewb_config - * - isph3a_af_config - * - isphist_config + * - omap3isp_h3a_aewb_config + * - omap3isp_h3a_af_config + * - omap3isp_hist_config */ u32 buf_size; u16 config_counter; diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 208a7ec739d7..9cd8f1aa567b 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -47,29 +47,59 @@ static struct isp_format_info formats[] = { { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, - V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, }, + V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, + V4L2_PIX_FMT_GREY, 8, }, + { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10, + V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8, + V4L2_PIX_FMT_Y10, 10, }, + { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10, + V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8, + V4L2_PIX_FMT_Y12, 12, }, + { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_PIX_FMT_SBGGR8, 8, }, + { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_PIX_FMT_SGBRG8, 8, }, + { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_PIX_FMT_SGRBG8, 8, }, + { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_PIX_FMT_SRGGB8, 8, }, { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, - V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, + V4L2_MBUS_FMT_SGRBG10_1X10, 0, + V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 10, }, + V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_PIX_FMT_SBGGR10, 10, }, { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 10, }, + V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_PIX_FMT_SGBRG10, 10, }, { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 10, }, + V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_PIX_FMT_SGRBG10, 10, }, { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 10, }, + V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_PIX_FMT_SRGGB10, 10, }, { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 12, }, + V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_PIX_FMT_SBGGR12, 12, }, { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 12, }, + V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_PIX_FMT_SGBRG12, 12, }, { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 12, }, + V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_PIX_FMT_SGRBG12, 12, }, { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 12, }, + V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_PIX_FMT_SRGGB12, 12, }, { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16, - V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 16, }, + V4L2_MBUS_FMT_UYVY8_1X16, 0, + V4L2_PIX_FMT_UYVY, 16, }, { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16, - V4L2_MBUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 16, }, + V4L2_MBUS_FMT_YUYV8_1X16, 0, + V4L2_PIX_FMT_YUYV, 16, }, }; const struct isp_format_info * @@ -85,6 +115,37 @@ omap3isp_video_format_info(enum v4l2_mbus_pixelcode code) return NULL; } +/* + * Decide whether desired output pixel code can be obtained with + * the lane shifter by shifting the input pixel code. + * @in: input pixelcode to shifter + * @out: output pixelcode from shifter + * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0] + * + * return true if the combination is possible + * return false otherwise + */ +static bool isp_video_is_shiftable(enum v4l2_mbus_pixelcode in, + enum v4l2_mbus_pixelcode out, + unsigned int additional_shift) +{ + const struct isp_format_info *in_info, *out_info; + + if (in == out) + return true; + + in_info = omap3isp_video_format_info(in); + out_info = omap3isp_video_format_info(out); + + if ((in_info->flavor == 0) || (out_info->flavor == 0)) + return false; + + if (in_info->flavor != out_info->flavor) + return false; + + return in_info->bpp - out_info->bpp + additional_shift <= 6; +} + /* * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format * @video: ISP video instance @@ -235,6 +296,7 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) return -EPIPE; while (1) { + unsigned int shifter_link; /* Retrieve the sink format */ pad = &subdev->entity.pads[0]; if (!(pad->flags & MEDIA_PAD_FL_SINK)) @@ -263,6 +325,10 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) return -ENOSPC; } + /* If sink pad is on CCDC, the link has the lane shifter + * in the middle of it. */ + shifter_link = subdev == &isp->isp_ccdc.subdev; + /* Retrieve the source format */ pad = media_entity_remote_source(pad); if (pad == NULL || @@ -278,10 +344,24 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) return -EPIPE; /* Check if the two ends match */ - if (fmt_source.format.code != fmt_sink.format.code || - fmt_source.format.width != fmt_sink.format.width || + if (fmt_source.format.width != fmt_sink.format.width || fmt_source.format.height != fmt_sink.format.height) return -EPIPE; + + if (shifter_link) { + unsigned int parallel_shift = 0; + if (isp->isp_ccdc.input == CCDC_INPUT_PARALLEL) { + struct isp_parallel_platform_data *pdata = + &((struct isp_v4l2_subdevs_group *) + subdev->host_priv)->bus.parallel; + parallel_shift = pdata->data_lane_shift * 2; + } + if (!isp_video_is_shiftable(fmt_source.format.code, + fmt_sink.format.code, + parallel_shift)) + return -EPIPE; + } else if (fmt_source.format.code != fmt_sink.format.code) + return -EPIPE; } return 0; diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h index 524a1acd0906..911bea64e78a 100644 --- a/drivers/media/video/omap3isp/ispvideo.h +++ b/drivers/media/video/omap3isp/ispvideo.h @@ -49,6 +49,8 @@ struct v4l2_pix_format; * bits. Identical to @code if the format is 10 bits wide or less. * @uncompressed: V4L2 media bus format code for the corresponding uncompressed * format. Identical to @code if the format is not DPCM compressed. + * @flavor: V4L2 media bus format code for the same pixel layout but + * shifted to be 8 bits per pixel. =0 if format is not shiftable. * @pixelformat: V4L2 pixel format FCC identifier * @bpp: Bits per pixel */ @@ -56,6 +58,7 @@ struct isp_format_info { enum v4l2_mbus_pixelcode code; enum v4l2_mbus_pixelcode truncated; enum v4l2_mbus_pixelcode uncompressed; + enum v4l2_mbus_pixelcode flavor; u32 pixelformat; unsigned int bpp; }; diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 95f8b4e11e46..d142b40ea64e 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -527,7 +527,7 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, if (ret) return ret; - if (vb2_is_streaming(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) + if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) return -EBUSY; frame = &ctx->d_frame; @@ -539,8 +539,10 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, return -EINVAL; } - for (i = 0; i < frame->fmt->colplanes; i++) - frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; + for (i = 0; i < frame->fmt->colplanes; i++) { + frame->payload[i] = + (pix->width * pix->height * frame->fmt->depth[i]) >> 3; + } /* Output DMA frame pixel size and offsets. */ frame->f_width = pix->plane_fmt[0].bytesperline * 8 diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 6c919b38a3d8..dc91a8511af6 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -361,10 +361,20 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *v_buf; + struct timeval *tv; + struct timespec ts; if (!list_empty(&cap->active_buf_q) && test_bit(ST_CAPT_RUN, &fimc->state)) { + ktime_get_real_ts(&ts); + v_buf = active_queue_pop(cap); + + tv = &v_buf->vb.v4l2_buf.timestamp; + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; + v_buf->vb.v4l2_buf.sequence = cap->frame_count++; + vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); } @@ -758,7 +768,7 @@ static void fimc_unlock(struct vb2_queue *vq) mutex_unlock(&ctx->fimc_dev->lock); } -struct vb2_ops fimc_qops = { +static struct vb2_ops fimc_qops = { .queue_setup = fimc_queue_setup, .buf_prepare = fimc_buf_prepare, .buf_queue = fimc_buf_queue, @@ -927,23 +937,23 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, pix->num_planes = fmt->memplanes; pix->colorspace = V4L2_COLORSPACE_JPEG; + for (i = 0; i < pix->num_planes; ++i) { - int bpl = pix->plane_fmt[i].bytesperline; + u32 bpl = pix->plane_fmt[i].bytesperline; + u32 *sizeimage = &pix->plane_fmt[i].sizeimage; - dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d", - i, bpl, fmt->depth[i], pix->width, pix->height); + if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width)) + bpl = pix->width; /* Planar */ - if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width) - bpl = (pix->width * fmt->depth[0]) >> 3; + if (fmt->colplanes == 1 && /* Packed */ + (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width)) + bpl = (pix->width * fmt->depth[0]) / 8; - if (!pix->plane_fmt[i].sizeimage) - pix->plane_fmt[i].sizeimage = pix->height * bpl; + if (i == 0) /* Same bytesperline for each plane. */ + mod_x = bpl; - pix->plane_fmt[i].bytesperline = bpl; - - dbg("[%d]: bpl: %d, sizeimage: %d", - i, pix->plane_fmt[i].bytesperline, - pix->plane_fmt[i].sizeimage); + pix->plane_fmt[i].bytesperline = mod_x; + *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8; } return 0; @@ -965,7 +975,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - if (vb2_is_streaming(vq)) { + if (vb2_is_busy(vq)) { v4l2_err(&fimc->m2m.v4l2_dev, "queue (%d) busy\n", f->type); return -EBUSY; } @@ -985,8 +995,10 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, if (!frame->fmt) return -EINVAL; - for (i = 0; i < frame->fmt->colplanes; i++) - frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; + for (i = 0; i < frame->fmt->colplanes; i++) { + frame->payload[i] = + (pix->width * pix->height * frame->fmt->depth[i]) / 8; + } frame->f_width = pix->plane_fmt[0].bytesperline * 8 / frame->fmt->depth[0]; @@ -1750,7 +1762,7 @@ static int __devexit fimc_remove(struct platform_device *pdev) } /* Image pixel limits, similar across several FIMC HW revisions. */ -static struct fimc_pix_limit s5p_pix_limit[3] = { +static struct fimc_pix_limit s5p_pix_limit[4] = { [0] = { .scaler_en_w = 3264, .scaler_dis_w = 8192, @@ -1775,6 +1787,14 @@ static struct fimc_pix_limit s5p_pix_limit[3] = { .out_rot_en_w = 1280, .out_rot_dis_w = 1920, }, + [3] = { + .scaler_en_w = 1920, + .scaler_dis_w = 8192, + .in_rot_en_h = 1366, + .in_rot_dis_w = 8192, + .out_rot_en_w = 1366, + .out_rot_dis_w = 1920, + }, }; static struct samsung_fimc_variant fimc0_variant_s5p = { @@ -1827,7 +1847,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv210 = { .pix_limit = &s5p_pix_limit[2], }; -static struct samsung_fimc_variant fimc0_variant_s5pv310 = { +static struct samsung_fimc_variant fimc0_variant_exynos4 = { .pix_hoff = 1, .has_inp_rot = 1, .has_out_rot = 1, @@ -1840,7 +1860,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = { .pix_limit = &s5p_pix_limit[1], }; -static struct samsung_fimc_variant fimc2_variant_s5pv310 = { +static struct samsung_fimc_variant fimc2_variant_exynos4 = { .pix_hoff = 1, .has_cistatus2 = 1, .has_mainscaler_ext = 1, @@ -1848,7 +1868,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv310 = { .min_out_pixsize = 16, .hor_offs_align = 1, .out_buf_count = 32, - .pix_limit = &s5p_pix_limit[2], + .pix_limit = &s5p_pix_limit[3], }; /* S5PC100 */ @@ -1874,12 +1894,12 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = { }; /* S5PV310, S5PC210 */ -static struct samsung_fimc_driverdata fimc_drvdata_s5pv310 = { +static struct samsung_fimc_driverdata fimc_drvdata_exynos4 = { .variant = { - [0] = &fimc0_variant_s5pv310, - [1] = &fimc0_variant_s5pv310, - [2] = &fimc0_variant_s5pv310, - [3] = &fimc2_variant_s5pv310, + [0] = &fimc0_variant_exynos4, + [1] = &fimc0_variant_exynos4, + [2] = &fimc0_variant_exynos4, + [3] = &fimc2_variant_exynos4, }, .num_entities = 4, .lclk_frequency = 166000000UL, @@ -1893,8 +1913,8 @@ static struct platform_device_id fimc_driver_ids[] = { .name = "s5pv210-fimc", .driver_data = (unsigned long)&fimc_drvdata_s5pv210, }, { - .name = "s5pv310-fimc", - .driver_data = (unsigned long)&fimc_drvdata_s5pv310, + .name = "exynos4-fimc", + .driver_data = (unsigned long)&fimc_drvdata_exynos4, }, {}, }; diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 3fe54bf41142..134e86bf6d97 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -922,7 +922,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int /* Try 2560x1920, 1280x960, 640x480, 320x240 */ mf.width = 2560 >> shift; mf.height = 1920 >> shift; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, s_mbus_fmt, &mf); if (ret < 0) return ret; @@ -1224,7 +1224,7 @@ static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_cropcap cap; int ret; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, s_mbus_fmt, mf); if (ret < 0) return ret; @@ -1254,7 +1254,7 @@ static int client_s_fmt(struct soc_camera_device *icd, tmp_h = min(2 * tmp_h, max_height); mf->width = tmp_w; mf->height = tmp_h; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, s_mbus_fmt, mf); dev_geo(dev, "Camera scaled to %ux%u\n", mf->width, mf->height); @@ -1658,7 +1658,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, mf.code = xlate->code; mf.colorspace = pix->colorspace; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, try_mbus_fmt, &mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, try_mbus_fmt, &mf); if (ret < 0) return ret; @@ -1682,7 +1682,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, */ mf.width = 2560; mf.height = 1920; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, try_mbus_fmt, &mf); if (ret < 0) { /* Shouldn't actually happen... */ diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index dd1b81b1442b..98b87481fa94 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -38,6 +38,8 @@ struct sh_csi2 { void __iomem *base; struct platform_device *pdev; struct sh_csi2_client_config *client; + unsigned long (*query_bus_param)(struct soc_camera_device *); + int (*set_bus_param)(struct soc_camera_device *, unsigned long); }; static int sh_csi2_try_fmt(struct v4l2_subdev *sd, @@ -208,6 +210,7 @@ static int sh_csi2_notify(struct notifier_block *nb, case BUS_NOTIFY_BOUND_DRIVER: snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s", dev_name(v4l2_dev->dev), ".mipi-csi"); + priv->subdev.grp_id = (long)icd; ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev); dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret); if (ret < 0) @@ -215,6 +218,8 @@ static int sh_csi2_notify(struct notifier_block *nb, priv->client = pdata->clients + i; + priv->set_bus_param = icd->ops->set_bus_param; + priv->query_bus_param = icd->ops->query_bus_param; icd->ops->set_bus_param = sh_csi2_set_bus_param; icd->ops->query_bus_param = sh_csi2_query_bus_param; @@ -226,8 +231,10 @@ static int sh_csi2_notify(struct notifier_block *nb, priv->client = NULL; /* Driver is about to be unbound */ - icd->ops->set_bus_param = NULL; - icd->ops->query_bus_param = NULL; + icd->ops->set_bus_param = priv->set_bus_param; + icd->ops->query_bus_param = priv->query_bus_param; + priv->set_bus_param = NULL; + priv->query_bus_param = NULL; v4l2_device_unregister_subdev(&priv->subdev); diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 46284489e4eb..ddb4c091dedc 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -136,11 +136,50 @@ unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, } EXPORT_SYMBOL(soc_camera_apply_sensor_flags); +#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ + ((x) >> 24) & 0xff + +static int soc_camera_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct v4l2_pix_format *pix = &f->fmt.pix; + int ret; + + dev_dbg(&icd->dev, "TRY_FMT(%c%c%c%c, %ux%u)\n", + pixfmtstr(pix->pixelformat), pix->width, pix->height); + + pix->bytesperline = 0; + pix->sizeimage = 0; + + ret = ici->ops->try_fmt(icd, f); + if (ret < 0) + return ret; + + if (!pix->sizeimage) { + if (!pix->bytesperline) { + const struct soc_camera_format_xlate *xlate; + + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); + if (!xlate) + return -EINVAL; + + ret = soc_mbus_bytes_per_line(pix->width, + xlate->host_fmt); + if (ret > 0) + pix->bytesperline = ret; + } + if (pix->bytesperline) + pix->sizeimage = pix->bytesperline * pix->height; + } + + return 0; +} + static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); WARN_ON(priv != file->private_data); @@ -149,7 +188,7 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; /* limit format to hardware capabilities */ - return ici->ops->try_fmt(icd, f); + return soc_camera_try_fmt(icd, f); } static int soc_camera_enum_input(struct file *file, void *priv, @@ -362,9 +401,6 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd) icd->user_formats = NULL; } -#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ - ((x) >> 24) & 0xff - /* Called with .vb_lock held, or from the first open(2), see comment there */ static int soc_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_format *f) @@ -377,7 +413,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd, pixfmtstr(pix->pixelformat), pix->width, pix->height); /* We always call try_fmt() before set_fmt() or set_crop() */ - ret = ici->ops->try_fmt(icd, f); + ret = soc_camera_try_fmt(icd, f); if (ret < 0) return ret; @@ -996,10 +1032,11 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd) { struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct i2c_adapter *adap = client->adapter; dev_set_drvdata(&icd->dev, NULL); v4l2_device_unregister_subdev(i2c_get_clientdata(client)); i2c_unregister_device(client); - i2c_put_adapter(client->adapter); + i2c_put_adapter(adap); } #else #define soc_camera_init_i2c(icd, icl) (-ENODEV) @@ -1071,6 +1108,9 @@ static int soc_camera_probe(struct device *dev) } } + sd = soc_camera_to_subdev(icd); + sd->grp_id = (long)icd; + /* At this point client .probe() should have run already */ ret = soc_camera_init_user_formats(icd); if (ret < 0) @@ -1092,7 +1132,6 @@ static int soc_camera_probe(struct device *dev) goto evidstart; /* Try to improve our guess of a reasonable window format */ - sd = soc_camera_to_subdev(icd); if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { icd->user_width = mf.width; icd->user_height = mf.height; diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c index 5d4cf3b3d435..22fa8202d5ca 100644 --- a/drivers/media/video/tda9840.c +++ b/drivers/media/video/tda9840.c @@ -171,7 +171,7 @@ static int tda9840_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); if (sd == NULL) return -ENOMEM; v4l2_i2c_subdev_init(sd, client, &tda9840_ops); diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c index 19621ed523ec..827425c5b866 100644 --- a/drivers/media/video/tea6415c.c +++ b/drivers/media/video/tea6415c.c @@ -152,7 +152,7 @@ static int tea6415c_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); if (sd == NULL) return -ENOMEM; v4l2_i2c_subdev_init(sd, client, &tea6415c_ops); diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c index 5ea840401f21..f350b6c24500 100644 --- a/drivers/media/video/tea6420.c +++ b/drivers/media/video/tea6420.c @@ -125,7 +125,7 @@ static int tea6420_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); if (sd == NULL) return -ENOMEM; v4l2_i2c_subdev_init(sd, client, &tea6420_ops); diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index f8138c75be8b..1aab96a88203 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -230,7 +230,7 @@ static int upd64031a_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL); + state = kzalloc(sizeof(struct upd64031a_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; sd = &state->sd; diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 28e0e6b6ca84..9bbe61700fd5 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -202,7 +202,7 @@ static int upd64083_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL); + state = kzalloc(sizeof(struct upd64083_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; sd = &state->sd; diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 498e6742579e..6dc7196296b3 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -389,7 +389,8 @@ static int v4l2_open(struct inode *inode, struct file *filp) video_get(vdev); mutex_unlock(&videodev_lock); #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) { entity = media_entity_get(&vdev->entity); if (!entity) { ret = -EBUSY; @@ -415,7 +416,8 @@ static int v4l2_open(struct inode *inode, struct file *filp) /* decrease the refcount in case of an error */ if (ret) { #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) media_entity_put(entity); #endif video_put(vdev); @@ -437,7 +439,8 @@ static int v4l2_release(struct inode *inode, struct file *filp) mutex_unlock(vdev->lock); } #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) media_entity_put(&vdev->entity); #endif /* decrease the refcount unconditionally since the release() @@ -686,7 +689,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr, #if defined(CONFIG_MEDIA_CONTROLLER) /* Part 5: Register the entity. */ - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) { vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; vdev->entity.name = vdev->name; vdev->entity.v4l.major = VIDEO_MAJOR; @@ -733,7 +737,8 @@ void video_unregister_device(struct video_device *vdev) return; #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) media_device_unregister_entity(&vdev->entity); #endif diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index 5aeaf876ba9b..4aae501f02d0 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -155,8 +155,10 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, sd->v4l2_dev = v4l2_dev; if (sd->internal_ops && sd->internal_ops->registered) { err = sd->internal_ops->registered(sd); - if (err) + if (err) { + module_put(sd->owner); return err; + } } /* This just returns 0 if either of the two args is NULL */ @@ -164,6 +166,7 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, if (err) { if (sd->internal_ops && sd->internal_ops->unregistered) sd->internal_ops->unregistered(sd); + module_put(sd->owner); return err; } diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 0b8064490676..812729ebf09e 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -155,25 +155,25 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) switch (cmd) { case VIDIOC_QUERYCTRL: - return v4l2_subdev_queryctrl(sd, arg); + return v4l2_queryctrl(sd->ctrl_handler, arg); case VIDIOC_QUERYMENU: - return v4l2_subdev_querymenu(sd, arg); + return v4l2_querymenu(sd->ctrl_handler, arg); case VIDIOC_G_CTRL: - return v4l2_subdev_g_ctrl(sd, arg); + return v4l2_g_ctrl(sd->ctrl_handler, arg); case VIDIOC_S_CTRL: - return v4l2_subdev_s_ctrl(sd, arg); + return v4l2_s_ctrl(sd->ctrl_handler, arg); case VIDIOC_G_EXT_CTRLS: - return v4l2_subdev_g_ext_ctrls(sd, arg); + return v4l2_g_ext_ctrls(sd->ctrl_handler, arg); case VIDIOC_S_EXT_CTRLS: - return v4l2_subdev_s_ext_ctrls(sd, arg); + return v4l2_s_ext_ctrls(sd->ctrl_handler, arg); case VIDIOC_TRY_EXT_CTRLS: - return v4l2_subdev_try_ext_ctrls(sd, arg); + return v4l2_try_ext_ctrls(sd->ctrl_handler, arg); case VIDIOC_DQEVENT: if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c index c4742fc15529..c9691115f2d2 100644 --- a/drivers/media/video/videobuf-dma-contig.c +++ b/drivers/media/video/videobuf-dma-contig.c @@ -300,7 +300,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); retval = remap_pfn_range(vma, vma->vm_start, - PFN_DOWN(virt_to_phys(mem->vaddr)), + mem->dma_handle >> PAGE_SHIFT, size, vma->vm_page_prot); if (retval) { dev_err(q->dev, "mmap: remap failed with error %d. ", retval); diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 6698c77e0f64..6ba1461d51ef 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -37,6 +37,9 @@ module_param(debug, int, 0644); #define call_qop(q, op, args...) \ (((q)->ops->op) ? ((q)->ops->op(args)) : 0) +#define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ + V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR) + /** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer */ @@ -51,7 +54,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb, for (plane = 0; plane < vb->num_planes; ++plane) { mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane], plane_sizes[plane]); - if (!mem_priv) + if (IS_ERR_OR_NULL(mem_priv)) goto free; /* Associate allocator private data with this plane */ @@ -284,7 +287,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) struct vb2_queue *q = vb->vb2_queue; int ret = 0; - /* Copy back data such as timestamp, input, etc. */ + /* Copy back data such as timestamp, flags, input, etc. */ memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); b->input = vb->v4l2_buf.input; b->reserved = vb->v4l2_buf.reserved; @@ -313,7 +316,10 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) b->m.userptr = vb->v4l2_planes[0].m.userptr; } - b->flags = 0; + /* + * Clear any buffer state related flags. + */ + b->flags &= ~V4L2_BUFFER_STATE_FLAGS; switch (vb->state) { case VB2_BUF_STATE_QUEUED: @@ -519,6 +525,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME); memset(plane_sizes, 0, sizeof(plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); + q->memory = req->memory; /* * Ask the driver how many buffers and planes per buffer it requires. @@ -560,8 +567,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) ret = num_buffers; } - q->memory = req->memory; - /* * Return the number of successfully allocated buffers * to the userspace. @@ -715,6 +720,8 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, vb->v4l2_buf.field = b->field; vb->v4l2_buf.timestamp = b->timestamp; + vb->v4l2_buf.input = b->input; + vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS; return 0; } diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c index 58205d596138..a790a5f8c06f 100644 --- a/drivers/media/video/videobuf2-dma-contig.c +++ b/drivers/media/video/videobuf2-dma-contig.c @@ -46,7 +46,7 @@ static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size) GFP_KERNEL); if (!buf->vaddr) { dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n", - buf->size); + size); kfree(buf); return ERR_PTR(-ENOMEM); } diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 1735c84ff757..fe902338539b 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.18" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.18" +#define MPT_LINUX_VERSION_COMMON "3.04.19" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.19" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 66f94125de4e..7596aecd5072 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -5012,7 +5012,6 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) { VirtTarget *vtarget = NULL; u8 id, channel; - u32 log_info = le32_to_cpu(reply->IOCLogInfo); id = sas_event_data->TargetID; channel = sas_event_data->Bus; @@ -5023,7 +5022,8 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) "LogInfo (0x%x) available for " "INTERNAL_DEVICE_RESET" "fw_id %d fw_channel %d\n", ioc->name, - log_info, id, channel)); + le32_to_cpu(reply->IOCLogInfo), + id, channel)); if (vtarget->raidVolume) { devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Skipping Raid Volume for inDMD\n", diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 0d9b82a44540..a1d4ee6671be 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1415,11 +1415,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n", ioc->name, SCpnt, done)); - if (ioc->taskmgmt_quiesce_io) { - dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", - ioc->name, SCpnt)); + if (ioc->taskmgmt_quiesce_io) return SCSI_MLQUEUE_HOST_BUSY; - } /* * Put together a MPT SCSI request... @@ -1773,7 +1770,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) int scpnt_idx; int retval; VirtDevice *vdevice; - ulong sn = SCpnt->serial_number; MPT_ADAPTER *ioc; /* If we can't locate our host adapter structure, return FAILED status. @@ -1859,8 +1855,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) vdevice->vtarget->id, vdevice->lun, ctx2abort, mptscsih_get_tm_timeout(ioc)); - if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx && - SCpnt->serial_number == sn) { + if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx) { dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: command still in active list! (sc=%p)\n", ioc->name, SCpnt)); @@ -1873,9 +1868,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) } out: - printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p) (sn=%ld)\n", + printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p)\n", ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval, - SCpnt, SCpnt->serial_number); + SCpnt); return retval; } diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 6d9568d2ec59..8f61ba6aac23 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -867,6 +867,10 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget, struct _x_config_parms cfg; struct _CONFIG_PAGE_HEADER hdr; int err = -EBUSY; + u32 nego_parms; + u32 period; + struct scsi_device *sdev; + int i; /* don't allow updating nego parameters on RAID devices */ if (starget->channel == 0 && @@ -904,6 +908,24 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget, pg1->Header.PageNumber = hdr.PageNumber; pg1->Header.PageType = hdr.PageType; + nego_parms = le32_to_cpu(pg1->RequestedParameters); + period = (nego_parms & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK) >> + MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD; + if (period == 8) { + /* Turn on inline data padding for TAPE when running U320 */ + for (i = 0 ; i < 16; i++) { + sdev = scsi_device_lookup_by_target(starget, i); + if (sdev && sdev->type == TYPE_TAPE) { + sdev_printk(KERN_DEBUG, sdev, MYIOC_s_FMT + "IDP:ON\n", ioc->name); + nego_parms |= MPI_SCSIDEVPAGE1_RP_IDP; + pg1->RequestedParameters = + cpu_to_le32(nego_parms); + break; + } + } + } + mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters)); if (mpt_config(ioc, &cfg)) { diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 643ad52e3ca2..4796bbf0ae4e 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -1000,7 +1000,6 @@ static struct i2o_block_device *i2o_block_device_alloc(void) gd->major = I2O_MAJOR; gd->queue = queue; gd->fops = &i2o_block_fops; - gd->events = DISK_EVENT_MEDIA_CHANGE; gd->private_data = dev; dev->gd = gd; diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index f003957e8e1c..74fbe56321ff 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c @@ -361,7 +361,7 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m, */ error = le32_to_cpu(msg->body[0]); - osm_debug("Completed %ld\n", cmd->serial_number); + osm_debug("Completed %0x%p\n", cmd); cmd->result = error & 0xff; /* @@ -678,7 +678,7 @@ static int i2o_scsi_queuecommand_lck(struct scsi_cmnd *SCpnt, /* Queue the message */ i2o_msg_post(c, msg); - osm_debug("Issued %ld\n", SCpnt->serial_number); + osm_debug("Issued %0x%p\n", SCpnt); return 0; diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index d4a851c6b5bf..0b4d5b23bec9 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -144,7 +144,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) int iter, i; unsigned long flags; - data->chip->irq_ack(irq_data); + data->chip->irq_ack(data); for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) { u32 status; diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 53450f433f10..3ab9ffa00aad 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #define USBHS_DRIVER_NAME "usbhs-omap" @@ -700,8 +699,7 @@ static int usbhs_enable(struct device *dev) dev_dbg(dev, "starting TI HSUSB Controller\n"); if (!pdata) { dev_dbg(dev, "missing platform_data\n"); - ret = -ENODEV; - goto end_enable; + return -ENODEV; } spin_lock_irqsave(&omap->lock, flags); @@ -719,14 +717,14 @@ static int usbhs_enable(struct device *dev) gpio_request(pdata->ehci_data->reset_gpio_port[0], "USB1 PHY reset"); gpio_direction_output - (pdata->ehci_data->reset_gpio_port[0], 1); + (pdata->ehci_data->reset_gpio_port[0], 0); } if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) { gpio_request(pdata->ehci_data->reset_gpio_port[1], "USB2 PHY reset"); gpio_direction_output - (pdata->ehci_data->reset_gpio_port[1], 1); + (pdata->ehci_data->reset_gpio_port[1], 0); } /* Hold the PHY in RESET for enough time till DIR is high */ @@ -906,16 +904,17 @@ static int usbhs_enable(struct device *dev) if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_set_value - (pdata->ehci_data->reset_gpio_port[0], 0); + (pdata->ehci_data->reset_gpio_port[0], 1); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_set_value - (pdata->ehci_data->reset_gpio_port[1], 0); + (pdata->ehci_data->reset_gpio_port[1], 1); } end_count: omap->count++; - goto end_enable; + spin_unlock_irqrestore(&omap->lock, flags); + return 0; err_tll: if (pdata->ehci_data->phy_reset) { @@ -931,8 +930,6 @@ static int usbhs_enable(struct device *dev) clk_disable(omap->usbhost_fs_fck); clk_disable(omap->usbhost_hs_fck); clk_disable(omap->usbhost_ick); - -end_enable: spin_unlock_irqrestore(&omap->lock, flags); return ret; } diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 16422de0823a..2c0d4d16491a 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -447,12 +447,13 @@ static int __init load_twl4030_script(struct twl4030_script *tscript, if (err) goto out; } - if (tscript->flags & TWL4030_SLEEP_SCRIPT) + if (tscript->flags & TWL4030_SLEEP_SCRIPT) { if (order) pr_warning("TWL4030: Bad order of scripts (sleep "\ "script before wakeup) Leads to boot"\ "failure on some boards\n"); err = twl4030_config_sleep_sequence(address); + } out: return err; } diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 4e007c6a4b44..d80dcdee88f3 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -481,5 +481,6 @@ source "drivers/misc/cb710/Kconfig" source "drivers/misc/iwmc3200top/Kconfig" source "drivers/misc/ti-st/Kconfig" source "drivers/misc/lis3lv02d/Kconfig" +source "drivers/misc/carma/Kconfig" endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index f5468602961f..848e8464faab 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -44,3 +44,4 @@ obj-$(CONFIG_PCH_PHUB) += pch_phub.o obj-y += ti-st/ obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o obj-y += lis3lv02d/ +obj-y += carma/ diff --git a/drivers/misc/carma/Kconfig b/drivers/misc/carma/Kconfig new file mode 100644 index 000000000000..c90370ed712b --- /dev/null +++ b/drivers/misc/carma/Kconfig @@ -0,0 +1,17 @@ +config CARMA_FPGA + tristate "CARMA DATA-FPGA Access Driver" + depends on FSL_SOC && PPC_83xx && MEDIA_SUPPORT && HAS_DMA && FSL_DMA + select VIDEOBUF_DMA_SG + default n + help + Say Y here to include support for communicating with the data + processing FPGAs on the OVRO CARMA board. + +config CARMA_FPGA_PROGRAM + tristate "CARMA DATA-FPGA Programmer" + depends on FSL_SOC && PPC_83xx && MEDIA_SUPPORT && HAS_DMA && FSL_DMA + select VIDEOBUF_DMA_SG + default n + help + Say Y here to include support for programming the data processing + FPGAs on the OVRO CARMA board. diff --git a/drivers/misc/carma/Makefile b/drivers/misc/carma/Makefile new file mode 100644 index 000000000000..ff36ac2ce534 --- /dev/null +++ b/drivers/misc/carma/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_CARMA_FPGA) += carma-fpga.o +obj-$(CONFIG_CARMA_FPGA_PROGRAM) += carma-fpga-program.o diff --git a/drivers/misc/carma/carma-fpga-program.c b/drivers/misc/carma/carma-fpga-program.c new file mode 100644 index 000000000000..7ce6065dc20e --- /dev/null +++ b/drivers/misc/carma/carma-fpga-program.c @@ -0,0 +1,1141 @@ +/* + * CARMA Board DATA-FPGA Programmer + * + * Copyright (c) 2009-2011 Ira W. Snyder + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* MPC8349EMDS specific get_immrbase() */ +#include + +static const char drv_name[] = "carma-fpga-program"; + +/* + * Firmware images are always this exact size + * + * 12849552 bytes for a CARMA Digitizer Board (EP2S90 FPGAs) + * 18662880 bytes for a CARMA Correlator Board (EP2S130 FPGAs) + */ +#define FW_SIZE_EP2S90 12849552 +#define FW_SIZE_EP2S130 18662880 + +struct fpga_dev { + struct miscdevice miscdev; + + /* Reference count */ + struct kref ref; + + /* Device Registers */ + struct device *dev; + void __iomem *regs; + void __iomem *immr; + + /* Freescale DMA Device */ + struct dma_chan *chan; + + /* Interrupts */ + int irq, status; + struct completion completion; + + /* FPGA Bitfile */ + struct mutex lock; + + struct videobuf_dmabuf vb; + bool vb_allocated; + + /* max size and written bytes */ + size_t fw_size; + size_t bytes; +}; + +/* + * FPGA Bitfile Helpers + */ + +/** + * fpga_drop_firmware_data() - drop the bitfile image from memory + * @priv: the driver's private data structure + * + * LOCKING: must hold priv->lock + */ +static void fpga_drop_firmware_data(struct fpga_dev *priv) +{ + videobuf_dma_free(&priv->vb); + priv->vb_allocated = false; + priv->bytes = 0; +} + +/* + * Private Data Reference Count + */ + +static void fpga_dev_remove(struct kref *ref) +{ + struct fpga_dev *priv = container_of(ref, struct fpga_dev, ref); + + /* free any firmware image that was not programmed */ + fpga_drop_firmware_data(priv); + + mutex_destroy(&priv->lock); + kfree(priv); +} + +/* + * LED Trigger (could be a seperate module) + */ + +/* + * NOTE: this whole thing does have the problem that whenever the led's are + * NOTE: first set to use the fpga trigger, they could be in the wrong state + */ + +DEFINE_LED_TRIGGER(ledtrig_fpga); + +static void ledtrig_fpga_programmed(bool enabled) +{ + if (enabled) + led_trigger_event(ledtrig_fpga, LED_FULL); + else + led_trigger_event(ledtrig_fpga, LED_OFF); +} + +/* + * FPGA Register Helpers + */ + +/* Register Definitions */ +#define FPGA_CONFIG_CONTROL 0x40 +#define FPGA_CONFIG_STATUS 0x44 +#define FPGA_CONFIG_FIFO_SIZE 0x48 +#define FPGA_CONFIG_FIFO_USED 0x4C +#define FPGA_CONFIG_TOTAL_BYTE_COUNT 0x50 +#define FPGA_CONFIG_CUR_BYTE_COUNT 0x54 + +#define FPGA_FIFO_ADDRESS 0x3000 + +static int fpga_fifo_size(void __iomem *regs) +{ + return ioread32be(regs + FPGA_CONFIG_FIFO_SIZE); +} + +#define CFG_STATUS_ERR_MASK 0xfffe + +static int fpga_config_error(void __iomem *regs) +{ + return ioread32be(regs + FPGA_CONFIG_STATUS) & CFG_STATUS_ERR_MASK; +} + +static int fpga_fifo_empty(void __iomem *regs) +{ + return ioread32be(regs + FPGA_CONFIG_FIFO_USED) == 0; +} + +static void fpga_fifo_write(void __iomem *regs, u32 val) +{ + iowrite32be(val, regs + FPGA_FIFO_ADDRESS); +} + +static void fpga_set_byte_count(void __iomem *regs, u32 count) +{ + iowrite32be(count, regs + FPGA_CONFIG_TOTAL_BYTE_COUNT); +} + +#define CFG_CTL_ENABLE (1 << 0) +#define CFG_CTL_RESET (1 << 1) +#define CFG_CTL_DMA (1 << 2) + +static void fpga_programmer_enable(struct fpga_dev *priv, bool dma) +{ + u32 val; + + val = (dma) ? (CFG_CTL_ENABLE | CFG_CTL_DMA) : CFG_CTL_ENABLE; + iowrite32be(val, priv->regs + FPGA_CONFIG_CONTROL); +} + +static void fpga_programmer_disable(struct fpga_dev *priv) +{ + iowrite32be(0x0, priv->regs + FPGA_CONFIG_CONTROL); +} + +static void fpga_dump_registers(struct fpga_dev *priv) +{ + u32 control, status, size, used, total, curr; + + /* good status: do nothing */ + if (priv->status == 0) + return; + + /* Dump all status registers */ + control = ioread32be(priv->regs + FPGA_CONFIG_CONTROL); + status = ioread32be(priv->regs + FPGA_CONFIG_STATUS); + size = ioread32be(priv->regs + FPGA_CONFIG_FIFO_SIZE); + used = ioread32be(priv->regs + FPGA_CONFIG_FIFO_USED); + total = ioread32be(priv->regs + FPGA_CONFIG_TOTAL_BYTE_COUNT); + curr = ioread32be(priv->regs + FPGA_CONFIG_CUR_BYTE_COUNT); + + dev_err(priv->dev, "Configuration failed, dumping status registers\n"); + dev_err(priv->dev, "Control: 0x%.8x\n", control); + dev_err(priv->dev, "Status: 0x%.8x\n", status); + dev_err(priv->dev, "FIFO Size: 0x%.8x\n", size); + dev_err(priv->dev, "FIFO Used: 0x%.8x\n", used); + dev_err(priv->dev, "FIFO Total: 0x%.8x\n", total); + dev_err(priv->dev, "FIFO Curr: 0x%.8x\n", curr); +} + +/* + * FPGA Power Supply Code + */ + +#define CTL_PWR_CONTROL 0x2006 +#define CTL_PWR_STATUS 0x200A +#define CTL_PWR_FAIL 0x200B + +#define PWR_CONTROL_ENABLE 0x01 + +#define PWR_STATUS_ERROR_MASK 0x10 +#define PWR_STATUS_GOOD 0x0f + +/* + * Determine if the FPGA power is good for all supplies + */ +static bool fpga_power_good(struct fpga_dev *priv) +{ + u8 val; + + val = ioread8(priv->regs + CTL_PWR_STATUS); + if (val & PWR_STATUS_ERROR_MASK) + return false; + + return val == PWR_STATUS_GOOD; +} + +/* + * Disable the FPGA power supplies + */ +static void fpga_disable_power_supplies(struct fpga_dev *priv) +{ + unsigned long start; + u8 val; + + iowrite8(0x0, priv->regs + CTL_PWR_CONTROL); + + /* + * Wait 500ms for the power rails to discharge + * + * Without this delay, the CTL-CPLD state machine can get into a + * state where it is waiting for the power-goods to assert, but they + * never do. This only happens when enabling and disabling the + * power sequencer very rapidly. + * + * The loop below will also wait for the power goods to de-assert, + * but testing has shown that they are always disabled by the time + * the sleep completes. However, omitting the sleep and only waiting + * for the power-goods to de-assert was not sufficient to ensure + * that the power sequencer would not wedge itself. + */ + msleep(500); + + start = jiffies; + while (time_before(jiffies, start + HZ)) { + val = ioread8(priv->regs + CTL_PWR_STATUS); + if (!(val & PWR_STATUS_GOOD)) + break; + + usleep_range(5000, 10000); + } + + val = ioread8(priv->regs + CTL_PWR_STATUS); + if (val & PWR_STATUS_GOOD) { + dev_err(priv->dev, "power disable failed: " + "power goods: status 0x%.2x\n", val); + } + + if (val & PWR_STATUS_ERROR_MASK) { + dev_err(priv->dev, "power disable failed: " + "alarm bit set: status 0x%.2x\n", val); + } +} + +/** + * fpga_enable_power_supplies() - enable the DATA-FPGA power supplies + * @priv: the driver's private data structure + * + * Enable the DATA-FPGA power supplies, waiting up to 1 second for + * them to enable successfully. + * + * Returns 0 on success, -ERRNO otherwise + */ +static int fpga_enable_power_supplies(struct fpga_dev *priv) +{ + unsigned long start = jiffies; + + if (fpga_power_good(priv)) { + dev_dbg(priv->dev, "power was already good\n"); + return 0; + } + + iowrite8(PWR_CONTROL_ENABLE, priv->regs + CTL_PWR_CONTROL); + while (time_before(jiffies, start + HZ)) { + if (fpga_power_good(priv)) + return 0; + + usleep_range(5000, 10000); + } + + return fpga_power_good(priv) ? 0 : -ETIMEDOUT; +} + +/* + * Determine if the FPGA power supplies are all enabled + */ +static bool fpga_power_enabled(struct fpga_dev *priv) +{ + u8 val; + + val = ioread8(priv->regs + CTL_PWR_CONTROL); + if (val & PWR_CONTROL_ENABLE) + return true; + + return false; +} + +/* + * Determine if the FPGA's are programmed and running correctly + */ +static bool fpga_running(struct fpga_dev *priv) +{ + if (!fpga_power_good(priv)) + return false; + + /* Check the config done bit */ + return ioread32be(priv->regs + FPGA_CONFIG_STATUS) & (1 << 18); +} + +/* + * FPGA Programming Code + */ + +/** + * fpga_program_block() - put a block of data into the programmer's FIFO + * @priv: the driver's private data structure + * @buf: the data to program + * @count: the length of data to program (must be a multiple of 4 bytes) + * + * Returns 0 on success, -ERRNO otherwise + */ +static int fpga_program_block(struct fpga_dev *priv, void *buf, size_t count) +{ + u32 *data = buf; + int size = fpga_fifo_size(priv->regs); + int i, len; + unsigned long timeout; + + /* enforce correct data length for the FIFO */ + BUG_ON(count % 4 != 0); + + while (count > 0) { + + /* Get the size of the block to write (maximum is FIFO_SIZE) */ + len = min_t(size_t, count, size); + timeout = jiffies + HZ / 4; + + /* Write the block */ + for (i = 0; i < len / 4; i++) + fpga_fifo_write(priv->regs, data[i]); + + /* Update the amounts left */ + count -= len; + data += len / 4; + + /* Wait for the fifo to empty */ + while (true) { + + if (fpga_fifo_empty(priv->regs)) { + break; + } else { + dev_dbg(priv->dev, "Fifo not empty\n"); + cpu_relax(); + } + + if (fpga_config_error(priv->regs)) { + dev_err(priv->dev, "Error detected\n"); + return -EIO; + } + + if (time_after(jiffies, timeout)) { + dev_err(priv->dev, "Fifo drain timeout\n"); + return -ETIMEDOUT; + } + + usleep_range(5000, 10000); + } + } + + return 0; +} + +/** + * fpga_program_cpu() - program the DATA-FPGA's using the CPU + * @priv: the driver's private data structure + * + * This is useful when the DMA programming method fails. It is possible to + * wedge the Freescale DMA controller such that the DMA programming method + * always fails. This method has always succeeded. + * + * Returns 0 on success, -ERRNO otherwise + */ +static noinline int fpga_program_cpu(struct fpga_dev *priv) +{ + int ret; + + /* Disable the programmer */ + fpga_programmer_disable(priv); + + /* Set the total byte count */ + fpga_set_byte_count(priv->regs, priv->bytes); + dev_dbg(priv->dev, "total byte count %u bytes\n", priv->bytes); + + /* Enable the controller for programming */ + fpga_programmer_enable(priv, false); + dev_dbg(priv->dev, "enabled the controller\n"); + + /* Write each chunk of the FPGA bitfile to FPGA programmer */ + ret = fpga_program_block(priv, priv->vb.vaddr, priv->bytes); + if (ret) + goto out_disable_controller; + + /* Wait for the interrupt handler to signal that programming finished */ + ret = wait_for_completion_timeout(&priv->completion, 2 * HZ); + if (!ret) { + dev_err(priv->dev, "Timed out waiting for completion\n"); + ret = -ETIMEDOUT; + goto out_disable_controller; + } + + /* Retrieve the status from the interrupt handler */ + ret = priv->status; + +out_disable_controller: + fpga_programmer_disable(priv); + return ret; +} + +#define FIFO_DMA_ADDRESS 0xf0003000 +#define FIFO_MAX_LEN 4096 + +/** + * fpga_program_dma() - program the DATA-FPGA's using the DMA engine + * @priv: the driver's private data structure + * + * Program the DATA-FPGA's using the Freescale DMA engine. This requires that + * the engine is programmed such that the hardware DMA request lines can + * control the entire DMA transaction. The system controller FPGA then + * completely offloads the programming from the CPU. + * + * Returns 0 on success, -ERRNO otherwise + */ +static noinline int fpga_program_dma(struct fpga_dev *priv) +{ + struct videobuf_dmabuf *vb = &priv->vb; + struct dma_chan *chan = priv->chan; + struct dma_async_tx_descriptor *tx; + size_t num_pages, len, avail = 0; + struct dma_slave_config config; + struct scatterlist *sg; + struct sg_table table; + dma_cookie_t cookie; + int ret, i; + + /* Disable the programmer */ + fpga_programmer_disable(priv); + + /* Allocate a scatterlist for the DMA destination */ + num_pages = DIV_ROUND_UP(priv->bytes, FIFO_MAX_LEN); + ret = sg_alloc_table(&table, num_pages, GFP_KERNEL); + if (ret) { + dev_err(priv->dev, "Unable to allocate dst scatterlist\n"); + ret = -ENOMEM; + goto out_return; + } + + /* + * This is an ugly hack + * + * We fill in a scatterlist as if it were mapped for DMA. This is + * necessary because there exists no better structure for this + * inside the kernel code. + * + * As an added bonus, we can use the DMAEngine API for all of this, + * rather than inventing another extremely similar API. + */ + avail = priv->bytes; + for_each_sg(table.sgl, sg, num_pages, i) { + len = min_t(size_t, avail, FIFO_MAX_LEN); + sg_dma_address(sg) = FIFO_DMA_ADDRESS; + sg_dma_len(sg) = len; + + avail -= len; + } + + /* Map the buffer for DMA */ + ret = videobuf_dma_map(priv->dev, &priv->vb); + if (ret) { + dev_err(priv->dev, "Unable to map buffer for DMA\n"); + goto out_free_table; + } + + /* + * Configure the DMA channel to transfer FIFO_SIZE / 2 bytes per + * transaction, and then put it under external control + */ + memset(&config, 0, sizeof(config)); + config.direction = DMA_TO_DEVICE; + config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + config.dst_maxburst = fpga_fifo_size(priv->regs) / 2 / 4; + ret = chan->device->device_control(chan, DMA_SLAVE_CONFIG, + (unsigned long)&config); + if (ret) { + dev_err(priv->dev, "DMA slave configuration failed\n"); + goto out_dma_unmap; + } + + ret = chan->device->device_control(chan, FSLDMA_EXTERNAL_START, 1); + if (ret) { + dev_err(priv->dev, "DMA external control setup failed\n"); + goto out_dma_unmap; + } + + /* setup and submit the DMA transaction */ + tx = chan->device->device_prep_dma_sg(chan, + table.sgl, num_pages, + vb->sglist, vb->sglen, 0); + if (!tx) { + dev_err(priv->dev, "Unable to prep DMA transaction\n"); + ret = -ENOMEM; + goto out_dma_unmap; + } + + cookie = tx->tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_err(priv->dev, "Unable to submit DMA transaction\n"); + ret = -ENOMEM; + goto out_dma_unmap; + } + + dma_async_memcpy_issue_pending(chan); + + /* Set the total byte count */ + fpga_set_byte_count(priv->regs, priv->bytes); + dev_dbg(priv->dev, "total byte count %u bytes\n", priv->bytes); + + /* Enable the controller for DMA programming */ + fpga_programmer_enable(priv, true); + dev_dbg(priv->dev, "enabled the controller\n"); + + /* Wait for the interrupt handler to signal that programming finished */ + ret = wait_for_completion_timeout(&priv->completion, 2 * HZ); + if (!ret) { + dev_err(priv->dev, "Timed out waiting for completion\n"); + ret = -ETIMEDOUT; + goto out_disable_controller; + } + + /* Retrieve the status from the interrupt handler */ + ret = priv->status; + +out_disable_controller: + fpga_programmer_disable(priv); +out_dma_unmap: + videobuf_dma_unmap(priv->dev, vb); +out_free_table: + sg_free_table(&table); +out_return: + return ret; +} + +/* + * Interrupt Handling + */ + +static irqreturn_t fpga_irq(int irq, void *dev_id) +{ + struct fpga_dev *priv = dev_id; + + /* Save the status */ + priv->status = fpga_config_error(priv->regs) ? -EIO : 0; + dev_dbg(priv->dev, "INTERRUPT status %d\n", priv->status); + fpga_dump_registers(priv); + + /* Disabling the programmer clears the interrupt */ + fpga_programmer_disable(priv); + + /* Notify any waiters */ + complete(&priv->completion); + + return IRQ_HANDLED; +} + +/* + * SYSFS Helpers + */ + +/** + * fpga_do_stop() - deconfigure (reset) the DATA-FPGA's + * @priv: the driver's private data structure + * + * LOCKING: must hold priv->lock + */ +static int fpga_do_stop(struct fpga_dev *priv) +{ + u32 val; + + /* Set the led to unprogrammed */ + ledtrig_fpga_programmed(false); + + /* Pulse the config line to reset the FPGA's */ + val = CFG_CTL_ENABLE | CFG_CTL_RESET; + iowrite32be(val, priv->regs + FPGA_CONFIG_CONTROL); + iowrite32be(0x0, priv->regs + FPGA_CONFIG_CONTROL); + + return 0; +} + +static noinline int fpga_do_program(struct fpga_dev *priv) +{ + int ret; + + if (priv->bytes != priv->fw_size) { + dev_err(priv->dev, "Incorrect bitfile size: got %zu bytes, " + "should be %zu bytes\n", + priv->bytes, priv->fw_size); + return -EINVAL; + } + + if (!fpga_power_enabled(priv)) { + dev_err(priv->dev, "Power not enabled\n"); + return -EINVAL; + } + + if (!fpga_power_good(priv)) { + dev_err(priv->dev, "Power not good\n"); + return -EINVAL; + } + + /* Set the LED to unprogrammed */ + ledtrig_fpga_programmed(false); + + /* Try to program the FPGA's using DMA */ + ret = fpga_program_dma(priv); + + /* If DMA failed or doesn't exist, try with CPU */ + if (ret) { + dev_warn(priv->dev, "Falling back to CPU programming\n"); + ret = fpga_program_cpu(priv); + } + + if (ret) { + dev_err(priv->dev, "Unable to program FPGA's\n"); + return ret; + } + + /* Drop the firmware bitfile from memory */ + fpga_drop_firmware_data(priv); + + dev_dbg(priv->dev, "FPGA programming successful\n"); + ledtrig_fpga_programmed(true); + + return 0; +} + +/* + * File Operations + */ + +static int fpga_open(struct inode *inode, struct file *filp) +{ + /* + * The miscdevice layer puts our struct miscdevice into the + * filp->private_data field. We use this to find our private + * data and then overwrite it with our own private structure. + */ + struct fpga_dev *priv = container_of(filp->private_data, + struct fpga_dev, miscdev); + unsigned int nr_pages; + int ret; + + /* We only allow one process at a time */ + ret = mutex_lock_interruptible(&priv->lock); + if (ret) + return ret; + + filp->private_data = priv; + kref_get(&priv->ref); + + /* Truncation: drop any existing data */ + if (filp->f_flags & O_TRUNC) + priv->bytes = 0; + + /* Check if we have already allocated a buffer */ + if (priv->vb_allocated) + return 0; + + /* Allocate a buffer to hold enough data for the bitfile */ + nr_pages = DIV_ROUND_UP(priv->fw_size, PAGE_SIZE); + ret = videobuf_dma_init_kernel(&priv->vb, DMA_TO_DEVICE, nr_pages); + if (ret) { + dev_err(priv->dev, "unable to allocate data buffer\n"); + mutex_unlock(&priv->lock); + kref_put(&priv->ref, fpga_dev_remove); + return ret; + } + + priv->vb_allocated = true; + return 0; +} + +static int fpga_release(struct inode *inode, struct file *filp) +{ + struct fpga_dev *priv = filp->private_data; + + mutex_unlock(&priv->lock); + kref_put(&priv->ref, fpga_dev_remove); + return 0; +} + +static ssize_t fpga_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + struct fpga_dev *priv = filp->private_data; + + /* FPGA bitfiles have an exact size: disallow anything else */ + if (priv->bytes >= priv->fw_size) + return -ENOSPC; + + count = min_t(size_t, priv->fw_size - priv->bytes, count); + if (copy_from_user(priv->vb.vaddr + priv->bytes, buf, count)) + return -EFAULT; + + priv->bytes += count; + return count; +} + +static ssize_t fpga_read(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + struct fpga_dev *priv = filp->private_data; + + count = min_t(size_t, priv->bytes - *f_pos, count); + if (copy_to_user(buf, priv->vb.vaddr + *f_pos, count)) + return -EFAULT; + + *f_pos += count; + return count; +} + +static loff_t fpga_llseek(struct file *filp, loff_t offset, int origin) +{ + struct fpga_dev *priv = filp->private_data; + loff_t newpos; + + /* only read-only opens are allowed to seek */ + if ((filp->f_flags & O_ACCMODE) != O_RDONLY) + return -EINVAL; + + switch (origin) { + case SEEK_SET: /* seek relative to the beginning of the file */ + newpos = offset; + break; + case SEEK_CUR: /* seek relative to current position in the file */ + newpos = filp->f_pos + offset; + break; + case SEEK_END: /* seek relative to the end of the file */ + newpos = priv->fw_size - offset; + break; + default: + return -EINVAL; + } + + /* check for sanity */ + if (newpos > priv->fw_size) + return -EINVAL; + + filp->f_pos = newpos; + return newpos; +} + +static const struct file_operations fpga_fops = { + .open = fpga_open, + .release = fpga_release, + .write = fpga_write, + .read = fpga_read, + .llseek = fpga_llseek, +}; + +/* + * Device Attributes + */ + +static ssize_t pfail_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fpga_dev *priv = dev_get_drvdata(dev); + u8 val; + + val = ioread8(priv->regs + CTL_PWR_FAIL); + return snprintf(buf, PAGE_SIZE, "0x%.2x\n", val); +} + +static ssize_t pgood_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fpga_dev *priv = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", fpga_power_good(priv)); +} + +static ssize_t penable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fpga_dev *priv = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", fpga_power_enabled(priv)); +} + +static ssize_t penable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fpga_dev *priv = dev_get_drvdata(dev); + unsigned long val; + int ret; + + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + if (val) { + ret = fpga_enable_power_supplies(priv); + if (ret) + return ret; + } else { + fpga_do_stop(priv); + fpga_disable_power_supplies(priv); + } + + return count; +} + +static ssize_t program_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fpga_dev *priv = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", fpga_running(priv)); +} + +static ssize_t program_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fpga_dev *priv = dev_get_drvdata(dev); + unsigned long val; + int ret; + + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + /* We can't have an image writer and be programming simultaneously */ + if (mutex_lock_interruptible(&priv->lock)) + return -ERESTARTSYS; + + /* Program or Reset the FPGA's */ + ret = val ? fpga_do_program(priv) : fpga_do_stop(priv); + if (ret) + goto out_unlock; + + /* Success */ + ret = count; + +out_unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static DEVICE_ATTR(power_fail, S_IRUGO, pfail_show, NULL); +static DEVICE_ATTR(power_good, S_IRUGO, pgood_show, NULL); +static DEVICE_ATTR(power_enable, S_IRUGO | S_IWUSR, + penable_show, penable_store); + +static DEVICE_ATTR(program, S_IRUGO | S_IWUSR, + program_show, program_store); + +static struct attribute *fpga_attributes[] = { + &dev_attr_power_fail.attr, + &dev_attr_power_good.attr, + &dev_attr_power_enable.attr, + &dev_attr_program.attr, + NULL, +}; + +static const struct attribute_group fpga_attr_group = { + .attrs = fpga_attributes, +}; + +/* + * OpenFirmware Device Subsystem + */ + +#define SYS_REG_VERSION 0x00 +#define SYS_REG_GEOGRAPHIC 0x10 + +static bool dma_filter(struct dma_chan *chan, void *data) +{ + /* + * DMA Channel #0 is the only acceptable device + * + * This probably won't survive an unload/load cycle of the Freescale + * DMAEngine driver, but that won't be a problem + */ + return chan->chan_id == 0 && chan->device->dev_id == 0; +} + +static int fpga_of_remove(struct platform_device *op) +{ + struct fpga_dev *priv = dev_get_drvdata(&op->dev); + struct device *this_device = priv->miscdev.this_device; + + sysfs_remove_group(&this_device->kobj, &fpga_attr_group); + misc_deregister(&priv->miscdev); + + free_irq(priv->irq, priv); + irq_dispose_mapping(priv->irq); + + /* make sure the power supplies are off */ + fpga_disable_power_supplies(priv); + + /* unmap registers */ + iounmap(priv->immr); + iounmap(priv->regs); + + dma_release_channel(priv->chan); + + /* drop our reference to the private data structure */ + kref_put(&priv->ref, fpga_dev_remove); + return 0; +} + +/* CTL-CPLD Version Register */ +#define CTL_CPLD_VERSION 0x2000 + +static int fpga_of_probe(struct platform_device *op, + const struct of_device_id *match) +{ + struct device_node *of_node = op->dev.of_node; + struct device *this_device; + struct fpga_dev *priv; + dma_cap_mask_t mask; + u32 ver; + int ret; + + /* Allocate private data */ + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&op->dev, "Unable to allocate private data\n"); + ret = -ENOMEM; + goto out_return; + } + + /* Setup the miscdevice */ + priv->miscdev.minor = MISC_DYNAMIC_MINOR; + priv->miscdev.name = drv_name; + priv->miscdev.fops = &fpga_fops; + + kref_init(&priv->ref); + + dev_set_drvdata(&op->dev, priv); + priv->dev = &op->dev; + mutex_init(&priv->lock); + init_completion(&priv->completion); + videobuf_dma_init(&priv->vb); + + dev_set_drvdata(priv->dev, priv); + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + dma_cap_set(DMA_INTERRUPT, mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_SG, mask); + + /* Get control of DMA channel #0 */ + priv->chan = dma_request_channel(mask, dma_filter, NULL); + if (!priv->chan) { + dev_err(&op->dev, "Unable to acquire DMA channel #0\n"); + ret = -ENODEV; + goto out_free_priv; + } + + /* Remap the registers for use */ + priv->regs = of_iomap(of_node, 0); + if (!priv->regs) { + dev_err(&op->dev, "Unable to ioremap registers\n"); + ret = -ENOMEM; + goto out_dma_release_channel; + } + + /* Remap the IMMR for use */ + priv->immr = ioremap(get_immrbase(), 0x100000); + if (!priv->immr) { + dev_err(&op->dev, "Unable to ioremap IMMR\n"); + ret = -ENOMEM; + goto out_unmap_regs; + } + + /* + * Check that external DMA is configured + * + * U-Boot does this for us, but we should check it and bail out if + * there is a problem. Failing to have this register setup correctly + * will cause the DMA controller to transfer a single cacheline + * worth of data, then wedge itself. + */ + if ((ioread32be(priv->immr + 0x114) & 0xE00) != 0xE00) { + dev_err(&op->dev, "External DMA control not configured\n"); + ret = -ENODEV; + goto out_unmap_immr; + } + + /* + * Check the CTL-CPLD version + * + * This driver uses the CTL-CPLD DATA-FPGA power sequencer, and we + * don't want to run on any version of the CTL-CPLD that does not use + * a compatible register layout. + * + * v2: changed register layout, added power sequencer + * v3: added glitch filter on the i2c overcurrent/overtemp outputs + */ + ver = ioread8(priv->regs + CTL_CPLD_VERSION); + if (ver != 0x02 && ver != 0x03) { + dev_err(&op->dev, "CTL-CPLD is not version 0x02 or 0x03!\n"); + ret = -ENODEV; + goto out_unmap_immr; + } + + /* Set the exact size that the firmware image should be */ + ver = ioread32be(priv->regs + SYS_REG_VERSION); + priv->fw_size = (ver & (1 << 18)) ? FW_SIZE_EP2S130 : FW_SIZE_EP2S90; + + /* Find the correct IRQ number */ + priv->irq = irq_of_parse_and_map(of_node, 0); + if (priv->irq == NO_IRQ) { + dev_err(&op->dev, "Unable to find IRQ line\n"); + ret = -ENODEV; + goto out_unmap_immr; + } + + /* Request the IRQ */ + ret = request_irq(priv->irq, fpga_irq, IRQF_SHARED, drv_name, priv); + if (ret) { + dev_err(&op->dev, "Unable to request IRQ %d\n", priv->irq); + ret = -ENODEV; + goto out_irq_dispose_mapping; + } + + /* Reset and stop the FPGA's, just in case */ + fpga_do_stop(priv); + + /* Register the miscdevice */ + ret = misc_register(&priv->miscdev); + if (ret) { + dev_err(&op->dev, "Unable to register miscdevice\n"); + goto out_free_irq; + } + + /* Create the sysfs files */ + this_device = priv->miscdev.this_device; + dev_set_drvdata(this_device, priv); + ret = sysfs_create_group(&this_device->kobj, &fpga_attr_group); + if (ret) { + dev_err(&op->dev, "Unable to create sysfs files\n"); + goto out_misc_deregister; + } + + dev_info(priv->dev, "CARMA FPGA Programmer: %s rev%s with %s FPGAs\n", + (ver & (1 << 17)) ? "Correlator" : "Digitizer", + (ver & (1 << 16)) ? "B" : "A", + (ver & (1 << 18)) ? "EP2S130" : "EP2S90"); + + return 0; + +out_misc_deregister: + misc_deregister(&priv->miscdev); +out_free_irq: + free_irq(priv->irq, priv); +out_irq_dispose_mapping: + irq_dispose_mapping(priv->irq); +out_unmap_immr: + iounmap(priv->immr); +out_unmap_regs: + iounmap(priv->regs); +out_dma_release_channel: + dma_release_channel(priv->chan); +out_free_priv: + kref_put(&priv->ref, fpga_dev_remove); +out_return: + return ret; +} + +static struct of_device_id fpga_of_match[] = { + { .compatible = "carma,fpga-programmer", }, + {}, +}; + +static struct of_platform_driver fpga_of_driver = { + .probe = fpga_of_probe, + .remove = fpga_of_remove, + .driver = { + .name = drv_name, + .of_match_table = fpga_of_match, + .owner = THIS_MODULE, + }, +}; + +/* + * Module Init / Exit + */ + +static int __init fpga_init(void) +{ + led_trigger_register_simple("fpga", &ledtrig_fpga); + return of_register_platform_driver(&fpga_of_driver); +} + +static void __exit fpga_exit(void) +{ + of_unregister_platform_driver(&fpga_of_driver); + led_trigger_unregister_simple(ledtrig_fpga); +} + +MODULE_AUTHOR("Ira W. Snyder "); +MODULE_DESCRIPTION("CARMA Board DATA-FPGA Programmer"); +MODULE_LICENSE("GPL"); + +module_init(fpga_init); +module_exit(fpga_exit); diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c new file mode 100644 index 000000000000..3965821fef17 --- /dev/null +++ b/drivers/misc/carma/carma-fpga.c @@ -0,0 +1,1433 @@ +/* + * CARMA DATA-FPGA Access Driver + * + * Copyright (c) 2009-2011 Ira W. Snyder + * + * 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. + */ + +/* + * FPGA Memory Dump Format + * + * FPGA #0 control registers (32 x 32-bit words) + * FPGA #1 control registers (32 x 32-bit words) + * FPGA #2 control registers (32 x 32-bit words) + * FPGA #3 control registers (32 x 32-bit words) + * SYSFPGA control registers (32 x 32-bit words) + * FPGA #0 correlation array (NUM_CORL0 correlation blocks) + * FPGA #1 correlation array (NUM_CORL1 correlation blocks) + * FPGA #2 correlation array (NUM_CORL2 correlation blocks) + * FPGA #3 correlation array (NUM_CORL3 correlation blocks) + * + * Each correlation array consists of: + * + * Correlation Data (2 x NUM_LAGSn x 32-bit words) + * Pipeline Metadata (2 x NUM_METAn x 32-bit words) + * Quantization Counters (2 x NUM_QCNTn x 32-bit words) + * + * The NUM_CORLn, NUM_LAGSn, NUM_METAn, and NUM_QCNTn values come from + * the FPGA configuration registers. They do not change once the FPGA's + * have been programmed, they only change on re-programming. + */ + +/* + * Basic Description: + * + * This driver is used to capture correlation spectra off of the four data + * processing FPGAs. The FPGAs are often reprogrammed at runtime, therefore + * this driver supports dynamic enable/disable of capture while the device + * remains open. + * + * The nominal capture rate is 64Hz (every 15.625ms). To facilitate this fast + * capture rate, all buffers are pre-allocated to avoid any potentially long + * running memory allocations while capturing. + * + * There are two lists and one pointer which are used to keep track of the + * different states of data buffers. + * + * 1) free list + * This list holds all empty data buffers which are ready to receive data. + * + * 2) inflight pointer + * This pointer holds the currently inflight data buffer. This buffer is having + * data copied into it by the DMA engine. + * + * 3) used list + * This list holds data buffers which have been filled, and are waiting to be + * read by userspace. + * + * All buffers start life on the free list, then move successively to the + * inflight pointer, and then to the used list. After they have been read by + * userspace, they are moved back to the free list. The cycle repeats as long + * as necessary. + * + * It should be noted that all buffers are mapped and ready for DMA when they + * are on any of the three lists. They are only unmapped when they are in the + * process of being read by userspace. + */ + +/* + * Notes on the IRQ masking scheme: + * + * The IRQ masking scheme here is different than most other hardware. The only + * way for the DATA-FPGAs to detect if the kernel has taken too long to copy + * the data is if the status registers are not cleared before the next + * correlation data dump is ready. + * + * The interrupt line is connected to the status registers, such that when they + * are cleared, the interrupt is de-asserted. Therein lies our problem. We need + * to schedule a long-running DMA operation and return from the interrupt + * handler quickly, but we cannot clear the status registers. + * + * To handle this, the system controller FPGA has the capability to connect the + * interrupt line to a user-controlled GPIO pin. This pin is driven high + * (unasserted) and left that way. To mask the interrupt, we change the + * interrupt source to the GPIO pin. Tada, we hid the interrupt. :) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* system controller registers */ +#define SYS_IRQ_SOURCE_CTL 0x24 +#define SYS_IRQ_OUTPUT_EN 0x28 +#define SYS_IRQ_OUTPUT_DATA 0x2C +#define SYS_IRQ_INPUT_DATA 0x30 +#define SYS_FPGA_CONFIG_STATUS 0x44 + +/* GPIO IRQ line assignment */ +#define IRQ_CORL_DONE 0x10 + +/* FPGA registers */ +#define MMAP_REG_VERSION 0x00 +#define MMAP_REG_CORL_CONF1 0x08 +#define MMAP_REG_CORL_CONF2 0x0C +#define MMAP_REG_STATUS 0x48 + +#define SYS_FPGA_BLOCK 0xF0000000 + +#define DATA_FPGA_START 0x400000 +#define DATA_FPGA_SIZE 0x80000 + +static const char drv_name[] = "carma-fpga"; + +#define NUM_FPGA 4 + +#define MIN_DATA_BUFS 8 +#define MAX_DATA_BUFS 64 + +struct fpga_info { + unsigned int num_lag_ram; + unsigned int blk_size; +}; + +struct data_buf { + struct list_head entry; + struct videobuf_dmabuf vb; + size_t size; +}; + +struct fpga_device { + /* character device */ + struct miscdevice miscdev; + struct device *dev; + struct mutex mutex; + + /* reference count */ + struct kref ref; + + /* FPGA registers and information */ + struct fpga_info info[NUM_FPGA]; + void __iomem *regs; + int irq; + + /* FPGA Physical Address/Size Information */ + resource_size_t phys_addr; + size_t phys_size; + + /* DMA structures */ + struct sg_table corl_table; + unsigned int corl_nents; + struct dma_chan *chan; + + /* Protection for all members below */ + spinlock_t lock; + + /* Device enable/disable flag */ + bool enabled; + + /* Correlation data buffers */ + wait_queue_head_t wait; + struct list_head free; + struct list_head used; + struct data_buf *inflight; + + /* Information about data buffers */ + unsigned int num_dropped; + unsigned int num_buffers; + size_t bufsize; + struct dentry *dbg_entry; +}; + +struct fpga_reader { + struct fpga_device *priv; + struct data_buf *buf; + off_t buf_start; +}; + +static void fpga_device_release(struct kref *ref) +{ + struct fpga_device *priv = container_of(ref, struct fpga_device, ref); + + /* the last reader has exited, cleanup the last bits */ + mutex_destroy(&priv->mutex); + kfree(priv); +} + +/* + * Data Buffer Allocation Helpers + */ + +/** + * data_free_buffer() - free a single data buffer and all allocated memory + * @buf: the buffer to free + * + * This will free all of the pages allocated to the given data buffer, and + * then free the structure itself + */ +static void data_free_buffer(struct data_buf *buf) +{ + /* It is ok to free a NULL buffer */ + if (!buf) + return; + + /* free all memory */ + videobuf_dma_free(&buf->vb); + kfree(buf); +} + +/** + * data_alloc_buffer() - allocate and fill a data buffer with pages + * @bytes: the number of bytes required + * + * This allocates all space needed for a data buffer. It must be mapped before + * use in a DMA transaction using videobuf_dma_map(). + * + * Returns NULL on failure + */ +static struct data_buf *data_alloc_buffer(const size_t bytes) +{ + unsigned int nr_pages; + struct data_buf *buf; + int ret; + + /* calculate the number of pages necessary */ + nr_pages = DIV_ROUND_UP(bytes, PAGE_SIZE); + + /* allocate the buffer structure */ + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + goto out_return; + + /* initialize internal fields */ + INIT_LIST_HEAD(&buf->entry); + buf->size = bytes; + + /* allocate the videobuf */ + videobuf_dma_init(&buf->vb); + ret = videobuf_dma_init_kernel(&buf->vb, DMA_FROM_DEVICE, nr_pages); + if (ret) + goto out_free_buf; + + return buf; + +out_free_buf: + kfree(buf); +out_return: + return NULL; +} + +/** + * data_free_buffers() - free all allocated buffers + * @priv: the driver's private data structure + * + * Free all buffers allocated by the driver (except those currently in the + * process of being read by userspace). + * + * LOCKING: must hold dev->mutex + * CONTEXT: user + */ +static void data_free_buffers(struct fpga_device *priv) +{ + struct data_buf *buf, *tmp; + + /* the device should be stopped, no DMA in progress */ + BUG_ON(priv->inflight != NULL); + + list_for_each_entry_safe(buf, tmp, &priv->free, entry) { + list_del_init(&buf->entry); + videobuf_dma_unmap(priv->dev, &buf->vb); + data_free_buffer(buf); + } + + list_for_each_entry_safe(buf, tmp, &priv->used, entry) { + list_del_init(&buf->entry); + videobuf_dma_unmap(priv->dev, &buf->vb); + data_free_buffer(buf); + } + + priv->num_buffers = 0; + priv->bufsize = 0; +} + +/** + * data_alloc_buffers() - allocate 1 seconds worth of data buffers + * @priv: the driver's private data structure + * + * Allocate enough buffers for a whole second worth of data + * + * This routine will attempt to degrade nicely by succeeding even if a full + * second worth of data buffers could not be allocated, as long as a minimum + * number were allocated. In this case, it will print a message to the kernel + * log. + * + * The device must not be modifying any lists when this is called. + * + * CONTEXT: user + * LOCKING: must hold dev->mutex + * + * Returns 0 on success, -ERRNO otherwise + */ +static int data_alloc_buffers(struct fpga_device *priv) +{ + struct data_buf *buf; + int i, ret; + + for (i = 0; i < MAX_DATA_BUFS; i++) { + + /* allocate a buffer */ + buf = data_alloc_buffer(priv->bufsize); + if (!buf) + break; + + /* map it for DMA */ + ret = videobuf_dma_map(priv->dev, &buf->vb); + if (ret) { + data_free_buffer(buf); + break; + } + + /* add it to the list of free buffers */ + list_add_tail(&buf->entry, &priv->free); + priv->num_buffers++; + } + + /* Make sure we allocated the minimum required number of buffers */ + if (priv->num_buffers < MIN_DATA_BUFS) { + dev_err(priv->dev, "Unable to allocate enough data buffers\n"); + data_free_buffers(priv); + return -ENOMEM; + } + + /* Warn if we are running in a degraded state, but do not fail */ + if (priv->num_buffers < MAX_DATA_BUFS) { + dev_warn(priv->dev, + "Unable to allocate %d buffers, using %d buffers instead\n", + MAX_DATA_BUFS, i); + } + + return 0; +} + +/* + * DMA Operations Helpers + */ + +/** + * fpga_start_addr() - get the physical address a DATA-FPGA + * @priv: the driver's private data structure + * @fpga: the DATA-FPGA number (zero based) + */ +static dma_addr_t fpga_start_addr(struct fpga_device *priv, unsigned int fpga) +{ + return priv->phys_addr + 0x400000 + (0x80000 * fpga); +} + +/** + * fpga_block_addr() - get the physical address of a correlation data block + * @priv: the driver's private data structure + * @fpga: the DATA-FPGA number (zero based) + * @blknum: the correlation block number (zero based) + */ +static dma_addr_t fpga_block_addr(struct fpga_device *priv, unsigned int fpga, + unsigned int blknum) +{ + return fpga_start_addr(priv, fpga) + (0x10000 * (1 + blknum)); +} + +#define REG_BLOCK_SIZE (32 * 4) + +/** + * data_setup_corl_table() - create the scatterlist for correlation dumps + * @priv: the driver's private data structure + * + * Create the scatterlist for transferring a correlation dump from the + * DATA FPGAs. This structure will be reused for each buffer than needs + * to be filled with correlation data. + * + * Returns 0 on success, -ERRNO otherwise + */ +static int data_setup_corl_table(struct fpga_device *priv) +{ + struct sg_table *table = &priv->corl_table; + struct scatterlist *sg; + struct fpga_info *info; + int i, j, ret; + + /* Calculate the number of entries needed */ + priv->corl_nents = (1 + NUM_FPGA) * REG_BLOCK_SIZE; + for (i = 0; i < NUM_FPGA; i++) + priv->corl_nents += priv->info[i].num_lag_ram; + + /* Allocate the scatterlist table */ + ret = sg_alloc_table(table, priv->corl_nents, GFP_KERNEL); + if (ret) { + dev_err(priv->dev, "unable to allocate DMA table\n"); + return ret; + } + + /* Add the DATA FPGA registers to the scatterlist */ + sg = table->sgl; + for (i = 0; i < NUM_FPGA; i++) { + sg_dma_address(sg) = fpga_start_addr(priv, i); + sg_dma_len(sg) = REG_BLOCK_SIZE; + sg = sg_next(sg); + } + + /* Add the SYS-FPGA registers to the scatterlist */ + sg_dma_address(sg) = SYS_FPGA_BLOCK; + sg_dma_len(sg) = REG_BLOCK_SIZE; + sg = sg_next(sg); + + /* Add the FPGA correlation data blocks to the scatterlist */ + for (i = 0; i < NUM_FPGA; i++) { + info = &priv->info[i]; + for (j = 0; j < info->num_lag_ram; j++) { + sg_dma_address(sg) = fpga_block_addr(priv, i, j); + sg_dma_len(sg) = info->blk_size; + sg = sg_next(sg); + } + } + + /* + * All physical addresses and lengths are present in the structure + * now. It can be reused for every FPGA DATA interrupt + */ + return 0; +} + +/* + * FPGA Register Access Helpers + */ + +static void fpga_write_reg(struct fpga_device *priv, unsigned int fpga, + unsigned int reg, u32 val) +{ + const int fpga_start = DATA_FPGA_START + (fpga * DATA_FPGA_SIZE); + iowrite32be(val, priv->regs + fpga_start + reg); +} + +static u32 fpga_read_reg(struct fpga_device *priv, unsigned int fpga, + unsigned int reg) +{ + const int fpga_start = DATA_FPGA_START + (fpga * DATA_FPGA_SIZE); + return ioread32be(priv->regs + fpga_start + reg); +} + +/** + * data_calculate_bufsize() - calculate the data buffer size required + * @priv: the driver's private data structure + * + * Calculate the total buffer size needed to hold a single block + * of correlation data + * + * CONTEXT: user + * + * Returns 0 on success, -ERRNO otherwise + */ +static int data_calculate_bufsize(struct fpga_device *priv) +{ + u32 num_corl, num_lags, num_meta, num_qcnt, num_pack; + u32 conf1, conf2, version; + u32 num_lag_ram, blk_size; + int i; + + /* Each buffer starts with the 5 FPGA register areas */ + priv->bufsize = (1 + NUM_FPGA) * REG_BLOCK_SIZE; + + /* Read and store the configuration data for each FPGA */ + for (i = 0; i < NUM_FPGA; i++) { + version = fpga_read_reg(priv, i, MMAP_REG_VERSION); + conf1 = fpga_read_reg(priv, i, MMAP_REG_CORL_CONF1); + conf2 = fpga_read_reg(priv, i, MMAP_REG_CORL_CONF2); + + /* minor version 2 and later */ + if ((version & 0x000000FF) >= 2) { + num_corl = (conf1 & 0x000000F0) >> 4; + num_pack = (conf1 & 0x00000F00) >> 8; + num_lags = (conf1 & 0x00FFF000) >> 12; + num_meta = (conf1 & 0x7F000000) >> 24; + num_qcnt = (conf2 & 0x00000FFF) >> 0; + } else { + num_corl = (conf1 & 0x000000F0) >> 4; + num_pack = 1; /* implied */ + num_lags = (conf1 & 0x000FFF00) >> 8; + num_meta = (conf1 & 0x7FF00000) >> 20; + num_qcnt = (conf2 & 0x00000FFF) >> 0; + } + + num_lag_ram = (num_corl + num_pack - 1) / num_pack; + blk_size = ((num_pack * num_lags) + num_meta + num_qcnt) * 8; + + priv->info[i].num_lag_ram = num_lag_ram; + priv->info[i].blk_size = blk_size; + priv->bufsize += num_lag_ram * blk_size; + + dev_dbg(priv->dev, "FPGA %d NUM_CORL: %d\n", i, num_corl); + dev_dbg(priv->dev, "FPGA %d NUM_PACK: %d\n", i, num_pack); + dev_dbg(priv->dev, "FPGA %d NUM_LAGS: %d\n", i, num_lags); + dev_dbg(priv->dev, "FPGA %d NUM_META: %d\n", i, num_meta); + dev_dbg(priv->dev, "FPGA %d NUM_QCNT: %d\n", i, num_qcnt); + dev_dbg(priv->dev, "FPGA %d BLK_SIZE: %d\n", i, blk_size); + } + + dev_dbg(priv->dev, "TOTAL BUFFER SIZE: %zu bytes\n", priv->bufsize); + return 0; +} + +/* + * Interrupt Handling + */ + +/** + * data_disable_interrupts() - stop the device from generating interrupts + * @priv: the driver's private data structure + * + * Hide interrupts by switching to GPIO interrupt source + * + * LOCKING: must hold dev->lock + */ +static void data_disable_interrupts(struct fpga_device *priv) +{ + /* hide the interrupt by switching the IRQ driver to GPIO */ + iowrite32be(0x2F, priv->regs + SYS_IRQ_SOURCE_CTL); +} + +/** + * data_enable_interrupts() - allow the device to generate interrupts + * @priv: the driver's private data structure + * + * Unhide interrupts by switching to the FPGA interrupt source. At the + * same time, clear the DATA-FPGA status registers. + * + * LOCKING: must hold dev->lock + */ +static void data_enable_interrupts(struct fpga_device *priv) +{ + /* clear the actual FPGA corl_done interrupt */ + fpga_write_reg(priv, 0, MMAP_REG_STATUS, 0x0); + fpga_write_reg(priv, 1, MMAP_REG_STATUS, 0x0); + fpga_write_reg(priv, 2, MMAP_REG_STATUS, 0x0); + fpga_write_reg(priv, 3, MMAP_REG_STATUS, 0x0); + + /* flush the writes */ + fpga_read_reg(priv, 0, MMAP_REG_STATUS); + + /* switch back to the external interrupt source */ + iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL); +} + +/** + * data_dma_cb() - DMAEngine callback for DMA completion + * @data: the driver's private data structure + * + * Complete a DMA transfer from the DATA-FPGA's + * + * This is called via the DMA callback mechanism, and will handle moving the + * completed DMA transaction to the used list, and then wake any processes + * waiting for new data + * + * CONTEXT: any, softirq expected + */ +static void data_dma_cb(void *data) +{ + struct fpga_device *priv = data; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + /* If there is no inflight buffer, we've got a bug */ + BUG_ON(priv->inflight == NULL); + + /* Move the inflight buffer onto the used list */ + list_move_tail(&priv->inflight->entry, &priv->used); + priv->inflight = NULL; + + /* clear the FPGA status and re-enable interrupts */ + data_enable_interrupts(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + + /* + * We've changed both the inflight and used lists, so we need + * to wake up any processes that are blocking for those events + */ + wake_up(&priv->wait); +} + +/** + * data_submit_dma() - prepare and submit the required DMA to fill a buffer + * @priv: the driver's private data structure + * @buf: the data buffer + * + * Prepare and submit the necessary DMA transactions to fill a correlation + * data buffer. + * + * LOCKING: must hold dev->lock + * CONTEXT: hardirq only + * + * Returns 0 on success, -ERRNO otherwise + */ +static int data_submit_dma(struct fpga_device *priv, struct data_buf *buf) +{ + struct scatterlist *dst_sg, *src_sg; + unsigned int dst_nents, src_nents; + struct dma_chan *chan = priv->chan; + struct dma_async_tx_descriptor *tx; + dma_cookie_t cookie; + dma_addr_t dst, src; + + dst_sg = buf->vb.sglist; + dst_nents = buf->vb.sglen; + + src_sg = priv->corl_table.sgl; + src_nents = priv->corl_nents; + + /* + * All buffers passed to this function should be ready and mapped + * for DMA already. Therefore, we don't need to do anything except + * submit it to the Freescale DMA Engine for processing + */ + + /* setup the scatterlist to scatterlist transfer */ + tx = chan->device->device_prep_dma_sg(chan, + dst_sg, dst_nents, + src_sg, src_nents, + 0); + if (!tx) { + dev_err(priv->dev, "unable to prep scatterlist DMA\n"); + return -ENOMEM; + } + + /* submit the transaction to the DMA controller */ + cookie = tx->tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_err(priv->dev, "unable to submit scatterlist DMA\n"); + return -ENOMEM; + } + + /* Prepare the re-read of the SYS-FPGA block */ + dst = sg_dma_address(dst_sg) + (NUM_FPGA * REG_BLOCK_SIZE); + src = SYS_FPGA_BLOCK; + tx = chan->device->device_prep_dma_memcpy(chan, dst, src, + REG_BLOCK_SIZE, + DMA_PREP_INTERRUPT); + if (!tx) { + dev_err(priv->dev, "unable to prep SYS-FPGA DMA\n"); + return -ENOMEM; + } + + /* Setup the callback */ + tx->callback = data_dma_cb; + tx->callback_param = priv; + + /* submit the transaction to the DMA controller */ + cookie = tx->tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_err(priv->dev, "unable to submit SYS-FPGA DMA\n"); + return -ENOMEM; + } + + return 0; +} + +#define CORL_DONE 0x1 +#define CORL_ERR 0x2 + +static irqreturn_t data_irq(int irq, void *dev_id) +{ + struct fpga_device *priv = dev_id; + bool submitted = false; + struct data_buf *buf; + u32 status; + int i; + + /* detect spurious interrupts via FPGA status */ + for (i = 0; i < 4; i++) { + status = fpga_read_reg(priv, i, MMAP_REG_STATUS); + if (!(status & (CORL_DONE | CORL_ERR))) { + dev_err(priv->dev, "spurious irq detected (FPGA)\n"); + return IRQ_NONE; + } + } + + /* detect spurious interrupts via raw IRQ pin readback */ + status = ioread32be(priv->regs + SYS_IRQ_INPUT_DATA); + if (status & IRQ_CORL_DONE) { + dev_err(priv->dev, "spurious irq detected (IRQ)\n"); + return IRQ_NONE; + } + + spin_lock(&priv->lock); + + /* hide the interrupt by switching the IRQ driver to GPIO */ + data_disable_interrupts(priv); + + /* If there are no free buffers, drop this data */ + if (list_empty(&priv->free)) { + priv->num_dropped++; + goto out; + } + + buf = list_first_entry(&priv->free, struct data_buf, entry); + list_del_init(&buf->entry); + BUG_ON(buf->size != priv->bufsize); + + /* Submit a DMA transfer to get the correlation data */ + if (data_submit_dma(priv, buf)) { + dev_err(priv->dev, "Unable to setup DMA transfer\n"); + list_move_tail(&buf->entry, &priv->free); + goto out; + } + + /* Save the buffer for the DMA callback */ + priv->inflight = buf; + submitted = true; + + /* Start the DMA Engine */ + dma_async_memcpy_issue_pending(priv->chan); + +out: + /* If no DMA was submitted, re-enable interrupts */ + if (!submitted) + data_enable_interrupts(priv); + + spin_unlock(&priv->lock); + return IRQ_HANDLED; +} + +/* + * Realtime Device Enable Helpers + */ + +/** + * data_device_enable() - enable the device for buffered dumping + * @priv: the driver's private data structure + * + * Enable the device for buffered dumping. Allocates buffers and hooks up + * the interrupt handler. When this finishes, data will come pouring in. + * + * LOCKING: must hold dev->mutex + * CONTEXT: user context only + * + * Returns 0 on success, -ERRNO otherwise + */ +static int data_device_enable(struct fpga_device *priv) +{ + u32 val; + int ret; + + /* multiple enables are safe: they do nothing */ + if (priv->enabled) + return 0; + + /* check that the FPGAs are programmed */ + val = ioread32be(priv->regs + SYS_FPGA_CONFIG_STATUS); + if (!(val & (1 << 18))) { + dev_err(priv->dev, "DATA-FPGAs are not enabled\n"); + return -ENODATA; + } + + /* read the FPGAs to calculate the buffer size */ + ret = data_calculate_bufsize(priv); + if (ret) { + dev_err(priv->dev, "unable to calculate buffer size\n"); + goto out_error; + } + + /* allocate the correlation data buffers */ + ret = data_alloc_buffers(priv); + if (ret) { + dev_err(priv->dev, "unable to allocate buffers\n"); + goto out_error; + } + + /* setup the source scatterlist for dumping correlation data */ + ret = data_setup_corl_table(priv); + if (ret) { + dev_err(priv->dev, "unable to setup correlation DMA table\n"); + goto out_error; + } + + /* hookup the irq handler */ + ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv); + if (ret) { + dev_err(priv->dev, "unable to request IRQ handler\n"); + goto out_error; + } + + /* switch to the external FPGA IRQ line */ + data_enable_interrupts(priv); + + /* success, we're enabled */ + priv->enabled = true; + return 0; + +out_error: + sg_free_table(&priv->corl_table); + priv->corl_nents = 0; + + data_free_buffers(priv); + return ret; +} + +/** + * data_device_disable() - disable the device for buffered dumping + * @priv: the driver's private data structure + * + * Disable the device for buffered dumping. Stops new DMA transactions from + * being generated, waits for all outstanding DMA to complete, and then frees + * all buffers. + * + * LOCKING: must hold dev->mutex + * CONTEXT: user only + * + * Returns 0 on success, -ERRNO otherwise + */ +static int data_device_disable(struct fpga_device *priv) +{ + int ret; + + /* allow multiple disable */ + if (!priv->enabled) + return 0; + + /* switch to the internal GPIO IRQ line */ + data_disable_interrupts(priv); + + /* unhook the irq handler */ + free_irq(priv->irq, priv); + + /* + * wait for all outstanding DMA to complete + * + * Device interrupts are disabled, therefore another buffer cannot + * be marked inflight. + */ + ret = wait_event_interruptible(priv->wait, priv->inflight == NULL); + if (ret) + return ret; + + /* free the correlation table */ + sg_free_table(&priv->corl_table); + priv->corl_nents = 0; + + /* + * We are taking the spinlock not to protect priv->enabled, but instead + * to make sure that there are no readers in the process of altering + * the free or used lists while we are setting this flag. + */ + spin_lock_irq(&priv->lock); + priv->enabled = false; + spin_unlock_irq(&priv->lock); + + /* free all buffers: the free and used lists are not being changed */ + data_free_buffers(priv); + return 0; +} + +/* + * DEBUGFS Interface + */ +#ifdef CONFIG_DEBUG_FS + +/* + * Count the number of entries in the given list + */ +static unsigned int list_num_entries(struct list_head *list) +{ + struct list_head *entry; + unsigned int ret = 0; + + list_for_each(entry, list) + ret++; + + return ret; +} + +static int data_debug_show(struct seq_file *f, void *offset) +{ + struct fpga_device *priv = f->private; + int ret; + + /* + * Lock the mutex first, so that we get an accurate value for enable + * Lock the spinlock next, to get accurate list counts + */ + ret = mutex_lock_interruptible(&priv->mutex); + if (ret) + return ret; + + spin_lock_irq(&priv->lock); + + seq_printf(f, "enabled: %d\n", priv->enabled); + seq_printf(f, "bufsize: %d\n", priv->bufsize); + seq_printf(f, "num_buffers: %d\n", priv->num_buffers); + seq_printf(f, "num_free: %d\n", list_num_entries(&priv->free)); + seq_printf(f, "inflight: %d\n", priv->inflight != NULL); + seq_printf(f, "num_used: %d\n", list_num_entries(&priv->used)); + seq_printf(f, "num_dropped: %d\n", priv->num_dropped); + + spin_unlock_irq(&priv->lock); + mutex_unlock(&priv->mutex); + return 0; +} + +static int data_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, data_debug_show, inode->i_private); +} + +static const struct file_operations data_debug_fops = { + .owner = THIS_MODULE, + .open = data_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int data_debugfs_init(struct fpga_device *priv) +{ + priv->dbg_entry = debugfs_create_file(drv_name, S_IRUGO, NULL, priv, + &data_debug_fops); + if (IS_ERR(priv->dbg_entry)) + return PTR_ERR(priv->dbg_entry); + + return 0; +} + +static void data_debugfs_exit(struct fpga_device *priv) +{ + debugfs_remove(priv->dbg_entry); +} + +#else + +static inline int data_debugfs_init(struct fpga_device *priv) +{ + return 0; +} + +static inline void data_debugfs_exit(struct fpga_device *priv) +{ +} + +#endif /* CONFIG_DEBUG_FS */ + +/* + * SYSFS Attributes + */ + +static ssize_t data_en_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fpga_device *priv = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled); +} + +static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fpga_device *priv = dev_get_drvdata(dev); + unsigned long enable; + int ret; + + ret = strict_strtoul(buf, 0, &enable); + if (ret) { + dev_err(priv->dev, "unable to parse enable input\n"); + return -EINVAL; + } + + ret = mutex_lock_interruptible(&priv->mutex); + if (ret) + return ret; + + if (enable) + ret = data_device_enable(priv); + else + ret = data_device_disable(priv); + + if (ret) { + dev_err(priv->dev, "device %s failed\n", + enable ? "enable" : "disable"); + count = ret; + goto out_unlock; + } + +out_unlock: + mutex_unlock(&priv->mutex); + return count; +} + +static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, data_en_show, data_en_set); + +static struct attribute *data_sysfs_attrs[] = { + &dev_attr_enable.attr, + NULL, +}; + +static const struct attribute_group rt_sysfs_attr_group = { + .attrs = data_sysfs_attrs, +}; + +/* + * FPGA Realtime Data Character Device + */ + +static int data_open(struct inode *inode, struct file *filp) +{ + /* + * The miscdevice layer puts our struct miscdevice into the + * filp->private_data field. We use this to find our private + * data and then overwrite it with our own private structure. + */ + struct fpga_device *priv = container_of(filp->private_data, + struct fpga_device, miscdev); + struct fpga_reader *reader; + int ret; + + /* allocate private data */ + reader = kzalloc(sizeof(*reader), GFP_KERNEL); + if (!reader) + return -ENOMEM; + + reader->priv = priv; + reader->buf = NULL; + + filp->private_data = reader; + ret = nonseekable_open(inode, filp); + if (ret) { + dev_err(priv->dev, "nonseekable-open failed\n"); + kfree(reader); + return ret; + } + + /* + * success, increase the reference count of the private data structure + * so that it doesn't disappear if the device is unbound + */ + kref_get(&priv->ref); + return 0; +} + +static int data_release(struct inode *inode, struct file *filp) +{ + struct fpga_reader *reader = filp->private_data; + struct fpga_device *priv = reader->priv; + + /* free the per-reader structure */ + data_free_buffer(reader->buf); + kfree(reader); + filp->private_data = NULL; + + /* decrement our reference count to the private data */ + kref_put(&priv->ref, fpga_device_release); + return 0; +} + +static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count, + loff_t *f_pos) +{ + struct fpga_reader *reader = filp->private_data; + struct fpga_device *priv = reader->priv; + struct list_head *used = &priv->used; + struct data_buf *dbuf; + size_t avail; + void *data; + int ret; + + /* check if we already have a partial buffer */ + if (reader->buf) { + dbuf = reader->buf; + goto have_buffer; + } + + spin_lock_irq(&priv->lock); + + /* Block until there is at least one buffer on the used list */ + while (list_empty(used)) { + spin_unlock_irq(&priv->lock); + + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible(priv->wait, !list_empty(used)); + if (ret) + return ret; + + spin_lock_irq(&priv->lock); + } + + /* Grab the first buffer off of the used list */ + dbuf = list_first_entry(used, struct data_buf, entry); + list_del_init(&dbuf->entry); + + spin_unlock_irq(&priv->lock); + + /* Buffers are always mapped: unmap it */ + videobuf_dma_unmap(priv->dev, &dbuf->vb); + + /* save the buffer for later */ + reader->buf = dbuf; + reader->buf_start = 0; + +have_buffer: + /* Get the number of bytes available */ + avail = dbuf->size - reader->buf_start; + data = dbuf->vb.vaddr + reader->buf_start; + + /* Get the number of bytes we can transfer */ + count = min(count, avail); + + /* Copy the data to the userspace buffer */ + if (copy_to_user(ubuf, data, count)) + return -EFAULT; + + /* Update the amount of available space */ + avail -= count; + + /* + * If there is still some data available, save the buffer for the + * next userspace call to read() and return + */ + if (avail > 0) { + reader->buf_start += count; + reader->buf = dbuf; + return count; + } + + /* + * Get the buffer ready to be reused for DMA + * + * If it fails, we pretend that the read never happed and return + * -EFAULT to userspace. The read will be retried. + */ + ret = videobuf_dma_map(priv->dev, &dbuf->vb); + if (ret) { + dev_err(priv->dev, "unable to remap buffer for DMA\n"); + return -EFAULT; + } + + /* Lock against concurrent enable/disable */ + spin_lock_irq(&priv->lock); + + /* the reader is finished with this buffer */ + reader->buf = NULL; + + /* + * One of two things has happened, the device is disabled, or the + * device has been reconfigured underneath us. In either case, we + * should just throw away the buffer. + */ + if (!priv->enabled || dbuf->size != priv->bufsize) { + videobuf_dma_unmap(priv->dev, &dbuf->vb); + data_free_buffer(dbuf); + goto out_unlock; + } + + /* The buffer is safe to reuse, so add it back to the free list */ + list_add_tail(&dbuf->entry, &priv->free); + +out_unlock: + spin_unlock_irq(&priv->lock); + return count; +} + +static unsigned int data_poll(struct file *filp, struct poll_table_struct *tbl) +{ + struct fpga_reader *reader = filp->private_data; + struct fpga_device *priv = reader->priv; + unsigned int mask = 0; + + poll_wait(filp, &priv->wait, tbl); + + if (!list_empty(&priv->used)) + mask |= POLLIN | POLLRDNORM; + + return mask; +} + +static int data_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct fpga_reader *reader = filp->private_data; + struct fpga_device *priv = reader->priv; + unsigned long offset, vsize, psize, addr; + + /* VMA properties */ + offset = vma->vm_pgoff << PAGE_SHIFT; + vsize = vma->vm_end - vma->vm_start; + psize = priv->phys_size - offset; + addr = (priv->phys_addr + offset) >> PAGE_SHIFT; + + /* Check against the FPGA region's physical memory size */ + if (vsize > psize) { + dev_err(priv->dev, "requested mmap mapping too large\n"); + return -EINVAL; + } + + /* IO memory (stop cacheing) */ + vma->vm_flags |= VM_IO | VM_RESERVED; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + return io_remap_pfn_range(vma, vma->vm_start, addr, vsize, + vma->vm_page_prot); +} + +static const struct file_operations data_fops = { + .owner = THIS_MODULE, + .open = data_open, + .release = data_release, + .read = data_read, + .poll = data_poll, + .mmap = data_mmap, + .llseek = no_llseek, +}; + +/* + * OpenFirmware Device Subsystem + */ + +static bool dma_filter(struct dma_chan *chan, void *data) +{ + /* + * DMA Channel #0 is used for the FPGA Programmer, so ignore it + * + * This probably won't survive an unload/load cycle of the Freescale + * DMAEngine driver, but that won't be a problem + */ + if (chan->chan_id == 0 && chan->device->dev_id == 0) + return false; + + return true; +} + +static int data_of_probe(struct platform_device *op, + const struct of_device_id *match) +{ + struct device_node *of_node = op->dev.of_node; + struct device *this_device; + struct fpga_device *priv; + struct resource res; + dma_cap_mask_t mask; + int ret; + + /* Allocate private data */ + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&op->dev, "Unable to allocate device private data\n"); + ret = -ENOMEM; + goto out_return; + } + + dev_set_drvdata(&op->dev, priv); + priv->dev = &op->dev; + kref_init(&priv->ref); + mutex_init(&priv->mutex); + + dev_set_drvdata(priv->dev, priv); + spin_lock_init(&priv->lock); + INIT_LIST_HEAD(&priv->free); + INIT_LIST_HEAD(&priv->used); + init_waitqueue_head(&priv->wait); + + /* Setup the misc device */ + priv->miscdev.minor = MISC_DYNAMIC_MINOR; + priv->miscdev.name = drv_name; + priv->miscdev.fops = &data_fops; + + /* Get the physical address of the FPGA registers */ + ret = of_address_to_resource(of_node, 0, &res); + if (ret) { + dev_err(&op->dev, "Unable to find FPGA physical address\n"); + ret = -ENODEV; + goto out_free_priv; + } + + priv->phys_addr = res.start; + priv->phys_size = resource_size(&res); + + /* ioremap the registers for use */ + priv->regs = of_iomap(of_node, 0); + if (!priv->regs) { + dev_err(&op->dev, "Unable to ioremap registers\n"); + ret = -ENOMEM; + goto out_free_priv; + } + + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + dma_cap_set(DMA_INTERRUPT, mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_SG, mask); + + /* Request a DMA channel */ + priv->chan = dma_request_channel(mask, dma_filter, NULL); + if (!priv->chan) { + dev_err(&op->dev, "Unable to request DMA channel\n"); + ret = -ENODEV; + goto out_unmap_regs; + } + + /* Find the correct IRQ number */ + priv->irq = irq_of_parse_and_map(of_node, 0); + if (priv->irq == NO_IRQ) { + dev_err(&op->dev, "Unable to find IRQ line\n"); + ret = -ENODEV; + goto out_release_dma; + } + + /* Drive the GPIO for FPGA IRQ high (no interrupt) */ + iowrite32be(IRQ_CORL_DONE, priv->regs + SYS_IRQ_OUTPUT_DATA); + + /* Register the miscdevice */ + ret = misc_register(&priv->miscdev); + if (ret) { + dev_err(&op->dev, "Unable to register miscdevice\n"); + goto out_irq_dispose_mapping; + } + + /* Create the debugfs files */ + ret = data_debugfs_init(priv); + if (ret) { + dev_err(&op->dev, "Unable to create debugfs files\n"); + goto out_misc_deregister; + } + + /* Create the sysfs files */ + this_device = priv->miscdev.this_device; + dev_set_drvdata(this_device, priv); + ret = sysfs_create_group(&this_device->kobj, &rt_sysfs_attr_group); + if (ret) { + dev_err(&op->dev, "Unable to create sysfs files\n"); + goto out_data_debugfs_exit; + } + + dev_info(&op->dev, "CARMA FPGA Realtime Data Driver Loaded\n"); + return 0; + +out_data_debugfs_exit: + data_debugfs_exit(priv); +out_misc_deregister: + misc_deregister(&priv->miscdev); +out_irq_dispose_mapping: + irq_dispose_mapping(priv->irq); +out_release_dma: + dma_release_channel(priv->chan); +out_unmap_regs: + iounmap(priv->regs); +out_free_priv: + kref_put(&priv->ref, fpga_device_release); +out_return: + return ret; +} + +static int data_of_remove(struct platform_device *op) +{ + struct fpga_device *priv = dev_get_drvdata(&op->dev); + struct device *this_device = priv->miscdev.this_device; + + /* remove all sysfs files, now the device cannot be re-enabled */ + sysfs_remove_group(&this_device->kobj, &rt_sysfs_attr_group); + + /* remove all debugfs files */ + data_debugfs_exit(priv); + + /* disable the device from generating data */ + data_device_disable(priv); + + /* remove the character device to stop new readers from appearing */ + misc_deregister(&priv->miscdev); + + /* cleanup everything not needed by readers */ + irq_dispose_mapping(priv->irq); + dma_release_channel(priv->chan); + iounmap(priv->regs); + + /* release our reference */ + kref_put(&priv->ref, fpga_device_release); + return 0; +} + +static struct of_device_id data_of_match[] = { + { .compatible = "carma,carma-fpga", }, + {}, +}; + +static struct of_platform_driver data_of_driver = { + .probe = data_of_probe, + .remove = data_of_remove, + .driver = { + .name = drv_name, + .of_match_table = data_of_match, + .owner = THIS_MODULE, + }, +}; + +/* + * Module Init / Exit + */ + +static int __init data_init(void) +{ + return of_register_platform_driver(&data_of_driver); +} + +static void __exit data_exit(void) +{ + of_unregister_platform_driver(&data_of_driver); +} + +MODULE_AUTHOR("Ira W. Snyder "); +MODULE_DESCRIPTION("CARMA DATA-FPGA Access Driver"); +MODULE_LICENSE("GPL"); + +module_init(data_init); +module_exit(data_exit); diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index 38657cdaf54d..c4acac74725c 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "gru.h" #include "grutables.h" diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index f8538bbd0bfa..ae16c8cb4f3e 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "gru.h" #include "grutables.h" diff --git a/drivers/misc/ti-st/Kconfig b/drivers/misc/ti-st/Kconfig index 2c8c3f39710d..abb5de1afce3 100644 --- a/drivers/misc/ti-st/Kconfig +++ b/drivers/misc/ti-st/Kconfig @@ -5,7 +5,7 @@ menu "Texas Instruments shared transport line discipline" config TI_ST tristate "Shared transport core driver" - depends on RFKILL + depends on NET && GPIOLIB select FW_LOADER help This enables the shared transport core driver for TI diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 486117f72c9f..f91f82eabda7 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -43,13 +43,15 @@ static void add_channel_to_table(struct st_data_s *st_gdata, pr_info("%s: id %d\n", __func__, new_proto->chnl_id); /* list now has the channel id as index itself */ st_gdata->list[new_proto->chnl_id] = new_proto; + st_gdata->is_registered[new_proto->chnl_id] = true; } static void remove_channel_from_table(struct st_data_s *st_gdata, struct st_proto_s *proto) { pr_info("%s: id %d\n", __func__, proto->chnl_id); - st_gdata->list[proto->chnl_id] = NULL; +/* st_gdata->list[proto->chnl_id] = NULL; */ + st_gdata->is_registered[proto->chnl_id] = false; } /* @@ -104,7 +106,7 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) if (unlikely (st_gdata == NULL || st_gdata->rx_skb == NULL - || st_gdata->list[chnl_id] == NULL)) { + || st_gdata->is_registered[chnl_id] == false)) { pr_err("chnl_id %d not registered, no data to send?", chnl_id); kfree_skb(st_gdata->rx_skb); @@ -141,14 +143,15 @@ void st_reg_complete(struct st_data_s *st_gdata, char err) unsigned char i = 0; pr_info(" %s ", __func__); for (i = 0; i < ST_MAX_CHANNELS; i++) { - if (likely(st_gdata != NULL && st_gdata->list[i] != NULL && - st_gdata->list[i]->reg_complete_cb != NULL)) { + if (likely(st_gdata != NULL && + st_gdata->is_registered[i] == true && + st_gdata->list[i]->reg_complete_cb != NULL)) { st_gdata->list[i]->reg_complete_cb (st_gdata->list[i]->priv_data, err); pr_info("protocol %d's cb sent %d\n", i, err); if (err) { /* cleanup registered protocol */ st_gdata->protos_registered--; - st_gdata->list[i] = NULL; + st_gdata->is_registered[i] = false; } } } @@ -475,9 +478,9 @@ void kim_st_list_protocols(struct st_data_s *st_gdata, void *buf) { seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n", st_gdata->protos_registered, - st_gdata->list[0x04] != NULL ? 'R' : 'U', - st_gdata->list[0x08] != NULL ? 'R' : 'U', - st_gdata->list[0x09] != NULL ? 'R' : 'U'); + st_gdata->is_registered[0x04] == true ? 'R' : 'U', + st_gdata->is_registered[0x08] == true ? 'R' : 'U', + st_gdata->is_registered[0x09] == true ? 'R' : 'U'); } /********************************************************************/ @@ -504,7 +507,7 @@ long st_register(struct st_proto_s *new_proto) return -EPROTONOSUPPORT; } - if (st_gdata->list[new_proto->chnl_id] != NULL) { + if (st_gdata->is_registered[new_proto->chnl_id] == true) { pr_err("chnl_id %d already registered", new_proto->chnl_id); return -EALREADY; } @@ -563,7 +566,7 @@ long st_register(struct st_proto_s *new_proto) /* check for already registered once more, * since the above check is old */ - if (st_gdata->list[new_proto->chnl_id] != NULL) { + if (st_gdata->is_registered[new_proto->chnl_id] == true) { pr_err(" proto %d already registered ", new_proto->chnl_id); return -EALREADY; diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index b4488c8f6b23..5da93ee6f6be 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 63667a8f140c..d6d62fd07ee9 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -284,6 +284,7 @@ int mmc_add_card(struct mmc_card *card) type = "SD-combo"; if (mmc_card_blockaddr(card)) type = "SDHC-combo"; + break; default: type = "?"; break; diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 2e032f0e8cf4..a6c329040140 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -832,7 +832,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) return IRQ_HANDLED; } - if (end_command) + if (end_command && host->cmd) mmc_omap_cmd_done(host, host->cmd); if (host->data != NULL) { if (transfer_error) diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c index f9b611fc773e..60e4186a4345 100644 --- a/drivers/mmc/host/sdhci-of-core.c +++ b/drivers/mmc/host/sdhci-of-core.c @@ -124,8 +124,10 @@ static bool __devinit sdhci_of_wp_inverted(struct device_node *np) #endif } +static const struct of_device_id sdhci_of_match[]; static int __devinit sdhci_of_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct sdhci_of_data *sdhci_of_data; struct sdhci_host *host; @@ -134,9 +136,10 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev) int size; int ret; - if (!ofdev->dev.of_match) + match = of_match_device(sdhci_of_match, &ofdev->dev); + if (!match) return -EINVAL; - sdhci_of_data = ofdev->dev.of_match->data; + sdhci_of_data = match->data; if (!of_device_is_available(np)) return -ENODEV; diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index a136be706347..f8b5f37007b2 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -957,6 +957,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( host->ioaddr = pci_ioremap_bar(pdev, bar); if (!host->ioaddr) { dev_err(&pdev->dev, "failed to remap registers\n"); + ret = -ENOMEM; goto release; } diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9e15f41f87be..5d20661bc357 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1334,6 +1334,13 @@ static void sdhci_tasklet_finish(unsigned long param) host = (struct sdhci_host*)param; + /* + * If this tasklet gets rescheduled while running, it will + * be run again afterwards but without any active request. + */ + if (!host->mrq) + return; + spin_lock_irqsave(&host->lock, flags); del_timer(&host->timer); @@ -1345,7 +1352,7 @@ static void sdhci_tasklet_finish(unsigned long param) * upon error conditions. */ if (!(host->flags & SDHCI_DEVICE_DEAD) && - (mrq->cmd->error || + ((mrq->cmd && mrq->cmd->error) || (mrq->data && (mrq->data->error || (mrq->data->stop && mrq->data->stop->error))) || (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 62d37de6de76..710339a85c84 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -728,15 +728,15 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) tmio_mmc_set_clock(host, ios->clock); /* Power sequence - OFF -> UP -> ON */ - if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { + if (ios->power_mode == MMC_POWER_UP) { + /* power up SD bus */ + if (host->set_pwr) + host->set_pwr(host->pdev, 1); + } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { /* power down SD bus */ if (ios->power_mode == MMC_POWER_OFF && host->set_pwr) host->set_pwr(host->pdev, 0); tmio_mmc_clk_stop(host); - } else if (ios->power_mode == MMC_POWER_UP) { - /* power up SD bus */ - if (host->set_pwr) - host->set_pwr(host->pdev, 1); } else { /* start bus clock */ tmio_mmc_clk_start(host); diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 44b1f46458ca..5069111c81cc 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -260,6 +260,13 @@ config MTD_BCM963XX Support for parsing CFE image tag and creating MTD partitions on Broadcom BCM63xx boards. +config MTD_LANTIQ + tristate "Lantiq SoC NOR support" + depends on LANTIQ + select MTD_PARTITIONS + help + Support for NOR flash attached to the Lantiq SoC's External Bus Unit. + config MTD_DILNETPC tristate "CFI Flash device mapped on DIL/Net PC" depends on X86 && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 08533bd5cba7..6adf4c9b9057 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -60,3 +60,4 @@ obj-$(CONFIG_MTD_VMU) += vmu-flash.o obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o +obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c new file mode 100644 index 000000000000..a90cabd7b84d --- /dev/null +++ b/drivers/mtd/maps/lantiq-flash.c @@ -0,0 +1,251 @@ +/* + * 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. + * + * Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * The NOR flash is connected to the same external bus unit (EBU) as PCI. + * To make PCI work we need to enable the endianness swapping for the address + * written to the EBU. This endianness swapping works for PCI correctly but + * fails for attached NOR devices. To workaround this we need to use a complex + * map. The workaround involves swapping all addresses whilst probing the chip. + * Once probing is complete we stop swapping the addresses but swizzle the + * unlock addresses to ensure that access to the NOR device works correctly. + */ + +enum { + LTQ_NOR_PROBING, + LTQ_NOR_NORMAL +}; + +struct ltq_mtd { + struct resource *res; + struct mtd_info *mtd; + struct map_info *map; +}; + +static char ltq_map_name[] = "ltq_nor"; + +static map_word +ltq_read16(struct map_info *map, unsigned long adr) +{ + unsigned long flags; + map_word temp; + + if (map->map_priv_1 == LTQ_NOR_PROBING) + adr ^= 2; + spin_lock_irqsave(&ebu_lock, flags); + temp.x[0] = *(u16 *)(map->virt + adr); + spin_unlock_irqrestore(&ebu_lock, flags); + return temp; +} + +static void +ltq_write16(struct map_info *map, map_word d, unsigned long adr) +{ + unsigned long flags; + + if (map->map_priv_1 == LTQ_NOR_PROBING) + adr ^= 2; + spin_lock_irqsave(&ebu_lock, flags); + *(u16 *)(map->virt + adr) = d.x[0]; + spin_unlock_irqrestore(&ebu_lock, flags); +} + +/* + * The following 2 functions copy data between iomem and a cached memory + * section. As memcpy() makes use of pre-fetching we cannot use it here. + * The normal alternative of using memcpy_{to,from}io also makes use of + * memcpy() on MIPS so it is not applicable either. We are therefore stuck + * with having to use our own loop. + */ +static void +ltq_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + unsigned char *f = (unsigned char *)map->virt + from; + unsigned char *t = (unsigned char *)to; + unsigned long flags; + + spin_lock_irqsave(&ebu_lock, flags); + while (len--) + *t++ = *f++; + spin_unlock_irqrestore(&ebu_lock, flags); +} + +static void +ltq_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) +{ + unsigned char *f = (unsigned char *)from; + unsigned char *t = (unsigned char *)map->virt + to; + unsigned long flags; + + spin_lock_irqsave(&ebu_lock, flags); + while (len--) + *t++ = *f++; + spin_unlock_irqrestore(&ebu_lock, flags); +} + +static const char const *part_probe_types[] = { "cmdlinepart", NULL }; + +static int __init +ltq_mtd_probe(struct platform_device *pdev) +{ + struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev); + struct ltq_mtd *ltq_mtd; + struct mtd_partition *parts; + struct resource *res; + int nr_parts = 0; + struct cfi_private *cfi; + int err; + + ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL); + platform_set_drvdata(pdev, ltq_mtd); + + ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!ltq_mtd->res) { + dev_err(&pdev->dev, "failed to get memory resource"); + err = -ENOENT; + goto err_out; + } + + res = devm_request_mem_region(&pdev->dev, ltq_mtd->res->start, + resource_size(ltq_mtd->res), dev_name(&pdev->dev)); + if (!ltq_mtd->res) { + dev_err(&pdev->dev, "failed to request mem resource"); + err = -EBUSY; + goto err_out; + } + + ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL); + ltq_mtd->map->phys = res->start; + ltq_mtd->map->size = resource_size(res); + ltq_mtd->map->virt = devm_ioremap_nocache(&pdev->dev, + ltq_mtd->map->phys, ltq_mtd->map->size); + if (!ltq_mtd->map->virt) { + dev_err(&pdev->dev, "failed to ioremap!\n"); + err = -ENOMEM; + goto err_free; + } + + ltq_mtd->map->name = ltq_map_name; + ltq_mtd->map->bankwidth = 2; + ltq_mtd->map->read = ltq_read16; + ltq_mtd->map->write = ltq_write16; + ltq_mtd->map->copy_from = ltq_copy_from; + ltq_mtd->map->copy_to = ltq_copy_to; + + ltq_mtd->map->map_priv_1 = LTQ_NOR_PROBING; + ltq_mtd->mtd = do_map_probe("cfi_probe", ltq_mtd->map); + ltq_mtd->map->map_priv_1 = LTQ_NOR_NORMAL; + + if (!ltq_mtd->mtd) { + dev_err(&pdev->dev, "probing failed\n"); + err = -ENXIO; + goto err_unmap; + } + + ltq_mtd->mtd->owner = THIS_MODULE; + + cfi = ltq_mtd->map->fldrv_priv; + cfi->addr_unlock1 ^= 1; + cfi->addr_unlock2 ^= 1; + + nr_parts = parse_mtd_partitions(ltq_mtd->mtd, + part_probe_types, &parts, 0); + if (nr_parts > 0) { + dev_info(&pdev->dev, + "using %d partitions from cmdline", nr_parts); + } else { + nr_parts = ltq_mtd_data->nr_parts; + parts = ltq_mtd_data->parts; + } + + err = add_mtd_partitions(ltq_mtd->mtd, parts, nr_parts); + if (err) { + dev_err(&pdev->dev, "failed to add partitions\n"); + goto err_destroy; + } + + return 0; + +err_destroy: + map_destroy(ltq_mtd->mtd); +err_unmap: + iounmap(ltq_mtd->map->virt); +err_free: + kfree(ltq_mtd->map); +err_out: + kfree(ltq_mtd); + return err; +} + +static int __devexit +ltq_mtd_remove(struct platform_device *pdev) +{ + struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); + + if (ltq_mtd) { + if (ltq_mtd->mtd) { + del_mtd_partitions(ltq_mtd->mtd); + map_destroy(ltq_mtd->mtd); + } + if (ltq_mtd->map->virt) + iounmap(ltq_mtd->map->virt); + kfree(ltq_mtd->map); + kfree(ltq_mtd); + } + return 0; +} + +static struct platform_driver ltq_mtd_driver = { + .remove = __devexit_p(ltq_mtd_remove), + .driver = { + .name = "ltq_nor", + .owner = THIS_MODULE, + }, +}; + +static int __init +init_ltq_mtd(void) +{ + int ret = platform_driver_probe(<q_mtd_driver, ltq_mtd_probe); + + if (ret) + pr_err("ltq_nor: error registering platform driver"); + return ret; +} + +static void __exit +exit_ltq_mtd(void) +{ + platform_driver_unregister(<q_mtd_driver); +} + +module_init(init_ltq_mtd); +module_exit(exit_ltq_mtd); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("John Crispin "); +MODULE_DESCRIPTION("Lantiq SoC NOR"); diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index bd483f0c57e1..c1d33464aee8 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -214,11 +214,13 @@ static void __devinit of_free_probes(const char **probes) } #endif +static struct of_device_id of_flash_match[]; static int __devinit of_flash_probe(struct platform_device *dev) { #ifdef CONFIG_MTD_PARTITIONS const char **part_probe_types; #endif + const struct of_device_id *match; struct device_node *dp = dev->dev.of_node; struct resource res; struct of_flash *info; @@ -232,9 +234,10 @@ static int __devinit of_flash_probe(struct platform_device *dev) struct mtd_info **mtd_list = NULL; resource_size_t res_size; - if (!dev->dev.of_match) + match = of_match_device(of_flash_match, &dev->dev); + if (!match) return -EINVAL; - probe_type = dev->dev.of_match->data; + probe_type = match->data; reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32); diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 3ffe05db4923..5d513b54a7d7 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -470,7 +471,7 @@ static int __init au1xxx_nand_init(void) #ifdef CONFIG_MIPS_PB1550 /* set gpio206 high */ - au_writel(au_readl(GPIO2_DIR) & ~(1 << 6), GPIO2_DIR); + gpio_direction_input(206); boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr_read(BCSR_STATUS) >> 6) & 0x1); diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 96c0b34ba8db..657b9f4b6f9b 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -400,7 +400,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - /* We can't' use dev_ready here, but at least we wait for the + /* We can't use dev_ready here, but at least we wait for the * command to complete */ udelay(50); diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 91abb965fb44..5f25889e27ef 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -185,7 +185,7 @@ static int max_interrupt_work = 10; static int nopnp; #endif -static int __devinit el3_common_init(struct net_device *dev); +static int el3_common_init(struct net_device *dev); static void el3_common_remove(struct net_device *dev); static ushort id_read_eeprom(int index); static ushort read_eeprom(int ioaddr, int index); @@ -395,7 +395,7 @@ static struct isa_driver el3_isa_driver = { static int isa_registered; #ifdef CONFIG_PNP -static struct pnp_device_id el3_pnp_ids[] = { +static const struct pnp_device_id el3_pnp_ids[] __devinitconst = { { .id = "TCM5090" }, /* 3Com Etherlink III (TP) */ { .id = "TCM5091" }, /* 3Com Etherlink III */ { .id = "TCM5094" }, /* 3Com Etherlink III (combo) */ @@ -478,7 +478,7 @@ static int pnp_registered; #endif /* CONFIG_PNP */ #ifdef CONFIG_EISA -static struct eisa_device_id el3_eisa_ids[] = { +static const struct eisa_device_id el3_eisa_ids[] __devinitconst = { { "TCM5090" }, { "TCM5091" }, { "TCM5092" }, @@ -508,7 +508,7 @@ static int eisa_registered; #ifdef CONFIG_MCA static int el3_mca_probe(struct device *dev); -static short el3_mca_adapter_ids[] __initdata = { +static const short el3_mca_adapter_ids[] __devinitconst = { 0x627c, 0x627d, 0x62db, @@ -517,7 +517,7 @@ static short el3_mca_adapter_ids[] __initdata = { 0x0000 }; -static char *el3_mca_adapter_names[] __initdata = { +static const char *const el3_mca_adapter_names[] __devinitconst = { "3Com 3c529 EtherLink III (10base2)", "3Com 3c529 EtherLink III (10baseT)", "3Com 3c529 EtherLink III (test mode)", @@ -601,7 +601,7 @@ static void el3_common_remove (struct net_device *dev) } #ifdef CONFIG_MCA -static int __init el3_mca_probe(struct device *device) +static int __devinit el3_mca_probe(struct device *device) { /* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch, * heavily modified by Chris Beauregard @@ -671,7 +671,7 @@ static int __init el3_mca_probe(struct device *device) #endif /* CONFIG_MCA */ #ifdef CONFIG_EISA -static int __init el3_eisa_probe (struct device *device) +static int __devinit el3_eisa_probe (struct device *device) { short i; int ioaddr, irq, if_port; @@ -1207,7 +1207,7 @@ el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->duplex = DUPLEX_FULL; } - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); EL3WINDOW(1); return 0; } diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 8cc22568ebd3..99f43d275442 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -901,14 +901,14 @@ static const struct dev_pm_ops vortex_pm_ops = { #endif /* !CONFIG_PM */ #ifdef CONFIG_EISA -static struct eisa_device_id vortex_eisa_ids[] = { +static const struct eisa_device_id vortex_eisa_ids[] __devinitconst = { { "TCM5920", CH_3C592 }, { "TCM5970", CH_3C597 }, { "" } }; MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids); -static int __init vortex_eisa_probe(struct device *device) +static int __devinit vortex_eisa_probe(struct device *device) { void __iomem *ioaddr; struct eisa_device *edev; diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index dd16e83933a2..10c45051caea 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -758,8 +758,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, entry = cp->tx_head; eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; - if (dev->features & NETIF_F_TSO) - mss = skb_shinfo(skb)->gso_size; + mss = skb_shinfo(skb)->gso_size; if (skb_shinfo(skb)->nr_frags == 0) { struct cp_desc *txd = &cp->tx_ring[entry]; @@ -1416,32 +1415,23 @@ static void cp_set_msglevel(struct net_device *dev, u32 value) cp->msg_enable = value; } -static u32 cp_get_rx_csum(struct net_device *dev) +static int cp_set_features(struct net_device *dev, u32 features) { struct cp_private *cp = netdev_priv(dev); - return (cpr16(CpCmd) & RxChkSum) ? 1 : 0; -} + unsigned long flags; -static int cp_set_rx_csum(struct net_device *dev, u32 data) -{ - struct cp_private *cp = netdev_priv(dev); - u16 cmd = cp->cpcmd, newcmd; + if (!((dev->features ^ features) & NETIF_F_RXCSUM)) + return 0; - newcmd = cmd; + spin_lock_irqsave(&cp->lock, flags); - if (data) - newcmd |= RxChkSum; + if (features & NETIF_F_RXCSUM) + cp->cpcmd |= RxChkSum; else - newcmd &= ~RxChkSum; + cp->cpcmd &= ~RxChkSum; - if (newcmd != cmd) { - unsigned long flags; - - spin_lock_irqsave(&cp->lock, flags); - cp->cpcmd = newcmd; - cpw16_f(CpCmd, newcmd); - spin_unlock_irqrestore(&cp->lock, flags); - } + cpw16_f(CpCmd, cp->cpcmd); + spin_unlock_irqrestore(&cp->lock, flags); return 0; } @@ -1554,11 +1544,6 @@ static const struct ethtool_ops cp_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = cp_get_msglevel, .set_msglevel = cp_set_msglevel, - .get_rx_csum = cp_get_rx_csum, - .set_rx_csum = cp_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, .get_regs = cp_get_regs, .get_wol = cp_get_wol, .set_wol = cp_set_wol, @@ -1831,6 +1816,7 @@ static const struct net_device_ops cp_netdev_ops = { .ndo_do_ioctl = cp_ioctl, .ndo_start_xmit = cp_start_xmit, .ndo_tx_timeout = cp_tx_timeout, + .ndo_set_features = cp_set_features, #if CP_VLAN_TAG_USED .ndo_vlan_rx_register = cp_vlan_rx_register, #endif @@ -1934,6 +1920,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) cp->cpcmd = (pci_using_dac ? PCIDAC : 0) | PCIMulRW | RxChkSum | CpRxOn | CpTxOn; + dev->features |= NETIF_F_RXCSUM; + dev->hw_features |= NETIF_F_RXCSUM; + regs = ioremap(pciaddr, CP_REGS_SIZE); if (!regs) { rc = -EIO; @@ -1966,9 +1955,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; -#if 0 /* disabled by default until verified */ - dev->features |= NETIF_F_TSO; -#endif + /* disabled by default until verified */ + dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; dev->irq = pdev->irq; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index dc280bc8eba2..19f04a34783a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2017,6 +2017,13 @@ config FTMAC100 from Faraday. It is used on Faraday A320, Andes AG101 and some other ARM/NDS32 SoC's. +config LANTIQ_ETOP + tristate "Lantiq SoC ETOP driver" + depends on SOC_TYPE_XWAY + help + Support for the MII0 inside the Lantiq SoC + + source "drivers/net/fs_enet/Kconfig" source "drivers/net/octeon/Kconfig" @@ -2536,7 +2543,7 @@ config S6GMAC source "drivers/net/stmmac/Kconfig" config PCH_GBE - tristate "PCH Gigabit Ethernet" + tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GbE" depends on PCI select MII ---help--- @@ -2548,6 +2555,12 @@ config PCH_GBE to Gigabit Ethernet. This driver enables Gigabit Ethernet function. + This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ + Output Hub), ML7223. + ML7223 IOH is for MP(Media Phone) use. + ML7223 is companion chip for Intel Atom E6xx series. + ML7223 is completely compatible for Intel EG20T PCH. + endif # NETDEV_1000 # diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 01b604ad155e..209fbb70619b 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -144,7 +144,7 @@ obj-$(CONFIG_NE3210) += ne3210.o 8390.o obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_B44) += b44.o obj-$(CONFIG_FORCEDETH) += forcedeth.o -obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o +obj-$(CONFIG_NE_H8300) += ne-h8300.o obj-$(CONFIG_AX88796) += ax88796.o obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o obj-$(CONFIG_FTMAC100) += ftmac100.o @@ -219,7 +219,7 @@ obj-$(CONFIG_SC92031) += sc92031.o obj-$(CONFIG_LP486E) += lp486e.o obj-$(CONFIG_ETH16I) += eth16i.o -obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o +obj-$(CONFIG_ZORRO8390) += zorro8390.o obj-$(CONFIG_HPLANCE) += hplance.o 7990.o obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o obj-$(CONFIG_EQUALIZER) += eql.o @@ -231,7 +231,7 @@ obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o obj-$(CONFIG_DECLANCE) += declance.o obj-$(CONFIG_ATARILANCE) += atarilance.o obj-$(CONFIG_A2065) += a2065.o -obj-$(CONFIG_HYDRA) += hydra.o 8390.o +obj-$(CONFIG_HYDRA) += hydra.o obj-$(CONFIG_ARIADNE) += ariadne.o obj-$(CONFIG_CS89x0) += cs89x0.o obj-$(CONFIG_MACSONIC) += macsonic.o @@ -259,6 +259,7 @@ obj-$(CONFIG_MLX4_CORE) += mlx4/ obj-$(CONFIG_ENC28J60) += enc28j60.o obj-$(CONFIG_ETHOC) += ethoc.o obj-$(CONFIG_GRETH) += greth.o +obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index ee648fe5d96f..d7c1bfe4b6ec 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -68,6 +68,7 @@ #include #include #include +#include #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #include @@ -2658,15 +2659,15 @@ static int ace_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) link = readl(®s->GigLnkState); if (link & LNK_1000MB) - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); else { link = readl(®s->FastLnkState); if (link & LNK_100MB) - ecmd->speed = SPEED_100; + ethtool_cmd_speed_set(ecmd, SPEED_100); else if (link & LNK_10MB) - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); else - ecmd->speed = 0; + ethtool_cmd_speed_set(ecmd, 0); } if (link & LNK_FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; @@ -2718,9 +2719,9 @@ static int ace_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) link |= LNK_TX_FLOW_CTL_Y; if (ecmd->autoneg == AUTONEG_ENABLE) link |= LNK_NEGOTIATE; - if (ecmd->speed != speed) { + if (ethtool_cmd_speed(ecmd) != speed) { link &= ~(LNK_1000MB | LNK_100MB | LNK_10MB); - switch (speed) { + switch (ethtool_cmd_speed(ecmd)) { case SPEED_1000: link |= LNK_1000MB; break; diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 88495c48a81d..241b185e6569 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -106,7 +106,7 @@ MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version "M MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl); module_param_array(speed_duplex, int, NULL, 0); -MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); +MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotiate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); module_param_array(coalesce, bool, NULL, 0); MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0: Disable"); module_param_array(dynamic_ipg, bool, NULL, 0); diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 4af235d41fda..03e217a868d4 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -527,7 +527,7 @@ static void __init etherh_banner(void) * Read the ethernet address string from the on board rom. * This is an ascii string... */ -static int __init etherh_addr(char *addr, struct expansion_card *ec) +static int __devinit etherh_addr(char *addr, struct expansion_card *ec) { struct in_chunk_dir cd; char *s; @@ -591,10 +591,11 @@ static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i static int etherh_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { cmd->supported = etherh_priv(dev)->supported; - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); cmd->duplex = DUPLEX_HALF; cmd->port = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC; - cmd->autoneg = dev->flags & IFF_AUTOMEDIA ? AUTONEG_ENABLE : AUTONEG_DISABLE; + cmd->autoneg = (dev->flags & IFF_AUTOMEDIA ? + AUTONEG_ENABLE : AUTONEG_DISABLE); return 0; } @@ -655,7 +656,7 @@ static const struct net_device_ops etherh_netdev_ops = { static u32 etherh_regoffsets[16]; static u32 etherm_regoffsets[16]; -static int __init +static int __devinit etherh_probe(struct expansion_card *ec, const struct ecard_id *id) { const struct etherh_data *data = id->data; diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index aa07657744c3..a7b0caa18179 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -891,15 +891,16 @@ ks8695_wan_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) cmd->advertising |= ADVERTISED_Pause; cmd->autoneg = AUTONEG_ENABLE; - cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(cmd, + (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10); cmd->duplex = (ctrl & WMC_WDS) ? DUPLEX_FULL : DUPLEX_HALF; } else { /* auto-negotiation is disabled */ cmd->autoneg = AUTONEG_DISABLE; - cmd->speed = (ctrl & WMC_WANF100) ? - SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(cmd, ((ctrl & WMC_WANF100) ? + SPEED_100 : SPEED_10)); cmd->duplex = (ctrl & WMC_WANFF) ? DUPLEX_FULL : DUPLEX_HALF; } diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index ce0091eb06f5..1264d781b554 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -554,7 +554,7 @@ static unsigned long __init lance_probe1( struct net_device *dev, memaddr == (unsigned short *)0xffe00000) { /* PAMs card and Riebl on ST use level 5 autovector */ if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO, - "PAM/Riebl-ST Ethernet", dev)) { + "PAM,Riebl-ST Ethernet", dev)) { printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 ); return 0; } diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h index 7cb375e0e29c..925929d764ca 100644 --- a/drivers/net/atl1c/atl1c.h +++ b/drivers/net/atl1c/atl1c.h @@ -566,9 +566,9 @@ struct atl1c_adapter { #define __AT_TESTING 0x0001 #define __AT_RESETTING 0x0002 #define __AT_DOWN 0x0003 - u8 work_event; -#define ATL1C_WORK_EVENT_RESET 0x01 -#define ATL1C_WORK_EVENT_LINK_CHANGE 0x02 + unsigned long work_event; +#define ATL1C_WORK_EVENT_RESET 0 +#define ATL1C_WORK_EVENT_LINK_CHANGE 1 u32 msg_enable; bool have_msi; diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c index 7c521508313c..7be884d0aaf6 100644 --- a/drivers/net/atl1c/atl1c_ethtool.c +++ b/drivers/net/atl1c/atl1c_ethtool.c @@ -50,13 +50,13 @@ static int atl1c_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_INTERNAL; if (adapter->link_speed != SPEED_0) { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); if (adapter->link_duplex == FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } @@ -77,7 +77,8 @@ static int atl1c_set_settings(struct net_device *netdev, if (ecmd->autoneg == AUTONEG_ENABLE) { autoneg_advertised = ADVERTISED_Autoneg; } else { - if (ecmd->speed == SPEED_1000) { + u32 speed = ethtool_cmd_speed(ecmd); + if (speed == SPEED_1000) { if (ecmd->duplex != DUPLEX_FULL) { if (netif_msg_link(adapter)) dev_warn(&adapter->pdev->dev, @@ -86,7 +87,7 @@ static int atl1c_set_settings(struct net_device *netdev, return -EINVAL; } autoneg_advertised = ADVERTISED_1000baseT_Full; - } else if (ecmd->speed == SPEED_100) { + } else if (speed == SPEED_100) { if (ecmd->duplex == DUPLEX_FULL) autoneg_advertised = ADVERTISED_100baseT_Full; else @@ -113,11 +114,6 @@ static int atl1c_set_settings(struct net_device *netdev, return 0; } -static u32 atl1c_get_tx_csum(struct net_device *netdev) -{ - return (netdev->features & NETIF_F_HW_CSUM) != 0; -} - static u32 atl1c_get_msglevel(struct net_device *netdev) { struct atl1c_adapter *adapter = netdev_priv(netdev); @@ -307,9 +303,6 @@ static const struct ethtool_ops atl1c_ethtool_ops = { .get_link = ethtool_op_get_link, .get_eeprom_len = atl1c_get_eeprom_len, .get_eeprom = atl1c_get_eeprom, - .get_tx_csum = atl1c_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, }; void atl1c_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 7d9d5067a65c..1269ba5d6e56 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -325,7 +325,7 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter) } } - adapter->work_event |= ATL1C_WORK_EVENT_LINK_CHANGE; + set_bit(ATL1C_WORK_EVENT_LINK_CHANGE, &adapter->work_event); schedule_work(&adapter->common_task); } @@ -337,20 +337,16 @@ static void atl1c_common_task(struct work_struct *work) adapter = container_of(work, struct atl1c_adapter, common_task); netdev = adapter->netdev; - if (adapter->work_event & ATL1C_WORK_EVENT_RESET) { - adapter->work_event &= ~ATL1C_WORK_EVENT_RESET; + if (test_and_clear_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event)) { netif_device_detach(netdev); atl1c_down(adapter); atl1c_up(adapter); netif_device_attach(netdev); - return; } - if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE) { - adapter->work_event &= ~ATL1C_WORK_EVENT_LINK_CHANGE; + if (test_and_clear_bit(ATL1C_WORK_EVENT_LINK_CHANGE, + &adapter->work_event)) atl1c_check_link_status(adapter); - } - return; } @@ -369,7 +365,7 @@ static void atl1c_tx_timeout(struct net_device *netdev) struct atl1c_adapter *adapter = netdev_priv(netdev); /* Do the reset outside of interrupt context */ - adapter->work_event |= ATL1C_WORK_EVENT_RESET; + set_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event); schedule_work(&adapter->common_task); } @@ -484,6 +480,15 @@ static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter, adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ? roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE; } + +static u32 atl1c_fix_features(struct net_device *netdev, u32 features) +{ + if (netdev->mtu > MAX_TSO_FRAME_SIZE) + features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + + return features; +} + /* * atl1c_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure @@ -510,14 +515,8 @@ static int atl1c_change_mtu(struct net_device *netdev, int new_mtu) netdev->mtu = new_mtu; adapter->hw.max_frame_size = new_mtu; atl1c_set_rxbufsize(adapter, netdev); - if (new_mtu > MAX_TSO_FRAME_SIZE) { - adapter->netdev->features &= ~NETIF_F_TSO; - adapter->netdev->features &= ~NETIF_F_TSO6; - } else { - adapter->netdev->features |= NETIF_F_TSO; - adapter->netdev->features |= NETIF_F_TSO6; - } atl1c_down(adapter); + netdev_update_features(netdev); atl1c_up(adapter); clear_bit(__AT_RESETTING, &adapter->flags); if (adapter->hw.ctrl_flags & ATL1C_FPGA_VERSION) { @@ -1092,10 +1091,8 @@ static void atl1c_configure_tx(struct atl1c_adapter *adapter) u32 max_pay_load; u16 tx_offload_thresh; u32 txq_ctrl_data; - u32 extra_size = 0; /* Jumbo frame threshold in QWORD unit */ u32 max_pay_load_data; - extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN; tx_offload_thresh = MAX_TX_OFFLOAD_THRESH; AT_WRITE_REG(hw, REG_TX_TSO_OFFLOAD_THRESH, (tx_offload_thresh >> 3) & TX_TSO_OFFLOAD_THRESH_MASK); @@ -2540,6 +2537,7 @@ static int atl1c_suspend(struct device *dev) return 0; } +#ifdef CONFIG_PM_SLEEP static int atl1c_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); @@ -2566,6 +2564,7 @@ static int atl1c_resume(struct device *dev) return 0; } +#endif static void atl1c_shutdown(struct pci_dev *pdev) { @@ -2585,6 +2584,7 @@ static const struct net_device_ops atl1c_netdev_ops = { .ndo_set_mac_address = atl1c_set_mac_addr, .ndo_set_multicast_list = atl1c_set_multi, .ndo_change_mtu = atl1c_change_mtu, + .ndo_fix_features = atl1c_fix_features, .ndo_do_ioctl = atl1c_ioctl, .ndo_tx_timeout = atl1c_tx_timeout, .ndo_get_stats = atl1c_get_stats, @@ -2605,12 +2605,13 @@ static int atl1c_init_netdev(struct net_device *netdev, struct pci_dev *pdev) atl1c_set_ethtool_ops(netdev); /* TODO: add when ready */ - netdev->features = NETIF_F_SG | + netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | NETIF_F_TSO | NETIF_F_TSO6; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_RX; return 0; } diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c index 1209297433b8..6269438d365f 100644 --- a/drivers/net/atl1e/atl1e_ethtool.c +++ b/drivers/net/atl1e/atl1e_ethtool.c @@ -51,13 +51,13 @@ static int atl1e_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_INTERNAL; if (adapter->link_speed != SPEED_0) { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); if (adapter->link_duplex == FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } @@ -382,9 +382,6 @@ static const struct ethtool_ops atl1e_ethtool_ops = { .get_eeprom_len = atl1e_get_eeprom_len, .get_eeprom = atl1e_get_eeprom, .set_eeprom = atl1e_set_eeprom, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, }; void atl1e_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index b0a71e2f28a9..86a912283134 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -691,10 +691,8 @@ static void atl1e_cal_ring_size(struct atl1e_adapter *adapter, u32 *ring_size) static void atl1e_init_ring_resources(struct atl1e_adapter *adapter) { - struct atl1e_tx_ring *tx_ring = NULL; struct atl1e_rx_ring *rx_ring = NULL; - tx_ring = &adapter->tx_ring; rx_ring = &adapter->rx_ring; rx_ring->real_page_size = adapter->rx_ring.page_size @@ -1927,11 +1925,7 @@ void atl1e_down(struct atl1e_adapter *adapter) * reschedule our watchdog timer */ set_bit(__AT_DOWN, &adapter->flags); -#ifdef NETIF_F_LLTX netif_stop_queue(netdev); -#else - netif_tx_disable(netdev); -#endif /* reset MAC to disable all RX/TX */ atl1e_reset_hw(&adapter->hw); @@ -2223,10 +2217,10 @@ static int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev) netdev->watchdog_timeo = AT_TX_WATCHDOG; atl1e_set_ethtool_ops(netdev); - netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - netdev->features |= NETIF_F_LLTX; - netdev->features |= NETIF_F_TSO; + netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO | + NETIF_F_HW_VLAN_TX; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_LLTX; return 0; } diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 67f40b9c16ed..c5298d1ab744 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2074,9 +2074,6 @@ static void atl1_intr_tx(struct atl1_adapter *adapter) cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx); while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) { - struct tx_packet_desc *tpd; - - tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean); buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean]; if (buffer_info->dma) { pci_unmap_page(adapter->pdev, buffer_info->dma, @@ -2572,7 +2569,7 @@ static s32 atl1_up(struct atl1_adapter *adapter) { struct net_device *netdev = adapter->netdev; int err; - int irq_flags = IRQF_SAMPLE_RANDOM; + int irq_flags = 0; /* hardware has been reset, we need to reload some things */ atlx_set_multi(netdev); @@ -2986,6 +2983,11 @@ static int __devinit atl1_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_SG; netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); + netdev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_TSO; + + /* is this valid? see atl1_setup_mac_ctrl() */ + netdev->features |= NETIF_F_RXCSUM; + /* * patch for some L1 of old version, * the final version of L1 may not need these @@ -3229,13 +3231,13 @@ static int atl1_get_settings(struct net_device *netdev, if (netif_carrier_ok(adapter->netdev)) { u16 link_speed, link_duplex; atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex); - ecmd->speed = link_speed; + ethtool_cmd_speed_set(ecmd, link_speed); if (link_duplex == FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || @@ -3266,7 +3268,8 @@ static int atl1_set_settings(struct net_device *netdev, if (ecmd->autoneg == AUTONEG_ENABLE) hw->media_type = MEDIA_TYPE_AUTO_SENSOR; else { - if (ecmd->speed == SPEED_1000) { + u32 speed = ethtool_cmd_speed(ecmd); + if (speed == SPEED_1000) { if (ecmd->duplex != DUPLEX_FULL) { if (netif_msg_link(adapter)) dev_warn(&adapter->pdev->dev, @@ -3275,7 +3278,7 @@ static int atl1_set_settings(struct net_device *netdev, goto exit_sset; } hw->media_type = MEDIA_TYPE_1000M_FULL; - } else if (ecmd->speed == SPEED_100) { + } else if (speed == SPEED_100) { if (ecmd->duplex == DUPLEX_FULL) hw->media_type = MEDIA_TYPE_100M_FULL; else @@ -3595,12 +3598,6 @@ static int atl1_set_pauseparam(struct net_device *netdev, return 0; } -/* FIXME: is this right? -- CHS */ -static u32 atl1_get_rx_csum(struct net_device *netdev) -{ - return 1; -} - static void atl1_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { @@ -3668,13 +3665,9 @@ static const struct ethtool_ops atl1_ethtool_ops = { .set_ringparam = atl1_set_ringparam, .get_pauseparam = atl1_get_pauseparam, .set_pauseparam = atl1_set_pauseparam, - .get_rx_csum = atl1_get_rx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, .get_link = ethtool_op_get_link, - .set_sg = ethtool_op_set_sg, .get_strings = atl1_get_strings, .nway_reset = atl1_nway_reset, .get_ethtool_stats = atl1_get_ethtool_stats, .get_sset_count = atl1_get_sset_count, - .set_tso = ethtool_op_set_tso, }; diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index e3cbf45dc612..16249e9b6b95 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -1411,9 +1411,8 @@ static int __devinit atl2_probe(struct pci_dev *pdev, err = -EIO; -#ifdef NETIF_F_HW_VLAN_TX + netdev->hw_features = NETIF_F_SG; netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); -#endif /* Init PHY as early as possible due to power saving issue */ atl2_phy_init(&adapter->hw); @@ -1770,13 +1769,13 @@ static int atl2_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_INTERNAL; if (adapter->link_speed != SPEED_0) { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); if (adapter->link_duplex == FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } @@ -1840,11 +1839,6 @@ static int atl2_set_settings(struct net_device *netdev, return 0; } -static u32 atl2_get_tx_csum(struct net_device *netdev) -{ - return (netdev->features & NETIF_F_HW_CSUM) != 0; -} - static u32 atl2_get_msglevel(struct net_device *netdev) { return 0; @@ -2112,12 +2106,6 @@ static const struct ethtool_ops atl2_ethtool_ops = { .get_eeprom_len = atl2_get_eeprom_len, .get_eeprom = atl2_get_eeprom, .set_eeprom = atl2_set_eeprom, - .get_tx_csum = atl2_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, -#ifdef NETIF_F_TSO - .get_tso = ethtool_op_get_tso, -#endif }; static void atl2_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 2e2b76258ab4..a69331e06b8d 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1807,8 +1807,8 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (bp->flags & B44_FLAG_ADV_100FULL) cmd->advertising |= ADVERTISED_100baseT_Full; cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; - cmd->speed = (bp->flags & B44_FLAG_100_BASE_T) ? - SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(cmd, ((bp->flags & B44_FLAG_100_BASE_T) ? + SPEED_100 : SPEED_10)); cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; cmd->port = 0; @@ -1820,7 +1820,7 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (cmd->autoneg == AUTONEG_ENABLE) cmd->advertising |= ADVERTISED_Autoneg; if (!netif_running(dev)){ - cmd->speed = 0; + ethtool_cmd_speed_set(cmd, 0); cmd->duplex = 0xff; } cmd->maxtxpkt = 0; @@ -1831,6 +1831,7 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct b44 *bp = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(cmd); /* We do not support gigabit. */ if (cmd->autoneg == AUTONEG_ENABLE) { @@ -1838,8 +1839,8 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) return -EINVAL; - } else if ((cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || + } else if ((speed != SPEED_100 && + speed != SPEED_10) || (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL)) { return -EINVAL; @@ -1873,7 +1874,7 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) } else { bp->flags |= B44_FLAG_FORCE_LINK; bp->flags &= ~(B44_FLAG_100_BASE_T | B44_FLAG_FULL_DUPLEX); - if (cmd->speed == SPEED_100) + if (speed == SPEED_100) bp->flags |= B44_FLAG_100_BASE_T; if (cmd->duplex == DUPLEX_FULL) bp->flags |= B44_FLAG_FULL_DUPLEX; diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c index c48104b08861..f1573d492e90 100644 --- a/drivers/net/bcm63xx_enet.c +++ b/drivers/net/bcm63xx_enet.c @@ -839,8 +839,8 @@ static int bcm_enet_open(struct net_device *dev) if (ret) goto out_phy_disconnect; - ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, - IRQF_SAMPLE_RANDOM | IRQF_DISABLED, dev->name, dev); + ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, IRQF_DISABLED, + dev->name, dev); if (ret) goto out_freeirq; @@ -1346,7 +1346,8 @@ static int bcm_enet_get_settings(struct net_device *dev, return phy_ethtool_gset(priv->phydev, cmd); } else { cmd->autoneg = 0; - cmd->speed = (priv->force_speed_100) ? SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(cmd, ((priv->force_speed_100) + ? SPEED_100 : SPEED_10)); cmd->duplex = (priv->force_duplex_full) ? DUPLEX_FULL : DUPLEX_HALF; cmd->supported = ADVERTISED_10baseT_Half | diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 66823eded7a3..a7db870d1641 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -49,6 +49,7 @@ #define OC_DEVICE_ID1 0x700 /* Device Id for BE2 cards */ #define OC_DEVICE_ID2 0x710 /* Device Id for BE3 cards */ #define OC_DEVICE_ID3 0xe220 /* Device id for Lancer cards */ +#define OC_DEVICE_ID4 0xe228 /* Device id for VF in Lancer */ static inline char *nic_name(struct pci_dev *pdev) { @@ -58,6 +59,7 @@ static inline char *nic_name(struct pci_dev *pdev) case OC_DEVICE_ID2: return OC_NAME_BE; case OC_DEVICE_ID3: + case OC_DEVICE_ID4: return OC_NAME_LANCER; case BE_DEVICE_ID2: return BE3_NAME; @@ -84,15 +86,14 @@ static inline char *nic_name(struct pci_dev *pdev) #define MCC_CQ_LEN 256 #define MAX_RSS_QS 4 /* BE limit is 4 queues/port */ -#define BE_MAX_MSIX_VECTORS (MAX_RSS_QS + 1 + 1)/* RSS qs + 1 def Rx + Tx */ +#define MAX_RX_QS (MAX_RSS_QS + 1) /* RSS qs + 1 def Rx */ +#define BE_MAX_MSIX_VECTORS (MAX_RX_QS + 1)/* RX + TX */ #define BE_NAPI_WEIGHT 64 #define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ #define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST) #define FW_VER_LEN 32 -#define BE_MAX_VF 32 - struct be_dma_mem { void *va; dma_addr_t dma; @@ -213,7 +214,7 @@ struct be_rx_stats { struct be_rx_compl_info { u32 rss_hash; - u16 vid; + u16 vlan_tag; u16 pkt_size; u16 rxq_idx; u16 mac_id; @@ -245,6 +246,43 @@ struct be_rx_obj { struct be_drv_stats { u8 be_on_die_temperature; + u64 be_tx_events; + u64 eth_red_drops; + u64 rx_drops_no_pbuf; + u64 rx_drops_no_txpb; + u64 rx_drops_no_erx_descr; + u64 rx_drops_no_tpre_descr; + u64 rx_drops_too_many_frags; + u64 rx_drops_invalid_ring; + u64 forwarded_packets; + u64 rx_drops_mtu; + u64 rx_crc_errors; + u64 rx_alignment_symbol_errors; + u64 rx_pause_frames; + u64 rx_priority_pause_frames; + u64 rx_control_frames; + u64 rx_in_range_errors; + u64 rx_out_range_errors; + u64 rx_frame_too_long; + u64 rx_address_match_errors; + u64 rx_dropped_too_small; + u64 rx_dropped_too_short; + u64 rx_dropped_header_too_small; + u64 rx_dropped_tcp_length; + u64 rx_dropped_runt; + u64 rx_ip_checksum_errs; + u64 rx_tcp_checksum_errs; + u64 rx_udp_checksum_errs; + u64 rx_switched_unicast_packets; + u64 rx_switched_multicast_packets; + u64 rx_switched_broadcast_packets; + u64 tx_pauseframes; + u64 tx_priority_pauseframes; + u64 tx_controlframes; + u64 rxpp_fifo_overflow_drop; + u64 rx_input_fifo_overflow_drop; + u64 pmem_fifo_overflow_drop; + u64 jabber_events; }; struct be_vf_cfg { @@ -276,7 +314,7 @@ struct be_adapter { spinlock_t mcc_cq_lock; struct msix_entry msix_entries[BE_MAX_MSIX_VECTORS]; - bool msix_enabled; + u32 num_msix_vec; bool isr_registered; /* TX Rings */ @@ -287,7 +325,7 @@ struct be_adapter { u32 cache_line_break[8]; /* Rx rings */ - struct be_rx_obj rx_obj[MAX_RSS_QS + 1]; /* one default non-rss Q */ + struct be_rx_obj rx_obj[MAX_RX_QS]; u32 num_rx_qs; u32 big_page_size; /* Compounded page size shared by rx wrbs */ @@ -308,10 +346,10 @@ struct be_adapter { u16 work_counter; /* Ethtool knobs and info */ - bool rx_csum; /* BE card must perform rx-checksumming */ char fw_ver[FW_VER_LEN]; u32 if_handle; /* Used to configure filtering */ u32 pmac_id; /* MAC addr handle used by BE card */ + u32 beacon_state; /* for set_phys_id */ bool eeh_err; bool link_up; @@ -334,7 +372,7 @@ struct be_adapter { bool be3_native; bool sriov_enabled; - struct be_vf_cfg vf_cfg[BE_MAX_VF]; + struct be_vf_cfg *vf_cfg; u8 is_virtfn; u32 sli_family; u8 hba_port_num; @@ -347,10 +385,12 @@ struct be_adapter { #define BE_GEN2 2 #define BE_GEN3 3 -#define lancer_chip(adapter) (adapter->pdev->device == OC_DEVICE_ID3) +#define lancer_chip(adapter) ((adapter->pdev->device == OC_DEVICE_ID3) || \ + (adapter->pdev->device == OC_DEVICE_ID4)) extern const struct ethtool_ops be_ethtool_ops; +#define msix_enabled(adapter) (adapter->num_msix_vec > 0) #define tx_stats(adapter) (&adapter->tx_stats) #define rx_stats(rxo) (&rxo->stats) @@ -455,18 +495,10 @@ static inline u8 is_udp_pkt(struct sk_buff *skb) static inline void be_check_sriov_fn_type(struct be_adapter *adapter) { - u8 data; u32 sli_intf; - if (lancer_chip(adapter)) { - pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, - &sli_intf); - adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; - } else { - pci_write_config_byte(adapter->pdev, 0xFE, 0xAA); - pci_read_config_byte(adapter->pdev, 0xFE, &data); - adapter->is_virtfn = (data != 0xAA); - } + pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf); + adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; } static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) @@ -482,9 +514,15 @@ static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) memcpy(mac, adapter->netdev->dev_addr, 3); } +static inline bool be_multi_rxq(const struct be_adapter *adapter) +{ + return adapter->num_rx_qs > 1; +} + extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); extern void be_link_status_update(struct be_adapter *adapter, bool link_up); extern void netdev_stats_update(struct be_adapter *adapter); +extern void be_parse_stats(struct be_adapter *adapter); extern int be_load_fw(struct be_adapter *adapter, u8 *func); #endif /* BE_H */ diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 1e2d825bb94a..2463b1c97922 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -71,18 +71,38 @@ static int be_mcc_compl_process(struct be_adapter *adapter, compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & CQE_STATUS_COMPL_MASK; - if ((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) && + if (((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) || + (compl->tag0 == OPCODE_COMMON_WRITE_OBJECT)) && (compl->tag1 == CMD_SUBSYSTEM_COMMON)) { adapter->flash_status = compl_status; complete(&adapter->flash_compl); } if (compl_status == MCC_STATUS_SUCCESS) { - if (compl->tag0 == OPCODE_ETH_GET_STATISTICS) { - struct be_cmd_resp_get_stats *resp = - adapter->stats_cmd.va; - be_dws_le_to_cpu(&resp->hw_stats, - sizeof(resp->hw_stats)); + if (((compl->tag0 == OPCODE_ETH_GET_STATISTICS) || + (compl->tag0 == OPCODE_ETH_GET_PPORT_STATS)) && + (compl->tag1 == CMD_SUBSYSTEM_ETH)) { + if (adapter->generation == BE_GEN3) { + if (lancer_chip(adapter)) { + struct lancer_cmd_resp_pport_stats + *resp = adapter->stats_cmd.va; + be_dws_le_to_cpu(&resp->pport_stats, + sizeof(resp->pport_stats)); + } else { + struct be_cmd_resp_get_stats_v1 *resp = + adapter->stats_cmd.va; + + be_dws_le_to_cpu(&resp->hw_stats, + sizeof(resp->hw_stats)); + } + } else { + struct be_cmd_resp_get_stats_v0 *resp = + adapter->stats_cmd.va; + + be_dws_le_to_cpu(&resp->hw_stats, + sizeof(resp->hw_stats)); + } + be_parse_stats(adapter); netdev_stats_update(adapter); adapter->stats_cmd_sent = false; } @@ -132,7 +152,7 @@ static void be_async_grp5_pvid_state_process(struct be_adapter *adapter, struct be_async_event_grp5_pvid_state *evt) { if (evt->enabled) - adapter->pvid = evt->tag; + adapter->pvid = le16_to_cpu(evt->tag); else adapter->pvid = 0; } @@ -292,12 +312,12 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) if (msecs > 4000) { dev_err(&adapter->pdev->dev, "mbox poll timed out\n"); - be_detect_dump_ue(adapter); + if (!lancer_chip(adapter)) + be_detect_dump_ue(adapter); return -1; } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(1)); + msleep(1); msecs++; } while (true); @@ -374,23 +394,25 @@ int be_cmd_POST(struct be_adapter *adapter) { u16 stage; int status, timeout = 0; + struct device *dev = &adapter->pdev->dev; do { status = be_POST_stage_get(adapter, &stage); if (status) { - dev_err(&adapter->pdev->dev, "POST error; stage=0x%x\n", - stage); + dev_err(dev, "POST error; stage=0x%x\n", stage); return -1; } else if (stage != POST_STAGE_ARMFW_RDY) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(2 * HZ); + if (msleep_interruptible(2000)) { + dev_err(dev, "Waiting for POST aborted\n"); + return -EINTR; + } timeout += 2; } else { return 0; } } while (timeout < 40); - dev_err(&adapter->pdev->dev, "POST timeout; stage=0x%x\n", stage); + dev_err(dev, "POST timeout; stage=0x%x\n", stage); return -1; } @@ -728,8 +750,6 @@ int be_cmd_cq_create(struct be_adapter *adapter, if (lancer_chip(adapter)) { req->hdr.version = 2; req->page_size = 1; /* 1 for 4K */ - AMAP_SET_BITS(struct amap_cq_context_lancer, coalescwm, ctxt, - coalesce_wm); AMAP_SET_BITS(struct amap_cq_context_lancer, nodelay, ctxt, no_delay); AMAP_SET_BITS(struct amap_cq_context_lancer, count, ctxt, @@ -1074,7 +1094,7 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain) int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) { struct be_mcc_wrb *wrb; - struct be_cmd_req_get_stats *req; + struct be_cmd_req_hdr *hdr; struct be_sge *sge; int status = 0; @@ -1083,6 +1103,48 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) spin_lock_bh(&adapter->mcc_lock); + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + hdr = nonemb_cmd->va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1, + OPCODE_ETH_GET_STATISTICS); + + be_cmd_hdr_prepare(hdr, CMD_SUBSYSTEM_ETH, + OPCODE_ETH_GET_STATISTICS, nonemb_cmd->size); + + if (adapter->generation == BE_GEN3) + hdr->version = 1; + + wrb->tag1 = CMD_SUBSYSTEM_ETH; + 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(adapter); + adapter->stats_cmd_sent = true; + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Lancer Stats */ +int lancer_cmd_get_pport_stats(struct be_adapter *adapter, + struct be_dma_mem *nonemb_cmd) +{ + + struct be_mcc_wrb *wrb; + struct lancer_cmd_req_pport_stats *req; + struct be_sge *sge; + int status = 0; + + spin_lock_bh(&adapter->mcc_lock); + wrb = wrb_from_mccq(adapter); if (!wrb) { status = -EBUSY; @@ -1091,11 +1153,17 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) req = nonemb_cmd->va; sge = nonembedded_sgl(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, - OPCODE_ETH_GET_STATISTICS); + be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1, + OPCODE_ETH_GET_PPORT_STATS); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, - OPCODE_ETH_GET_STATISTICS, sizeof(*req)); + OPCODE_ETH_GET_PPORT_STATS, nonemb_cmd->size); + + + req->cmd_params.params.pport_num = cpu_to_le16(adapter->port_num); + req->cmd_params.params.reset_stats = 0; + + wrb->tag1 = CMD_SUBSYSTEM_ETH; 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); @@ -1110,7 +1178,7 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) /* Uses synchronous mcc */ int be_cmd_link_status_query(struct be_adapter *adapter, - bool *link_up, u8 *mac_speed, u16 *link_speed) + bool *link_up, u8 *mac_speed, u16 *link_speed, u32 dom) { struct be_mcc_wrb *wrb; struct be_cmd_req_link_status *req; @@ -1186,6 +1254,116 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter) return status; } +/* Uses synchronous mcc */ +int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_fat *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_MANAGE_FAT); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MANAGE_FAT, sizeof(*req)); + req->fat_operation = cpu_to_le32(QUERY_FAT); + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_fat *resp = embedded_payload(wrb); + if (log_size && resp->log_size) + *log_size = le32_to_cpu(resp->log_size) - + sizeof(u32); + } +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf) +{ + struct be_dma_mem get_fat_cmd; + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_fat *req; + struct be_sge *sge; + u32 offset = 0, total_size, buf_size, + log_offset = sizeof(u32), payload_len; + int status; + + if (buf_len == 0) + return; + + total_size = buf_len; + + get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60*1024; + get_fat_cmd.va = pci_alloc_consistent(adapter->pdev, + get_fat_cmd.size, + &get_fat_cmd.dma); + if (!get_fat_cmd.va) { + status = -ENOMEM; + dev_err(&adapter->pdev->dev, + "Memory allocation failure while retrieving FAT data\n"); + return; + } + + spin_lock_bh(&adapter->mcc_lock); + + while (total_size) { + buf_size = min(total_size, (u32)60*1024); + total_size -= buf_size; + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = get_fat_cmd.va; + sge = nonembedded_sgl(wrb); + + payload_len = sizeof(struct be_cmd_req_get_fat) + buf_size; + be_wrb_hdr_prepare(wrb, payload_len, false, 1, + OPCODE_COMMON_MANAGE_FAT); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MANAGE_FAT, payload_len); + + sge->pa_hi = cpu_to_le32(upper_32_bits(get_fat_cmd.dma)); + sge->pa_lo = cpu_to_le32(get_fat_cmd.dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(get_fat_cmd.size); + + req->fat_operation = cpu_to_le32(RETRIEVE_FAT); + req->read_log_offset = cpu_to_le32(log_offset); + req->read_log_length = cpu_to_le32(buf_size); + req->data_buffer_size = cpu_to_le32(buf_size); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_fat *resp = get_fat_cmd.va; + memcpy(buf + offset, + resp->data_buffer, + resp->read_log_length); + } else { + dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n"); + goto err; + } + offset += buf_size; + log_offset += buf_size; + } +err: + pci_free_consistent(adapter->pdev, get_fat_cmd.size, + get_fat_cmd.va, + get_fat_cmd.dma); + spin_unlock_bh(&adapter->mcc_lock); +} + /* Uses Mbox */ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) { @@ -1293,12 +1471,24 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, /* Uses MCC for this command as it may be called in BH context * Uses synchronous mcc */ -int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en) +int be_cmd_promiscuous_config(struct be_adapter *adapter, bool en) { struct be_mcc_wrb *wrb; - struct be_cmd_req_promiscuous_config *req; + struct be_cmd_req_rx_filter *req; + struct be_dma_mem promiscous_cmd; + struct be_sge *sge; int status; + memset(&promiscous_cmd, 0, sizeof(struct be_dma_mem)); + promiscous_cmd.size = sizeof(struct be_cmd_req_rx_filter); + promiscous_cmd.va = pci_alloc_consistent(adapter->pdev, + promiscous_cmd.size, &promiscous_cmd.dma); + if (!promiscous_cmd.va) { + dev_err(&adapter->pdev->dev, + "Memory allocation failure\n"); + return -ENOMEM; + } + spin_lock_bh(&adapter->mcc_lock); wrb = wrb_from_mccq(adapter); @@ -1306,26 +1496,30 @@ int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en) status = -EBUSY; goto err; } - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_ETH_PROMISCUOUS); + req = promiscous_cmd.va; + sge = nonembedded_sgl(wrb); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, - OPCODE_ETH_PROMISCUOUS, sizeof(*req)); + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, + OPCODE_COMMON_NTWK_RX_FILTER); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_RX_FILTER, sizeof(*req)); - /* In FW versions X.102.149/X.101.487 and later, - * the port setting associated only with the - * issuing pci function will take effect - */ - if (port_num) - req->port1_promiscuous = en; - else - req->port0_promiscuous = en; + req->if_id = cpu_to_le32(adapter->if_handle); + req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS); + if (en) + req->if_flags = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS); + + sge->pa_hi = cpu_to_le32(upper_32_bits(promiscous_cmd.dma)); + sge->pa_lo = cpu_to_le32(promiscous_cmd.dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(promiscous_cmd.size); status = be_mcc_notify_wait(adapter); err: spin_unlock_bh(&adapter->mcc_lock); + pci_free_consistent(adapter->pdev, promiscous_cmd.size, + promiscous_cmd.va, promiscous_cmd.dma); return status; } @@ -1608,6 +1802,81 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state) return status; } +int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, + u32 data_size, u32 data_offset, const char *obj_name, + u32 *data_written, u8 *addn_status) +{ + struct be_mcc_wrb *wrb; + struct lancer_cmd_req_write_object *req; + struct lancer_cmd_resp_write_object *resp; + void *ctxt = NULL; + int status; + + spin_lock_bh(&adapter->mcc_lock); + adapter->flash_status = 0; + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err_unlock; + } + + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(struct lancer_cmd_req_write_object), + true, 1, OPCODE_COMMON_WRITE_OBJECT); + wrb->tag1 = CMD_SUBSYSTEM_COMMON; + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_WRITE_OBJECT, + sizeof(struct lancer_cmd_req_write_object)); + + ctxt = &req->context; + AMAP_SET_BITS(struct amap_lancer_write_obj_context, + write_length, ctxt, data_size); + + if (data_size == 0) + AMAP_SET_BITS(struct amap_lancer_write_obj_context, + eof, ctxt, 1); + else + AMAP_SET_BITS(struct amap_lancer_write_obj_context, + eof, ctxt, 0); + + be_dws_cpu_to_le(ctxt, sizeof(req->context)); + req->write_offset = cpu_to_le32(data_offset); + strcpy(req->object_name, obj_name); + req->descriptor_count = cpu_to_le32(1); + req->buf_len = cpu_to_le32(data_size); + req->addr_low = cpu_to_le32((cmd->dma + + sizeof(struct lancer_cmd_req_write_object)) + & 0xFFFFFFFF); + req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma + + sizeof(struct lancer_cmd_req_write_object))); + + be_mcc_notify(adapter); + spin_unlock_bh(&adapter->mcc_lock); + + if (!wait_for_completion_timeout(&adapter->flash_compl, + msecs_to_jiffies(12000))) + status = -1; + else + status = adapter->flash_status; + + resp = embedded_payload(wrb); + if (!status) { + *data_written = le32_to_cpu(resp->actual_write_len); + } else { + *addn_status = resp->additional_status; + status = resp->status; + } + + return status; + +err_unlock: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 flash_type, u32 flash_opcode, u32 buf_size) { diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 4f254cfaabe2..8148cc66cbe9 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -186,12 +186,14 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_NTWK_PMAC_ADD 59 #define OPCODE_COMMON_NTWK_PMAC_DEL 60 #define OPCODE_COMMON_FUNCTION_RESET 61 +#define OPCODE_COMMON_MANAGE_FAT 68 #define OPCODE_COMMON_ENABLE_DISABLE_BEACON 69 #define OPCODE_COMMON_GET_BEACON_STATE 70 #define OPCODE_COMMON_READ_TRANSRECV_DATA 73 #define OPCODE_COMMON_GET_PHY_DETAILS 102 #define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP 103 #define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121 +#define OPCODE_COMMON_WRITE_OBJECT 172 #define OPCODE_ETH_RSS_CONFIG 1 #define OPCODE_ETH_ACPI_CONFIG 2 @@ -202,6 +204,7 @@ struct be_mcc_mailbox { #define OPCODE_ETH_TX_DESTROY 9 #define OPCODE_ETH_RX_DESTROY 10 #define OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG 12 +#define OPCODE_ETH_GET_PPORT_STATS 18 #define OPCODE_LOWLEVEL_HOST_DDR_DMA 17 #define OPCODE_LOWLEVEL_LOOPBACK_TEST 18 @@ -380,6 +383,24 @@ struct be_cmd_resp_cq_create { u16 rsvd0; } __packed; +struct be_cmd_req_get_fat { + struct be_cmd_req_hdr hdr; + u32 fat_operation; + u32 read_log_offset; + u32 read_log_length; + u32 data_buffer_size; + u32 data_buffer[1]; +} __packed; + +struct be_cmd_resp_get_fat { + struct be_cmd_resp_hdr hdr; + u32 log_size; + u32 read_log_length; + u32 rsvd[2]; + u32 data_buffer[1]; +} __packed; + + /******************** Create MCCQ ***************************/ /* 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 */ @@ -549,7 +570,7 @@ struct be_cmd_req_if_destroy { }; /*************** HW Stats Get **********************************/ -struct be_port_rxf_stats { +struct be_port_rxf_stats_v0 { u32 rx_bytes_lsd; /* dword 0*/ u32 rx_bytes_msd; /* dword 1*/ u32 rx_total_frames; /* dword 2*/ @@ -618,8 +639,8 @@ struct be_port_rxf_stats { u32 rx_input_fifo_overflow; /* dword 65*/ }; -struct be_rxf_stats { - struct be_port_rxf_stats port[2]; +struct be_rxf_stats_v0 { + struct be_port_rxf_stats_v0 port[2]; u32 rx_drops_no_pbuf; /* dword 132*/ u32 rx_drops_no_txpb; /* dword 133*/ u32 rx_drops_no_erx_descr; /* dword 134*/ @@ -642,36 +663,227 @@ struct be_rxf_stats { u32 rsvd1[6]; }; -struct be_erx_stats { +struct be_erx_stats_v0 { u32 rx_drops_no_fragments[44]; /* dwordS 0 to 43*/ - u32 debug_wdma_sent_hold; /* dword 44*/ - u32 debug_wdma_pbfree_sent_hold; /* dword 45*/ - u32 debug_wdma_zerobyte_pbfree_sent_hold; /* dword 46*/ - u32 debug_pmem_pbuf_dealloc; /* dword 47*/ + u32 rsvd[4]; }; struct be_pmem_stats { u32 eth_red_drops; - u32 rsvd[4]; + u32 rsvd[5]; }; -struct be_hw_stats { - struct be_rxf_stats rxf; +struct be_hw_stats_v0 { + struct be_rxf_stats_v0 rxf; u32 rsvd[48]; - struct be_erx_stats erx; + struct be_erx_stats_v0 erx; struct be_pmem_stats pmem; }; -struct be_cmd_req_get_stats { +struct be_cmd_req_get_stats_v0 { struct be_cmd_req_hdr hdr; - u8 rsvd[sizeof(struct be_hw_stats)]; + u8 rsvd[sizeof(struct be_hw_stats_v0)]; }; -struct be_cmd_resp_get_stats { +struct be_cmd_resp_get_stats_v0 { struct be_cmd_resp_hdr hdr; - struct be_hw_stats hw_stats; + struct be_hw_stats_v0 hw_stats; }; +#define make_64bit_val(hi_32, lo_32) (((u64)hi_32<<32) | lo_32) +struct lancer_cmd_pport_stats { + u32 tx_packets_lo; + u32 tx_packets_hi; + u32 tx_unicast_packets_lo; + u32 tx_unicast_packets_hi; + u32 tx_multicast_packets_lo; + u32 tx_multicast_packets_hi; + u32 tx_broadcast_packets_lo; + u32 tx_broadcast_packets_hi; + u32 tx_bytes_lo; + u32 tx_bytes_hi; + u32 tx_unicast_bytes_lo; + u32 tx_unicast_bytes_hi; + u32 tx_multicast_bytes_lo; + u32 tx_multicast_bytes_hi; + u32 tx_broadcast_bytes_lo; + u32 tx_broadcast_bytes_hi; + u32 tx_discards_lo; + u32 tx_discards_hi; + u32 tx_errors_lo; + u32 tx_errors_hi; + u32 tx_pause_frames_lo; + u32 tx_pause_frames_hi; + u32 tx_pause_on_frames_lo; + u32 tx_pause_on_frames_hi; + u32 tx_pause_off_frames_lo; + u32 tx_pause_off_frames_hi; + u32 tx_internal_mac_errors_lo; + u32 tx_internal_mac_errors_hi; + u32 tx_control_frames_lo; + u32 tx_control_frames_hi; + u32 tx_packets_64_bytes_lo; + u32 tx_packets_64_bytes_hi; + u32 tx_packets_65_to_127_bytes_lo; + u32 tx_packets_65_to_127_bytes_hi; + u32 tx_packets_128_to_255_bytes_lo; + u32 tx_packets_128_to_255_bytes_hi; + u32 tx_packets_256_to_511_bytes_lo; + u32 tx_packets_256_to_511_bytes_hi; + u32 tx_packets_512_to_1023_bytes_lo; + u32 tx_packets_512_to_1023_bytes_hi; + u32 tx_packets_1024_to_1518_bytes_lo; + u32 tx_packets_1024_to_1518_bytes_hi; + u32 tx_packets_1519_to_2047_bytes_lo; + u32 tx_packets_1519_to_2047_bytes_hi; + u32 tx_packets_2048_to_4095_bytes_lo; + u32 tx_packets_2048_to_4095_bytes_hi; + u32 tx_packets_4096_to_8191_bytes_lo; + u32 tx_packets_4096_to_8191_bytes_hi; + u32 tx_packets_8192_to_9216_bytes_lo; + u32 tx_packets_8192_to_9216_bytes_hi; + u32 tx_lso_packets_lo; + u32 tx_lso_packets_hi; + u32 rx_packets_lo; + u32 rx_packets_hi; + u32 rx_unicast_packets_lo; + u32 rx_unicast_packets_hi; + u32 rx_multicast_packets_lo; + u32 rx_multicast_packets_hi; + u32 rx_broadcast_packets_lo; + u32 rx_broadcast_packets_hi; + u32 rx_bytes_lo; + u32 rx_bytes_hi; + u32 rx_unicast_bytes_lo; + u32 rx_unicast_bytes_hi; + u32 rx_multicast_bytes_lo; + u32 rx_multicast_bytes_hi; + u32 rx_broadcast_bytes_lo; + u32 rx_broadcast_bytes_hi; + u32 rx_unknown_protos; + u32 rsvd_69; /* Word 69 is reserved */ + u32 rx_discards_lo; + u32 rx_discards_hi; + u32 rx_errors_lo; + u32 rx_errors_hi; + u32 rx_crc_errors_lo; + u32 rx_crc_errors_hi; + u32 rx_alignment_errors_lo; + u32 rx_alignment_errors_hi; + u32 rx_symbol_errors_lo; + u32 rx_symbol_errors_hi; + u32 rx_pause_frames_lo; + u32 rx_pause_frames_hi; + u32 rx_pause_on_frames_lo; + u32 rx_pause_on_frames_hi; + u32 rx_pause_off_frames_lo; + u32 rx_pause_off_frames_hi; + u32 rx_frames_too_long_lo; + u32 rx_frames_too_long_hi; + u32 rx_internal_mac_errors_lo; + u32 rx_internal_mac_errors_hi; + u32 rx_undersize_packets; + u32 rx_oversize_packets; + u32 rx_fragment_packets; + u32 rx_jabbers; + u32 rx_control_frames_lo; + u32 rx_control_frames_hi; + u32 rx_control_frames_unknown_opcode_lo; + u32 rx_control_frames_unknown_opcode_hi; + u32 rx_in_range_errors; + u32 rx_out_of_range_errors; + u32 rx_address_match_errors; + u32 rx_vlan_mismatch_errors; + u32 rx_dropped_too_small; + u32 rx_dropped_too_short; + u32 rx_dropped_header_too_small; + u32 rx_dropped_invalid_tcp_length; + u32 rx_dropped_runt; + u32 rx_ip_checksum_errors; + u32 rx_tcp_checksum_errors; + u32 rx_udp_checksum_errors; + u32 rx_non_rss_packets; + u32 rsvd_111; + u32 rx_ipv4_packets_lo; + u32 rx_ipv4_packets_hi; + u32 rx_ipv6_packets_lo; + u32 rx_ipv6_packets_hi; + u32 rx_ipv4_bytes_lo; + u32 rx_ipv4_bytes_hi; + u32 rx_ipv6_bytes_lo; + u32 rx_ipv6_bytes_hi; + u32 rx_nic_packets_lo; + u32 rx_nic_packets_hi; + u32 rx_tcp_packets_lo; + u32 rx_tcp_packets_hi; + u32 rx_iscsi_packets_lo; + u32 rx_iscsi_packets_hi; + u32 rx_management_packets_lo; + u32 rx_management_packets_hi; + u32 rx_switched_unicast_packets_lo; + u32 rx_switched_unicast_packets_hi; + u32 rx_switched_multicast_packets_lo; + u32 rx_switched_multicast_packets_hi; + u32 rx_switched_broadcast_packets_lo; + u32 rx_switched_broadcast_packets_hi; + u32 num_forwards_lo; + u32 num_forwards_hi; + u32 rx_fifo_overflow; + u32 rx_input_fifo_overflow; + u32 rx_drops_too_many_frags_lo; + u32 rx_drops_too_many_frags_hi; + u32 rx_drops_invalid_queue; + u32 rsvd_141; + u32 rx_drops_mtu_lo; + u32 rx_drops_mtu_hi; + u32 rx_packets_64_bytes_lo; + u32 rx_packets_64_bytes_hi; + u32 rx_packets_65_to_127_bytes_lo; + u32 rx_packets_65_to_127_bytes_hi; + u32 rx_packets_128_to_255_bytes_lo; + u32 rx_packets_128_to_255_bytes_hi; + u32 rx_packets_256_to_511_bytes_lo; + u32 rx_packets_256_to_511_bytes_hi; + u32 rx_packets_512_to_1023_bytes_lo; + u32 rx_packets_512_to_1023_bytes_hi; + u32 rx_packets_1024_to_1518_bytes_lo; + u32 rx_packets_1024_to_1518_bytes_hi; + u32 rx_packets_1519_to_2047_bytes_lo; + u32 rx_packets_1519_to_2047_bytes_hi; + u32 rx_packets_2048_to_4095_bytes_lo; + u32 rx_packets_2048_to_4095_bytes_hi; + u32 rx_packets_4096_to_8191_bytes_lo; + u32 rx_packets_4096_to_8191_bytes_hi; + u32 rx_packets_8192_to_9216_bytes_lo; + u32 rx_packets_8192_to_9216_bytes_hi; +}; + +struct pport_stats_params { + u16 pport_num; + u8 rsvd; + u8 reset_stats; +}; + +struct lancer_cmd_req_pport_stats { + struct be_cmd_req_hdr hdr; + union { + struct pport_stats_params params; + u8 rsvd[sizeof(struct lancer_cmd_pport_stats)]; + } cmd_params; +}; + +struct lancer_cmd_resp_pport_stats { + struct be_cmd_resp_hdr hdr; + struct lancer_cmd_pport_stats pport_stats; +}; + +static inline struct lancer_cmd_pport_stats* + pport_stats_from_cmd(struct be_adapter *adapter) +{ + struct lancer_cmd_resp_pport_stats *cmd = adapter->stats_cmd.va; + return &cmd->pport_stats; +} + struct be_cmd_req_get_cntl_addnl_attribs { struct be_cmd_req_hdr hdr; u8 rsvd[8]; @@ -695,13 +907,6 @@ struct be_cmd_req_vlan_config { u16 normal_vlan[64]; } __packed; -struct be_cmd_req_promiscuous_config { - struct be_cmd_req_hdr hdr; - u8 port0_promiscuous; - u8 port1_promiscuous; - u16 rsvd0; -} __packed; - /******************** Multicast MAC Config *******************/ #define BE_MAX_MC 64 /* set mcast promisc if > 64 */ struct macaddr { @@ -716,11 +921,18 @@ struct be_cmd_req_mcast_mac_config { struct macaddr mac[BE_MAX_MC]; } __packed; -static inline struct be_hw_stats * -hw_stats_from_cmd(struct be_cmd_resp_get_stats *cmd) -{ - return &cmd->hw_stats; -} +/******************* RX FILTER ******************************/ +struct be_cmd_req_rx_filter { + struct be_cmd_req_hdr hdr; + u32 global_flags_mask; + u32 global_flags; + u32 if_flags_mask; + u32 if_flags; + u32 if_id; + u32 multicast_num; + struct macaddr mac[BE_MAX_MC]; +}; + /******************** Link Status Query *******************/ struct be_cmd_req_link_status { @@ -920,6 +1132,36 @@ struct be_cmd_write_flashrom { struct flashrom_params params; }; +/**************** Lancer Firmware Flash ************/ +struct amap_lancer_write_obj_context { + u8 write_length[24]; + u8 reserved1[7]; + u8 eof; +} __packed; + +struct lancer_cmd_req_write_object { + struct be_cmd_req_hdr hdr; + u8 context[sizeof(struct amap_lancer_write_obj_context) / 8]; + u32 write_offset; + u8 object_name[104]; + u32 descriptor_count; + u32 buf_len; + u32 addr_low; + u32 addr_high; +}; + +struct lancer_cmd_resp_write_object { + u8 opcode; + u8 subsystem; + u8 rsvd1[2]; + u8 status; + u8 additional_status; + u8 rsvd2[2]; + u32 resp_len; + u32 actual_resp_len; + u32 actual_write_len; +}; + /************************ WOL *******************************/ struct be_cmd_req_acpi_wol_magic_config{ struct be_cmd_req_hdr hdr; @@ -1061,6 +1303,151 @@ struct be_cmd_resp_set_func_cap { u8 rsvd[212]; }; +/*************** HW Stats Get v1 **********************************/ +#define BE_TXP_SW_SZ 48 +struct be_port_rxf_stats_v1 { + u32 rsvd0[12]; + u32 rx_crc_errors; + u32 rx_alignment_symbol_errors; + u32 rx_pause_frames; + u32 rx_priority_pause_frames; + u32 rx_control_frames; + u32 rx_in_range_errors; + u32 rx_out_range_errors; + u32 rx_frame_too_long; + u32 rx_address_match_errors; + u32 rx_dropped_too_small; + u32 rx_dropped_too_short; + u32 rx_dropped_header_too_small; + u32 rx_dropped_tcp_length; + u32 rx_dropped_runt; + u32 rsvd1[10]; + u32 rx_ip_checksum_errs; + u32 rx_tcp_checksum_errs; + u32 rx_udp_checksum_errs; + u32 rsvd2[7]; + u32 rx_switched_unicast_packets; + u32 rx_switched_multicast_packets; + u32 rx_switched_broadcast_packets; + u32 rsvd3[3]; + u32 tx_pauseframes; + u32 tx_priority_pauseframes; + u32 tx_controlframes; + u32 rsvd4[10]; + u32 rxpp_fifo_overflow_drop; + u32 rx_input_fifo_overflow_drop; + u32 pmem_fifo_overflow_drop; + u32 jabber_events; + u32 rsvd5[3]; +}; + + +struct be_rxf_stats_v1 { + struct be_port_rxf_stats_v1 port[4]; + u32 rsvd0[2]; + u32 rx_drops_no_pbuf; + u32 rx_drops_no_txpb; + u32 rx_drops_no_erx_descr; + u32 rx_drops_no_tpre_descr; + u32 rsvd1[6]; + u32 rx_drops_too_many_frags; + u32 rx_drops_invalid_ring; + u32 forwarded_packets; + u32 rx_drops_mtu; + u32 rsvd2[14]; +}; + +struct be_erx_stats_v1 { + u32 rx_drops_no_fragments[68]; /* dwordS 0 to 67*/ + u32 rsvd[4]; +}; + +struct be_hw_stats_v1 { + struct be_rxf_stats_v1 rxf; + u32 rsvd0[BE_TXP_SW_SZ]; + struct be_erx_stats_v1 erx; + struct be_pmem_stats pmem; + u32 rsvd1[3]; +}; + +struct be_cmd_req_get_stats_v1 { + struct be_cmd_req_hdr hdr; + u8 rsvd[sizeof(struct be_hw_stats_v1)]; +}; + +struct be_cmd_resp_get_stats_v1 { + struct be_cmd_resp_hdr hdr; + struct be_hw_stats_v1 hw_stats; +}; + +static inline void * +hw_stats_from_cmd(struct be_adapter *adapter) +{ + if (adapter->generation == BE_GEN3) { + struct be_cmd_resp_get_stats_v1 *cmd = adapter->stats_cmd.va; + + return &cmd->hw_stats; + } else { + struct be_cmd_resp_get_stats_v0 *cmd = adapter->stats_cmd.va; + + return &cmd->hw_stats; + } +} + +static inline void *be_port_rxf_stats_from_cmd(struct be_adapter *adapter) +{ + if (adapter->generation == BE_GEN3) { + struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); + struct be_rxf_stats_v1 *rxf_stats = &hw_stats->rxf; + + return &rxf_stats->port[adapter->port_num]; + } else { + struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); + struct be_rxf_stats_v0 *rxf_stats = &hw_stats->rxf; + + return &rxf_stats->port[adapter->port_num]; + } +} + +static inline void *be_rxf_stats_from_cmd(struct be_adapter *adapter) +{ + if (adapter->generation == BE_GEN3) { + struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->rxf; + } else { + struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->rxf; + } +} + +static inline void *be_erx_stats_from_cmd(struct be_adapter *adapter) +{ + if (adapter->generation == BE_GEN3) { + struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->erx; + } else { + struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->erx; + } +} + +static inline void *be_pmem_stats_from_cmd(struct be_adapter *adapter) +{ + if (adapter->generation == BE_GEN3) { + struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->pmem; + } else { + struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->pmem; + } +} + extern int be_pci_fnum_get(struct be_adapter *adapter); extern int be_cmd_POST(struct be_adapter *adapter); extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, @@ -1093,18 +1480,19 @@ extern int be_cmd_rxq_create(struct be_adapter *adapter, extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, int type); extern int be_cmd_link_status_query(struct be_adapter *adapter, - bool *link_up, u8 *mac_speed, u16 *link_speed); + bool *link_up, u8 *mac_speed, u16 *link_speed, u32 dom); extern int be_cmd_reset(struct be_adapter *adapter); extern int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd); +extern int lancer_cmd_get_pport_stats(struct be_adapter *adapter, + struct be_dma_mem *nonemb_cmd); extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver); extern int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd); extern int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, u32 num, bool untagged, bool promiscuous); -extern int be_cmd_promiscuous_config(struct be_adapter *adapter, - u8 port_num, bool en); +extern int be_cmd_promiscuous_config(struct be_adapter *adapter, bool en); extern int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id, struct net_device *netdev, struct be_dma_mem *mem); extern int be_cmd_set_flow_control(struct be_adapter *adapter, @@ -1124,6 +1512,11 @@ extern int be_cmd_get_beacon_state(struct be_adapter *adapter, extern int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 flash_oper, u32 flash_opcode, u32 buf_size); +extern int lancer_cmd_write_object(struct be_adapter *adapter, + struct be_dma_mem *cmd, + u32 data_size, u32 data_offset, + const char *obj_name, + u32 *data_written, u8 *addn_status); int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, int offset); extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, @@ -1148,4 +1541,6 @@ extern void be_detect_dump_ue(struct be_adapter *adapter); extern int be_cmd_get_die_temperature(struct be_adapter *adapter); extern int be_cmd_get_cntl_attributes(struct be_adapter *adapter); extern int be_cmd_check_native_mode(struct be_adapter *adapter); +extern int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size); +extern void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index aac248fbd18b..facfe3ca5c40 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -26,8 +26,8 @@ struct be_ethtool_stat { int offset; }; -enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT, - PMEMSTAT, DRVSTAT}; +enum {NETSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT, + DRVSTAT}; #define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \ offsetof(_struct, field) #define NETSTAT_INFO(field) #field, NETSTAT,\ @@ -37,15 +37,8 @@ enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT, FIELDINFO(struct be_tx_stats, field) #define DRVSTAT_RX_INFO(field) #field, DRVSTAT_RX,\ FIELDINFO(struct be_rx_stats, field) -#define MISCSTAT_INFO(field) #field, MISCSTAT,\ - FIELDINFO(struct be_rxf_stats, field) -#define PORTSTAT_INFO(field) #field, PORTSTAT,\ - FIELDINFO(struct be_port_rxf_stats, \ - field) -#define ERXSTAT_INFO(field) #field, ERXSTAT,\ - FIELDINFO(struct be_erx_stats, field) -#define PMEMSTAT_INFO(field) #field, PMEMSTAT,\ - FIELDINFO(struct be_pmem_stats, field) +#define ERXSTAT_INFO(field) #field, ERXSTAT,\ + FIELDINFO(struct be_erx_stats_v1, field) #define DRVSTAT_INFO(field) #field, DRVSTAT,\ FIELDINFO(struct be_drv_stats, \ field) @@ -65,50 +58,41 @@ static const struct be_ethtool_stat et_stats[] = { {DRVSTAT_TX_INFO(be_tx_stops)}, {DRVSTAT_TX_INFO(be_tx_events)}, {DRVSTAT_TX_INFO(be_tx_compl)}, - {PORTSTAT_INFO(rx_unicast_frames)}, - {PORTSTAT_INFO(rx_multicast_frames)}, - {PORTSTAT_INFO(rx_broadcast_frames)}, - {PORTSTAT_INFO(rx_crc_errors)}, - {PORTSTAT_INFO(rx_alignment_symbol_errors)}, - {PORTSTAT_INFO(rx_pause_frames)}, - {PORTSTAT_INFO(rx_control_frames)}, - {PORTSTAT_INFO(rx_in_range_errors)}, - {PORTSTAT_INFO(rx_out_range_errors)}, - {PORTSTAT_INFO(rx_frame_too_long)}, - {PORTSTAT_INFO(rx_address_match_errors)}, - {PORTSTAT_INFO(rx_vlan_mismatch)}, - {PORTSTAT_INFO(rx_dropped_too_small)}, - {PORTSTAT_INFO(rx_dropped_too_short)}, - {PORTSTAT_INFO(rx_dropped_header_too_small)}, - {PORTSTAT_INFO(rx_dropped_tcp_length)}, - {PORTSTAT_INFO(rx_dropped_runt)}, - {PORTSTAT_INFO(rx_fifo_overflow)}, - {PORTSTAT_INFO(rx_input_fifo_overflow)}, - {PORTSTAT_INFO(rx_ip_checksum_errs)}, - {PORTSTAT_INFO(rx_tcp_checksum_errs)}, - {PORTSTAT_INFO(rx_udp_checksum_errs)}, - {PORTSTAT_INFO(rx_non_rss_packets)}, - {PORTSTAT_INFO(rx_ipv4_packets)}, - {PORTSTAT_INFO(rx_ipv6_packets)}, - {PORTSTAT_INFO(rx_switched_unicast_packets)}, - {PORTSTAT_INFO(rx_switched_multicast_packets)}, - {PORTSTAT_INFO(rx_switched_broadcast_packets)}, - {PORTSTAT_INFO(tx_unicastframes)}, - {PORTSTAT_INFO(tx_multicastframes)}, - {PORTSTAT_INFO(tx_broadcastframes)}, - {PORTSTAT_INFO(tx_pauseframes)}, - {PORTSTAT_INFO(tx_controlframes)}, - {MISCSTAT_INFO(rx_drops_no_pbuf)}, - {MISCSTAT_INFO(rx_drops_no_txpb)}, - {MISCSTAT_INFO(rx_drops_no_erx_descr)}, - {MISCSTAT_INFO(rx_drops_no_tpre_descr)}, - {MISCSTAT_INFO(rx_drops_too_many_frags)}, - {MISCSTAT_INFO(rx_drops_invalid_ring)}, - {MISCSTAT_INFO(forwarded_packets)}, - {MISCSTAT_INFO(rx_drops_mtu)}, - {MISCSTAT_INFO(port0_jabber_events)}, - {MISCSTAT_INFO(port1_jabber_events)}, - {PMEMSTAT_INFO(eth_red_drops)}, + {DRVSTAT_INFO(rx_crc_errors)}, + {DRVSTAT_INFO(rx_alignment_symbol_errors)}, + {DRVSTAT_INFO(rx_pause_frames)}, + {DRVSTAT_INFO(rx_control_frames)}, + {DRVSTAT_INFO(rx_in_range_errors)}, + {DRVSTAT_INFO(rx_out_range_errors)}, + {DRVSTAT_INFO(rx_frame_too_long)}, + {DRVSTAT_INFO(rx_address_match_errors)}, + {DRVSTAT_INFO(rx_dropped_too_small)}, + {DRVSTAT_INFO(rx_dropped_too_short)}, + {DRVSTAT_INFO(rx_dropped_header_too_small)}, + {DRVSTAT_INFO(rx_dropped_tcp_length)}, + {DRVSTAT_INFO(rx_dropped_runt)}, + {DRVSTAT_INFO(rxpp_fifo_overflow_drop)}, + {DRVSTAT_INFO(rx_input_fifo_overflow_drop)}, + {DRVSTAT_INFO(rx_ip_checksum_errs)}, + {DRVSTAT_INFO(rx_tcp_checksum_errs)}, + {DRVSTAT_INFO(rx_udp_checksum_errs)}, + {DRVSTAT_INFO(rx_switched_unicast_packets)}, + {DRVSTAT_INFO(rx_switched_multicast_packets)}, + {DRVSTAT_INFO(rx_switched_broadcast_packets)}, + {DRVSTAT_INFO(tx_pauseframes)}, + {DRVSTAT_INFO(tx_controlframes)}, + {DRVSTAT_INFO(rx_priority_pause_frames)}, + {DRVSTAT_INFO(pmem_fifo_overflow_drop)}, + {DRVSTAT_INFO(jabber_events)}, + {DRVSTAT_INFO(rx_drops_no_pbuf)}, + {DRVSTAT_INFO(rx_drops_no_txpb)}, + {DRVSTAT_INFO(rx_drops_no_erx_descr)}, + {DRVSTAT_INFO(rx_drops_no_tpre_descr)}, + {DRVSTAT_INFO(rx_drops_too_many_frags)}, + {DRVSTAT_INFO(rx_drops_invalid_ring)}, + {DRVSTAT_INFO(forwarded_packets)}, + {DRVSTAT_INFO(rx_drops_mtu)}, + {DRVSTAT_INFO(eth_red_drops)}, {DRVSTAT_INFO(be_on_die_temperature)} }; #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats) @@ -155,6 +139,29 @@ be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) drvinfo->eedump_len = 0; } +static int +be_get_reg_len(struct net_device *netdev) +{ + struct be_adapter *adapter = netdev_priv(netdev); + u32 log_size = 0; + + if (be_physfn(adapter)) + be_cmd_get_reg_len(adapter, &log_size); + + return log_size; +} + +static void +be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf) +{ + struct be_adapter *adapter = netdev_priv(netdev); + + if (be_physfn(adapter)) { + memset(buf, 0, regs->len); + be_cmd_get_regs(adapter, regs->len, buf); + } +} + static int be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) { @@ -186,9 +193,9 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) struct be_rx_obj *rxo; struct be_eq_obj *rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; - u32 tx_max, tx_min, tx_cur; u32 rx_max, rx_min, rx_cur; int status = 0, i; + u32 tx_cur; if (coalesce->use_adaptive_tx_coalesce == 1) return -EINVAL; @@ -227,8 +234,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) } } - tx_max = coalesce->tx_coalesce_usecs_high; - tx_min = coalesce->tx_coalesce_usecs_low; tx_cur = coalesce->tx_coalesce_usecs; if (tx_cur > BE_MAX_EQD) @@ -242,32 +247,11 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) return 0; } -static u32 be_get_rx_csum(struct net_device *netdev) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - return adapter->rx_csum; -} - -static int be_set_rx_csum(struct net_device *netdev, uint32_t data) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - if (data) - adapter->rx_csum = true; - else - adapter->rx_csum = false; - - return 0; -} - static void be_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va); - struct be_erx_stats *erx_stats = &hw_stats->erx; struct be_rx_obj *rxo; void *p = NULL; int i, j; @@ -280,15 +264,6 @@ be_get_ethtool_stats(struct net_device *netdev, case DRVSTAT_TX: p = &adapter->tx_stats; break; - case PORTSTAT: - p = &hw_stats->rxf.port[adapter->port_num]; - break; - case MISCSTAT: - p = &hw_stats->rxf; - break; - case PMEMSTAT: - p = &hw_stats->pmem; - break; case DRVSTAT: p = &adapter->drv_stats; break; @@ -306,7 +281,8 @@ be_get_ethtool_stats(struct net_device *netdev, p = (u8 *)&rxo->stats + et_rx_stats[i].offset; break; case ERXSTAT: - p = (u32 *)erx_stats + rxo->q.id; + p = (u32 *)be_erx_stats_from_cmd(adapter) + + rxo->q.id; break; } data[ETHTOOL_STATS_NUM + j * ETHTOOL_RXSTATS_NUM + i] = @@ -374,19 +350,28 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) { status = be_cmd_link_status_query(adapter, &link_up, - &mac_speed, &link_speed); + &mac_speed, &link_speed, 0); be_link_status_update(adapter, link_up); /* link_speed is in units of 10 Mbps */ if (link_speed) { - ecmd->speed = link_speed*10; + ethtool_cmd_speed_set(ecmd, link_speed*10); } else { switch (mac_speed) { + case PHY_LINK_SPEED_10MBPS: + ethtool_cmd_speed_set(ecmd, SPEED_10); + break; + case PHY_LINK_SPEED_100MBPS: + ethtool_cmd_speed_set(ecmd, SPEED_100); + break; case PHY_LINK_SPEED_1GBPS: - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); break; case PHY_LINK_SPEED_10GBPS: - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); + break; + case PHY_LINK_SPEED_ZERO: + ethtool_cmd_speed_set(ecmd, 0); break; } } @@ -429,14 +414,14 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) } /* Save for future use */ - adapter->link_speed = ecmd->speed; + adapter->link_speed = ethtool_cmd_speed(ecmd); adapter->port_type = ecmd->port; adapter->transceiver = ecmd->transceiver; adapter->autoneg = ecmd->autoneg; dma_free_coherent(&adapter->pdev->dev, phy_cmd.size, phy_cmd.va, phy_cmd.dma); } else { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); ecmd->port = adapter->port_type; ecmd->transceiver = adapter->transceiver; ecmd->autoneg = adapter->autoneg; @@ -507,29 +492,33 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) } static int -be_phys_id(struct net_device *netdev, u32 data) +be_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct be_adapter *adapter = netdev_priv(netdev); - int status; - u32 cur; - be_cmd_get_beacon_state(adapter, adapter->hba_port_num, &cur); + switch (state) { + case ETHTOOL_ID_ACTIVE: + be_cmd_get_beacon_state(adapter, adapter->hba_port_num, + &adapter->beacon_state); + return 1; /* cycle on/off once per second */ - if (cur == BEACON_STATE_ENABLED) - return 0; + case ETHTOOL_ID_ON: + be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, + BEACON_STATE_ENABLED); + break; - if (data < 2) - data = 2; + case ETHTOOL_ID_OFF: + be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, + BEACON_STATE_DISABLED); + break; - status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, - BEACON_STATE_ENABLED); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(data*HZ); + case ETHTOOL_ID_INACTIVE: + be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, + adapter->beacon_state); + } - status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, - BEACON_STATE_DISABLED); - - return status; + return 0; } static bool @@ -646,7 +635,7 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) } if (be_cmd_link_status_query(adapter, &link_up, &mac_speed, - &qos_link_speed) != 0) { + &qos_link_speed, 0) != 0) { test->flags |= ETH_TEST_FL_FAILED; data[4] = -1; } else if (!mac_speed) { @@ -660,11 +649,9 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) { struct be_adapter *adapter = netdev_priv(netdev); char file_name[ETHTOOL_FLASH_MAX_FILENAME]; - u32 region; file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; strcpy(file_name, efl->data); - region = efl->region; return be_load_fw(adapter, file_name); } @@ -725,18 +712,12 @@ const struct ethtool_ops be_ethtool_ops = { .get_ringparam = be_get_ringparam, .get_pauseparam = be_get_pauseparam, .set_pauseparam = be_set_pauseparam, - .get_rx_csum = be_get_rx_csum, - .set_rx_csum = be_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, .get_strings = be_get_stat_strings, - .phys_id = be_phys_id, + .set_phys_id = be_set_phys_id, .get_sset_count = be_get_sset_count, .get_ethtool_stats = be_get_ethtool_stats, + .get_regs_len = be_get_reg_len, + .get_regs = be_get_regs, .flash_device = be_do_flash, .self_test = be_self_test, }; diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index d4344a06090b..53d658afea2a 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -155,6 +155,10 @@ /********** SRIOV VF PCICFG OFFSET ********/ #define SRIOV_VF_PCICFG_OFFSET (4096) +/********** FAT TABLE ********/ +#define RETRIEVE_FAT 0 +#define QUERY_FAT 1 + /* Flashrom related descriptors */ #define IMAGE_TYPE_FIRMWARE 160 #define IMAGE_TYPE_BOOTCODE 224 diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 7cb5a114c733..4b5e0ed49ed8 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -42,6 +42,7 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) }, { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) }, { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)}, + { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID4)}, { 0 } }; MODULE_DEVICE_TABLE(pci, be_dev_ids); @@ -116,11 +117,6 @@ static char *ue_status_hi_desc[] = { "Unknown" }; -static inline bool be_multi_rxq(struct be_adapter *adapter) -{ - return (adapter->num_rx_qs > 1); -} - static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q) { struct be_dma_mem *mem = &q->dma_mem; @@ -250,14 +246,185 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) return status; } +static void populate_be2_stats(struct be_adapter *adapter) +{ + + struct be_drv_stats *drvs = &adapter->drv_stats; + struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter); + struct be_port_rxf_stats_v0 *port_stats = + be_port_rxf_stats_from_cmd(adapter); + struct be_rxf_stats_v0 *rxf_stats = + be_rxf_stats_from_cmd(adapter); + + drvs->rx_pause_frames = port_stats->rx_pause_frames; + drvs->rx_crc_errors = port_stats->rx_crc_errors; + drvs->rx_control_frames = port_stats->rx_control_frames; + drvs->rx_in_range_errors = port_stats->rx_in_range_errors; + drvs->rx_frame_too_long = port_stats->rx_frame_too_long; + drvs->rx_dropped_runt = port_stats->rx_dropped_runt; + drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs; + drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs; + drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs; + drvs->rxpp_fifo_overflow_drop = port_stats->rx_fifo_overflow; + drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length; + drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small; + drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short; + drvs->rx_out_range_errors = port_stats->rx_out_range_errors; + drvs->rx_input_fifo_overflow_drop = + port_stats->rx_input_fifo_overflow; + drvs->rx_dropped_header_too_small = + port_stats->rx_dropped_header_too_small; + drvs->rx_address_match_errors = + port_stats->rx_address_match_errors; + drvs->rx_alignment_symbol_errors = + port_stats->rx_alignment_symbol_errors; + + drvs->tx_pauseframes = port_stats->tx_pauseframes; + drvs->tx_controlframes = port_stats->tx_controlframes; + + if (adapter->port_num) + drvs->jabber_events = + rxf_stats->port1_jabber_events; + else + drvs->jabber_events = + rxf_stats->port0_jabber_events; + drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf; + drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb; + drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr; + drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring; + drvs->forwarded_packets = rxf_stats->forwarded_packets; + drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu; + drvs->rx_drops_no_tpre_descr = + rxf_stats->rx_drops_no_tpre_descr; + drvs->rx_drops_too_many_frags = + rxf_stats->rx_drops_too_many_frags; + adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops; +} + +static void populate_be3_stats(struct be_adapter *adapter) +{ + struct be_drv_stats *drvs = &adapter->drv_stats; + struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter); + + struct be_rxf_stats_v1 *rxf_stats = + be_rxf_stats_from_cmd(adapter); + struct be_port_rxf_stats_v1 *port_stats = + be_port_rxf_stats_from_cmd(adapter); + + drvs->rx_priority_pause_frames = 0; + drvs->pmem_fifo_overflow_drop = 0; + drvs->rx_pause_frames = port_stats->rx_pause_frames; + drvs->rx_crc_errors = port_stats->rx_crc_errors; + drvs->rx_control_frames = port_stats->rx_control_frames; + drvs->rx_in_range_errors = port_stats->rx_in_range_errors; + drvs->rx_frame_too_long = port_stats->rx_frame_too_long; + drvs->rx_dropped_runt = port_stats->rx_dropped_runt; + drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs; + drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs; + drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs; + drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length; + drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small; + drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short; + drvs->rx_out_range_errors = port_stats->rx_out_range_errors; + drvs->rx_dropped_header_too_small = + port_stats->rx_dropped_header_too_small; + drvs->rx_input_fifo_overflow_drop = + port_stats->rx_input_fifo_overflow_drop; + drvs->rx_address_match_errors = + port_stats->rx_address_match_errors; + drvs->rx_alignment_symbol_errors = + port_stats->rx_alignment_symbol_errors; + drvs->rxpp_fifo_overflow_drop = + port_stats->rxpp_fifo_overflow_drop; + drvs->tx_pauseframes = port_stats->tx_pauseframes; + drvs->tx_controlframes = port_stats->tx_controlframes; + drvs->jabber_events = port_stats->jabber_events; + drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf; + drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb; + drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr; + drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring; + drvs->forwarded_packets = rxf_stats->forwarded_packets; + drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu; + drvs->rx_drops_no_tpre_descr = + rxf_stats->rx_drops_no_tpre_descr; + drvs->rx_drops_too_many_frags = + rxf_stats->rx_drops_too_many_frags; + adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops; +} + +static void populate_lancer_stats(struct be_adapter *adapter) +{ + + struct be_drv_stats *drvs = &adapter->drv_stats; + struct lancer_cmd_pport_stats *pport_stats = pport_stats_from_cmd + (adapter); + drvs->rx_priority_pause_frames = 0; + drvs->pmem_fifo_overflow_drop = 0; + drvs->rx_pause_frames = + make_64bit_val(pport_stats->rx_pause_frames_lo, + pport_stats->rx_pause_frames_hi); + drvs->rx_crc_errors = make_64bit_val(pport_stats->rx_crc_errors_hi, + pport_stats->rx_crc_errors_lo); + drvs->rx_control_frames = + make_64bit_val(pport_stats->rx_control_frames_hi, + pport_stats->rx_control_frames_lo); + drvs->rx_in_range_errors = pport_stats->rx_in_range_errors; + drvs->rx_frame_too_long = + make_64bit_val(pport_stats->rx_internal_mac_errors_hi, + pport_stats->rx_frames_too_long_lo); + drvs->rx_dropped_runt = pport_stats->rx_dropped_runt; + drvs->rx_ip_checksum_errs = pport_stats->rx_ip_checksum_errors; + drvs->rx_tcp_checksum_errs = pport_stats->rx_tcp_checksum_errors; + drvs->rx_udp_checksum_errs = pport_stats->rx_udp_checksum_errors; + drvs->rx_dropped_tcp_length = + pport_stats->rx_dropped_invalid_tcp_length; + drvs->rx_dropped_too_small = pport_stats->rx_dropped_too_small; + drvs->rx_dropped_too_short = pport_stats->rx_dropped_too_short; + drvs->rx_out_range_errors = pport_stats->rx_out_of_range_errors; + drvs->rx_dropped_header_too_small = + pport_stats->rx_dropped_header_too_small; + drvs->rx_input_fifo_overflow_drop = pport_stats->rx_fifo_overflow; + drvs->rx_address_match_errors = pport_stats->rx_address_match_errors; + drvs->rx_alignment_symbol_errors = + make_64bit_val(pport_stats->rx_symbol_errors_hi, + pport_stats->rx_symbol_errors_lo); + drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow; + drvs->tx_pauseframes = make_64bit_val(pport_stats->tx_pause_frames_hi, + pport_stats->tx_pause_frames_lo); + drvs->tx_controlframes = + make_64bit_val(pport_stats->tx_control_frames_hi, + pport_stats->tx_control_frames_lo); + drvs->jabber_events = pport_stats->rx_jabbers; + drvs->rx_drops_no_pbuf = 0; + drvs->rx_drops_no_txpb = 0; + drvs->rx_drops_no_erx_descr = 0; + drvs->rx_drops_invalid_ring = pport_stats->rx_drops_invalid_queue; + drvs->forwarded_packets = make_64bit_val(pport_stats->num_forwards_hi, + pport_stats->num_forwards_lo); + drvs->rx_drops_mtu = make_64bit_val(pport_stats->rx_drops_mtu_hi, + pport_stats->rx_drops_mtu_lo); + drvs->rx_drops_no_tpre_descr = 0; + drvs->rx_drops_too_many_frags = + make_64bit_val(pport_stats->rx_drops_too_many_frags_hi, + pport_stats->rx_drops_too_many_frags_lo); +} + +void be_parse_stats(struct be_adapter *adapter) +{ + if (adapter->generation == BE_GEN3) { + if (lancer_chip(adapter)) + populate_lancer_stats(adapter); + else + populate_be3_stats(adapter); + } else { + populate_be2_stats(adapter); + } +} + void netdev_stats_update(struct be_adapter *adapter) { - struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va); - struct be_rxf_stats *rxf_stats = &hw_stats->rxf; - struct be_port_rxf_stats *port_stats = - &rxf_stats->port[adapter->port_num]; + struct be_drv_stats *drvs = &adapter->drv_stats; struct net_device_stats *dev_stats = &adapter->netdev->stats; - struct be_erx_stats *erx_stats = &hw_stats->erx; struct be_rx_obj *rxo; int i; @@ -267,43 +434,54 @@ void netdev_stats_update(struct be_adapter *adapter) dev_stats->rx_bytes += rx_stats(rxo)->rx_bytes; dev_stats->multicast += rx_stats(rxo)->rx_mcast_pkts; /* no space in linux buffers: best possible approximation */ - dev_stats->rx_dropped += - erx_stats->rx_drops_no_fragments[rxo->q.id]; + if (adapter->generation == BE_GEN3) { + if (!(lancer_chip(adapter))) { + struct be_erx_stats_v1 *erx_stats = + be_erx_stats_from_cmd(adapter); + dev_stats->rx_dropped += + erx_stats->rx_drops_no_fragments[rxo->q.id]; + } + } else { + struct be_erx_stats_v0 *erx_stats = + be_erx_stats_from_cmd(adapter); + dev_stats->rx_dropped += + erx_stats->rx_drops_no_fragments[rxo->q.id]; + } } dev_stats->tx_packets = tx_stats(adapter)->be_tx_pkts; dev_stats->tx_bytes = tx_stats(adapter)->be_tx_bytes; /* bad pkts received */ - dev_stats->rx_errors = port_stats->rx_crc_errors + - port_stats->rx_alignment_symbol_errors + - port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + - port_stats->rx_frame_too_long + - port_stats->rx_dropped_too_small + - port_stats->rx_dropped_too_short + - port_stats->rx_dropped_header_too_small + - port_stats->rx_dropped_tcp_length + - port_stats->rx_dropped_runt + - port_stats->rx_tcp_checksum_errs + - port_stats->rx_ip_checksum_errs + - port_stats->rx_udp_checksum_errs; + dev_stats->rx_errors = drvs->rx_crc_errors + + drvs->rx_alignment_symbol_errors + + drvs->rx_in_range_errors + + drvs->rx_out_range_errors + + drvs->rx_frame_too_long + + drvs->rx_dropped_too_small + + drvs->rx_dropped_too_short + + drvs->rx_dropped_header_too_small + + drvs->rx_dropped_tcp_length + + drvs->rx_dropped_runt + + drvs->rx_tcp_checksum_errs + + drvs->rx_ip_checksum_errs + + drvs->rx_udp_checksum_errs; /* detailed rx errors */ - dev_stats->rx_length_errors = port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + - port_stats->rx_frame_too_long; + dev_stats->rx_length_errors = drvs->rx_in_range_errors + + drvs->rx_out_range_errors + + drvs->rx_frame_too_long; - dev_stats->rx_crc_errors = port_stats->rx_crc_errors; + dev_stats->rx_crc_errors = drvs->rx_crc_errors; /* frame alignment errors */ - dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors; + dev_stats->rx_frame_errors = drvs->rx_alignment_symbol_errors; /* receiver fifo overrun */ /* drops_no_pbuf is no per i/f, it's per BE card */ - dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow + - port_stats->rx_input_fifo_overflow + - rxf_stats->rx_drops_no_pbuf; + dev_stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop + + drvs->rx_input_fifo_overflow_drop + + drvs->rx_drops_no_pbuf; } void be_link_status_update(struct be_adapter *adapter, bool link_up) @@ -703,7 +881,7 @@ static void be_set_multicast_list(struct net_device *netdev) struct be_adapter *adapter = netdev_priv(netdev); if (netdev->flags & IFF_PROMISC) { - be_cmd_promiscuous_config(adapter, adapter->port_num, 1); + be_cmd_promiscuous_config(adapter, true); adapter->promiscuous = true; goto done; } @@ -711,7 +889,7 @@ static void be_set_multicast_list(struct net_device *netdev) /* BE was previously in promiscuous mode; disable it */ if (adapter->promiscuous) { adapter->promiscuous = false; - be_cmd_promiscuous_config(adapter, adapter->port_num, 0); + be_cmd_promiscuous_config(adapter, false); } /* Enable multicast promisc if num configured exceeds what we support */ @@ -993,9 +1171,10 @@ static void be_rx_compl_process(struct be_adapter *adapter, struct be_rx_obj *rxo, struct be_rx_compl_info *rxcp) { + struct net_device *netdev = adapter->netdev; struct sk_buff *skb; - skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN); + skb = netdev_alloc_skb_ip_align(netdev, BE_HDR_LEN); if (unlikely(!skb)) { if (net_ratelimit()) dev_warn(&adapter->pdev->dev, "skb alloc failed\n"); @@ -1005,20 +1184,24 @@ static void be_rx_compl_process(struct be_adapter *adapter, skb_fill_rx_data(adapter, rxo, skb, rxcp); - if (likely(adapter->rx_csum && csum_passed(rxcp))) + if (likely((netdev->features & NETIF_F_RXCSUM) && csum_passed(rxcp))) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); skb->truesize = skb->len + sizeof(struct sk_buff); - skb->protocol = eth_type_trans(skb, adapter->netdev); + skb->protocol = eth_type_trans(skb, netdev); + if (adapter->netdev->features & NETIF_F_RXHASH) + skb->rxhash = rxcp->rss_hash; + if (unlikely(rxcp->vlanf)) { if (!adapter->vlan_grp || adapter->vlans_added == 0) { kfree_skb(skb); return; } - vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, rxcp->vid); + vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, + rxcp->vlan_tag); } else { netif_receive_skb(skb); } @@ -1072,11 +1255,14 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, skb->data_len = rxcp->pkt_size; skb->truesize += rxcp->pkt_size; skb->ip_summed = CHECKSUM_UNNECESSARY; + if (adapter->netdev->features & NETIF_F_RXHASH) + skb->rxhash = rxcp->rss_hash; if (likely(!rxcp->vlanf)) napi_gro_frags(&eq_obj->napi); else - vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, rxcp->vid); + vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, + rxcp->vlan_tag); } static void be_parse_rx_compl_v1(struct be_adapter *adapter, @@ -1101,8 +1287,14 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter, AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl); rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl); - rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl); - rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, compl); + rxcp->rss_hash = + AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, rxcp); + if (rxcp->vlanf) { + rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, + compl); + rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, + compl); + } } static void be_parse_rx_compl_v0(struct be_adapter *adapter, @@ -1127,8 +1319,14 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter, AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl); rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl); - rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl); - rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, compl); + rxcp->rss_hash = + AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, rxcp); + if (rxcp->vlanf) { + rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, + compl); + rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, + compl); + } } static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) @@ -1150,15 +1348,20 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) else be_parse_rx_compl_v0(adapter, compl, rxcp); - /* vlanf could be wrongly set in some cards. ignore if vtm is not set */ - if ((adapter->function_mode & 0x400) && !rxcp->vtm) - rxcp->vlanf = 0; + if (rxcp->vlanf) { + /* vlanf could be wrongly set in some cards. + * ignore if vtm is not set */ + if ((adapter->function_mode & 0x400) && !rxcp->vtm) + rxcp->vlanf = 0; - if (!lancer_chip(adapter)) - rxcp->vid = swab16(rxcp->vid); + if (!lancer_chip(adapter)) + rxcp->vlan_tag = swab16(rxcp->vlan_tag); - if ((adapter->pvid == rxcp->vid) && !adapter->vlan_tag[rxcp->vid]) - rxcp->vlanf = 0; + if (((adapter->pvid & VLAN_VID_MASK) == + (rxcp->vlan_tag & VLAN_VID_MASK)) && + !adapter->vlan_tag[rxcp->vlan_tag]) + rxcp->vlanf = 0; + } /* As the compl has been parsed, reset it; we wont touch it again */ compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] = 0; @@ -1255,7 +1458,7 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) return txcp; } -static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) +static u16 be_tx_compl_process(struct be_adapter *adapter, u16 last_index) { struct be_queue_info *txq = &adapter->tx_obj.q; struct be_eth_wrb *wrb; @@ -1282,9 +1485,8 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) queue_tail_inc(txq); } while (cur_index != last_index); - atomic_sub(num_wrbs, &txq->used); - kfree_skb(sent_skb); + return num_wrbs; } static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj) @@ -1367,7 +1569,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter) struct be_queue_info *tx_cq = &adapter->tx_obj.cq; struct be_queue_info *txq = &adapter->tx_obj.q; struct be_eth_tx_compl *txcp; - u16 end_idx, cmpl = 0, timeo = 0; + u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0; struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; struct sk_buff *sent_skb; bool dummy_wrb; @@ -1377,12 +1579,14 @@ static void be_tx_compl_clean(struct be_adapter *adapter) while ((txcp = be_tx_compl_get(tx_cq))) { end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, wrb_index, txcp); - be_tx_compl_process(adapter, end_idx); + num_wrbs += be_tx_compl_process(adapter, end_idx); cmpl++; } if (cmpl) { be_cq_notify(adapter, tx_cq->id, false, cmpl); + atomic_sub(num_wrbs, &txq->used); cmpl = 0; + num_wrbs = 0; } if (atomic_read(&txq->used) == 0 || ++timeo > 200) @@ -1402,7 +1606,8 @@ static void be_tx_compl_clean(struct be_adapter *adapter) index_adv(&end_idx, wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1, txq->len); - be_tx_compl_process(adapter, end_idx); + num_wrbs = be_tx_compl_process(adapter, end_idx); + atomic_sub(num_wrbs, &txq->used); } } @@ -1567,12 +1772,31 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) } } +static u32 be_num_rxqs_want(struct be_adapter *adapter) +{ + if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) && + !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) { + return 1 + MAX_RSS_QS; /* one default non-RSS queue */ + } else { + dev_warn(&adapter->pdev->dev, + "No support for multiple RX queues\n"); + return 1; + } +} + static int be_rx_queues_create(struct be_adapter *adapter) { struct be_queue_info *eq, *q, *cq; struct be_rx_obj *rxo; int rc, i; + adapter->num_rx_qs = min(be_num_rxqs_want(adapter), + msix_enabled(adapter) ? + adapter->num_msix_vec - 1 : 1); + if (adapter->num_rx_qs != MAX_RX_QS) + dev_warn(&adapter->pdev->dev, + "Can create only %d RX queues", adapter->num_rx_qs); + adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE; for_all_rx_queues(adapter, rxo, i) { rxo->adapter = adapter; @@ -1718,12 +1942,15 @@ static int be_poll_rx(struct napi_struct *napi, int budget) break; /* Ignore flush completions */ - if (rxcp->num_rcvd) { + if (rxcp->num_rcvd && rxcp->pkt_size) { if (do_gro(rxcp)) be_rx_compl_process_gro(adapter, rxo, rxcp); else be_rx_compl_process(adapter, rxo, rxcp); + } else if (rxcp->pkt_size == 0) { + be_rx_compl_discard(adapter, rxo, rxcp); } + be_rx_stats_update(rxo, rxcp); } @@ -1754,12 +1981,12 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) struct be_queue_info *tx_cq = &adapter->tx_obj.cq; struct be_eth_tx_compl *txcp; int tx_compl = 0, mcc_compl, status = 0; - u16 end_idx; + u16 end_idx, num_wrbs = 0; while ((txcp = be_tx_compl_get(tx_cq))) { end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, wrb_index, txcp); - be_tx_compl_process(adapter, end_idx); + num_wrbs += be_tx_compl_process(adapter, end_idx); tx_compl++; } @@ -1775,6 +2002,8 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) if (tx_compl) { be_cq_notify(adapter, adapter->tx_obj.cq.id, true, tx_compl); + atomic_sub(num_wrbs, &txq->used); + /* As Tx wrbs have been freed up, wake up netdev queue if * it was stopped due to lack of tx wrbs. */ @@ -1837,6 +2066,9 @@ static void be_worker(struct work_struct *work) struct be_rx_obj *rxo; int i; + if (!adapter->ue_detected && !lancer_chip(adapter)) + be_detect_dump_ue(adapter); + /* when interrupts are not yet enabled, just reap any pending * mcc completions */ if (!netif_running(adapter->netdev)) { @@ -1849,15 +2081,16 @@ static void be_worker(struct work_struct *work) be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); } - if (!adapter->ue_detected && !lancer_chip(adapter)) - be_detect_dump_ue(adapter); - goto reschedule; } - if (!adapter->stats_cmd_sent) - be_cmd_get_stats(adapter, &adapter->stats_cmd); - + if (!adapter->stats_cmd_sent) { + if (lancer_chip(adapter)) + lancer_cmd_get_pport_stats(adapter, + &adapter->stats_cmd); + else + be_cmd_get_stats(adapter, &adapter->stats_cmd); + } be_tx_rate_update(adapter); for_all_rx_queues(adapter, rxo, i) { @@ -1869,60 +2102,43 @@ static void be_worker(struct work_struct *work) be_post_rx_frags(rxo, GFP_KERNEL); } } - if (!adapter->ue_detected && !lancer_chip(adapter)) - be_detect_dump_ue(adapter); reschedule: + adapter->work_counter++; schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); } static void be_msix_disable(struct be_adapter *adapter) { - if (adapter->msix_enabled) { + if (msix_enabled(adapter)) { pci_disable_msix(adapter->pdev); - adapter->msix_enabled = false; - } -} - -static int be_num_rxqs_get(struct be_adapter *adapter) -{ - if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) && - !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) { - return 1 + MAX_RSS_QS; /* one default non-RSS queue */ - } else { - dev_warn(&adapter->pdev->dev, - "No support for multiple RX queues\n"); - return 1; + adapter->num_msix_vec = 0; } } static void be_msix_enable(struct be_adapter *adapter) { #define BE_MIN_MSIX_VECTORS (1 + 1) /* Rx + Tx */ - int i, status; + int i, status, num_vec; - adapter->num_rx_qs = be_num_rxqs_get(adapter); + num_vec = be_num_rxqs_want(adapter) + 1; - for (i = 0; i < (adapter->num_rx_qs + 1); i++) + for (i = 0; i < num_vec; i++) adapter->msix_entries[i].entry = i; - status = pci_enable_msix(adapter->pdev, adapter->msix_entries, - adapter->num_rx_qs + 1); + status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec); if (status == 0) { goto done; } else if (status >= BE_MIN_MSIX_VECTORS) { + num_vec = status; if (pci_enable_msix(adapter->pdev, adapter->msix_entries, - status) == 0) { - adapter->num_rx_qs = status - 1; - dev_warn(&adapter->pdev->dev, - "Could alloc only %d MSIx vectors. " - "Using %d RX Qs\n", status, adapter->num_rx_qs); + num_vec) == 0) goto done; - } } return; done: - adapter->msix_enabled = true; + adapter->num_msix_vec = num_vec; + return; } static void be_sriov_enable(struct be_adapter *adapter) @@ -1930,7 +2146,20 @@ static void be_sriov_enable(struct be_adapter *adapter) be_check_sriov_fn_type(adapter); #ifdef CONFIG_PCI_IOV if (be_physfn(adapter) && num_vfs) { - int status; + int status, pos; + u16 nvfs; + + pos = pci_find_ext_capability(adapter->pdev, + PCI_EXT_CAP_ID_SRIOV); + pci_read_config_word(adapter->pdev, + pos + PCI_SRIOV_TOTAL_VF, &nvfs); + + if (num_vfs > nvfs) { + dev_info(&adapter->pdev->dev, + "Device supports %d VFs and not %d\n", + nvfs, num_vfs); + num_vfs = nvfs; + } status = pci_enable_sriov(adapter->pdev, num_vfs); adapter->sriov_enabled = status ? false : true; @@ -2003,8 +2232,7 @@ static int be_msix_register(struct be_adapter *adapter) err: dev_warn(&adapter->pdev->dev, "MSIX Request IRQ failed - err %d\n", status); - pci_disable_msix(adapter->pdev); - adapter->msix_enabled = false; + be_msix_disable(adapter); return status; } @@ -2013,7 +2241,7 @@ static int be_irq_register(struct be_adapter *adapter) struct net_device *netdev = adapter->netdev; int status; - if (adapter->msix_enabled) { + if (msix_enabled(adapter)) { status = be_msix_register(adapter); if (status == 0) goto done; @@ -2046,7 +2274,7 @@ static void be_irq_unregister(struct be_adapter *adapter) return; /* INTx */ - if (!adapter->msix_enabled) { + if (!msix_enabled(adapter)) { free_irq(netdev->irq, adapter); goto done; } @@ -2088,7 +2316,7 @@ static int be_close(struct net_device *netdev) be_cq_notify(adapter, rxo->cq.id, false, 0); } - if (adapter->msix_enabled) { + if (msix_enabled(adapter)) { vec = be_msix_vec_get(adapter, tx_eq); synchronize_irq(vec); @@ -2141,7 +2369,7 @@ static int be_open(struct net_device *netdev) be_async_mcc_enable(adapter); status = be_cmd_link_status_query(adapter, &link_up, &mac_speed, - &link_speed); + &link_speed, 0); if (status) goto err; be_link_status_update(adapter, link_up); @@ -2261,7 +2489,7 @@ static int be_setup(struct be_adapter *adapter) BE_IF_FLAGS_PASS_L3L4_ERRORS; en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS; - if (be_multi_rxq(adapter)) { + if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) { cap_flags |= BE_IF_FLAGS_RSS; en_flags |= BE_IF_FLAGS_RSS; } @@ -2318,7 +2546,6 @@ static int be_setup(struct be_adapter *adapter) return 0; - be_mcc_queues_destroy(adapter); rx_qs_destroy: be_rx_queues_destroy(adapter); tx_qs_destroy: @@ -2486,7 +2713,6 @@ static int be_flash_data(struct be_adapter *adapter, "cmd to write to flash rom failed.\n"); return -1; } - yield(); } } return 0; @@ -2504,32 +2730,96 @@ static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr) return 0; } -int be_load_fw(struct be_adapter *adapter, u8 *func) +static int lancer_fw_download(struct be_adapter *adapter, + const struct firmware *fw) +{ +#define LANCER_FW_DOWNLOAD_CHUNK (32 * 1024) +#define LANCER_FW_DOWNLOAD_LOCATION "/prg" + struct be_dma_mem flash_cmd; + const u8 *data_ptr = NULL; + u8 *dest_image_ptr = NULL; + size_t image_size = 0; + u32 chunk_size = 0; + u32 data_written = 0; + u32 offset = 0; + int status = 0; + u8 add_status = 0; + + if (!IS_ALIGNED(fw->size, sizeof(u32))) { + dev_err(&adapter->pdev->dev, + "FW Image not properly aligned. " + "Length must be 4 byte aligned.\n"); + status = -EINVAL; + goto lancer_fw_exit; + } + + flash_cmd.size = sizeof(struct lancer_cmd_req_write_object) + + LANCER_FW_DOWNLOAD_CHUNK; + flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size, + &flash_cmd.dma, GFP_KERNEL); + if (!flash_cmd.va) { + status = -ENOMEM; + dev_err(&adapter->pdev->dev, + "Memory allocation failure while flashing\n"); + goto lancer_fw_exit; + } + + dest_image_ptr = flash_cmd.va + + sizeof(struct lancer_cmd_req_write_object); + image_size = fw->size; + data_ptr = fw->data; + + while (image_size) { + chunk_size = min_t(u32, image_size, LANCER_FW_DOWNLOAD_CHUNK); + + /* Copy the image chunk content. */ + memcpy(dest_image_ptr, data_ptr, chunk_size); + + status = lancer_cmd_write_object(adapter, &flash_cmd, + chunk_size, offset, LANCER_FW_DOWNLOAD_LOCATION, + &data_written, &add_status); + + if (status) + break; + + offset += data_written; + data_ptr += data_written; + image_size -= data_written; + } + + if (!status) { + /* Commit the FW written */ + status = lancer_cmd_write_object(adapter, &flash_cmd, + 0, offset, LANCER_FW_DOWNLOAD_LOCATION, + &data_written, &add_status); + } + + dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va, + flash_cmd.dma); + if (status) { + dev_err(&adapter->pdev->dev, + "Firmware load error. " + "Status code: 0x%x Additional Status: 0x%x\n", + status, add_status); + goto lancer_fw_exit; + } + + dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n"); +lancer_fw_exit: + return status; +} + +static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw) { - char fw_file[ETHTOOL_FLASH_MAX_FILENAME]; - const struct firmware *fw; struct flash_file_hdr_g2 *fhdr; struct flash_file_hdr_g3 *fhdr3; struct image_hdr *img_hdr_ptr = NULL; struct be_dma_mem flash_cmd; - int status, i = 0, num_imgs = 0; const u8 *p; - - if (!netif_running(adapter->netdev)) { - dev_err(&adapter->pdev->dev, - "Firmware load not allowed (interface is down)\n"); - return -EPERM; - } - - strcpy(fw_file, func); - - status = request_firmware(&fw, fw_file, &adapter->pdev->dev); - if (status) - goto fw_exit; + int status = 0, i = 0, num_imgs = 0; p = fw->data; fhdr = (struct flash_file_hdr_g2 *) p; - dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file); flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024; flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size, @@ -2538,7 +2828,7 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) status = -ENOMEM; dev_err(&adapter->pdev->dev, "Memory allocation failure while flashing\n"); - goto fw_exit; + goto be_fw_exit; } if ((adapter->generation == BE_GEN3) && @@ -2566,11 +2856,37 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) flash_cmd.dma); if (status) { dev_err(&adapter->pdev->dev, "Firmware load error\n"); - goto fw_exit; + goto be_fw_exit; } dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n"); +be_fw_exit: + return status; +} + +int be_load_fw(struct be_adapter *adapter, u8 *fw_file) +{ + const struct firmware *fw; + int status; + + if (!netif_running(adapter->netdev)) { + dev_err(&adapter->pdev->dev, + "Firmware load not allowed (interface is down)\n"); + return -1; + } + + status = request_firmware(&fw, fw_file, &adapter->pdev->dev); + if (status) + goto fw_exit; + + dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file); + + if (lancer_chip(adapter)) + status = lancer_fw_download(adapter, fw); + else + status = be_fw_download(adapter, fw); + fw_exit: release_firmware(fw); return status; @@ -2599,10 +2915,14 @@ static void be_netdev_init(struct net_device *netdev) struct be_rx_obj *rxo; int i; - netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_GRO | NETIF_F_TSO6; + netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_TX; + if (be_multi_rxq(adapter)) + netdev->hw_features |= NETIF_F_RXHASH; + + netdev->features |= netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; @@ -2612,8 +2932,6 @@ static void be_netdev_init(struct net_device *netdev) netdev->flags |= IFF_MULTICAST; - adapter->rx_csum = true; - /* Default settings for Rx and Tx flow control */ adapter->rx_fc = true; adapter->tx_fc = true; @@ -2781,7 +3099,14 @@ static int be_stats_init(struct be_adapter *adapter) { struct be_dma_mem *cmd = &adapter->stats_cmd; - cmd->size = sizeof(struct be_cmd_req_get_stats); + if (adapter->generation == BE_GEN2) { + cmd->size = sizeof(struct be_cmd_req_get_stats_v0); + } else { + if (lancer_chip(adapter)) + cmd->size = sizeof(struct lancer_cmd_req_pport_stats); + else + cmd->size = sizeof(struct be_cmd_req_get_stats_v1); + } cmd->va = dma_alloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma, GFP_KERNEL); if (cmd->va == NULL) @@ -2807,6 +3132,7 @@ static void __devexit be_remove(struct pci_dev *pdev) be_ctrl_cleanup(adapter); + kfree(adapter->vf_cfg); be_sriov_disable(adapter); be_msix_disable(adapter); @@ -2834,7 +3160,8 @@ static int be_get_config(struct be_adapter *adapter) memset(mac, 0, ETH_ALEN); - if (be_physfn(adapter)) { + /* A default permanent address is given to each VF for Lancer*/ + if (be_physfn(adapter) || lancer_chip(adapter)) { status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0); @@ -2876,6 +3203,7 @@ static int be_dev_family_check(struct be_adapter *adapter) adapter->generation = BE_GEN3; break; case OC_DEVICE_ID3: + case OC_DEVICE_ID4: pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf); if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >> SLI_INTF_IF_TYPE_SHIFT; @@ -2885,10 +3213,6 @@ static int be_dev_family_check(struct be_adapter *adapter) dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n"); return -EINVAL; } - if (num_vfs > 0) { - dev_err(&pdev->dev, "VFs not supported\n"); - return -EINVAL; - } adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >> SLI_INTF_FAMILY_SHIFT); adapter->generation = BE_GEN3; @@ -2991,16 +3315,23 @@ static int __devinit be_probe(struct pci_dev *pdev, } be_sriov_enable(adapter); + if (adapter->sriov_enabled) { + adapter->vf_cfg = kcalloc(num_vfs, + sizeof(struct be_vf_cfg), GFP_KERNEL); + + if (!adapter->vf_cfg) + goto free_netdev; + } status = be_ctrl_init(adapter); if (status) - goto free_netdev; + goto free_vf_cfg; if (lancer_chip(adapter)) { status = lancer_test_and_set_rdy_state(adapter); if (status) { dev_err(&pdev->dev, "Adapter in non recoverable error\n"); - goto free_netdev; + goto ctrl_clean; } } @@ -3043,9 +3374,24 @@ static int __devinit be_probe(struct pci_dev *pdev, netif_carrier_off(netdev); if (be_physfn(adapter) && adapter->sriov_enabled) { - status = be_vf_eth_addr_config(adapter); - if (status) - goto unreg_netdev; + u8 mac_speed; + bool link_up; + u16 vf, lnk_speed; + + if (!lancer_chip(adapter)) { + status = be_vf_eth_addr_config(adapter); + if (status) + goto unreg_netdev; + } + + for (vf = 0; vf < num_vfs; vf++) { + status = be_cmd_link_status_query(adapter, &link_up, + &mac_speed, &lnk_speed, vf + 1); + if (!status) + adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10; + else + goto unreg_netdev; + } } dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); @@ -3062,6 +3408,8 @@ static int __devinit be_probe(struct pci_dev *pdev, be_stats_cleanup(adapter); ctrl_clean: be_ctrl_cleanup(adapter); +free_vf_cfg: + kfree(adapter->vf_cfg); free_netdev: be_sriov_disable(adapter); free_netdev(netdev); @@ -3146,16 +3494,15 @@ static void be_shutdown(struct pci_dev *pdev) if (!adapter) return; - if (netif_running(adapter->netdev)) - cancel_delayed_work_sync(&adapter->work); + cancel_delayed_work_sync(&adapter->work); netif_device_detach(adapter->netdev); - be_cmd_reset_function(adapter); - if (adapter->wol) be_setup_wol(adapter, true); + be_cmd_reset_function(adapter); + pci_disable_device(pdev); } @@ -3267,13 +3614,6 @@ static int __init be_init_module(void) rx_frag_size = 2048; } - if (num_vfs > 32) { - printk(KERN_WARNING DRV_NAME - " : Module param num_vfs must not be greater than 32." - "Using 32\n"); - num_vfs = 32; - } - return pci_register_driver(&be_driver); } module_init(be_init_module); diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/bna/bfa_ioc.c index e3de0b8625cd..fcb9bb3169e0 100644 --- a/drivers/net/bna/bfa_ioc.c +++ b/drivers/net/bna/bfa_ioc.c @@ -38,6 +38,8 @@ #define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc)) #define bfa_ioc_notify_fail(__ioc) \ ((__ioc)->ioc_hwif->ioc_notify_fail(__ioc)) +#define bfa_ioc_sync_start(__ioc) \ + ((__ioc)->ioc_hwif->ioc_sync_start(__ioc)) #define bfa_ioc_sync_join(__ioc) \ ((__ioc)->ioc_hwif->ioc_sync_join(__ioc)) #define bfa_ioc_sync_leave(__ioc) \ @@ -80,7 +82,6 @@ static void bfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc); static void bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param); static u32 bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr); -static u32 bfa_ioc_smem_pgoff(struct bfa_ioc *ioc, u32 fmaddr); static void bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc, char *serial_num); static void bfa_ioc_get_adapter_fw_ver(struct bfa_ioc *ioc, @@ -602,7 +603,7 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_SEMLOCKED: if (bfa_ioc_firmware_lock(ioc)) { - if (bfa_ioc_sync_complete(ioc)) { + if (bfa_ioc_sync_start(ioc)) { iocpf->retry_count = 0; bfa_ioc_sync_join(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); @@ -1272,13 +1273,12 @@ bfa_ioc_lpu_stop(struct bfa_ioc *ioc) void bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr) { - u32 pgnum, pgoff; + u32 pgnum; u32 loff = 0; int i; u32 *fwsig = (u32 *) fwhdr; pgnum = bfa_ioc_smem_pgnum(ioc, loff); - pgoff = bfa_ioc_smem_pgoff(ioc, loff); writel(pgnum, ioc->ioc_regs.host_page_num_fn); for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr) / sizeof(u32)); @@ -1314,7 +1314,7 @@ bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr) * execution context (driver/bios) must match. */ static bool -bfa_ioc_fwver_valid(struct bfa_ioc *ioc) +bfa_ioc_fwver_valid(struct bfa_ioc *ioc, u32 boot_env) { struct bfi_ioc_image_hdr fwhdr, *drv_fwhdr; @@ -1325,7 +1325,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc *ioc) if (fwhdr.signature != drv_fwhdr->signature) return false; - if (fwhdr.exec != drv_fwhdr->exec) + if (swab32(fwhdr.param) != boot_env) return false; return bfa_nw_ioc_fwver_cmp(ioc, &fwhdr); @@ -1352,9 +1352,12 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force) { enum bfi_ioc_state ioc_fwstate; bool fwvalid; + u32 boot_env; ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate); + boot_env = BFI_BOOT_LOADER_OS; + if (force) ioc_fwstate = BFI_IOC_UNINIT; @@ -1362,10 +1365,10 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force) * check if firmware is valid */ fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ? - false : bfa_ioc_fwver_valid(ioc); + false : bfa_ioc_fwver_valid(ioc, boot_env); if (!fwvalid) { - bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id); + bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, boot_env); return; } @@ -1396,7 +1399,7 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force) /** * Initialize the h/w for any other states. */ - bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id); + bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, boot_env); } void @@ -1506,10 +1509,10 @@ bfa_ioc_hb_stop(struct bfa_ioc *ioc) */ static void bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, - u32 boot_param) + u32 boot_env) { u32 *fwimg; - u32 pgnum, pgoff; + u32 pgnum; u32 loff = 0; u32 chunkno = 0; u32 i; @@ -1522,7 +1525,6 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno); pgnum = bfa_ioc_smem_pgnum(ioc, loff); - pgoff = bfa_ioc_smem_pgoff(ioc, loff); writel(pgnum, ioc->ioc_regs.host_page_num_fn); @@ -1558,10 +1560,10 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, /* * Set boot type and boot param at the end. */ - writel((swab32(swab32(boot_type))), ((ioc->ioc_regs.smem_page_start) + writel(boot_type, ((ioc->ioc_regs.smem_page_start) + (BFI_BOOT_TYPE_OFF))); - writel((swab32(swab32(boot_param))), ((ioc->ioc_regs.smem_page_start) - + (BFI_BOOT_PARAM_OFF))); + writel(boot_env, ((ioc->ioc_regs.smem_page_start) + + (BFI_BOOT_LOADER_OFF))); } static void @@ -1721,7 +1723,7 @@ bfa_ioc_pll_init(struct bfa_ioc *ioc) * as the entry vector. */ static void -bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param) +bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_env) { void __iomem *rb; @@ -1734,7 +1736,7 @@ bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param) * Initialize IOC state of all functions on a chip reset. */ rb = ioc->pcidev.pci_bar_kva; - if (boot_param == BFI_BOOT_TYPE_MEMTEST) { + if (boot_type == BFI_BOOT_TYPE_MEMTEST) { writel(BFI_IOC_MEMTEST, (rb + BFA_IOC0_STATE_REG)); writel(BFI_IOC_MEMTEST, (rb + BFA_IOC1_STATE_REG)); } else { @@ -1743,7 +1745,7 @@ bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param) } bfa_ioc_msgflush(ioc); - bfa_ioc_download_fw(ioc, boot_type, boot_param); + bfa_ioc_download_fw(ioc, boot_type, boot_env); /** * Enable interrupts just before starting LPU @@ -1920,12 +1922,6 @@ bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr) return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr); } -static u32 -bfa_ioc_smem_pgoff(struct bfa_ioc *ioc, u32 fmaddr) -{ - return PSS_SMEM_PGOFF(fmaddr); -} - /** * Register mailbox message handler function, to be called by common modules */ diff --git a/drivers/net/bna/bfa_ioc.h b/drivers/net/bna/bfa_ioc.h index e4974bc24ef6..bd48abee781f 100644 --- a/drivers/net/bna/bfa_ioc.h +++ b/drivers/net/bna/bfa_ioc.h @@ -194,6 +194,7 @@ struct bfa_ioc_hwif { bool msix); void (*ioc_notify_fail) (struct bfa_ioc *ioc); void (*ioc_ownership_reset) (struct bfa_ioc *ioc); + bool (*ioc_sync_start) (struct bfa_ioc *ioc); void (*ioc_sync_join) (struct bfa_ioc *ioc); void (*ioc_sync_leave) (struct bfa_ioc *ioc); void (*ioc_sync_ack) (struct bfa_ioc *ioc); diff --git a/drivers/net/bna/bfa_ioc_ct.c b/drivers/net/bna/bfa_ioc_ct.c index 469997c4ffd1..87aecdf22cf9 100644 --- a/drivers/net/bna/bfa_ioc_ct.c +++ b/drivers/net/bna/bfa_ioc_ct.c @@ -41,6 +41,7 @@ static void bfa_ioc_ct_map_port(struct bfa_ioc *ioc); static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix); static void bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc); static void bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc); +static bool bfa_ioc_ct_sync_start(struct bfa_ioc *ioc); static void bfa_ioc_ct_sync_join(struct bfa_ioc *ioc); static void bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc); static void bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc); @@ -63,6 +64,7 @@ bfa_nw_ioc_set_ct_hwif(struct bfa_ioc *ioc) nw_hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; nw_hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail; nw_hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset; + nw_hwif_ct.ioc_sync_start = bfa_ioc_ct_sync_start; nw_hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join; nw_hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave; nw_hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack; @@ -342,6 +344,32 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc) bfa_nw_ioc_hw_sem_release(ioc); } +/** + * Synchronized IOC failure processing routines + */ +static bool +bfa_ioc_ct_sync_start(struct bfa_ioc *ioc) +{ + u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync); + u32 sync_reqd = bfa_ioc_ct_get_sync_reqd(r32); + + /* + * Driver load time. If the sync required bit for this PCI fn + * is set, it is due to an unclean exit by the driver for this + * PCI fn in the previous incarnation. Whoever comes here first + * should clean it up, no matter which PCI fn. + */ + + if (sync_reqd & bfa_ioc_ct_sync_pos(ioc)) { + writel(0, ioc->ioc_regs.ioc_fail_sync); + writel(1, ioc->ioc_regs.ioc_usage_reg); + writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate); + writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate); + return true; + } + + return bfa_ioc_ct_sync_complete(ioc); +} /** * Synchronized IOC failure processing routines */ diff --git a/drivers/net/bna/bfi.h b/drivers/net/bna/bfi.h index a97396811050..6050379526f7 100644 --- a/drivers/net/bna/bfi.h +++ b/drivers/net/bna/bfi.h @@ -184,12 +184,14 @@ enum bfi_mclass { #define BFI_IOC_MSGLEN_MAX 32 /* 32 bytes */ #define BFI_BOOT_TYPE_OFF 8 -#define BFI_BOOT_PARAM_OFF 12 +#define BFI_BOOT_LOADER_OFF 12 -#define BFI_BOOT_TYPE_NORMAL 0 /* param is device id */ +#define BFI_BOOT_TYPE_NORMAL 0 #define BFI_BOOT_TYPE_FLASH 1 #define BFI_BOOT_TYPE_MEMTEST 2 +#define BFI_BOOT_LOADER_OS 0 + #define BFI_BOOT_MEMTEST_RES_ADDR 0x900 #define BFI_BOOT_MEMTEST_RES_SIG 0xA0A1A2A3 diff --git a/drivers/net/bna/bna_ctrl.c b/drivers/net/bna/bna_ctrl.c index e1527472b961..53b14169e363 100644 --- a/drivers/net/bna/bna_ctrl.c +++ b/drivers/net/bna/bna_ctrl.c @@ -246,7 +246,6 @@ static void bna_mbox_flush_q(struct bna *bna, struct list_head *q) { struct bna_mbox_qe *mb_qe = NULL; - struct bfi_mhdr *cmd_h; struct list_head *mb_q; void (*cbfn)(void *arg, int status); void *cbarg; @@ -260,7 +259,6 @@ bna_mbox_flush_q(struct bna *bna, struct list_head *q) bfa_q_qe_init(mb_qe); bna->mbox_mod.msg_pending--; - cmd_h = (struct bfi_mhdr *)(&mb_qe->cmd.msg[0]); if (cbfn) cbfn(cbarg, BNA_CB_NOT_EXEC); } @@ -2774,23 +2772,6 @@ bna_rit_mod_init(struct bna_rit_mod *rit_mod, } } -static void -bna_rit_mod_uninit(struct bna_rit_mod *rit_mod) -{ - struct bna_rit_segment *rit_segment; - struct list_head *qe; - int i; - int j; - - for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) { - j = 0; - list_for_each(qe, &rit_mod->rit_seg_pool[i]) { - rit_segment = (struct bna_rit_segment *)qe; - j++; - } - } -} - /* * Public functions */ @@ -2977,8 +2958,6 @@ bna_uninit(struct bna *bna) bna_ucam_mod_uninit(&bna->ucam_mod); - bna_rit_mod_uninit(&bna->rit_mod); - bna_ib_mod_uninit(&bna->ib_mod); bna_rx_mod_uninit(&bna->rx_mod); diff --git a/drivers/net/bna/bna_txrx.c b/drivers/net/bna/bna_txrx.c index 58c7664040dc..380085cc3088 100644 --- a/drivers/net/bna/bna_txrx.c +++ b/drivers/net/bna/bna_txrx.c @@ -2229,14 +2229,11 @@ void bna_rit_create(struct bna_rx *rx) { struct list_head *qe_rxp; - struct bna *bna; struct bna_rxp *rxp; struct bna_rxq *q0 = NULL; struct bna_rxq *q1 = NULL; int offset; - bna = rx->bna; - offset = 0; list_for_each(qe_rxp, &rx->rxp_q) { rxp = (struct bna_rxp *)qe_rxp; @@ -2830,7 +2827,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad, struct bna_mem_descr *dsqpt_mem; /* s/w qpt for data */ struct bna_mem_descr *hpage_mem; /* hdr page mem */ struct bna_mem_descr *dpage_mem; /* data page mem */ - int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0, ret; + int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0; int dpage_count, hpage_count, rcb_idx; struct bna_ib_config ibcfg; /* Fail if we don't have enough RXPs, RXQs */ @@ -2924,7 +2921,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad, ibcfg.interpkt_timeo = BFI_RX_INTERPKT_TIMEO; ibcfg.ctrl_flags = BFI_IB_CF_INT_ENABLE; - ret = bna_ib_config(rxp->cq.ib, &ibcfg); + bna_ib_config(rxp->cq.ib, &ibcfg); /* Link rxqs to rxp */ _rxp_add_rxqs(rxp, q0, q1); diff --git a/drivers/net/bna/bnad.c b/drivers/net/bna/bnad.c index 9f356d5d0f33..e588511f47fb 100644 --- a/drivers/net/bna/bnad.c +++ b/drivers/net/bna/bnad.c @@ -501,7 +501,7 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget) skb_put(skb, ntohs(cmpl->length)); if (likely - (bnad->rx_csum && + ((bnad->netdev->features & NETIF_F_RXCSUM) && (((flags & BNA_CQ_EF_IPV4) && (flags & BNA_CQ_EF_L3_CKSUM_OK)) || (flags & BNA_CQ_EF_IPV6)) && @@ -1837,7 +1837,6 @@ bnad_setup_rx(struct bnad *bnad, uint rx_id) /* Initialize the Rx event handlers */ rx_cbfn.rcb_setup_cbfn = bnad_cb_rcb_setup; rx_cbfn.rcb_destroy_cbfn = bnad_cb_rcb_destroy; - rx_cbfn.rcb_destroy_cbfn = NULL; rx_cbfn.ccb_setup_cbfn = bnad_cb_ccb_setup; rx_cbfn.ccb_destroy_cbfn = bnad_cb_ccb_destroy; rx_cbfn.rx_cleanup_cbfn = bnad_cb_rx_cleanup; @@ -2903,23 +2902,20 @@ bnad_netdev_init(struct bnad *bnad, bool using_dac) { struct net_device *netdev = bnad->netdev; - netdev->features |= NETIF_F_IPV6_CSUM; - netdev->features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO6; + netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_TX; - netdev->features |= NETIF_F_GRO; - pr_warn("bna: GRO enabled, using kernel stack GRO\n"); + netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6; - netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + netdev->features |= netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; if (using_dac) netdev->features |= NETIF_F_HIGHDMA; - netdev->features |= - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER; - - netdev->vlan_features = netdev->features; netdev->mem_start = bnad->mmio_start; netdev->mem_end = bnad->mmio_start + bnad->mmio_len - 1; @@ -2970,7 +2966,6 @@ bnad_init(struct bnad *bnad, bnad->txq_depth = BNAD_TXQ_DEPTH; bnad->rxq_depth = BNAD_RXQ_DEPTH; - bnad->rx_csum = true; bnad->tx_coalescing_timeo = BFI_TX_COALESCING_TIMEO; bnad->rx_coalescing_timeo = BFI_RX_COALESCING_TIMEO; diff --git a/drivers/net/bna/bnad.h b/drivers/net/bna/bnad.h index a89117fa4970..ccdabad0a40c 100644 --- a/drivers/net/bna/bnad.h +++ b/drivers/net/bna/bnad.h @@ -237,8 +237,6 @@ struct bnad { struct bna_rx_config rx_config[BNAD_MAX_RXS]; struct bna_tx_config tx_config[BNAD_MAX_TXS]; - u32 rx_csum; - void __iomem *bar0; /* BAR0 address */ struct bna bna; diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/bna/bnad_ethtool.c index 142d6047da27..3330cd78da2c 100644 --- a/drivers/net/bna/bnad_ethtool.c +++ b/drivers/net/bna/bnad_ethtool.c @@ -237,10 +237,10 @@ bnad_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) cmd->phy_address = 0; if (netif_carrier_ok(netdev)) { - cmd->speed = SPEED_10000; + ethtool_cmd_speed_set(cmd, SPEED_10000); cmd->duplex = DUPLEX_FULL; } else { - cmd->speed = -1; + ethtool_cmd_speed_set(cmd, -1); cmd->duplex = -1; } cmd->transceiver = XCVR_EXTERNAL; @@ -256,7 +256,8 @@ bnad_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd) /* 10G full duplex setting supported only */ if (cmd->autoneg == AUTONEG_ENABLE) return -EOPNOTSUPP; else { - if ((cmd->speed == SPEED_10000) && (cmd->duplex == DUPLEX_FULL)) + if ((ethtool_cmd_speed(cmd) == SPEED_10000) + && (cmd->duplex == DUPLEX_FULL)) return 0; } @@ -806,61 +807,6 @@ bnad_set_pauseparam(struct net_device *netdev, return 0; } -static u32 -bnad_get_rx_csum(struct net_device *netdev) -{ - u32 rx_csum; - struct bnad *bnad = netdev_priv(netdev); - - rx_csum = bnad->rx_csum; - return rx_csum; -} - -static int -bnad_set_rx_csum(struct net_device *netdev, u32 rx_csum) -{ - struct bnad *bnad = netdev_priv(netdev); - - mutex_lock(&bnad->conf_mutex); - bnad->rx_csum = rx_csum; - mutex_unlock(&bnad->conf_mutex); - return 0; -} - -static int -bnad_set_tx_csum(struct net_device *netdev, u32 tx_csum) -{ - struct bnad *bnad = netdev_priv(netdev); - - mutex_lock(&bnad->conf_mutex); - if (tx_csum) { - netdev->features |= NETIF_F_IP_CSUM; - netdev->features |= NETIF_F_IPV6_CSUM; - } else { - netdev->features &= ~NETIF_F_IP_CSUM; - netdev->features &= ~NETIF_F_IPV6_CSUM; - } - mutex_unlock(&bnad->conf_mutex); - return 0; -} - -static int -bnad_set_tso(struct net_device *netdev, u32 tso) -{ - struct bnad *bnad = netdev_priv(netdev); - - mutex_lock(&bnad->conf_mutex); - if (tso) { - netdev->features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO6; - } else { - netdev->features &= ~NETIF_F_TSO; - netdev->features &= ~NETIF_F_TSO6; - } - mutex_unlock(&bnad->conf_mutex); - return 0; -} - static void bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string) { @@ -1256,14 +1202,6 @@ static struct ethtool_ops bnad_ethtool_ops = { .set_ringparam = bnad_set_ringparam, .get_pauseparam = bnad_get_pauseparam, .set_pauseparam = bnad_set_pauseparam, - .get_rx_csum = bnad_get_rx_csum, - .set_rx_csum = bnad_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = bnad_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = bnad_set_tso, .get_strings = bnad_get_strings, .get_ethtool_stats = bnad_get_ethtool_stats, .get_sset_count = bnad_get_sset_count diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 8e6d618b5305..57d3293c65bd 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3174,7 +3174,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) } skb_checksum_none_assert(skb); - if (bp->rx_csum && + if ((bp->dev->features & NETIF_F_RXCSUM) && (status & (L2_FHDR_STATUS_TCP_SEGMENT | L2_FHDR_STATUS_UDP_DATAGRAM))) { @@ -6696,17 +6696,16 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (bp->autoneg & AUTONEG_SPEED) { cmd->autoneg = AUTONEG_ENABLE; - } - else { + } else { cmd->autoneg = AUTONEG_DISABLE; } if (netif_carrier_ok(dev)) { - cmd->speed = bp->line_speed; + ethtool_cmd_speed_set(cmd, bp->line_speed); cmd->duplex = bp->duplex; } else { - cmd->speed = -1; + ethtool_cmd_speed_set(cmd, -1); cmd->duplex = -1; } spin_unlock_bh(&bp->phy_lock); @@ -6758,21 +6757,21 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) advertising |= ADVERTISED_Autoneg; } else { + u32 speed = ethtool_cmd_speed(cmd); if (cmd->port == PORT_FIBRE) { - if ((cmd->speed != SPEED_1000 && - cmd->speed != SPEED_2500) || + if ((speed != SPEED_1000 && + speed != SPEED_2500) || (cmd->duplex != DUPLEX_FULL)) goto err_out_unlock; - if (cmd->speed == SPEED_2500 && + if (speed == SPEED_2500 && !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)) goto err_out_unlock; - } - else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500) + } else if (speed == SPEED_1000 || speed == SPEED_2500) goto err_out_unlock; autoneg &= ~AUTONEG_SPEED; - req_line_speed = cmd->speed; + req_line_speed = speed; req_duplex = cmd->duplex; advertising = 0; } @@ -7189,38 +7188,6 @@ bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) return 0; } -static u32 -bnx2_get_rx_csum(struct net_device *dev) -{ - struct bnx2 *bp = netdev_priv(dev); - - return bp->rx_csum; -} - -static int -bnx2_set_rx_csum(struct net_device *dev, u32 data) -{ - struct bnx2 *bp = netdev_priv(dev); - - bp->rx_csum = data; - return 0; -} - -static int -bnx2_set_tso(struct net_device *dev, u32 data) -{ - struct bnx2 *bp = netdev_priv(dev); - - if (data) { - dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; - if (CHIP_NUM(bp) == CHIP_NUM_5709) - dev->features |= NETIF_F_TSO6; - } else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 | - NETIF_F_TSO_ECN); - return 0; -} - static struct { char string[ETH_GSTRING_LEN]; } bnx2_stats_str_arr[] = { @@ -7495,82 +7462,74 @@ bnx2_get_ethtool_stats(struct net_device *dev, } static int -bnx2_phys_id(struct net_device *dev, u32 data) +bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state) { struct bnx2 *bp = netdev_priv(dev); - int i; - u32 save; - bnx2_set_power_state(bp, PCI_D0); + switch (state) { + case ETHTOOL_ID_ACTIVE: + bnx2_set_power_state(bp, PCI_D0); - if (data == 0) - data = 2; + bp->leds_save = REG_RD(bp, BNX2_MISC_CFG); + REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC); + return 1; /* cycle on/off once per second */ - save = REG_RD(bp, BNX2_MISC_CFG); - REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC); + case ETHTOOL_ID_ON: + REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE | + BNX2_EMAC_LED_1000MB_OVERRIDE | + BNX2_EMAC_LED_100MB_OVERRIDE | + BNX2_EMAC_LED_10MB_OVERRIDE | + BNX2_EMAC_LED_TRAFFIC_OVERRIDE | + BNX2_EMAC_LED_TRAFFIC); + break; - for (i = 0; i < (data * 2); i++) { - if ((i % 2) == 0) { - REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE); - } - else { - REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE | - BNX2_EMAC_LED_1000MB_OVERRIDE | - BNX2_EMAC_LED_100MB_OVERRIDE | - BNX2_EMAC_LED_10MB_OVERRIDE | - BNX2_EMAC_LED_TRAFFIC_OVERRIDE | - BNX2_EMAC_LED_TRAFFIC); - } - msleep_interruptible(500); - if (signal_pending(current)) - break; + case ETHTOOL_ID_OFF: + REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE); + break; + + case ETHTOOL_ID_INACTIVE: + REG_WR(bp, BNX2_EMAC_LED, 0); + REG_WR(bp, BNX2_MISC_CFG, bp->leds_save); + + if (!netif_running(dev)) + bnx2_set_power_state(bp, PCI_D3hot); + break; } - REG_WR(bp, BNX2_EMAC_LED, 0); - REG_WR(bp, BNX2_MISC_CFG, save); - - if (!netif_running(dev)) - bnx2_set_power_state(bp, PCI_D3hot); return 0; } -static int -bnx2_set_tx_csum(struct net_device *dev, u32 data) +static u32 +bnx2_fix_features(struct net_device *dev, u32 features) { struct bnx2 *bp = netdev_priv(dev); - if (CHIP_NUM(bp) == CHIP_NUM_5709) - return ethtool_op_set_tx_ipv6_csum(dev, data); - else - return ethtool_op_set_tx_csum(dev, data); + if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)) + features |= NETIF_F_HW_VLAN_RX; + + return features; } static int -bnx2_set_flags(struct net_device *dev, u32 data) +bnx2_set_features(struct net_device *dev, u32 features) { struct bnx2 *bp = netdev_priv(dev); - int rc; - - if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN) && - !(data & ETH_FLAG_RXVLAN)) - return -EINVAL; /* TSO with VLAN tag won't work with current firmware */ - if (!(data & ETH_FLAG_TXVLAN)) - return -EINVAL; + if (features & NETIF_F_HW_VLAN_TX) + dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO); + else + dev->vlan_features &= ~NETIF_F_ALL_TSO; - rc = ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH | ETH_FLAG_RXVLAN | - ETH_FLAG_TXVLAN); - if (rc) - return rc; - - if ((!!(data & ETH_FLAG_RXVLAN) != + if ((!!(features & NETIF_F_HW_VLAN_RX) != !!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) && netif_running(dev)) { bnx2_netif_stop(bp, false); + dev->features = features; bnx2_set_rx_mode(dev); bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1); bnx2_netif_start(bp, false); + return 1; } return 0; @@ -7595,18 +7554,11 @@ static const struct ethtool_ops bnx2_ethtool_ops = { .set_ringparam = bnx2_set_ringparam, .get_pauseparam = bnx2_get_pauseparam, .set_pauseparam = bnx2_set_pauseparam, - .get_rx_csum = bnx2_get_rx_csum, - .set_rx_csum = bnx2_set_rx_csum, - .set_tx_csum = bnx2_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = bnx2_set_tso, .self_test = bnx2_self_test, .get_strings = bnx2_get_strings, - .phys_id = bnx2_phys_id, + .set_phys_id = bnx2_set_phys_id, .get_ethtool_stats = bnx2_get_ethtool_stats, .get_sset_count = bnx2_get_sset_count, - .set_flags = bnx2_set_flags, - .get_flags = ethtool_op_get_flags, }; /* Called with rtnl_lock */ @@ -8118,8 +8070,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->tx_ring_size = MAX_TX_DESC_CNT; bnx2_set_rx_ring_size(bp, 255); - bp->rx_csum = 1; - bp->tx_quick_cons_trip_int = 2; bp->tx_quick_cons_trip = 20; bp->tx_ticks_int = 18; @@ -8311,17 +8261,14 @@ static const struct net_device_ops bnx2_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = bnx2_change_mac_addr, .ndo_change_mtu = bnx2_change_mtu, + .ndo_fix_features = bnx2_fix_features, + .ndo_set_features = bnx2_set_features, .ndo_tx_timeout = bnx2_tx_timeout, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = poll_bnx2, #endif }; -static inline void vlan_features_add(struct net_device *dev, u32 flags) -{ - dev->vlan_features |= flags; -} - static int __devinit bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -8361,20 +8308,17 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) memcpy(dev->dev_addr, bp->mac_addr, 6); memcpy(dev->perm_addr, bp->mac_addr, 6); - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO | - NETIF_F_RXHASH; - vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG); - if (CHIP_NUM(bp) == CHIP_NUM_5709) { - dev->features |= NETIF_F_IPV6_CSUM; - vlan_features_add(dev, NETIF_F_IPV6_CSUM); - } - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; - vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN); - if (CHIP_NUM(bp) == CHIP_NUM_5709) { - dev->features |= NETIF_F_TSO6; - vlan_features_add(dev, NETIF_F_TSO6); - } + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_TSO_ECN | + NETIF_F_RXHASH | NETIF_F_RXCSUM; + + if (CHIP_NUM(bp) == CHIP_NUM_5709) + dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + + dev->vlan_features = dev->hw_features; + dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->features |= dev->hw_features; + if ((rc = register_netdev(dev))) { dev_err(&pdev->dev, "Cannot register net device\n"); goto error; @@ -8413,6 +8357,8 @@ bnx2_remove_one(struct pci_dev *pdev) unregister_netdev(dev); + del_timer_sync(&bp->timer); + if (bp->mips_firmware) release_firmware(bp->mips_firmware); if (bp->rv2p_firmware) diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 68020451dc4f..bf371f6fe154 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6754,8 +6754,6 @@ struct bnx2 { u32 rx_max_ring_idx; u32 rx_max_pg_ring_idx; - u32 rx_csum; - /* TX constants */ int tx_ring_size; u32 tx_wake_thresh; @@ -6922,6 +6920,7 @@ struct bnx2 { u8 num_tx_rings; u8 num_rx_rings; + u32 leds_save; u32 idle_chk_status_idx; #ifdef BCM_CNIC diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index e0fca701d2f3..668a578c49e9 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -1,6 +1,6 @@ /* bnx2x.h: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 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 @@ -22,8 +22,8 @@ * (you will need to reboot afterwards) */ /* #define BNX2X_STOP_ON_ERROR */ -#define DRV_MODULE_VERSION "1.62.11-0" -#define DRV_MODULE_RELDATE "2011/01/31" +#define DRV_MODULE_VERSION "1.62.12-0" +#define DRV_MODULE_RELDATE "2011/03/20" #define BNX2X_BC_VER 0x040200 #define BNX2X_MULTI_QUEUE @@ -473,7 +473,8 @@ struct bnx2x_fastpath { #define NUM_RX_BD (RX_DESC_CNT * NUM_RX_RINGS) #define MAX_RX_BD (NUM_RX_BD - 1) #define MAX_RX_AVAIL (MAX_RX_DESC_CNT * NUM_RX_RINGS - 2) -#define MIN_RX_AVAIL 128 +#define MIN_RX_SIZE_TPA 72 +#define MIN_RX_SIZE_NONTPA 10 #define INIT_JUMBO_RX_RING_SIZE MAX_RX_AVAIL #define INIT_RX_RING_SIZE MAX_RX_AVAIL #define NEXT_RX_IDX(x) ((((x) & RX_DESC_MASK) == \ @@ -893,6 +894,22 @@ typedef enum { (&bp->def_status_blk->sp_sb.\ index_values[HC_SP_INDEX_EQ_CONS]) +/* This is a data that will be used to create a link report message. + * We will keep the data used for the last link report in order + * to prevent reporting the same link parameters twice. + */ +struct bnx2x_link_report_data { + u16 line_speed; /* Effective line speed */ + unsigned long link_report_flags;/* BNX2X_LINK_REPORT_XXX flags */ +}; + +enum { + BNX2X_LINK_REPORT_FD, /* Full DUPLEX */ + BNX2X_LINK_REPORT_LINK_DOWN, + BNX2X_LINK_REPORT_RX_FC_ON, + BNX2X_LINK_REPORT_TX_FC_ON, +}; + struct bnx2x { /* Fields used in the tx and intr/napi performance paths * are grouped together in the beginning of the structure @@ -918,7 +935,6 @@ struct bnx2x { int tx_ring_size; - u32 rx_csum; /* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */ #define ETH_OVREHEAD (ETH_HLEN + 8 + 8) #define ETH_MIN_PACKET_SIZE 60 @@ -1026,6 +1042,9 @@ struct bnx2x { struct link_params link_params; struct link_vars link_vars; + u32 link_cnt; + struct bnx2x_link_report_data last_reported_link; + struct mdio_if_info mdio; struct bnx2x_common common; @@ -1223,6 +1242,10 @@ struct bnx2x { /* DCBX Negotiation results */ struct dcbx_features dcbx_local_feat; u32 dcbx_error; +#ifdef BCM_DCBNL + struct dcbx_features dcbx_remote_feat; + u32 dcbx_remote_flags; +#endif u32 pending_max; }; @@ -1442,6 +1465,8 @@ struct bnx2x_func_init_params { #define WAIT_RAMROD_POLL 0x01 #define WAIT_RAMROD_COMMON 0x02 +void bnx2x_read_mf_cfg(struct bnx2x *bp); + /* dmae */ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32); void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index e83ac6dd6fc0..ca2bbc0e5d48 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -1,6 +1,6 @@ /* bnx2x_cmn.c: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 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 @@ -27,6 +27,49 @@ static int bnx2x_setup_irqs(struct bnx2x *bp); +/** + * bnx2x_bz_fp - zero content of the fastpath structure. + * + * @bp: driver handle + * @index: fastpath index to be zeroed + * + * Makes sure the contents of the bp->fp[index].napi is kept + * intact. + */ +static inline void bnx2x_bz_fp(struct bnx2x *bp, int index) +{ + struct bnx2x_fastpath *fp = &bp->fp[index]; + struct napi_struct orig_napi = fp->napi; + /* bzero bnx2x_fastpath contents */ + memset(fp, 0, sizeof(*fp)); + + /* Restore the NAPI object as it has been already initialized */ + fp->napi = orig_napi; +} + +/** + * bnx2x_move_fp - move content of the fastpath structure. + * + * @bp: driver handle + * @from: source FP index + * @to: destination FP index + * + * Makes sure the contents of the bp->fp[to].napi is kept + * intact. + */ +static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to) +{ + struct bnx2x_fastpath *from_fp = &bp->fp[from]; + struct bnx2x_fastpath *to_fp = &bp->fp[to]; + struct napi_struct orig_napi = to_fp->napi; + /* Move bnx2x_fastpath contents */ + memcpy(to_fp, from_fp, sizeof(*to_fp)); + to_fp->index = to; + + /* Restore the NAPI object as it has been already initialized */ + to_fp->napi = orig_napi; +} + /* free skb in the packet ring at pos idx * return idx of last bd freed */ @@ -265,13 +308,15 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue, */ #define TPA_TSTAMP_OPT_LEN 12 /** - * Calculate the approximate value of the MSS for this - * aggregation using the first packet of it. + * bnx2x_set_lro_mss - calculate the approximate value of the MSS * - * @param bp - * @param parsing_flags Parsing flags from the START CQE - * @param len_on_bd Total length of the first packet for the - * aggregation. + * @bp: driver handle + * @parsing_flags: parsing flags from the START CQE + * @len_on_bd: total length of the first packet for the + * aggregation. + * + * Approximate value of the MSS for this aggregation calculated using + * the first packet of it. */ static inline u16 bnx2x_set_lro_mss(struct bnx2x *bp, u16 parsing_flags, u16 len_on_bd) @@ -640,7 +685,7 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) skb_checksum_none_assert(skb); - if (bp->rx_csum) { + if (bp->dev->features & NETIF_F_RXCSUM) { if (likely(BNX2X_RX_CSUM_OK(cqe))) skb->ip_summed = CHECKSUM_UNNECESSARY; else @@ -758,35 +803,119 @@ u16 bnx2x_get_mf_speed(struct bnx2x *bp) return line_speed; } +/** + * bnx2x_fill_report_data - fill link report data to report + * + * @bp: driver handle + * @data: link state to update + * + * It uses a none-atomic bit operations because is called under the mutex. + */ +static inline void bnx2x_fill_report_data(struct bnx2x *bp, + struct bnx2x_link_report_data *data) +{ + u16 line_speed = bnx2x_get_mf_speed(bp); + + memset(data, 0, sizeof(*data)); + + /* Fill the report data: efective line speed */ + data->line_speed = line_speed; + + /* Link is down */ + if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS)) + __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &data->link_report_flags); + + /* Full DUPLEX */ + if (bp->link_vars.duplex == DUPLEX_FULL) + __set_bit(BNX2X_LINK_REPORT_FD, &data->link_report_flags); + + /* Rx Flow Control is ON */ + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) + __set_bit(BNX2X_LINK_REPORT_RX_FC_ON, &data->link_report_flags); + + /* Tx Flow Control is ON */ + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) + __set_bit(BNX2X_LINK_REPORT_TX_FC_ON, &data->link_report_flags); +} + +/** + * bnx2x_link_report - report link status to OS. + * + * @bp: driver handle + * + * Calls the __bnx2x_link_report() under the same locking scheme + * as a link/PHY state managing code to ensure a consistent link + * reporting. + */ + void bnx2x_link_report(struct bnx2x *bp) { - if (bp->flags & MF_FUNC_DIS) { + bnx2x_acquire_phy_lock(bp); + __bnx2x_link_report(bp); + bnx2x_release_phy_lock(bp); +} + +/** + * __bnx2x_link_report - report link status to OS. + * + * @bp: driver handle + * + * None atomic inmlementation. + * Should be called under the phy_lock. + */ +void __bnx2x_link_report(struct bnx2x *bp) +{ + struct bnx2x_link_report_data cur_data; + + /* reread mf_cfg */ + if (!CHIP_IS_E1(bp)) + bnx2x_read_mf_cfg(bp); + + /* Read the current link report info */ + bnx2x_fill_report_data(bp, &cur_data); + + /* Don't report link down or exactly the same link status twice */ + if (!memcmp(&cur_data, &bp->last_reported_link, sizeof(cur_data)) || + (test_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &bp->last_reported_link.link_report_flags) && + test_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &cur_data.link_report_flags))) + return; + + bp->link_cnt++; + + /* We are going to report a new link parameters now - + * remember the current data for the next time. + */ + memcpy(&bp->last_reported_link, &cur_data, sizeof(cur_data)); + + if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &cur_data.link_report_flags)) { netif_carrier_off(bp->dev); netdev_err(bp->dev, "NIC Link is Down\n"); return; - } - - if (bp->link_vars.link_up) { - u16 line_speed; - - if (bp->state == BNX2X_STATE_OPEN) - netif_carrier_on(bp->dev); + } else { + netif_carrier_on(bp->dev); netdev_info(bp->dev, "NIC Link is Up, "); + pr_cont("%d Mbps ", cur_data.line_speed); - line_speed = bnx2x_get_mf_speed(bp); - - pr_cont("%d Mbps ", line_speed); - - if (bp->link_vars.duplex == DUPLEX_FULL) + if (test_and_clear_bit(BNX2X_LINK_REPORT_FD, + &cur_data.link_report_flags)) pr_cont("full duplex"); else pr_cont("half duplex"); - if (bp->link_vars.flow_ctrl != BNX2X_FLOW_CTRL_NONE) { - if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) { + /* Handle the FC at the end so that only these flags would be + * possibly set. This way we may easily check if there is no FC + * enabled. + */ + if (cur_data.link_report_flags) { + if (test_bit(BNX2X_LINK_REPORT_RX_FC_ON, + &cur_data.link_report_flags)) { pr_cont(", receive "); - if (bp->link_vars.flow_ctrl & - BNX2X_FLOW_CTRL_TX) + if (test_bit(BNX2X_LINK_REPORT_TX_FC_ON, + &cur_data.link_report_flags)) pr_cont("& transmit "); } else { pr_cont(", transmit "); @@ -794,62 +923,9 @@ void bnx2x_link_report(struct bnx2x *bp) pr_cont("flow control ON"); } pr_cont("\n"); - - } else { /* link_down */ - netif_carrier_off(bp->dev); - netdev_err(bp->dev, "NIC Link is Down\n"); } } -/* Returns the number of actually allocated BDs */ -static inline int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp, - int rx_ring_size) -{ - struct bnx2x *bp = fp->bp; - u16 ring_prod, cqe_ring_prod; - int i; - - fp->rx_comp_cons = 0; - cqe_ring_prod = ring_prod = 0; - for (i = 0; i < rx_ring_size; i++) { - if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) { - BNX2X_ERR("was only able to allocate " - "%d rx skbs on queue[%d]\n", i, fp->index); - fp->eth_q_stats.rx_skb_alloc_failed++; - break; - } - ring_prod = NEXT_RX_IDX(ring_prod); - cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod); - WARN_ON(ring_prod <= i); - } - - fp->rx_bd_prod = ring_prod; - /* Limit the CQE producer by the CQE ring size */ - fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT, - cqe_ring_prod); - fp->rx_pkt = fp->rx_calls = 0; - - return i; -} - -static inline void bnx2x_alloc_rx_bd_ring(struct bnx2x_fastpath *fp) -{ - struct bnx2x *bp = fp->bp; - int rx_ring_size = bp->rx_ring_size ? bp->rx_ring_size : - MAX_RX_AVAIL/bp->num_queues; - - rx_ring_size = max_t(int, MIN_RX_AVAIL, rx_ring_size); - - bnx2x_alloc_rx_bds(fp, rx_ring_size); - - /* Warning! - * this will generate an interrupt (to the TSTORM) - * must only be done after chip is initialized - */ - bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod, - fp->rx_sge_prod); -} - void bnx2x_init_rx_rings(struct bnx2x *bp) { int func = BP_FUNC(bp); @@ -858,6 +934,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp) u16 ring_prod; int i, j; + /* Allocate TPA resources */ for_each_rx_queue(bp, j) { struct bnx2x_fastpath *fp = &bp->fp[j]; @@ -865,6 +942,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp) "mtu %d rx_buf_size %d\n", bp->dev->mtu, fp->rx_buf_size); if (!fp->disable_tpa) { + /* Fill the per-aggregation pool */ for (i = 0; i < max_agg_queues; i++) { fp->tpa_pool[i].skb = netdev_alloc_skb(bp->dev, fp->rx_buf_size); @@ -919,13 +997,13 @@ void bnx2x_init_rx_rings(struct bnx2x *bp) fp->rx_bd_cons = 0; - bnx2x_set_next_page_rx_bd(fp); - - /* CQ ring */ - bnx2x_set_next_page_rx_cq(fp); - - /* Allocate BDs and initialize BD ring */ - bnx2x_alloc_rx_bd_ring(fp); + /* Activate BD ring */ + /* Warning! + * this will generate an interrupt (to the TSTORM) + * must only be done after chip is initialized + */ + bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod, + fp->rx_sge_prod); if (j != 0) continue; @@ -959,27 +1037,40 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp) } } +static void bnx2x_free_rx_bds(struct bnx2x_fastpath *fp) +{ + struct bnx2x *bp = fp->bp; + int i; + + /* ring wasn't allocated */ + if (fp->rx_buf_ring == NULL) + return; + + for (i = 0; i < NUM_RX_BD; i++) { + struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i]; + struct sk_buff *skb = rx_buf->skb; + + if (skb == NULL) + continue; + + dma_unmap_single(&bp->pdev->dev, + dma_unmap_addr(rx_buf, mapping), + fp->rx_buf_size, DMA_FROM_DEVICE); + + rx_buf->skb = NULL; + dev_kfree_skb(skb); + } +} + static void bnx2x_free_rx_skbs(struct bnx2x *bp) { - int i, j; + int j; for_each_rx_queue(bp, j) { struct bnx2x_fastpath *fp = &bp->fp[j]; - for (i = 0; i < NUM_RX_BD; i++) { - struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i]; - struct sk_buff *skb = rx_buf->skb; + bnx2x_free_rx_bds(fp); - if (skb == NULL) - continue; - - dma_unmap_single(&bp->pdev->dev, - dma_unmap_addr(rx_buf, mapping), - fp->rx_buf_size, DMA_FROM_DEVICE); - - rx_buf->skb = NULL; - dev_kfree_skb(skb); - } if (!fp->disable_tpa) bnx2x_free_tpa_pool(bp, fp, CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 : @@ -1345,21 +1436,25 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD; + /* Set the initial link reported state to link down */ + bnx2x_acquire_phy_lock(bp); + memset(&bp->last_reported_link, 0, sizeof(bp->last_reported_link)); + __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &bp->last_reported_link.link_report_flags); + bnx2x_release_phy_lock(bp); + /* must be called before memory allocation and HW init */ bnx2x_ilt_set_info(bp); + /* zero fastpath structures preserving invariants like napi which are + * allocated only once + */ + for_each_queue(bp, i) + bnx2x_bz_fp(bp, i); + /* Set the receive queues buffer size */ bnx2x_set_rx_buf_size(bp); - if (bnx2x_alloc_mem(bp)) - return -ENOMEM; - - rc = bnx2x_set_real_num_queues(bp); - if (rc) { - BNX2X_ERR("Unable to set real_num_queues\n"); - goto load_error0; - } - for_each_queue(bp, i) bnx2x_fp(bp, i, disable_tpa) = ((bp->flags & TPA_ENABLE_FLAG) == 0); @@ -1368,6 +1463,20 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* We don't want TPA on FCoE L2 ring */ bnx2x_fcoe(bp, disable_tpa) = 1; #endif + + if (bnx2x_alloc_mem(bp)) + return -ENOMEM; + + /* As long as bnx2x_alloc_mem() may possibly update + * bp->num_queues, bnx2x_set_real_num_queues() should always + * come after it. + */ + rc = bnx2x_set_real_num_queues(bp); + if (rc) { + BNX2X_ERR("Unable to set real_num_queues\n"); + goto load_error0; + } + bnx2x_napi_enable(bp); /* Send LOAD_REQUEST command to MCP @@ -1976,12 +2085,11 @@ static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data, } /** - * Update PBD in GSO case. + * bnx2x_set_pbd_gso - update PBD in GSO case. * - * @param skb - * @param tx_start_bd - * @param pbd - * @param xmit_type + * @skb: packet skb + * @pbd: parse BD + * @xmit_type: xmit flags */ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb, struct eth_tx_parse_bd_e1x *pbd, @@ -2008,42 +2116,50 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb, } /** + * bnx2x_set_pbd_csum_e2 - update PBD with checksum and return header length * - * @param skb - * @param tx_start_bd - * @param pbd_e2 - * @param xmit_type + * @bp: driver handle + * @skb: packet skb + * @parsing_data: data to be updated + * @xmit_type: xmit flags * - * @return header len + * 57712 related */ static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, u32 *parsing_data, u32 xmit_type) { - *parsing_data |= ((tcp_hdrlen(skb)/4) << - ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & - ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; + *parsing_data |= + ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) << + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W; - *parsing_data |= ((((u8 *)tcp_hdr(skb) - skb->data) / 2) << - ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) & - ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W; + if (xmit_type & XMIT_CSUM_TCP) { + *parsing_data |= ((tcp_hdrlen(skb) / 4) << + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; - return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; + return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; + } else + /* We support checksum offload for TCP and UDP only. + * No need to pass the UDP header length - it's a constant. + */ + return skb_transport_header(skb) + + sizeof(struct udphdr) - skb->data; } /** + * bnx2x_set_pbd_csum - update PBD with checksum and return header length * - * @param skb - * @param tx_start_bd - * @param pbd - * @param xmit_type - * - * @return Header length + * @bp: driver handle + * @skb: packet skb + * @pbd: parse BD to be updated + * @xmit_type: xmit flags */ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, struct eth_tx_parse_bd_e1x *pbd, u32 xmit_type) { - u8 hlen = (skb_network_header(skb) - skb->data) / 2; + u8 hlen = (skb_network_header(skb) - skb->data) >> 1; /* for now NS flag is not used in Linux */ pbd->global_data = @@ -2051,9 +2167,15 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT)); pbd->ip_hlen_w = (skb_transport_header(skb) - - skb_network_header(skb)) / 2; + skb_network_header(skb)) >> 1; - hlen += pbd->ip_hlen_w + tcp_hdrlen(skb) / 2; + hlen += pbd->ip_hlen_w; + + /* We support checksum offload for TCP and UDP only */ + if (xmit_type & XMIT_CSUM_TCP) + hlen += tcp_hdrlen(skb) / 2; + else + hlen += sizeof(struct udphdr) / 2; pbd->total_hlen_w = cpu_to_le16(hlen); hlen = hlen*2; @@ -2379,6 +2501,232 @@ int bnx2x_change_mac_addr(struct net_device *dev, void *p) return 0; } +static void bnx2x_free_fp_mem_at(struct bnx2x *bp, int fp_index) +{ + union host_hc_status_block *sb = &bnx2x_fp(bp, fp_index, status_blk); + struct bnx2x_fastpath *fp = &bp->fp[fp_index]; + + /* Common */ +#ifdef BCM_CNIC + if (IS_FCOE_IDX(fp_index)) { + memset(sb, 0, sizeof(union host_hc_status_block)); + fp->status_blk_mapping = 0; + + } else { +#endif + /* status blocks */ + if (CHIP_IS_E2(bp)) + BNX2X_PCI_FREE(sb->e2_sb, + bnx2x_fp(bp, fp_index, + status_blk_mapping), + sizeof(struct host_hc_status_block_e2)); + else + BNX2X_PCI_FREE(sb->e1x_sb, + bnx2x_fp(bp, fp_index, + status_blk_mapping), + sizeof(struct host_hc_status_block_e1x)); +#ifdef BCM_CNIC + } +#endif + /* Rx */ + if (!skip_rx_queue(bp, fp_index)) { + bnx2x_free_rx_bds(fp); + + /* fastpath rx rings: rx_buf rx_desc rx_comp */ + BNX2X_FREE(bnx2x_fp(bp, fp_index, rx_buf_ring)); + BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_desc_ring), + bnx2x_fp(bp, fp_index, rx_desc_mapping), + sizeof(struct eth_rx_bd) * NUM_RX_BD); + + BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_comp_ring), + bnx2x_fp(bp, fp_index, rx_comp_mapping), + sizeof(struct eth_fast_path_rx_cqe) * + NUM_RCQ_BD); + + /* SGE ring */ + BNX2X_FREE(bnx2x_fp(bp, fp_index, rx_page_ring)); + BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_sge_ring), + bnx2x_fp(bp, fp_index, rx_sge_mapping), + BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); + } + + /* Tx */ + if (!skip_tx_queue(bp, fp_index)) { + /* fastpath tx rings: tx_buf tx_desc */ + BNX2X_FREE(bnx2x_fp(bp, fp_index, tx_buf_ring)); + BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, tx_desc_ring), + bnx2x_fp(bp, fp_index, tx_desc_mapping), + sizeof(union eth_tx_bd_types) * NUM_TX_BD); + } + /* end of fastpath */ +} + +void bnx2x_free_fp_mem(struct bnx2x *bp) +{ + int i; + for_each_queue(bp, i) + bnx2x_free_fp_mem_at(bp, i); +} + +static inline void set_sb_shortcuts(struct bnx2x *bp, int index) +{ + union host_hc_status_block status_blk = bnx2x_fp(bp, index, status_blk); + if (CHIP_IS_E2(bp)) { + bnx2x_fp(bp, index, sb_index_values) = + (__le16 *)status_blk.e2_sb->sb.index_values; + bnx2x_fp(bp, index, sb_running_index) = + (__le16 *)status_blk.e2_sb->sb.running_index; + } else { + bnx2x_fp(bp, index, sb_index_values) = + (__le16 *)status_blk.e1x_sb->sb.index_values; + bnx2x_fp(bp, index, sb_running_index) = + (__le16 *)status_blk.e1x_sb->sb.running_index; + } +} + +static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index) +{ + union host_hc_status_block *sb; + struct bnx2x_fastpath *fp = &bp->fp[index]; + int ring_size = 0; + + /* if rx_ring_size specified - use it */ + int rx_ring_size = bp->rx_ring_size ? bp->rx_ring_size : + MAX_RX_AVAIL/bp->num_queues; + + /* allocate at least number of buffers required by FW */ + rx_ring_size = max_t(int, fp->disable_tpa ? MIN_RX_SIZE_NONTPA : + MIN_RX_SIZE_TPA, + rx_ring_size); + + bnx2x_fp(bp, index, bp) = bp; + bnx2x_fp(bp, index, index) = index; + + /* Common */ + sb = &bnx2x_fp(bp, index, status_blk); +#ifdef BCM_CNIC + if (!IS_FCOE_IDX(index)) { +#endif + /* status blocks */ + if (CHIP_IS_E2(bp)) + BNX2X_PCI_ALLOC(sb->e2_sb, + &bnx2x_fp(bp, index, status_blk_mapping), + sizeof(struct host_hc_status_block_e2)); + else + BNX2X_PCI_ALLOC(sb->e1x_sb, + &bnx2x_fp(bp, index, status_blk_mapping), + sizeof(struct host_hc_status_block_e1x)); +#ifdef BCM_CNIC + } +#endif + set_sb_shortcuts(bp, index); + + /* Tx */ + if (!skip_tx_queue(bp, index)) { + /* fastpath tx rings: tx_buf tx_desc */ + BNX2X_ALLOC(bnx2x_fp(bp, index, tx_buf_ring), + sizeof(struct sw_tx_bd) * NUM_TX_BD); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, tx_desc_ring), + &bnx2x_fp(bp, index, tx_desc_mapping), + sizeof(union eth_tx_bd_types) * NUM_TX_BD); + } + + /* Rx */ + if (!skip_rx_queue(bp, index)) { + /* fastpath rx rings: rx_buf rx_desc rx_comp */ + BNX2X_ALLOC(bnx2x_fp(bp, index, rx_buf_ring), + sizeof(struct sw_rx_bd) * NUM_RX_BD); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_desc_ring), + &bnx2x_fp(bp, index, rx_desc_mapping), + sizeof(struct eth_rx_bd) * NUM_RX_BD); + + BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_comp_ring), + &bnx2x_fp(bp, index, rx_comp_mapping), + sizeof(struct eth_fast_path_rx_cqe) * + NUM_RCQ_BD); + + /* SGE ring */ + BNX2X_ALLOC(bnx2x_fp(bp, index, rx_page_ring), + sizeof(struct sw_rx_page) * NUM_RX_SGE); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_sge_ring), + &bnx2x_fp(bp, index, rx_sge_mapping), + BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); + /* RX BD ring */ + bnx2x_set_next_page_rx_bd(fp); + + /* CQ ring */ + bnx2x_set_next_page_rx_cq(fp); + + /* BDs */ + ring_size = bnx2x_alloc_rx_bds(fp, rx_ring_size); + if (ring_size < rx_ring_size) + goto alloc_mem_err; + } + + return 0; + +/* handles low memory cases */ +alloc_mem_err: + BNX2X_ERR("Unable to allocate full memory for queue %d (size %d)\n", + index, ring_size); + /* FW will drop all packets if queue is not big enough, + * In these cases we disable the queue + * Min size diferent for TPA and non-TPA queues + */ + if (ring_size < (fp->disable_tpa ? + MIN_RX_SIZE_TPA : MIN_RX_SIZE_NONTPA)) { + /* release memory allocated for this queue */ + bnx2x_free_fp_mem_at(bp, index); + return -ENOMEM; + } + return 0; +} + +int bnx2x_alloc_fp_mem(struct bnx2x *bp) +{ + int i; + + /** + * 1. Allocate FP for leading - fatal if error + * 2. {CNIC} Allocate FCoE FP - fatal if error + * 3. Allocate RSS - fix number of queues if error + */ + + /* leading */ + if (bnx2x_alloc_fp_mem_at(bp, 0)) + return -ENOMEM; +#ifdef BCM_CNIC + /* FCoE */ + if (bnx2x_alloc_fp_mem_at(bp, FCOE_IDX)) + return -ENOMEM; +#endif + /* RSS */ + for_each_nondefault_eth_queue(bp, i) + if (bnx2x_alloc_fp_mem_at(bp, i)) + break; + + /* handle memory failures */ + if (i != BNX2X_NUM_ETH_QUEUES(bp)) { + int delta = BNX2X_NUM_ETH_QUEUES(bp) - i; + + WARN_ON(delta < 0); +#ifdef BCM_CNIC + /** + * move non eth FPs next to last eth FP + * must be done in that order + * FCOE_IDX < FWD_IDX < OOO_IDX + */ + + /* move FCoE fp */ + bnx2x_move_fp(bp, FCOE_IDX, FCOE_IDX - delta); +#endif + bp->num_queues -= delta; + BNX2X_ERR("Adjusted num of queues from %d to %d\n", + bp->num_queues + delta, bp->num_queues); + } + + return 0; +} static int bnx2x_setup_irqs(struct bnx2x *bp) { @@ -2443,11 +2791,21 @@ int __devinit bnx2x_alloc_mem_bp(struct bnx2x *bp) } +static int bnx2x_reload_if_running(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (unlikely(!netif_running(dev))) + return 0; + + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + return bnx2x_nic_load(bp, LOAD_NORMAL); +} + /* called with rtnl_lock */ int bnx2x_change_mtu(struct net_device *dev, int new_mtu) { struct bnx2x *bp = netdev_priv(dev); - int rc = 0; if (bp->recovery_state != BNX2X_RECOVERY_DONE) { printk(KERN_ERR "Handling parity error recovery. Try again later\n"); @@ -2464,12 +2822,55 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu) */ dev->mtu = new_mtu; - if (netif_running(dev)) { - bnx2x_nic_unload(bp, UNLOAD_NORMAL); - rc = bnx2x_nic_load(bp, LOAD_NORMAL); + return bnx2x_reload_if_running(dev); +} + +u32 bnx2x_fix_features(struct net_device *dev, u32 features) +{ + struct bnx2x *bp = netdev_priv(dev); + + /* TPA requires Rx CSUM offloading */ + if (!(features & NETIF_F_RXCSUM) || bp->disable_tpa) + features &= ~NETIF_F_LRO; + + return features; +} + +int bnx2x_set_features(struct net_device *dev, u32 features) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 flags = bp->flags; + bool bnx2x_reload = false; + + if (features & NETIF_F_LRO) + flags |= TPA_ENABLE_FLAG; + else + flags &= ~TPA_ENABLE_FLAG; + + if (features & NETIF_F_LOOPBACK) { + if (bp->link_params.loopback_mode != LOOPBACK_BMAC) { + bp->link_params.loopback_mode = LOOPBACK_BMAC; + bnx2x_reload = true; + } + } else { + if (bp->link_params.loopback_mode != LOOPBACK_NONE) { + bp->link_params.loopback_mode = LOOPBACK_NONE; + bnx2x_reload = true; + } } - return rc; + if (flags ^ bp->flags) { + bp->flags = flags; + bnx2x_reload = true; + } + + if (bnx2x_reload) { + if (bp->recovery_state == BNX2X_RECOVERY_DONE) + return bnx2x_reload_if_running(dev); + /* else: bnx2x_nic_load() will be called at end of recovery */ + } + + return 0; } void bnx2x_tx_timeout(struct net_device *dev) diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h index ef37b98d6146..fab161e8030d 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.h +++ b/drivers/net/bnx2x/bnx2x_cmn.h @@ -1,6 +1,6 @@ /* bnx2x_cmn.h: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 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 @@ -25,260 +25,277 @@ extern int num_queues; +/************************ Macros ********************************/ +#define BNX2X_PCI_FREE(x, y, size) \ + do { \ + if (x) { \ + dma_free_coherent(&bp->pdev->dev, size, (void *)x, y); \ + x = NULL; \ + y = 0; \ + } \ + } while (0) + +#define BNX2X_FREE(x) \ + do { \ + if (x) { \ + kfree((void *)x); \ + x = NULL; \ + } \ + } while (0) + +#define BNX2X_PCI_ALLOC(x, y, size) \ + do { \ + x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ + if (x == NULL) \ + goto alloc_mem_err; \ + memset((void *)x, 0, size); \ + } while (0) + +#define BNX2X_ALLOC(x, size) \ + do { \ + x = kzalloc(size, GFP_KERNEL); \ + if (x == NULL) \ + goto alloc_mem_err; \ + } while (0) + /*********************** Interfaces **************************** * Functions that need to be implemented by each driver version */ /** - * Initialize link parameters structure variables. + * bnx2x_initial_phy_init - initialize link parameters structure variables. * - * @param bp - * @param load_mode - * - * @return u8 + * @bp: driver handle + * @load_mode: current mode */ u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode); /** - * Configure hw according to link parameters structure. + * bnx2x_link_set - configure hw according to link parameters structure. * - * @param bp + * @bp: driver handle */ void bnx2x_link_set(struct bnx2x *bp); /** - * Query link status + * bnx2x_link_test - query link status. * - * @param bp - * @param is_serdes + * @bp: driver handle + * @is_serdes: bool * - * @return 0 - link is UP + * Returns 0 if link is UP. */ u8 bnx2x_link_test(struct bnx2x *bp, u8 is_serdes); /** - * Handles link status change + * bnx2x__link_status_update - handles link status change. * - * @param bp + * @bp: driver handle */ void bnx2x__link_status_update(struct bnx2x *bp); /** - * Report link status to upper layer + * bnx2x_link_report - report link status to upper layer. * - * @param bp - * - * @return int + * @bp: driver handle */ void bnx2x_link_report(struct bnx2x *bp); +/* None-atomic version of bnx2x_link_report() */ +void __bnx2x_link_report(struct bnx2x *bp); + /** - * calculates MF speed according to current linespeed and MF - * configuration + * bnx2x_get_mf_speed - calculate MF speed. * - * @param bp + * @bp: driver handle * - * @return u16 + * Takes into account current linespeed and MF configuration. */ u16 bnx2x_get_mf_speed(struct bnx2x *bp); /** - * MSI-X slowpath interrupt handler + * bnx2x_msix_sp_int - MSI-X slowpath interrupt handler * - * @param irq - * @param dev_instance - * - * @return irqreturn_t + * @irq: irq number + * @dev_instance: private instance */ irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance); /** - * non MSI-X interrupt handler + * bnx2x_interrupt - non MSI-X interrupt handler * - * @param irq - * @param dev_instance - * - * @return irqreturn_t + * @irq: irq number + * @dev_instance: private instance */ irqreturn_t bnx2x_interrupt(int irq, void *dev_instance); #ifdef BCM_CNIC /** - * Send command to cnic driver + * bnx2x_cnic_notify - send command to cnic driver * - * @param bp - * @param cmd + * @bp: driver handle + * @cmd: command */ int bnx2x_cnic_notify(struct bnx2x *bp, int cmd); /** - * Provides cnic information for proper interrupt handling + * bnx2x_setup_cnic_irq_info - provides cnic with IRQ information * - * @param bp + * @bp: driver handle */ void bnx2x_setup_cnic_irq_info(struct bnx2x *bp); #endif /** - * Enable HW interrupts. + * bnx2x_int_enable - enable HW interrupts. * - * @param bp + * @bp: driver handle */ void bnx2x_int_enable(struct bnx2x *bp); /** - * Disable interrupts. This function ensures that there are no - * ISRs or SP DPCs (sp_task) are running after it returns. + * bnx2x_int_disable_sync - disable interrupts. * - * @param bp - * @param disable_hw if true, disable HW interrupts. + * @bp: driver handle + * @disable_hw: true, disable HW interrupts. + * + * This function ensures that there are no + * ISRs or SP DPCs (sp_task) are running after it returns. */ void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw); /** - * Loads device firmware + * bnx2x_init_firmware - loads device firmware * - * @param bp - * - * @return int + * @bp: driver handle */ int bnx2x_init_firmware(struct bnx2x *bp); /** - * Init HW blocks according to current initialization stage: - * COMMON, PORT or FUNCTION. + * bnx2x_init_hw - init HW blocks according to current initialization stage. * - * @param bp - * @param load_code: COMMON, PORT or FUNCTION - * - * @return int + * @bp: driver handle + * @load_code: COMMON, PORT or FUNCTION */ int bnx2x_init_hw(struct bnx2x *bp, u32 load_code); /** - * Init driver internals: + * bnx2x_nic_init - init driver internals. + * + * @bp: driver handle + * @load_code: COMMON, PORT or FUNCTION + * + * Initializes: * - rings * - status blocks * - etc. - * - * @param bp - * @param load_code COMMON, PORT or FUNCTION */ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code); /** - * Allocate driver's memory. + * bnx2x_alloc_mem - allocate driver's memory. * - * @param bp - * - * @return int + * @bp: driver handle */ int bnx2x_alloc_mem(struct bnx2x *bp); /** - * Release driver's memory. + * bnx2x_free_mem - release driver's memory. * - * @param bp + * @bp: driver handle */ void bnx2x_free_mem(struct bnx2x *bp); /** - * Setup eth Client. + * bnx2x_setup_client - setup eth client. * - * @param bp - * @param fp - * @param is_leading - * - * @return int + * @bp: driver handle + * @fp: pointer to fastpath structure + * @is_leading: boolean */ int bnx2x_setup_client(struct bnx2x *bp, struct bnx2x_fastpath *fp, int is_leading); /** - * Set number of queues according to mode - * - * @param bp + * bnx2x_set_num_queues - set number of queues according to mode. * + * @bp: driver handle */ void bnx2x_set_num_queues(struct bnx2x *bp); /** - * Cleanup chip internals: - * - Cleanup MAC configuration. - * - Close clients. - * - etc. + * bnx2x_chip_cleanup - cleanup chip internals. * - * @param bp - * @param unload_mode + * @bp: driver handle + * @unload_mode: COMMON, PORT, FUNCTION + * + * - Cleanup MAC configuration. + * - Closes clients. + * - etc. */ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode); /** - * Acquire HW lock. + * bnx2x_acquire_hw_lock - acquire HW lock. * - * @param bp - * @param resource Resource bit which was locked - * - * @return int + * @bp: driver handle + * @resource: resource bit which was locked */ int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource); /** - * Release HW lock. + * bnx2x_release_hw_lock - release HW lock. * - * @param bp driver handle - * @param resource Resource bit which was locked - * - * @return int + * @bp: driver handle + * @resource: resource bit which was locked */ int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource); /** - * Configure eth MAC address in the HW according to the value in - * netdev->dev_addr. + * bnx2x_set_eth_mac - configure eth MAC address in the HW * - * @param bp driver handle - * @param set + * @bp: driver handle + * @set: set or clear + * + * Configures according to the value in netdev->dev_addr. */ void bnx2x_set_eth_mac(struct bnx2x *bp, int set); #ifdef BCM_CNIC /** - * Set/Clear FIP MAC(s) at the next enties in the CAM after the ETH - * MAC(s). This function will wait until the ramdord completion - * returns. + * bnx2x_set_fip_eth_mac_addr - Set/Clear FIP MAC(s) * - * @param bp driver handle - * @param set set or clear the CAM entry + * @bp: driver handle + * @set: set or clear the CAM entry * - * @return 0 if cussess, -ENODEV if ramrod doesn't return. + * Used next enties in the CAM after the ETH MAC(s). + * This function will wait until the ramdord completion returns. + * Return 0 if cussess, -ENODEV if ramrod doesn't return. */ int bnx2x_set_fip_eth_mac_addr(struct bnx2x *bp, int set); /** - * Set/Clear ALL_ENODE mcast MAC. + * bnx2x_set_all_enode_macs - Set/Clear ALL_ENODE mcast MAC. * - * @param bp - * @param set - * - * @return int + * @bp: driver handle + * @set: set or clear */ int bnx2x_set_all_enode_macs(struct bnx2x *bp, int set); #endif /** - * Set MAC filtering configurations. + * bnx2x_set_rx_mode - set MAC filtering configurations. * - * @remarks called with netif_tx_lock from dev_mcast.c + * @dev: netdevice * - * @param dev net_device + * called with netif_tx_lock from dev_mcast.c */ void bnx2x_set_rx_mode(struct net_device *dev); /** - * Configure MAC filtering rules in a FW. + * bnx2x_set_storm_rx_mode - configure MAC filtering rules in a FW. * - * @param bp driver handle + * @bp: driver handle */ void bnx2x_set_storm_rx_mode(struct bnx2x *bp); @@ -290,63 +307,59 @@ bool bnx2x_reset_is_done(struct bnx2x *bp); void bnx2x_disable_close_the_gate(struct bnx2x *bp); /** - * Perform statistics handling according to event + * bnx2x_stats_handle - perform statistics handling according to event. * - * @param bp driver handle - * @param event bnx2x_stats_event + * @bp: driver handle + * @event: bnx2x_stats_event */ void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event); /** - * Handle ramrods completion + * bnx2x_sp_event - handle ramrods completion. * - * @param fp fastpath handle for the event - * @param rr_cqe eth_rx_cqe + * @fp: fastpath handle for the event + * @rr_cqe: eth_rx_cqe */ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe); /** - * Init/halt function before/after sending - * CLIENT_SETUP/CFC_DEL for the first/last client. + * bnx2x_func_start - init function * - * @param bp + * @bp: driver handle * - * @return int + * Must be called before sending CLIENT_SETUP for the first client. */ int bnx2x_func_start(struct bnx2x *bp); /** - * Prepare ILT configurations according to current driver - * parameters. + * bnx2x_ilt_set_info - prepare ILT configurations. * - * @param bp + * @bp: driver handle */ void bnx2x_ilt_set_info(struct bnx2x *bp); /** - * Inintialize dcbx protocol + * bnx2x_dcbx_init - initialize dcbx protocol. * - * @param bp + * @bp: driver handle */ void bnx2x_dcbx_init(struct bnx2x *bp); /** - * Set power state to the requested value. Currently only D0 and - * D3hot are supported. + * bnx2x_set_power_state - set power state to the requested value. * - * @param bp - * @param state D0 or D3hot + * @bp: driver handle + * @state: required state D0 or D3hot * - * @return int + * Currently only D0 and D3hot are supported. */ int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state); /** - * Updates MAX part of MF configuration in HW - * (if required) + * bnx2x_update_max_mf_config - update MAX part of MF configuration in HW. * - * @param bp - * @param value + * @bp: driver handle + * @value: new value */ void bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value); @@ -377,84 +390,73 @@ int bnx2x_resume(struct pci_dev *pdev); /* Release IRQ vectors */ void bnx2x_free_irq(struct bnx2x *bp); +void bnx2x_free_fp_mem(struct bnx2x *bp); +int bnx2x_alloc_fp_mem(struct bnx2x *bp); + void bnx2x_init_rx_rings(struct bnx2x *bp); void bnx2x_free_skbs(struct bnx2x *bp); void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw); void bnx2x_netif_start(struct bnx2x *bp); /** - * Fill msix_table, request vectors, update num_queues according - * to number of available vectors + * bnx2x_enable_msix - set msix configuration. * - * @param bp + * @bp: driver handle * - * @return int + * fills msix_table, requests vectors, updates num_queues + * according to number of available vectors. */ int bnx2x_enable_msix(struct bnx2x *bp); /** - * Request msi mode from OS, updated internals accordingly + * bnx2x_enable_msi - request msi mode from OS, updated internals accordingly * - * @param bp - * - * @return int + * @bp: driver handle */ int bnx2x_enable_msi(struct bnx2x *bp); /** - * NAPI callback + * bnx2x_poll - NAPI callback * - * @param napi - * @param budget + * @napi: napi structure + * @budget: * - * @return int */ int bnx2x_poll(struct napi_struct *napi, int budget); /** - * Allocate/release memories outsize main driver structure + * bnx2x_alloc_mem_bp - allocate memories outsize main driver structure * - * @param bp - * - * @return int + * @bp: driver handle */ int __devinit bnx2x_alloc_mem_bp(struct bnx2x *bp); + +/** + * bnx2x_free_mem_bp - release memories outsize main driver structure + * + * @bp: driver handle + */ void bnx2x_free_mem_bp(struct bnx2x *bp); /** - * Change mtu netdev callback + * bnx2x_change_mtu - change mtu netdev callback * - * @param dev - * @param new_mtu + * @dev: net device + * @new_mtu: requested mtu * - * @return int */ int bnx2x_change_mtu(struct net_device *dev, int new_mtu); +u32 bnx2x_fix_features(struct net_device *dev, u32 features); +int bnx2x_set_features(struct net_device *dev, u32 features); + /** - * tx timeout netdev callback + * bnx2x_tx_timeout - tx timeout netdev callback * - * @param dev - * @param new_mtu - * - * @return int + * @dev: net device */ void bnx2x_tx_timeout(struct net_device *dev); -#ifdef BCM_VLAN -/** - * vlan rx register netdev callback - * - * @param dev - * @param new_mtu - * - * @return int - */ -void bnx2x_vlan_rx_register(struct net_device *dev, - struct vlan_group *vlgrp); - -#endif - static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp) { barrier(); /* status block is written to by the chip */ @@ -705,7 +707,7 @@ static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp) /** * disables tx from stack point of view * - * @param bp + * @bp: driver handle */ static inline void bnx2x_tx_disable(struct bnx2x *bp) { @@ -880,6 +882,9 @@ static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp, { int i; + if (fp->disable_tpa) + return; + for (i = 0; i < last; i++) bnx2x_free_rx_sge(bp, fp, i); } @@ -908,36 +913,39 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp, } } +static inline void bnx2x_init_tx_ring_one(struct bnx2x_fastpath *fp) +{ + int i; + + for (i = 1; i <= NUM_TX_RINGS; i++) { + struct eth_tx_next_bd *tx_next_bd = + &fp->tx_desc_ring[TX_DESC_CNT * i - 1].next_bd; + + tx_next_bd->addr_hi = + cpu_to_le32(U64_HI(fp->tx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); + tx_next_bd->addr_lo = + cpu_to_le32(U64_LO(fp->tx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); + } + + SET_FLAG(fp->tx_db.data.header.header, DOORBELL_HDR_DB_TYPE, 1); + fp->tx_db.data.zero_fill1 = 0; + fp->tx_db.data.prod = 0; + + fp->tx_pkt_prod = 0; + fp->tx_pkt_cons = 0; + fp->tx_bd_prod = 0; + fp->tx_bd_cons = 0; + fp->tx_pkt = 0; +} static inline void bnx2x_init_tx_rings(struct bnx2x *bp) { - int i, j; + int i; - for_each_tx_queue(bp, j) { - struct bnx2x_fastpath *fp = &bp->fp[j]; - - for (i = 1; i <= NUM_TX_RINGS; i++) { - struct eth_tx_next_bd *tx_next_bd = - &fp->tx_desc_ring[TX_DESC_CNT * i - 1].next_bd; - - tx_next_bd->addr_hi = - cpu_to_le32(U64_HI(fp->tx_desc_mapping + - BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); - tx_next_bd->addr_lo = - cpu_to_le32(U64_LO(fp->tx_desc_mapping + - BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); - } - - SET_FLAG(fp->tx_db.data.header.header, DOORBELL_HDR_DB_TYPE, 1); - fp->tx_db.data.zero_fill1 = 0; - fp->tx_db.data.prod = 0; - - fp->tx_pkt_prod = 0; - fp->tx_pkt_cons = 0; - fp->tx_bd_prod = 0; - fp->tx_bd_cons = 0; - fp->tx_pkt = 0; - } + for_each_tx_queue(bp, i) + bnx2x_init_tx_ring_one(&bp->fp[i]); } static inline void bnx2x_set_next_page_rx_bd(struct bnx2x_fastpath *fp) @@ -992,6 +1000,44 @@ static inline void bnx2x_set_next_page_rx_cq(struct bnx2x_fastpath *fp) } } +/* Returns the number of actually allocated BDs */ +static inline int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp, + int rx_ring_size) +{ + struct bnx2x *bp = fp->bp; + u16 ring_prod, cqe_ring_prod; + int i; + + fp->rx_comp_cons = 0; + cqe_ring_prod = ring_prod = 0; + + /* This routine is called only during fo init so + * fp->eth_q_stats.rx_skb_alloc_failed = 0 + */ + for (i = 0; i < rx_ring_size; i++) { + if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) { + fp->eth_q_stats.rx_skb_alloc_failed++; + continue; + } + ring_prod = NEXT_RX_IDX(ring_prod); + cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod); + WARN_ON(ring_prod <= (i - fp->eth_q_stats.rx_skb_alloc_failed)); + } + + if (fp->eth_q_stats.rx_skb_alloc_failed) + BNX2X_ERR("was only able to allocate " + "%d rx skbs on queue[%d]\n", + (i - fp->eth_q_stats.rx_skb_alloc_failed), fp->index); + + fp->rx_bd_prod = ring_prod; + /* Limit the CQE producer by the CQE ring size */ + fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT, + cqe_ring_prod); + fp->rx_pkt = fp->rx_calls = 0; + + return i - fp->eth_q_stats.rx_skb_alloc_failed; +} + #ifdef BCM_CNIC static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp) { @@ -1041,12 +1087,23 @@ static inline void storm_memset_cmng(struct bnx2x *bp, struct cmng_struct_per_port *cmng, u8 port) { - size_t size = sizeof(struct cmng_struct_per_port); + size_t size = + sizeof(struct rate_shaping_vars_per_port) + + sizeof(struct fairness_vars_per_port) + + sizeof(struct safc_struct_per_port) + + sizeof(struct pfc_struct_per_port); u32 addr = BAR_XSTRORM_INTMEM + XSTORM_CMNG_PER_PORT_VARS_OFFSET(port); __storm_memset_struct(bp, addr, size, (u32 *)cmng); + + addr += size + 4 /* SKIP DCB+LLFC */; + size = sizeof(struct cmng_struct_per_port) - + size /* written */ - 4 /*skipped*/; + + __storm_memset_struct(bp, addr, size, + (u32 *)(cmng->traffic_type_to_priority_cos)); } /* HW Lock for shared dual port PHYs */ @@ -1054,12 +1111,11 @@ void bnx2x_acquire_phy_lock(struct bnx2x *bp); void bnx2x_release_phy_lock(struct bnx2x *bp); /** - * Extracts MAX BW part from MF configuration. + * bnx2x_extract_max_cfg - extract MAX BW part from MF configuration. * - * @param bp - * @param mf_cfg + * @bp: driver handle + * @mf_cfg: MF configuration * - * @return u16 */ static inline u16 bnx2x_extract_max_cfg(struct bnx2x *bp, u32 mf_cfg) { diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c index 9a24d79c71d9..410a49e571ac 100644 --- a/drivers/net/bnx2x/bnx2x_dcb.c +++ b/drivers/net/bnx2x/bnx2x_dcb.c @@ -1,6 +1,6 @@ /* bnx2x_dcb.c: Broadcom Everest network driver. * - * Copyright 2009-2010 Broadcom Corporation + * Copyright 2009-2011 Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -485,6 +485,36 @@ static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp) } } +#ifdef BCM_DCBNL +static int bnx2x_dcbx_read_shmem_remote_mib(struct bnx2x *bp) +{ + struct lldp_remote_mib remote_mib = {0}; + u32 dcbx_remote_mib_offset = SHMEM2_RD(bp, dcbx_remote_mib_offset); + int rc; + + DP(NETIF_MSG_LINK, "dcbx_remote_mib_offset 0x%x\n", + dcbx_remote_mib_offset); + + if (SHMEM_DCBX_REMOTE_MIB_NONE == dcbx_remote_mib_offset) { + BNX2X_ERR("FW doesn't support dcbx_remote_mib_offset\n"); + return -EINVAL; + } + + rc = bnx2x_dcbx_read_mib(bp, (u32 *)&remote_mib, dcbx_remote_mib_offset, + DCBX_READ_REMOTE_MIB); + + if (rc) { + BNX2X_ERR("Faild to read remote mib from FW\n"); + return rc; + } + + /* save features and flags */ + bp->dcbx_remote_feat = remote_mib.features; + bp->dcbx_remote_flags = remote_mib.flags; + return 0; +} +#endif + static int bnx2x_dcbx_read_shmem_neg_results(struct bnx2x *bp) { struct lldp_local_mib local_mib = {0}; @@ -571,6 +601,28 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state) { switch (state) { case BNX2X_DCBX_STATE_NEG_RECEIVED: +#ifdef BCM_CNIC + if (bp->state != BNX2X_STATE_OPENING_WAIT4_LOAD) { + struct cnic_ops *c_ops; + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG; + cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI_OOO; + cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI; + + rcu_read_lock(); + c_ops = rcu_dereference(bp->cnic_ops); + if (c_ops) { + bnx2x_cnic_notify(bp, CNIC_CTL_STOP_ISCSI_CMD); + rcu_read_unlock(); + return; + } + rcu_read_unlock(); + } + + /* fall through if no CNIC initialized */ + case BNX2X_DCBX_STATE_ISCSI_STOPPED: +#endif + { DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_NEG_RECEIVED\n"); #ifdef BCM_DCBNL @@ -579,6 +631,10 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state) * negotiation results */ bnx2x_dcbnl_update_applist(bp, true); + + /* Read rmeote mib if dcbx is in the FW */ + if (bnx2x_dcbx_read_shmem_remote_mib(bp)) + return; #endif /* Read neg results if dcbx is in the FW */ if (bnx2x_dcbx_read_shmem_neg_results(bp)) @@ -1057,12 +1113,6 @@ static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp, } } - -/******************************************************************************* - * Description: single priority group - * - * Return: - ******************************************************************************/ static void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp, struct cos_help_data *cos_data, u32 pri_join_mask) @@ -1075,11 +1125,6 @@ static void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp, cos_data->num_of_cos = 1; } -/******************************************************************************* - * Description: updating the cos bw - * - * Return: - ******************************************************************************/ static inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp, struct cos_entry_help_data *data, u8 pg_bw) @@ -1090,11 +1135,6 @@ static inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp, data->cos_bw += pg_bw; } -/******************************************************************************* - * Description: single priority group - * - * Return: - ******************************************************************************/ static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp, struct cos_help_data *cos_data, u32 *pg_pri_orginal_spread, @@ -1347,11 +1387,6 @@ static void bnx2x_dcbx_two_pg_to_cos_params( } } -/******************************************************************************* - * Description: Still - * - * Return: - ******************************************************************************/ static void bnx2x_dcbx_three_pg_to_cos_params( struct bnx2x *bp, struct pg_help_data *pg_help_data, @@ -1539,11 +1574,6 @@ static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp, } } -/******************************************************************************* - * Description: Fill pfc_config struct that will be sent in DCBX start ramrod - * - * Return: - ******************************************************************************/ static void bnx2x_pfc_fw_struct_e2(struct bnx2x *bp) { struct flow_control_configuration *pfc_fw_cfg = NULL; @@ -2035,7 +2065,6 @@ static u8 bnx2x_dcbnl_set_dcbx(struct net_device *netdev, u8 state) return 0; } - static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid, u8 *flags) { @@ -2115,31 +2144,100 @@ static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid, return rval; } +static int bnx2x_peer_appinfo(struct net_device *netdev, + struct dcb_peer_app_info *info, u16* app_count) +{ + int i; + struct bnx2x *bp = netdev_priv(netdev); + + DP(NETIF_MSG_LINK, "APP-INFO\n"); + + info->willing = (bp->dcbx_remote_flags & DCBX_APP_REM_WILLING) ?: 0; + info->error = (bp->dcbx_remote_flags & DCBX_APP_RX_ERROR) ?: 0; + *app_count = 0; + + for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) + if (bp->dcbx_remote_feat.app.app_pri_tbl[i].appBitfield & + DCBX_APP_ENTRY_VALID) + (*app_count)++; + return 0; +} + +static int bnx2x_peer_apptable(struct net_device *netdev, + struct dcb_app *table) +{ + int i, j; + struct bnx2x *bp = netdev_priv(netdev); + + DP(NETIF_MSG_LINK, "APP-TABLE\n"); + + for (i = 0, j = 0; i < DCBX_MAX_APP_PROTOCOL; i++) { + struct dcbx_app_priority_entry *ent = + &bp->dcbx_remote_feat.app.app_pri_tbl[i]; + + if (ent->appBitfield & DCBX_APP_ENTRY_VALID) { + table[j].selector = bnx2x_dcbx_dcbnl_app_idtype(ent); + table[j].priority = bnx2x_dcbx_dcbnl_app_up(ent); + table[j++].protocol = ent->app_id; + } + } + return 0; +} + +static int bnx2x_cee_peer_getpg(struct net_device *netdev, struct cee_pg *pg) +{ + int i; + struct bnx2x *bp = netdev_priv(netdev); + + pg->willing = (bp->dcbx_remote_flags & DCBX_ETS_REM_WILLING) ?: 0; + + for (i = 0; i < CEE_DCBX_MAX_PGS; i++) { + pg->pg_bw[i] = + DCBX_PG_BW_GET(bp->dcbx_remote_feat.ets.pg_bw_tbl, i); + pg->prio_pg[i] = + DCBX_PRI_PG_GET(bp->dcbx_remote_feat.ets.pri_pg_tbl, i); + } + return 0; +} + +static int bnx2x_cee_peer_getpfc(struct net_device *netdev, + struct cee_pfc *pfc) +{ + struct bnx2x *bp = netdev_priv(netdev); + pfc->tcs_supported = bp->dcbx_remote_feat.pfc.pfc_caps; + pfc->pfc_en = bp->dcbx_remote_feat.pfc.pri_en_bitmap; + return 0; +} + const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops = { - .getstate = bnx2x_dcbnl_get_state, - .setstate = bnx2x_dcbnl_set_state, - .getpermhwaddr = bnx2x_dcbnl_get_perm_hw_addr, - .setpgtccfgtx = bnx2x_dcbnl_set_pg_tccfg_tx, - .setpgbwgcfgtx = bnx2x_dcbnl_set_pg_bwgcfg_tx, - .setpgtccfgrx = bnx2x_dcbnl_set_pg_tccfg_rx, - .setpgbwgcfgrx = bnx2x_dcbnl_set_pg_bwgcfg_rx, - .getpgtccfgtx = bnx2x_dcbnl_get_pg_tccfg_tx, - .getpgbwgcfgtx = bnx2x_dcbnl_get_pg_bwgcfg_tx, - .getpgtccfgrx = bnx2x_dcbnl_get_pg_tccfg_rx, - .getpgbwgcfgrx = bnx2x_dcbnl_get_pg_bwgcfg_rx, - .setpfccfg = bnx2x_dcbnl_set_pfc_cfg, - .getpfccfg = bnx2x_dcbnl_get_pfc_cfg, - .setall = bnx2x_dcbnl_set_all, - .getcap = bnx2x_dcbnl_get_cap, - .getnumtcs = bnx2x_dcbnl_get_numtcs, - .setnumtcs = bnx2x_dcbnl_set_numtcs, - .getpfcstate = bnx2x_dcbnl_get_pfc_state, - .setpfcstate = bnx2x_dcbnl_set_pfc_state, - .setapp = bnx2x_dcbnl_set_app_up, - .getdcbx = bnx2x_dcbnl_get_dcbx, - .setdcbx = bnx2x_dcbnl_set_dcbx, - .getfeatcfg = bnx2x_dcbnl_get_featcfg, - .setfeatcfg = bnx2x_dcbnl_set_featcfg, + .getstate = bnx2x_dcbnl_get_state, + .setstate = bnx2x_dcbnl_set_state, + .getpermhwaddr = bnx2x_dcbnl_get_perm_hw_addr, + .setpgtccfgtx = bnx2x_dcbnl_set_pg_tccfg_tx, + .setpgbwgcfgtx = bnx2x_dcbnl_set_pg_bwgcfg_tx, + .setpgtccfgrx = bnx2x_dcbnl_set_pg_tccfg_rx, + .setpgbwgcfgrx = bnx2x_dcbnl_set_pg_bwgcfg_rx, + .getpgtccfgtx = bnx2x_dcbnl_get_pg_tccfg_tx, + .getpgbwgcfgtx = bnx2x_dcbnl_get_pg_bwgcfg_tx, + .getpgtccfgrx = bnx2x_dcbnl_get_pg_tccfg_rx, + .getpgbwgcfgrx = bnx2x_dcbnl_get_pg_bwgcfg_rx, + .setpfccfg = bnx2x_dcbnl_set_pfc_cfg, + .getpfccfg = bnx2x_dcbnl_get_pfc_cfg, + .setall = bnx2x_dcbnl_set_all, + .getcap = bnx2x_dcbnl_get_cap, + .getnumtcs = bnx2x_dcbnl_get_numtcs, + .setnumtcs = bnx2x_dcbnl_set_numtcs, + .getpfcstate = bnx2x_dcbnl_get_pfc_state, + .setpfcstate = bnx2x_dcbnl_set_pfc_state, + .setapp = bnx2x_dcbnl_set_app_up, + .getdcbx = bnx2x_dcbnl_get_dcbx, + .setdcbx = bnx2x_dcbnl_set_dcbx, + .getfeatcfg = bnx2x_dcbnl_get_featcfg, + .setfeatcfg = bnx2x_dcbnl_set_featcfg, + .peer_getappinfo = bnx2x_peer_appinfo, + .peer_getapptable = bnx2x_peer_apptable, + .cee_peer_getpg = bnx2x_cee_peer_getpg, + .cee_peer_getpfc = bnx2x_cee_peer_getpfc, }; #endif /* BCM_DCBNL */ diff --git a/drivers/net/bnx2x/bnx2x_dcb.h b/drivers/net/bnx2x/bnx2x_dcb.h index 71b8eda43bd0..bed369d67e02 100644 --- a/drivers/net/bnx2x/bnx2x_dcb.h +++ b/drivers/net/bnx2x/bnx2x_dcb.h @@ -1,6 +1,6 @@ /* bnx2x_dcb.h: Broadcom Everest network driver. * - * Copyright 2009-2010 Broadcom Corporation + * Copyright 2009-2011 Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -61,9 +61,6 @@ struct bnx2x_dcbx_port_params { #define BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE 1 #define BNX2X_DCBX_OVERWRITE_SETTINGS_INVALID (BNX2X_DCBX_CONFIG_INV_VALUE) -/******************************************************************************* - * LLDP protocol configuration parameters. - ******************************************************************************/ struct bnx2x_config_lldp_params { u32 overwrite_settings; u32 msg_tx_hold; @@ -83,9 +80,6 @@ struct bnx2x_admin_priority_app_table { u32 app_id; }; -/******************************************************************************* - * DCBX protocol configuration parameters. - ******************************************************************************/ struct bnx2x_config_dcbx_params { u32 overwrite_settings; u32 admin_dcbx_version; @@ -183,9 +177,13 @@ void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled); enum { BNX2X_DCBX_STATE_NEG_RECEIVED = 0x1, - BNX2X_DCBX_STATE_TX_PAUSED = 0x2, - BNX2X_DCBX_STATE_TX_RELEASED = 0x4 +#ifdef BCM_CNIC + BNX2X_DCBX_STATE_ISCSI_STOPPED, +#endif + BNX2X_DCBX_STATE_TX_PAUSED, + BNX2X_DCBX_STATE_TX_RELEASED }; + void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state); /* DCB netlink */ diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index f5050155c6b5..727fe89ff37f 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -1,6 +1,6 @@ /* bnx2x_ethtool.c: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 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 @@ -167,6 +167,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct bnx2x *bp = netdev_priv(dev); int cfg_idx = bnx2x_get_link_cfg_idx(bp); + /* Dual Media boards present all available port types */ cmd->supported = bp->port.supported[cfg_idx] | (bp->port.supported[cfg_idx ^ 1] & @@ -176,16 +177,16 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if ((bp->state == BNX2X_STATE_OPEN) && !(bp->flags & MF_FUNC_DIS) && (bp->link_vars.link_up)) { - cmd->speed = bp->link_vars.line_speed; + ethtool_cmd_speed_set(cmd, bp->link_vars.line_speed); cmd->duplex = bp->link_vars.duplex; } else { - - cmd->speed = bp->link_params.req_line_speed[cfg_idx]; + ethtool_cmd_speed_set( + cmd, bp->link_params.req_line_speed[cfg_idx]); cmd->duplex = bp->link_params.req_duplex[cfg_idx]; } if (IS_MF(bp)) - cmd->speed = bnx2x_get_mf_speed(bp); + ethtool_cmd_speed_set(cmd, bnx2x_get_mf_speed(bp)); if (bp->port.supported[cfg_idx] & SUPPORTED_TP) cmd->port = PORT_TP; @@ -206,10 +207,11 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->maxrxpkt = 0; DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" - DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n" + DP_LEVEL " supported 0x%x advertising 0x%x speed %u\n" DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n" DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n", - cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, + cmd->cmd, cmd->supported, cmd->advertising, + ethtool_cmd_speed(cmd), cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); @@ -226,16 +228,15 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return 0; DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" - " supported 0x%x advertising 0x%x speed %d speed_hi %d\n" + " supported 0x%x advertising 0x%x speed %u\n" " duplex %d port %d phy_address %d transceiver %d\n" " autoneg %d maxtxpkt %d maxrxpkt %d\n", - cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, - cmd->speed_hi, + cmd->cmd, cmd->supported, cmd->advertising, + ethtool_cmd_speed(cmd), cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); - speed = cmd->speed; - speed |= (cmd->speed_hi << 16); + speed = ethtool_cmd_speed(cmd); if (IS_MF_SI(bp)) { u32 part; @@ -439,7 +440,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) break; default: - DP(NETIF_MSG_LINK, "Unsupported speed %d\n", speed); + DP(NETIF_MSG_LINK, "Unsupported speed %u\n", speed); return -EINVAL; } @@ -1219,7 +1220,8 @@ static int bnx2x_set_ringparam(struct net_device *dev, } if ((ering->rx_pending > MAX_RX_AVAIL) || - (ering->rx_pending < MIN_RX_AVAIL) || + (ering->rx_pending < (bp->disable_tpa ? MIN_RX_SIZE_NONTPA : + MIN_RX_SIZE_TPA)) || (ering->tx_pending > MAX_TX_AVAIL) || (ering->tx_pending <= MAX_SKB_FRAGS + 4)) return -EINVAL; @@ -1299,91 +1301,6 @@ static int bnx2x_set_pauseparam(struct net_device *dev, return 0; } -static int bnx2x_set_flags(struct net_device *dev, u32 data) -{ - struct bnx2x *bp = netdev_priv(dev); - int changed = 0; - int rc = 0; - - if (bp->recovery_state != BNX2X_RECOVERY_DONE) { - printk(KERN_ERR "Handling parity error recovery. Try again later\n"); - return -EAGAIN; - } - - if (!(data & ETH_FLAG_RXVLAN)) - return -EINVAL; - - if ((data & ETH_FLAG_LRO) && bp->rx_csum && bp->disable_tpa) - return -EINVAL; - - rc = ethtool_op_set_flags(dev, data, ETH_FLAG_LRO | ETH_FLAG_RXVLAN | - ETH_FLAG_TXVLAN | ETH_FLAG_RXHASH); - if (rc) - return rc; - - /* TPA requires Rx CSUM offloading */ - if ((data & ETH_FLAG_LRO) && bp->rx_csum) { - if (!(bp->flags & TPA_ENABLE_FLAG)) { - bp->flags |= TPA_ENABLE_FLAG; - changed = 1; - } - } else if (bp->flags & TPA_ENABLE_FLAG) { - dev->features &= ~NETIF_F_LRO; - bp->flags &= ~TPA_ENABLE_FLAG; - changed = 1; - } - - if (changed && netif_running(dev)) { - bnx2x_nic_unload(bp, UNLOAD_NORMAL); - rc = bnx2x_nic_load(bp, LOAD_NORMAL); - } - - return rc; -} - -static u32 bnx2x_get_rx_csum(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - - return bp->rx_csum; -} - -static int bnx2x_set_rx_csum(struct net_device *dev, u32 data) -{ - struct bnx2x *bp = netdev_priv(dev); - int rc = 0; - - if (bp->recovery_state != BNX2X_RECOVERY_DONE) { - printk(KERN_ERR "Handling parity error recovery. Try again later\n"); - return -EAGAIN; - } - - bp->rx_csum = data; - - /* Disable TPA, when Rx CSUM is disabled. Otherwise all - TPA'ed packets will be discarded due to wrong TCP CSUM */ - if (!data) { - u32 flags = ethtool_op_get_flags(dev); - - rc = bnx2x_set_flags(dev, (flags & ~ETH_FLAG_LRO)); - } - - return rc; -} - -static int bnx2x_set_tso(struct net_device *dev, u32 data) -{ - if (data) { - dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->features |= NETIF_F_TSO6; - } else { - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->features &= ~NETIF_F_TSO6; - } - - return 0; -} - static const struct { char string[ETH_GSTRING_LEN]; } bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = { @@ -2097,36 +2014,37 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev, } } -static int bnx2x_phys_id(struct net_device *dev, u32 data) +static int bnx2x_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct bnx2x *bp = netdev_priv(dev); - int i; if (!netif_running(dev)) - return 0; + return -EAGAIN; if (!bp->port.pmf) - return 0; + return -EOPNOTSUPP; - if (data == 0) - data = 2; + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ - for (i = 0; i < (data * 2); i++) { - if ((i % 2) == 0) - bnx2x_set_led(&bp->link_params, &bp->link_vars, - LED_MODE_OPER, SPEED_1000); - else - bnx2x_set_led(&bp->link_params, &bp->link_vars, - LED_MODE_OFF, 0); + case ETHTOOL_ID_ON: + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_ON, SPEED_1000); + break; - msleep_interruptible(500); - if (signal_pending(current)) - break; - } + case ETHTOOL_ID_OFF: + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_FRONT_PANEL_OFF, 0); - if (bp->link_vars.link_up) - bnx2x_set_led(&bp->link_params, &bp->link_vars, LED_MODE_OPER, + break; + + case ETHTOOL_ID_INACTIVE: + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_OPER, bp->link_vars.line_speed); + } return 0; } @@ -2205,20 +2123,10 @@ static const struct ethtool_ops bnx2x_ethtool_ops = { .set_ringparam = bnx2x_set_ringparam, .get_pauseparam = bnx2x_get_pauseparam, .set_pauseparam = bnx2x_set_pauseparam, - .get_rx_csum = bnx2x_get_rx_csum, - .set_rx_csum = bnx2x_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .set_flags = bnx2x_set_flags, - .get_flags = ethtool_op_get_flags, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = bnx2x_set_tso, .self_test = bnx2x_self_test, .get_sset_count = bnx2x_get_sset_count, .get_strings = bnx2x_get_strings, - .phys_id = bnx2x_phys_id, + .set_phys_id = bnx2x_set_phys_id, .get_ethtool_stats = bnx2x_get_ethtool_stats, .get_rxnfc = bnx2x_get_rxnfc, .get_rxfh_indir = bnx2x_get_rxfh_indir, diff --git a/drivers/net/bnx2x/bnx2x_fw_defs.h b/drivers/net/bnx2x/bnx2x_fw_defs.h index f4e5b1ce8149..9fe367836a57 100644 --- a/drivers/net/bnx2x/bnx2x_fw_defs.h +++ b/drivers/net/bnx2x/bnx2x_fw_defs.h @@ -1,6 +1,6 @@ /* bnx2x_fw_defs.h: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 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/drivers/net/bnx2x/bnx2x_fw_file_hdr.h b/drivers/net/bnx2x/bnx2x_fw_file_hdr.h index f807262911e5..f4a07fbaed05 100644 --- a/drivers/net/bnx2x/bnx2x_fw_file_hdr.h +++ b/drivers/net/bnx2x/bnx2x_fw_file_hdr.h @@ -1,6 +1,6 @@ /* bnx2x_fw_file_hdr.h: FW binary file header structure. * - * Copyright (c) 2007-2009 Broadcom Corporation + * Copyright (c) 2007-2011 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/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h index dac1bf9cbbfa..cdf19fe7c7f6 100644 --- a/drivers/net/bnx2x/bnx2x_hsi.h +++ b/drivers/net/bnx2x/bnx2x_hsi.h @@ -1,6 +1,6 @@ /* bnx2x_hsi.h: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 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 @@ -1929,7 +1929,7 @@ struct host_func_stats { #define BCM_5710_FW_MAJOR_VERSION 6 #define BCM_5710_FW_MINOR_VERSION 2 -#define BCM_5710_FW_REVISION_VERSION 5 +#define BCM_5710_FW_REVISION_VERSION 9 #define BCM_5710_FW_ENGINEERING_VERSION 0 #define BCM_5710_FW_COMPILE_FLAGS 1 diff --git a/drivers/net/bnx2x/bnx2x_init.h b/drivers/net/bnx2x/bnx2x_init.h index fa6dbe3f2058..d5399206f66e 100644 --- a/drivers/net/bnx2x/bnx2x_init.h +++ b/drivers/net/bnx2x/bnx2x_init.h @@ -1,7 +1,7 @@ /* bnx2x_init.h: Broadcom Everest network driver. * Structures and macroes needed during the initialization. * - * Copyright (c) 2007-2009 Broadcom Corporation + * Copyright (c) 2007-2011 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/drivers/net/bnx2x/bnx2x_init_ops.h b/drivers/net/bnx2x/bnx2x_init_ops.h index 66df29fcf751..aafd0232393f 100644 --- a/drivers/net/bnx2x/bnx2x_init_ops.h +++ b/drivers/net/bnx2x/bnx2x_init_ops.h @@ -2,7 +2,7 @@ * Static functions needed during the initialization. * This file is "included" in bnx2x_main.c. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 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/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index 974ef2be36a5..076e11f5769f 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -385,7 +385,7 @@ u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos) return 0; } /******************************************************************/ -/* ETS section */ +/* PFC section */ /******************************************************************/ static void bnx2x_bmac2_get_pfc_stat(struct link_params *params, @@ -1301,14 +1301,12 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, return 0; } -/* - * get_emac_base +/** + * bnx2x_get_emac_base - retrive emac base address * - * @param cb - * @param mdc_mdio_access - * @param port - * - * @return u32 + * @bp: driver handle + * @mdc_mdio_access: access type + * @port: port id * * This function selects the MDC/MDIO access (through emac0 or * emac1) depend on the mdc_mdio_access, port, port swapped. Each diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index a97a4a1c344f..f45c0caf3240 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -1,6 +1,6 @@ /* bnx2x_main.c: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 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 @@ -2036,7 +2036,7 @@ static int bnx2x_get_cmng_fns_mode(struct bnx2x *bp) return CMNG_FNS_NONE; } -static void bnx2x_read_mf_cfg(struct bnx2x *bp) +void bnx2x_read_mf_cfg(struct bnx2x *bp) { int vn, n = (CHIP_MODE_IS_4_PORT(bp) ? 2 : 1); @@ -2123,7 +2123,6 @@ static inline void bnx2x_link_sync_notify(struct bnx2x *bp) /* This function is called upon link interrupt */ static void bnx2x_link_attn(struct bnx2x *bp) { - u32 prev_link_status = bp->link_vars.link_status; /* Make sure that we are synced with the current statistics */ bnx2x_stats_handle(bp, STATS_EVENT_STOP); @@ -2168,17 +2167,15 @@ static void bnx2x_link_attn(struct bnx2x *bp) "single function mode without fairness\n"); } + __bnx2x_link_report(bp); + if (IS_MF(bp)) bnx2x_link_sync_notify(bp); - - /* indicate link status only if link status actually changed */ - if (prev_link_status != bp->link_vars.link_status) - bnx2x_link_report(bp); } void bnx2x__link_status_update(struct bnx2x *bp) { - if ((bp->state != BNX2X_STATE_OPEN) || (bp->flags & MF_FUNC_DIS)) + if (bp->state != BNX2X_STATE_OPEN) return; bnx2x_link_status_update(&bp->link_params, &bp->link_vars); @@ -2188,10 +2185,6 @@ void bnx2x__link_status_update(struct bnx2x *bp) else bnx2x_stats_handle(bp, STATS_EVENT_STOP); - /* the link status update could be the result of a DCC event - hence re-read the shmem mf configuration */ - bnx2x_read_mf_cfg(bp); - /* indicate link status */ bnx2x_link_report(bp); } @@ -3120,10 +3113,14 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn) if (val & DRV_STATUS_SET_MF_BW) bnx2x_set_mf_bw(bp); - bnx2x__link_status_update(bp); if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF)) bnx2x_pmf_update(bp); + /* Always call it here: bnx2x_link_report() will + * prevent the link indication duplication. + */ + bnx2x__link_status_update(bp); + if (bp->port.pmf && (val & DRV_STATUS_DCBX_NEGOTIATION_RESULTS) && bp->dcbx_enabled > 0) @@ -3904,10 +3901,9 @@ static void bnx2x_timer(unsigned long data) if (poll) { struct bnx2x_fastpath *fp = &bp->fp[0]; - int rc; bnx2x_tx_int(fp); - rc = bnx2x_rx_int(fp, 1000); + bnx2x_rx_int(fp, 1000); } if (!BP_NOMCP(bp)) { @@ -4062,7 +4058,6 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, struct hc_status_block_data_e2 sb_data_e2; struct hc_status_block_data_e1x sb_data_e1x; struct hc_status_block_sm *hc_sm_p; - struct hc_index_data *hc_index_p; int data_size; u32 *sb_data_p; @@ -4083,7 +4078,6 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, sb_data_e2.common.host_sb_addr.hi = U64_HI(mapping); sb_data_e2.common.host_sb_addr.lo = U64_LO(mapping); hc_sm_p = sb_data_e2.common.state_machine; - hc_index_p = sb_data_e2.index_data; sb_data_p = (u32 *)&sb_data_e2; data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32); } else { @@ -4097,7 +4091,6 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, sb_data_e1x.common.host_sb_addr.hi = U64_HI(mapping); sb_data_e1x.common.host_sb_addr.lo = U64_LO(mapping); hc_sm_p = sb_data_e1x.common.state_machine; - hc_index_p = sb_data_e1x.index_data; sb_data_p = (u32 *)&sb_data_e1x; data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32); } @@ -4454,7 +4447,7 @@ static void bnx2x_init_fp_sb(struct bnx2x *bp, int fp_idx) fp->state = BNX2X_FP_STATE_CLOSED; - fp->index = fp->cid = fp_idx; + fp->cid = fp_idx; fp->cl_id = BP_L_ID(bp) + fp_idx; fp->fw_sb_id = bp->base_fw_ndsb + fp->cl_id + CNIC_CONTEXT_USE; fp->igu_sb_id = bp->igu_base_sb + fp_idx + CNIC_CONTEXT_USE; @@ -4566,9 +4559,11 @@ static int bnx2x_gunzip_init(struct bnx2x *bp) static void bnx2x_gunzip_end(struct bnx2x *bp) { - kfree(bp->strm->workspace); - kfree(bp->strm); - bp->strm = NULL; + if (bp->strm) { + kfree(bp->strm->workspace); + kfree(bp->strm); + bp->strm = NULL; + } if (bp->gunzip_buf) { dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf, @@ -5876,9 +5871,6 @@ int bnx2x_init_hw(struct bnx2x *bp, u32 load_code) bp->dmae_ready = 0; spin_lock_init(&bp->dmae_lock); - rc = bnx2x_gunzip_init(bp); - if (rc) - return rc; switch (load_code) { case FW_MSG_CODE_DRV_LOAD_COMMON: @@ -5922,80 +5914,10 @@ int bnx2x_init_hw(struct bnx2x *bp, u32 load_code) void bnx2x_free_mem(struct bnx2x *bp) { - -#define BNX2X_PCI_FREE(x, y, size) \ - do { \ - if (x) { \ - dma_free_coherent(&bp->pdev->dev, size, (void *)x, y); \ - x = NULL; \ - y = 0; \ - } \ - } while (0) - -#define BNX2X_FREE(x) \ - do { \ - if (x) { \ - kfree((void *)x); \ - x = NULL; \ - } \ - } while (0) - - int i; + bnx2x_gunzip_end(bp); /* fastpath */ - /* Common */ - for_each_queue(bp, i) { -#ifdef BCM_CNIC - /* FCoE client uses default status block */ - if (IS_FCOE_IDX(i)) { - union host_hc_status_block *sb = - &bnx2x_fp(bp, i, status_blk); - memset(sb, 0, sizeof(union host_hc_status_block)); - bnx2x_fp(bp, i, status_blk_mapping) = 0; - } else { -#endif - /* status blocks */ - if (CHIP_IS_E2(bp)) - BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk.e2_sb), - bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_hc_status_block_e2)); - else - BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk.e1x_sb), - bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_hc_status_block_e1x)); -#ifdef BCM_CNIC - } -#endif - } - /* Rx */ - for_each_rx_queue(bp, i) { - - /* fastpath rx rings: rx_buf rx_desc rx_comp */ - BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring)); - BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_desc_ring), - bnx2x_fp(bp, i, rx_desc_mapping), - sizeof(struct eth_rx_bd) * NUM_RX_BD); - - BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_comp_ring), - bnx2x_fp(bp, i, rx_comp_mapping), - sizeof(struct eth_fast_path_rx_cqe) * - NUM_RCQ_BD); - - /* SGE ring */ - BNX2X_FREE(bnx2x_fp(bp, i, rx_page_ring)); - BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_sge_ring), - bnx2x_fp(bp, i, rx_sge_mapping), - BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); - } - /* Tx */ - for_each_tx_queue(bp, i) { - - /* fastpath tx rings: tx_buf tx_desc */ - BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring)); - BNX2X_PCI_FREE(bnx2x_fp(bp, i, tx_desc_ring), - bnx2x_fp(bp, i, tx_desc_mapping), - sizeof(union eth_tx_bd_types) * NUM_TX_BD); - } + bnx2x_free_fp_mem(bp); /* end of fastpath */ BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping, @@ -6028,101 +5950,13 @@ void bnx2x_free_mem(struct bnx2x *bp) BCM_PAGE_SIZE * NUM_EQ_PAGES); BNX2X_FREE(bp->rx_indir_table); - -#undef BNX2X_PCI_FREE -#undef BNX2X_KFREE } -static inline void set_sb_shortcuts(struct bnx2x *bp, int index) -{ - union host_hc_status_block status_blk = bnx2x_fp(bp, index, status_blk); - if (CHIP_IS_E2(bp)) { - bnx2x_fp(bp, index, sb_index_values) = - (__le16 *)status_blk.e2_sb->sb.index_values; - bnx2x_fp(bp, index, sb_running_index) = - (__le16 *)status_blk.e2_sb->sb.running_index; - } else { - bnx2x_fp(bp, index, sb_index_values) = - (__le16 *)status_blk.e1x_sb->sb.index_values; - bnx2x_fp(bp, index, sb_running_index) = - (__le16 *)status_blk.e1x_sb->sb.running_index; - } -} int bnx2x_alloc_mem(struct bnx2x *bp) { -#define BNX2X_PCI_ALLOC(x, y, size) \ - do { \ - x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ - if (x == NULL) \ - goto alloc_mem_err; \ - memset(x, 0, size); \ - } while (0) - -#define BNX2X_ALLOC(x, size) \ - do { \ - x = kzalloc(size, GFP_KERNEL); \ - if (x == NULL) \ - goto alloc_mem_err; \ - } while (0) - - int i; - - /* fastpath */ - /* Common */ - for_each_queue(bp, i) { - union host_hc_status_block *sb = &bnx2x_fp(bp, i, status_blk); - bnx2x_fp(bp, i, bp) = bp; - /* status blocks */ -#ifdef BCM_CNIC - if (!IS_FCOE_IDX(i)) { -#endif - if (CHIP_IS_E2(bp)) - BNX2X_PCI_ALLOC(sb->e2_sb, - &bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_hc_status_block_e2)); - else - BNX2X_PCI_ALLOC(sb->e1x_sb, - &bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_hc_status_block_e1x)); -#ifdef BCM_CNIC - } -#endif - set_sb_shortcuts(bp, i); - } - /* Rx */ - for_each_queue(bp, i) { - - /* fastpath rx rings: rx_buf rx_desc rx_comp */ - BNX2X_ALLOC(bnx2x_fp(bp, i, rx_buf_ring), - sizeof(struct sw_rx_bd) * NUM_RX_BD); - BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_desc_ring), - &bnx2x_fp(bp, i, rx_desc_mapping), - sizeof(struct eth_rx_bd) * NUM_RX_BD); - - BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_comp_ring), - &bnx2x_fp(bp, i, rx_comp_mapping), - sizeof(struct eth_fast_path_rx_cqe) * - NUM_RCQ_BD); - - /* SGE ring */ - BNX2X_ALLOC(bnx2x_fp(bp, i, rx_page_ring), - sizeof(struct sw_rx_page) * NUM_RX_SGE); - BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_sge_ring), - &bnx2x_fp(bp, i, rx_sge_mapping), - BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); - } - /* Tx */ - for_each_queue(bp, i) { - - /* fastpath tx rings: tx_buf tx_desc */ - BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring), - sizeof(struct sw_tx_bd) * NUM_TX_BD); - BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, tx_desc_ring), - &bnx2x_fp(bp, i, tx_desc_mapping), - sizeof(union eth_tx_bd_types) * NUM_TX_BD); - } - /* end of fastpath */ + if (bnx2x_gunzip_init(bp)) + return -ENOMEM; #ifdef BCM_CNIC if (CHIP_IS_E2(bp)) @@ -6162,14 +5996,18 @@ int bnx2x_alloc_mem(struct bnx2x *bp) BNX2X_ALLOC(bp->rx_indir_table, sizeof(bp->rx_indir_table[0]) * TSTORM_INDIRECTION_TABLE_SIZE); + + /* fastpath */ + /* need to be done at the end, since it's self adjusting to amount + * of memory available for RSS queues + */ + if (bnx2x_alloc_fp_mem(bp)) + goto alloc_mem_err; return 0; alloc_mem_err: bnx2x_free_mem(bp); return -ENOMEM; - -#undef BNX2X_PCI_ALLOC -#undef BNX2X_ALLOC } /* @@ -6197,14 +6035,14 @@ static int bnx2x_func_stop(struct bnx2x *bp) } /** - * Sets a MAC in a CAM for a few L2 Clients for E1x chips + * bnx2x_set_mac_addr_gen - set a MAC in a CAM for a few L2 Clients for E1x chips * - * @param bp driver descriptor - * @param set set or clear an entry (1 or 0) - * @param mac pointer to a buffer containing a MAC - * @param cl_bit_vec bit vector of clients to register a MAC for - * @param cam_offset offset in a CAM to use - * @param is_bcast is the set MAC a broadcast address (for E1 only) + * @bp: driver handle + * @set: set or clear an entry (1 or 0) + * @mac: pointer to a buffer containing a MAC + * @cl_bit_vec: bit vector of clients to register a MAC for + * @cam_offset: offset in a CAM to use + * @is_bcast: is the set MAC a broadcast address (for E1 only) */ static void bnx2x_set_mac_addr_gen(struct bnx2x *bp, int set, const u8 *mac, u32 cl_bit_vec, u8 cam_offset, @@ -6564,14 +6402,13 @@ void bnx2x_invalidate_e1h_mc_list(struct bnx2x *bp) #ifdef BCM_CNIC /** - * Set iSCSI MAC(s) at the next enties in the CAM after the ETH - * MAC(s). This function will wait until the ramdord completion - * returns. + * bnx2x_set_iscsi_eth_mac_addr - set iSCSI MAC(s). * - * @param bp driver handle - * @param set set or clear the CAM entry + * @bp: driver handle + * @set: set or clear the CAM entry * - * @return 0 if cussess, -ENODEV if ramrod doesn't return. + * This function will wait until the ramdord completion returns. + * Return 0 if success, -ENODEV if ramrod doesn't return. */ static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set) { @@ -6592,14 +6429,13 @@ static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set) } /** - * Set FCoE L2 MAC(s) at the next enties in the CAM after the - * ETH MAC(s). This function will wait until the ramdord - * completion returns. + * bnx2x_set_fip_eth_mac_addr - set FCoE L2 MAC(s) * - * @param bp driver handle - * @param set set or clear the CAM entry + * @bp: driver handle + * @set: set or clear the CAM entry * - * @return 0 if cussess, -ENODEV if ramrod doesn't return. + * This function will wait until the ramrod completion returns. + * Returns 0 if success, -ENODEV if ramrod doesn't return. */ int bnx2x_set_fip_eth_mac_addr(struct bnx2x *bp, int set) { @@ -6803,12 +6639,11 @@ static int bnx2x_setup_fw_client(struct bnx2x *bp, } /** - * Configure interrupt mode according to current configuration. + * bnx2x_set_int_mode - configure interrupt mode + * + * @bp: driver handle + * * In case of MSI-X it will also try to enable MSI-X. - * - * @param bp - * - * @return int */ static int __devinit bnx2x_set_int_mode(struct bnx2x *bp) { @@ -7392,10 +7227,11 @@ static void bnx2x_clp_reset_prep(struct bnx2x *bp, u32 *magic_val) MF_CFG_WR(bp, shared_mf_config.clp_mb, val | SHARED_MF_CLP_MAGIC); } -/* Restore the value of the `magic' bit. +/** + * bnx2x_clp_reset_done - restore the value of the `magic' bit. * - * @param pdev Device handle. - * @param magic_val Old value of the `magic' bit. + * @bp: driver handle + * @magic_val: old value of the `magic' bit. */ static void bnx2x_clp_reset_done(struct bnx2x *bp, u32 magic_val) { @@ -7406,10 +7242,12 @@ static void bnx2x_clp_reset_done(struct bnx2x *bp, u32 magic_val) } /** - * Prepares for MCP reset: takes care of CLP configurations. + * bnx2x_reset_mcp_prep - prepare for MCP reset. * - * @param bp - * @param magic_val Old value of 'magic' bit. + * @bp: driver handle + * @magic_val: old value of 'magic' bit. + * + * Takes care of CLP configurations. */ static void bnx2x_reset_mcp_prep(struct bnx2x *bp, u32 *magic_val) { @@ -7434,10 +7272,10 @@ static void bnx2x_reset_mcp_prep(struct bnx2x *bp, u32 *magic_val) #define MCP_TIMEOUT 5000 /* 5 seconds (in ms) */ #define MCP_ONE_TIMEOUT 100 /* 100 ms */ -/* Waits for MCP_ONE_TIMEOUT or MCP_ONE_TIMEOUT*10, - * depending on the HW type. +/** + * bnx2x_mcp_wait_one - wait for MCP_ONE_TIMEOUT * - * @param bp + * @bp: driver handle */ static inline void bnx2x_mcp_wait_one(struct bnx2x *bp) { @@ -8059,13 +7897,9 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) (val >= REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL) ? FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY : 0; - if (BP_E1HVN(bp) == 0) { - pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc); - bp->flags |= (pmc & PCI_PM_CAP_PME_D3cold) ? 0 : NO_WOL_FLAG; - } else { - /* no WOL capability for E1HVN != 0 */ - bp->flags |= NO_WOL_FLAG; - } + pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc); + bp->flags |= (pmc & PCI_PM_CAP_PME_D3cold) ? 0 : NO_WOL_FLAG; + BNX2X_DEV_INFO("%sWoL capable\n", (bp->flags & NO_WOL_FLAG) ? "not " : ""); @@ -8571,15 +8405,6 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) BNX2X_DEV_INFO("Read iSCSI MAC: " "0x%x:0x%04x\n", val2, val); bnx2x_set_mac_buf(iscsi_mac, val, val2); - - /* Disable iSCSI OOO if MAC configuration is - * invalid. - */ - if (!is_valid_ether_addr(iscsi_mac)) { - bp->flags |= NO_ISCSI_OOO_FLAG | - NO_ISCSI_FLAG; - memset(iscsi_mac, 0, ETH_ALEN); - } } else bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG; @@ -8592,13 +8417,6 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) "0x%x:0x%04x\n", val2, val); bnx2x_set_mac_buf(fip_mac, val, val2); - /* Disable FCoE if MAC configuration is - * invalid. - */ - if (!is_valid_ether_addr(fip_mac)) { - bp->flags |= NO_FCOE_FLAG; - memset(bp->fip_mac, 0, ETH_ALEN); - } } else bp->flags |= NO_FCOE_FLAG; } @@ -8629,13 +8447,29 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) else if (!IS_MF(bp)) memcpy(fip_mac, iscsi_mac, ETH_ALEN); } + + /* Disable iSCSI if MAC configuration is + * invalid. + */ + if (!is_valid_ether_addr(iscsi_mac)) { + bp->flags |= NO_ISCSI_FLAG; + memset(iscsi_mac, 0, ETH_ALEN); + } + + /* Disable FCoE if MAC configuration is + * invalid. + */ + if (!is_valid_ether_addr(fip_mac)) { + bp->flags |= NO_FCOE_FLAG; + memset(bp->fip_mac, 0, ETH_ALEN); + } #endif } static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) { int /*abs*/func = BP_ABS_FUNC(bp); - int vn, port; + int vn; u32 val = 0; int rc = 0; @@ -8670,7 +8504,6 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) bp->mf_ov = 0; bp->mf_mode = 0; vn = BP_E1HVN(bp); - port = BP_PORT(bp); if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) { DP(NETIF_MSG_PROBE, @@ -8904,8 +8737,6 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) bp->multi_mode = multi_mode; bp->int_mode = int_mode; - bp->dev->features |= NETIF_F_GRO; - /* Set TPA flags */ if (disable_tpa) { bp->flags &= ~TPA_ENABLE_FLAG; @@ -8925,8 +8756,6 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) bp->tx_ring_size = MAX_TX_AVAIL; - bp->rx_csum = 1; - /* make sure that the numbers are in the right granularity */ bp->tx_ticks = (50 / BNX2X_BTR) * BNX2X_BTR; bp->rx_ticks = (25 / BNX2X_BTR) * BNX2X_BTR; @@ -9304,6 +9133,8 @@ static const struct net_device_ops bnx2x_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = bnx2x_ioctl, .ndo_change_mtu = bnx2x_change_mtu, + .ndo_fix_features = bnx2x_fix_features, + .ndo_set_features = bnx2x_set_features, .ndo_tx_timeout = bnx2x_tx_timeout, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = poll_bnx2x, @@ -9430,20 +9261,20 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, dev->netdev_ops = &bnx2x_netdev_ops; bnx2x_set_ethtool_ops(dev); - dev->features |= NETIF_F_SG; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | + NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_HW_VLAN_TX; + + dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_HIGHDMA; + + dev->features |= dev->hw_features | NETIF_F_HW_VLAN_RX; if (bp->flags & USING_DAC_FLAG) dev->features |= NETIF_F_HIGHDMA; - dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->features |= NETIF_F_TSO6; - dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); - dev->vlan_features |= NETIF_F_SG; - dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - if (bp->flags & USING_DAC_FLAG) - dev->vlan_features |= NETIF_F_HIGHDMA; - dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->vlan_features |= NETIF_F_TSO6; + /* Add Loopback capability to the device */ + dev->hw_features |= NETIF_F_LOOPBACK; #ifdef BCM_DCBNL dev->dcbnl_ops = &bnx2x_dcbnl_ops; @@ -10342,6 +10173,11 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl) break; } + case DRV_CTL_ISCSI_STOPPED_CMD: { + bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_ISCSI_STOPPED); + break; + } + default: BNX2X_ERR("unknown command %x\n", ctl->cmd); rc = -EINVAL; diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index 1509a2318af9..86bba25d2d3f 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -1,6 +1,6 @@ /* bnx2x_reg.h: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 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/drivers/net/bnx2x/bnx2x_stats.c b/drivers/net/bnx2x/bnx2x_stats.c index 3445ded6674f..e535bfa08945 100644 --- a/drivers/net/bnx2x/bnx2x_stats.c +++ b/drivers/net/bnx2x/bnx2x_stats.c @@ -1,6 +1,6 @@ /* bnx2x_stats.c: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 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/drivers/net/bnx2x/bnx2x_stats.h b/drivers/net/bnx2x/bnx2x_stats.h index 596798c47452..45d14d8bc1aa 100644 --- a/drivers/net/bnx2x/bnx2x_stats.h +++ b/drivers/net/bnx2x/bnx2x_stats.h @@ -1,6 +1,6 @@ /* bnx2x_stats.h: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 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/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile index 3c5c014e82b2..4c21bf6b8b2f 100644 --- a/drivers/net/bonding/Makefile +++ b/drivers/net/bonding/Makefile @@ -9,6 +9,3 @@ bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o bond_debugfs.o proc-$(CONFIG_PROC_FS) += bond_procfs.o bonding-objs += $(proc-y) -ipv6-$(subst m,y,$(CONFIG_IPV6)) += bond_ipv6.o -bonding-objs += $(ipv6-y) - diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 494bf960442d..c7537abca4f2 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -716,11 +716,9 @@ static void __set_agg_ports_ready(struct aggregator *aggregator, int val) static u32 __get_agg_bandwidth(struct aggregator *aggregator) { u32 bandwidth = 0; - u32 basic_speed; if (aggregator->num_of_ports) { - basic_speed = __get_link_speed(aggregator->lag_ports); - switch (basic_speed) { + switch (__get_link_speed(aggregator->lag_ports)) { case AD_LINK_SPEED_BITMASK_1MBPS: bandwidth = aggregator->num_of_ports; break; @@ -1482,8 +1480,11 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best, static int agg_device_up(const struct aggregator *agg) { - return (netif_running(agg->slave->dev) && - netif_carrier_ok(agg->slave->dev)); + struct port *port = agg->lag_ports; + if (!port) + return 0; + return (netif_running(port->slave->dev) && + netif_carrier_ok(port->slave->dev)); } /** @@ -2402,14 +2403,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) struct ad_info ad_info; int res = 1; - /* make sure that the slaves list will - * not change during tx - */ - read_lock(&bond->lock); - - if (!BOND_IS_OK(bond)) - goto out; - if (bond_3ad_get_active_agg_info(bond, &ad_info)) { pr_debug("%s: Error: bond_3ad_get_active_agg_info failed\n", dev->name); @@ -2463,39 +2456,20 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) /* no suitable interface, frame not sent */ dev_kfree_skb(skb); } - read_unlock(&bond->lock); + return NETDEV_TX_OK; } -int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev) +void bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, + struct slave *slave) { - struct bonding *bond = netdev_priv(dev); - struct slave *slave = NULL; - int ret = NET_RX_DROP; - - if (!(dev->flags & IFF_MASTER)) - goto out; - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - goto out; + if (skb->protocol != PKT_TYPE_LACPDU) + return; if (!pskb_may_pull(skb, sizeof(struct lacpdu))) - goto out; + return; read_lock(&bond->lock); - slave = bond_get_slave_by_dev(netdev_priv(dev), orig_dev); - if (!slave) - goto out_unlock; - bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len); - - ret = NET_RX_SUCCESS; - -out_unlock: read_unlock(&bond->lock); -out: - dev_kfree_skb(skb); - - return ret; } diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index b28baff70864..0ee3f1632c46 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -39,7 +39,7 @@ typedef struct mac_addr { u8 mac_addr_value[ETH_ALEN]; -} mac_addr_t; +} __packed mac_addr_t; enum { BOND_AD_STABLE = 0, @@ -134,12 +134,12 @@ typedef struct lacpdu { u8 tlv_type_terminator; // = terminator u8 terminator_length; // = 0 u8 reserved_50[50]; // = 0 -} lacpdu_t; +} __packed lacpdu_t; typedef struct lacpdu_header { struct ethhdr hdr; struct lacpdu lacpdu; -} lacpdu_header_t; +} __packed lacpdu_header_t; // Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) typedef struct bond_marker { @@ -155,12 +155,12 @@ typedef struct bond_marker { u8 tlv_type_terminator; // = 0x00 u8 terminator_length; // = 0x00 u8 reserved_90[90]; // = 0 -} bond_marker_t; +} __packed bond_marker_t; typedef struct bond_marker_header { struct ethhdr hdr; struct bond_marker marker; -} bond_marker_header_t; +} __packed bond_marker_header_t; #pragma pack() @@ -258,7 +258,6 @@ struct ad_bond_info { * requested */ struct timer_list ad_timer; - struct packet_type ad_pkt_type; }; struct ad_slave_info { @@ -280,7 +279,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave); void bond_3ad_handle_link_change(struct slave *slave, char link); int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info); int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev); -int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev); +void bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, + struct slave *slave); int bond_3ad_set_carrier(struct bonding *bond); #endif //__BOND_3AD_H__ diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 9bc5de3e04a8..8f2d2e7c70e5 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -176,7 +176,7 @@ static int tlb_initialize(struct bonding *bond) bond_info->tx_hashtbl = new_hashtbl; for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) { - tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1); + tlb_init_table_entry(&bond_info->tx_hashtbl[i], 0); } _unlock_tx_hashtbl(bond); @@ -308,49 +308,33 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) _unlock_rx_hashtbl(bond); } -static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype, struct net_device *orig_dev) +static void rlb_arp_recv(struct sk_buff *skb, struct bonding *bond, + struct slave *slave) { - struct bonding *bond; - struct arp_pkt *arp = (struct arp_pkt *)skb->data; - int res = NET_RX_DROP; + struct arp_pkt *arp; - while (bond_dev->priv_flags & IFF_802_1Q_VLAN) - bond_dev = vlan_dev_real_dev(bond_dev); - - if (!(bond_dev->priv_flags & IFF_BONDING) || - !(bond_dev->flags & IFF_MASTER)) - goto out; + if (skb->protocol != cpu_to_be16(ETH_P_ARP)) + return; + arp = (struct arp_pkt *) skb->data; if (!arp) { pr_debug("Packet has no ARP data\n"); - goto out; + return; } - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - goto out; - - if (!pskb_may_pull(skb, arp_hdr_len(bond_dev))) - goto out; + if (!pskb_may_pull(skb, arp_hdr_len(bond->dev))) + return; if (skb->len < sizeof(struct arp_pkt)) { pr_debug("Packet is too small to be an ARP\n"); - goto out; + return; } if (arp->op_code == htons(ARPOP_REPLY)) { /* update rx hash table for this ARP */ - bond = netdev_priv(bond_dev); rlb_update_entry_from_arp(bond, arp); pr_debug("Server received an ARP Reply from client\n"); } - - res = NET_RX_SUCCESS; - -out: - dev_kfree_skb(skb); - - return res; } /* Caller must hold bond lock for read */ @@ -701,7 +685,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) */ rlb_choose_channel(skb, bond); - /* The ARP relpy packets must be delayed so that + /* The ARP reply packets must be delayed so that * they can cancel out the influence of the ARP request. */ bond->alb_info.rlb_update_delay_counter = RLB_UPDATE_DELAY; @@ -759,7 +743,6 @@ static void rlb_init_table_entry(struct rlb_client_info *entry) static int rlb_initialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct packet_type *pk_type = &(BOND_ALB_INFO(bond).rlb_pkt_type); struct rlb_client_info *new_hashtbl; int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info); int i; @@ -784,13 +767,8 @@ static int rlb_initialize(struct bonding *bond) _unlock_rx_hashtbl(bond); - /*initialize packet type*/ - pk_type->type = cpu_to_be16(ETH_P_ARP); - pk_type->dev = bond->dev; - pk_type->func = rlb_arp_recv; - /* register to receive ARPs */ - dev_add_pack(pk_type); + bond->recv_probe = rlb_arp_recv; return 0; } @@ -799,8 +777,6 @@ static void rlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - dev_remove_pack(&(bond_info->rlb_pkt_type)); - _lock_rx_hashtbl(bond); kfree(bond_info->rx_hashtbl); @@ -1042,7 +1018,7 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla * * If the permanent hw address of @slave is @bond's hw address, we need to * find a different hw address to give @slave, that isn't in use by any other - * slave in the bond. This address must be, of course, one of the premanent + * slave in the bond. This address must be, of course, one of the permanent * addresses of the other slaves. * * We go over the slave list, and for each slave there we compare its @@ -1249,16 +1225,10 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) skb_reset_mac_header(skb); eth_data = eth_hdr(skb); - /* make sure that the curr_active_slave and the slaves list do - * not change during tx + /* make sure that the curr_active_slave do not change during tx */ - read_lock(&bond->lock); read_lock(&bond->curr_slave_lock); - if (!BOND_IS_OK(bond)) { - goto out; - } - switch (ntohs(skb->protocol)) { case ETH_P_IP: { const struct iphdr *iph = ip_hdr(skb); @@ -1358,13 +1328,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) } } -out: if (res) { /* no suitable interface, frame not sent */ dev_kfree_skb(skb); } read_unlock(&bond->curr_slave_lock); - read_unlock(&bond->lock); + return NETDEV_TX_OK; } diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 86861f08b24d..90f140a2d197 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -75,7 +75,7 @@ struct tlb_client_info { * gave this entry index. */ u32 tx_bytes; /* Each Client accumulates the BytesTx that - * were tranmitted to it, and after each + * were transmitted to it, and after each * CallBack the LoadHistory is divided * by the balance interval */ @@ -122,7 +122,6 @@ struct tlb_slave_info { }; struct alb_bond_info { - struct timer_list alb_timer; struct tlb_client_info *tx_hashtbl; /* Dynamically allocated */ spinlock_t tx_hashtbl_lock; u32 unbalanced_load; @@ -130,7 +129,6 @@ struct alb_bond_info { int lp_counter; /* -------- rlb parameters -------- */ int rlb_enabled; - struct packet_type rlb_pkt_type; struct rlb_client_info *rx_hashtbl; /* Receive hash table */ spinlock_t rx_hashtbl_lock; u32 rx_hashtbl_head; @@ -140,7 +138,6 @@ struct alb_bond_info { struct slave *next_rx_slave;/* next slave to be assigned * to a new rx client for */ - u32 rlb_interval_counter; u8 primary_is_promisc; /* boolean */ u32 rlb_promisc_timeout_counter;/* counts primary * promiscuity time diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 16d6fe954695..088fd845ffdf 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -89,8 +89,7 @@ static int max_bonds = BOND_DEFAULT_MAX_BONDS; static int tx_queues = BOND_DEFAULT_TX_QUEUES; -static int num_grat_arp = 1; -static int num_unsol_na = 1; +static int num_peer_notif = 1; static int miimon = BOND_LINK_MON_INTERV; static int updelay; static int downdelay; @@ -113,10 +112,10 @@ module_param(max_bonds, int, 0); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); module_param(tx_queues, int, 0); MODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)"); -module_param(num_grat_arp, int, 0644); -MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event"); -module_param(num_unsol_na, int, 0644); -MODULE_PARM_DESC(num_unsol_na, "Number of unsolicited IPv6 Neighbor Advertisements packets to send on failover event"); +module_param_named(num_grat_arp, num_peer_notif, int, 0644); +MODULE_PARM_DESC(num_grat_arp, "Number of peer notifications to send on failover event (alias of num_unsol_na)"); +module_param_named(num_unsol_na, num_peer_notif, int, 0644); +MODULE_PARM_DESC(num_unsol_na, "Number of peer notifications to send on failover event (alias of num_grat_arp)"); module_param(miimon, int, 0); MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); module_param(updelay, int, 0); @@ -234,7 +233,6 @@ struct bond_parm_tbl ad_select_tbl[] = { /*-------------------------- Forward declarations ---------------------------*/ -static void bond_send_gratuitous_arp(struct bonding *bond); static int bond_init(struct net_device *bond_dev); static void bond_uninit(struct net_device *bond_dev); @@ -345,32 +343,6 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) return res; } -/** - * bond_has_challenged_slaves - * @bond: the bond we're working on - * - * Searches the slave list. Returns 1 if a vlan challenged slave - * was found, 0 otherwise. - * - * Assumes bond->lock is held. - */ -static int bond_has_challenged_slaves(struct bonding *bond) -{ - struct slave *slave; - int i; - - bond_for_each_slave(bond, slave, i) { - if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) { - pr_debug("found VLAN challenged slave - %s\n", - slave->dev->name); - return 1; - } - } - - pr_debug("no VLAN challenged slaves found\n"); - return 0; -} - /** * bond_next_vlan - safely skip to the next item in the vlans list. * @bond: the bond we're working on @@ -631,7 +603,8 @@ static int bond_set_carrier(struct bonding *bond) static int bond_update_speed_duplex(struct slave *slave) { struct net_device *slave_dev = slave->dev; - struct ethtool_cmd etool; + struct ethtool_cmd etool = { .cmd = ETHTOOL_GSET }; + u32 slave_speed; int res; /* Fake speed and duplex */ @@ -645,7 +618,8 @@ static int bond_update_speed_duplex(struct slave *slave) if (res < 0) return -1; - switch (etool.speed) { + slave_speed = ethtool_cmd_speed(&etool); + switch (slave_speed) { case SPEED_10: case SPEED_100: case SPEED_1000: @@ -663,7 +637,7 @@ static int bond_update_speed_duplex(struct slave *slave) return -1; } - slave->speed = etool.speed; + slave->speed = slave_speed; slave->duplex = etool.duplex; return 0; @@ -1087,6 +1061,21 @@ static struct slave *bond_find_best_slave(struct bonding *bond) return bestslave; } +static bool bond_should_notify_peers(struct bonding *bond) +{ + struct slave *slave = bond->curr_active_slave; + + pr_debug("bond_should_notify_peers: bond %s slave %s\n", + bond->dev->name, slave ? slave->dev->name : "NULL"); + + if (!slave || !bond->send_peer_notif || + test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) + return false; + + bond->send_peer_notif--; + return true; +} + /** * change_active_interface - change the active slave into the specified one * @bond: our bonding struct @@ -1154,6 +1143,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_set_slave_inactive_flags(old_active); if (new_active) { + bool should_notify_peers = false; + bond_set_slave_active_flags(new_active); if (bond->params.fail_over_mac) @@ -1161,17 +1152,19 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) old_active); if (netif_running(bond->dev)) { - bond->send_grat_arp = bond->params.num_grat_arp; - bond_send_gratuitous_arp(bond); - - bond->send_unsol_na = bond->params.num_unsol_na; - bond_send_unsolicited_na(bond); + bond->send_peer_notif = + bond->params.num_peer_notif; + should_notify_peers = + bond_should_notify_peers(bond); } write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); netdev_bonding_change(bond->dev, NETDEV_BONDING_FAILOVER); + if (should_notify_peers) + netdev_bonding_change(bond->dev, + NETDEV_NOTIFY_PEERS); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); @@ -1387,52 +1380,68 @@ static int bond_sethwaddr(struct net_device *bond_dev, return 0; } -#define BOND_VLAN_FEATURES \ - (NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | \ - NETIF_F_HW_VLAN_FILTER) +static u32 bond_fix_features(struct net_device *dev, u32 features) +{ + struct slave *slave; + struct bonding *bond = netdev_priv(dev); + u32 mask; + int i; -/* - * Compute the common dev->feature set available to all slaves. Some - * feature bits are managed elsewhere, so preserve those feature bits - * on the master device. - */ -static int bond_compute_features(struct bonding *bond) + read_lock(&bond->lock); + + if (!bond->first_slave) { + /* Disable adding VLANs to empty bond. But why? --mq */ + features |= NETIF_F_VLAN_CHALLENGED; + goto out; + } + + mask = features; + features &= ~NETIF_F_ONE_FOR_ALL; + features |= NETIF_F_ALL_FOR_ALL; + + bond_for_each_slave(bond, slave, i) { + features = netdev_increment_features(features, + slave->dev->features, + mask); + } + +out: + read_unlock(&bond->lock); + return features; +} + +#define BOND_VLAN_FEATURES (NETIF_F_ALL_TX_OFFLOADS | \ + NETIF_F_SOFT_FEATURES | \ + NETIF_F_LRO) + +static void bond_compute_features(struct bonding *bond) { struct slave *slave; struct net_device *bond_dev = bond->dev; - u32 features = bond_dev->features; - u32 vlan_features = 0; - unsigned short max_hard_header_len = max((u16)ETH_HLEN, - bond_dev->hard_header_len); + u32 vlan_features = BOND_VLAN_FEATURES; + unsigned short max_hard_header_len = ETH_HLEN; int i; - features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); - features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM; + read_lock(&bond->lock); if (!bond->first_slave) goto done; - features &= ~NETIF_F_ONE_FOR_ALL; - - vlan_features = bond->first_slave->dev->vlan_features; bond_for_each_slave(bond, slave, i) { - features = netdev_increment_features(features, - slave->dev->features, - NETIF_F_ONE_FOR_ALL); vlan_features = netdev_increment_features(vlan_features, - slave->dev->vlan_features, - NETIF_F_ONE_FOR_ALL); + slave->dev->vlan_features, BOND_VLAN_FEATURES); + if (slave->dev->hard_header_len > max_hard_header_len) max_hard_header_len = slave->dev->hard_header_len; } done: - features |= (bond_dev->features & BOND_VLAN_FEATURES); - bond_dev->features = netdev_fix_features(bond_dev, features); - bond_dev->vlan_features = netdev_fix_features(bond_dev, vlan_features); + bond_dev->vlan_features = vlan_features; bond_dev->hard_header_len = max_hard_header_len; - return 0; + read_unlock(&bond->lock); + + netdev_change_features(bond_dev); } static void bond_setup_by_slave(struct net_device *bond_dev, @@ -1452,27 +1461,17 @@ static void bond_setup_by_slave(struct net_device *bond_dev, } /* On bonding slaves other than the currently active slave, suppress - * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and - * ARP on active-backup slaves with arp_validate enabled. + * duplicates except for alb non-mcast/bcast. */ static bool bond_should_deliver_exact_match(struct sk_buff *skb, struct slave *slave, struct bonding *bond) { if (bond_is_slave_inactive(slave)) { - if (slave_do_arp_validate(bond, slave) && - skb->protocol == __cpu_to_be16(ETH_P_ARP)) - return false; - if (bond->params.mode == BOND_MODE_ALB && skb->pkt_type != PACKET_BROADCAST && skb->pkt_type != PACKET_MULTICAST) - return false; - - if (bond->params.mode == BOND_MODE_8023AD && - skb->protocol == __cpu_to_be16(ETH_P_SLOW)) return false; - return true; } return false; @@ -1496,6 +1495,15 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) if (bond->params.arp_interval) slave->dev->last_rx = jiffies; + if (bond->recv_probe) { + struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC); + + if (likely(nskb)) { + bond->recv_probe(nskb, bond, slave); + dev_kfree_skb(nskb); + } + } + if (bond_should_deliver_exact_match(skb, slave, bond)) { return RX_HANDLER_EXACT; } @@ -1526,7 +1534,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) struct netdev_hw_addr *ha; struct sockaddr addr; int link_reporting; - int old_features = bond_dev->features; int res = 0; if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL && @@ -1559,16 +1566,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) pr_warning("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n", bond_dev->name, slave_dev->name, slave_dev->name, bond_dev->name); - bond_dev->features |= NETIF_F_VLAN_CHALLENGED; } } else { pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); - if (bond->slave_cnt == 0) { - /* First slave, and it is not VLAN challenged, - * so remove the block of adding VLANs over the bond. - */ - bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED; - } } /* @@ -1757,10 +1757,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) new_slave->delay = 0; new_slave->link_failure_count = 0; - bond_compute_features(bond); - write_unlock_bh(&bond->lock); + bond_compute_features(bond); + read_lock(&bond->lock); new_slave->last_arp_rx = jiffies; @@ -1940,7 +1940,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) kfree(new_slave); err_undo_flags: - bond_dev->features = old_features; + bond_compute_features(bond); return res; } @@ -1961,6 +1961,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *oldcurrent; struct sockaddr addr; + u32 old_features = bond_dev->features; /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || @@ -2021,8 +2022,6 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) /* release the slave from its bond */ bond_detach_slave(bond, slave); - bond_compute_features(bond); - if (bond->primary_slave == slave) bond->primary_slave = NULL; @@ -2066,24 +2065,23 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) */ memset(bond_dev->dev_addr, 0, bond_dev->addr_len); - if (!bond->vlgrp) { - bond_dev->features |= NETIF_F_VLAN_CHALLENGED; - } else { + if (bond->vlgrp) { pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n", bond_dev->name, bond_dev->name); pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n", bond_dev->name); } - } else if ((bond_dev->features & NETIF_F_VLAN_CHALLENGED) && - !bond_has_challenged_slaves(bond)) { - pr_info("%s: last VLAN challenged slave %s left bond %s. VLAN blocking is removed\n", - bond_dev->name, slave_dev->name, bond_dev->name); - bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED; } write_unlock_bh(&bond->lock); unblock_netpoll_tx(); + bond_compute_features(bond); + if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) && + (old_features & NETIF_F_VLAN_CHALLENGED)) + pr_info("%s: last VLAN challenged slave %s left bond %s. VLAN blocking is removed\n", + bond_dev->name, slave_dev->name, bond_dev->name); + /* must do this from outside any spinlocks */ bond_destroy_slave_symlinks(bond_dev, slave_dev); @@ -2201,8 +2199,6 @@ static int bond_release_all(struct net_device *bond_dev) bond_alb_deinit_slave(bond, slave); } - bond_compute_features(bond); - bond_destroy_slave_symlinks(bond_dev, slave_dev); bond_del_vlans_from_slave(bond, slave_dev); @@ -2251,9 +2247,7 @@ static int bond_release_all(struct net_device *bond_dev) */ memset(bond_dev->dev_addr, 0, bond_dev->addr_len); - if (!bond->vlgrp) { - bond_dev->features |= NETIF_F_VLAN_CHALLENGED; - } else { + if (bond->vlgrp) { pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n", bond_dev->name, bond_dev->name); pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n", @@ -2264,6 +2258,9 @@ static int bond_release_all(struct net_device *bond_dev) out: write_unlock_bh(&bond->lock); + + bond_compute_features(bond); + return 0; } @@ -2493,7 +2490,7 @@ static void bond_miimon_commit(struct bonding *bond) bond_update_speed_duplex(slave); - pr_info("%s: link status definitely up for interface %s, %d Mbps %s duplex.\n", + pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex.\n", bond->dev->name, slave->dev->name, slave->speed, slave->duplex ? "full" : "half"); @@ -2570,6 +2567,7 @@ void bond_mii_monitor(struct work_struct *work) { struct bonding *bond = container_of(work, struct bonding, mii_work.work); + bool should_notify_peers = false; read_lock(&bond->lock); if (bond->kill_timers) @@ -2578,17 +2576,7 @@ void bond_mii_monitor(struct work_struct *work) if (bond->slave_cnt == 0) goto re_arm; - if (bond->send_grat_arp) { - read_lock(&bond->curr_slave_lock); - bond_send_gratuitous_arp(bond); - read_unlock(&bond->curr_slave_lock); - } - - if (bond->send_unsol_na) { - read_lock(&bond->curr_slave_lock); - bond_send_unsolicited_na(bond); - read_unlock(&bond->curr_slave_lock); - } + should_notify_peers = bond_should_notify_peers(bond); if (bond_miimon_inspect(bond)) { read_unlock(&bond->lock); @@ -2608,6 +2596,12 @@ void bond_mii_monitor(struct work_struct *work) msecs_to_jiffies(bond->params.miimon)); out: read_unlock(&bond->lock); + + if (should_notify_peers) { + rtnl_lock(); + netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS); + rtnl_unlock(); + } } static __be32 bond_glean_dev_ip(struct net_device *dev) @@ -2751,44 +2745,6 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) } } -/* - * Kick out a gratuitous ARP for an IP on the bonding master plus one - * for each VLAN above us. - * - * Caller must hold curr_slave_lock for read or better - */ -static void bond_send_gratuitous_arp(struct bonding *bond) -{ - struct slave *slave = bond->curr_active_slave; - struct vlan_entry *vlan; - struct net_device *vlan_dev; - - pr_debug("bond_send_grat_arp: bond %s slave %s\n", - bond->dev->name, slave ? slave->dev->name : "NULL"); - - if (!slave || !bond->send_grat_arp || - test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) - return; - - bond->send_grat_arp--; - - if (bond->master_ip) { - bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip, - bond->master_ip, 0); - } - - if (!bond->vlgrp) - return; - - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); - if (vlan->vlan_ip) { - bond_arp_send(slave->dev, ARPOP_REPLY, vlan->vlan_ip, - vlan->vlan_ip, vlan->vlan_id); - } - } -} - static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip) { int i; @@ -2806,48 +2762,26 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 } } -static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) +static void bond_arp_rcv(struct sk_buff *skb, struct bonding *bond, + struct slave *slave) { struct arphdr *arp; - struct slave *slave; - struct bonding *bond; unsigned char *arp_ptr; __be32 sip, tip; - if (dev->priv_flags & IFF_802_1Q_VLAN) { - /* - * When using VLANS and bonding, dev and oriv_dev may be - * incorrect if the physical interface supports VLAN - * acceleration. With this change ARP validation now - * works for hosts only reachable on the VLAN interface. - */ - dev = vlan_dev_real_dev(dev); - orig_dev = dev_get_by_index_rcu(dev_net(skb->dev),skb->skb_iif); - } + if (skb->protocol != __cpu_to_be16(ETH_P_ARP)) + return; - if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) - goto out; - - bond = netdev_priv(dev); read_lock(&bond->lock); - pr_debug("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n", - bond->dev->name, skb->dev ? skb->dev->name : "NULL", - orig_dev ? orig_dev->name : "NULL"); + pr_debug("bond_arp_rcv: bond %s skb->dev %s\n", + bond->dev->name, skb->dev->name); - slave = bond_get_slave_by_dev(bond, orig_dev); - if (!slave || !slave_do_arp_validate(bond, slave)) - goto out_unlock; - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - goto out_unlock; - - if (!pskb_may_pull(skb, arp_hdr_len(dev))) + if (!pskb_may_pull(skb, arp_hdr_len(bond->dev))) goto out_unlock; arp = arp_hdr(skb); - if (arp->ar_hln != dev->addr_len || + if (arp->ar_hln != bond->dev->addr_len || skb->pkt_type == PACKET_OTHERHOST || skb->pkt_type == PACKET_LOOPBACK || arp->ar_hrd != htons(ARPHRD_ETHER) || @@ -2856,9 +2790,9 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack goto out_unlock; arp_ptr = (unsigned char *)(arp + 1); - arp_ptr += dev->addr_len; + arp_ptr += bond->dev->addr_len; memcpy(&sip, arp_ptr, 4); - arp_ptr += 4 + dev->addr_len; + arp_ptr += 4 + bond->dev->addr_len; memcpy(&tip, arp_ptr, 4); pr_debug("bond_arp_rcv: %s %s/%d av %d sv %d sip %pI4 tip %pI4\n", @@ -2881,9 +2815,6 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack out_unlock: read_unlock(&bond->lock); -out: - dev_kfree_skb(skb); - return NET_RX_SUCCESS; } /* @@ -3243,6 +3174,7 @@ void bond_activebackup_arp_mon(struct work_struct *work) { struct bonding *bond = container_of(work, struct bonding, arp_work.work); + bool should_notify_peers = false; int delta_in_ticks; read_lock(&bond->lock); @@ -3255,17 +3187,7 @@ void bond_activebackup_arp_mon(struct work_struct *work) if (bond->slave_cnt == 0) goto re_arm; - if (bond->send_grat_arp) { - read_lock(&bond->curr_slave_lock); - bond_send_gratuitous_arp(bond); - read_unlock(&bond->curr_slave_lock); - } - - if (bond->send_unsol_na) { - read_lock(&bond->curr_slave_lock); - bond_send_unsolicited_na(bond); - read_unlock(&bond->curr_slave_lock); - } + should_notify_peers = bond_should_notify_peers(bond); if (bond_ab_arp_inspect(bond, delta_in_ticks)) { read_unlock(&bond->lock); @@ -3286,6 +3208,12 @@ void bond_activebackup_arp_mon(struct work_struct *work) queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); out: read_unlock(&bond->lock); + + if (should_notify_peers) { + rtnl_lock(); + netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS); + rtnl_unlock(); + } } /*-------------------------- netdev event handling --------------------------*/ @@ -3339,8 +3267,8 @@ static int bond_slave_netdev_event(unsigned long event, slave = bond_get_slave_by_dev(bond, slave_dev); if (slave) { - u16 old_speed = slave->speed; - u16 old_duplex = slave->duplex; + u32 old_speed = slave->speed; + u8 old_duplex = slave->duplex; bond_update_speed_duplex(slave); @@ -3482,48 +3410,6 @@ static struct notifier_block bond_inetaddr_notifier = { .notifier_call = bond_inetaddr_event, }; -/*-------------------------- Packet type handling ---------------------------*/ - -/* register to receive lacpdus on a bond */ -static void bond_register_lacpdu(struct bonding *bond) -{ - struct packet_type *pk_type = &(BOND_AD_INFO(bond).ad_pkt_type); - - /* initialize packet type */ - pk_type->type = PKT_TYPE_LACPDU; - pk_type->dev = bond->dev; - pk_type->func = bond_3ad_lacpdu_recv; - - dev_add_pack(pk_type); -} - -/* unregister to receive lacpdus on a bond */ -static void bond_unregister_lacpdu(struct bonding *bond) -{ - dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); -} - -void bond_register_arp(struct bonding *bond) -{ - struct packet_type *pt = &bond->arp_mon_pt; - - if (pt->type) - return; - - pt->type = htons(ETH_P_ARP); - pt->dev = bond->dev; - pt->func = bond_arp_rcv; - dev_add_pack(pt); -} - -void bond_unregister_arp(struct bonding *bond) -{ - struct packet_type *pt = &bond->arp_mon_pt; - - dev_remove_pack(pt); - pt->type = 0; -} - /*---------------------------- Hashing Policies -----------------------------*/ /* @@ -3617,14 +3503,14 @@ static int bond_open(struct net_device *bond_dev) queue_delayed_work(bond->wq, &bond->arp_work, 0); if (bond->params.arp_validate) - bond_register_arp(bond); + bond->recv_probe = bond_arp_rcv; } if (bond->params.mode == BOND_MODE_8023AD) { INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler); queue_delayed_work(bond->wq, &bond->ad_work, 0); /* register to receive LACPDUs */ - bond_register_lacpdu(bond); + bond->recv_probe = bond_3ad_lacpdu_recv; bond_3ad_initiate_agg_selection(bond, 1); } @@ -3635,18 +3521,9 @@ static int bond_close(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); - if (bond->params.mode == BOND_MODE_8023AD) { - /* Unregister the receive of LACPDUs */ - bond_unregister_lacpdu(bond); - } - - if (bond->params.arp_validate) - bond_unregister_arp(bond); - write_lock_bh(&bond->lock); - bond->send_grat_arp = 0; - bond->send_unsol_na = 0; + bond->send_peer_notif = 0; /* signal timers not to re-arm */ bond->kill_timers = 1; @@ -3682,6 +3559,7 @@ static int bond_close(struct net_device *bond_dev) */ bond_alb_deinitialize(bond); } + bond->recv_probe = NULL; return 0; } @@ -4105,10 +3983,6 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev int i, slave_no, res = 1; struct iphdr *iph = ip_hdr(skb); - read_lock(&bond->lock); - - if (!BOND_IS_OK(bond)) - goto out; /* * Start with the curr_active_slave that joined the bond as the * default for sending IGMP traffic. For failover purposes one @@ -4155,7 +4029,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev /* no suitable interface, frame not sent */ dev_kfree_skb(skb); } - read_unlock(&bond->lock); + return NETDEV_TX_OK; } @@ -4169,24 +4043,18 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d struct bonding *bond = netdev_priv(bond_dev); int res = 1; - read_lock(&bond->lock); read_lock(&bond->curr_slave_lock); - if (!BOND_IS_OK(bond)) - goto out; + if (bond->curr_active_slave) + res = bond_dev_queue_xmit(bond, skb, + bond->curr_active_slave->dev); - if (!bond->curr_active_slave) - goto out; - - res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev); - -out: if (res) /* no suitable interface, frame not sent */ dev_kfree_skb(skb); read_unlock(&bond->curr_slave_lock); - read_unlock(&bond->lock); + return NETDEV_TX_OK; } @@ -4203,11 +4071,6 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) int i; int res = 1; - read_lock(&bond->lock); - - if (!BOND_IS_OK(bond)) - goto out; - slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt); bond_for_each_slave(bond, slave, i) { @@ -4227,12 +4090,11 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) } } -out: if (res) { /* no suitable interface, frame not sent */ dev_kfree_skb(skb); } - read_unlock(&bond->lock); + return NETDEV_TX_OK; } @@ -4247,11 +4109,6 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) int i; int res = 1; - read_lock(&bond->lock); - - if (!BOND_IS_OK(bond)) - goto out; - read_lock(&bond->curr_slave_lock); start_at = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); @@ -4290,7 +4147,6 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) dev_kfree_skb(skb); /* frame sent to all suitable interfaces */ - read_unlock(&bond->lock); return NETDEV_TX_OK; } @@ -4322,10 +4178,8 @@ static inline int bond_slave_override(struct bonding *bond, struct slave *slave = NULL; struct slave *check_slave; - read_lock(&bond->lock); - - if (!BOND_IS_OK(bond) || !skb->queue_mapping) - goto out; + if (!skb->queue_mapping) + return 1; /* Find out if any slaves have the same mapping as this skb. */ bond_for_each_slave(bond, check_slave, i) { @@ -4341,8 +4195,6 @@ static inline int bond_slave_override(struct bonding *bond, res = bond_dev_queue_xmit(bond, skb, slave->dev); } -out: - read_unlock(&bond->lock); return res; } @@ -4357,24 +4209,17 @@ static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb) u16 txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; if (unlikely(txq >= dev->real_num_tx_queues)) { - do + do { txq -= dev->real_num_tx_queues; - while (txq >= dev->real_num_tx_queues); + } while (txq >= dev->real_num_tx_queues); } return txq; } -static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bonding *bond = netdev_priv(dev); - /* - * If we risk deadlock from transmitting this in the - * netpoll path, tell netpoll to queue the frame for later tx - */ - if (is_netpoll_tx_blocked(dev)) - return NETDEV_TX_BUSY; - if (TX_QUEUE_OVERRIDE(bond->params.mode)) { if (!bond_slave_override(bond, skb)) return NETDEV_TX_OK; @@ -4404,6 +4249,29 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) } } +static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bonding *bond = netdev_priv(dev); + netdev_tx_t ret = NETDEV_TX_OK; + + /* + * If we risk deadlock from transmitting this in the + * netpoll path, tell netpoll to queue the frame for later tx + */ + if (is_netpoll_tx_blocked(dev)) + return NETDEV_TX_BUSY; + + read_lock(&bond->lock); + + if (bond->slave_cnt) + ret = __bond_start_xmit(skb, dev); + else + dev_kfree_skb(skb); + + read_unlock(&bond->lock); + + return ret; +} /* * set bond mode specific net device operations @@ -4448,11 +4316,6 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev, static const struct ethtool_ops bond_ethtool_ops = { .get_drvinfo = bond_ethtool_get_drvinfo, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .get_tso = ethtool_op_get_tso, - .get_ufo = ethtool_op_get_ufo, - .get_flags = ethtool_op_get_flags, }; static const struct net_device_ops bond_netdev_ops = { @@ -4478,6 +4341,7 @@ static const struct net_device_ops bond_netdev_ops = { #endif .ndo_add_slave = bond_enslave, .ndo_del_slave = bond_release, + .ndo_fix_features = bond_fix_features, }; static void bond_destructor(struct net_device *bond_dev) @@ -4533,14 +4397,14 @@ static void bond_setup(struct net_device *bond_dev) * when there are slaves that are not hw accel * capable */ - bond_dev->features |= (NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER); - /* By default, we enable GRO on bonding devices. - * Actual support requires lowlevel drivers are GRO ready. - */ - bond_dev->features |= NETIF_F_GRO; + bond_dev->hw_features = BOND_VLAN_FEATURES | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER; + + bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM); + bond_dev->features |= bond_dev->hw_features; } static void bond_work_cancel_all(struct bonding *bond) @@ -4724,16 +4588,10 @@ static int bond_check_params(struct bond_params *params) use_carrier = 1; } - if (num_grat_arp < 0 || num_grat_arp > 255) { - pr_warning("Warning: num_grat_arp (%d) not in range 0-255 so it was reset to 1\n", - num_grat_arp); - num_grat_arp = 1; - } - - if (num_unsol_na < 0 || num_unsol_na > 255) { - pr_warning("Warning: num_unsol_na (%d) not in range 0-255 so it was reset to 1\n", - num_unsol_na); - num_unsol_na = 1; + if (num_peer_notif < 0 || num_peer_notif > 255) { + pr_warning("Warning: num_grat_arp/num_unsol_na (%d) not in range 0-255 so it was reset to 1\n", + num_peer_notif); + num_peer_notif = 1; } /* reset values for 802.3ad */ @@ -4925,8 +4783,7 @@ static int bond_check_params(struct bond_params *params) params->mode = bond_mode; params->xmit_policy = xmit_hashtype; params->miimon = miimon; - params->num_grat_arp = num_grat_arp; - params->num_unsol_na = num_unsol_na; + params->num_peer_notif = num_peer_notif; params->arp_interval = arp_interval; params->arp_validate = arp_validate_value; params->updelay = updelay; @@ -5025,8 +4882,9 @@ int bond_create(struct net *net, const char *name) rtnl_lock(); - bond_dev = alloc_netdev_mq(sizeof(struct bonding), name ? name : "", - bond_setup, tx_queues); + bond_dev = alloc_netdev_mq(sizeof(struct bonding), + name ? name : "bond%d", + bond_setup, tx_queues); if (!bond_dev) { pr_err("%s: eek! can't alloc netdev!\n", name); rtnl_unlock(); @@ -5036,26 +4894,10 @@ int bond_create(struct net *net, const char *name) dev_net_set(bond_dev, net); bond_dev->rtnl_link_ops = &bond_link_ops; - if (!name) { - res = dev_alloc_name(bond_dev, "bond%d"); - if (res < 0) - goto out; - } else { - /* - * If we're given a name to register - * we need to ensure that its not already - * registered - */ - res = -EEXIST; - if (__dev_get_by_name(net, name) != NULL) - goto out; - } - res = register_netdevice(bond_dev); netif_carrier_off(bond_dev); -out: rtnl_unlock(); if (res < 0) bond_destructor(bond_dev); @@ -5121,7 +4963,6 @@ static int __init bonding_init(void) register_netdevice_notifier(&bond_netdev_notifier); register_inetaddr_notifier(&bond_inetaddr_notifier); - bond_register_ipv6_notifier(); out: return res; err: @@ -5136,7 +4977,6 @@ static void __exit bonding_exit(void) { unregister_netdevice_notifier(&bond_netdev_notifier); unregister_inetaddr_notifier(&bond_inetaddr_notifier); - bond_unregister_ipv6_notifier(); bond_destroy_sysfs(); bond_destroy_debugfs(); diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index c32ff55a34c1..c97307ddd1c9 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -4,8 +4,6 @@ #include "bonding.h" -extern const char *bond_mode_name(int mode); - static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) __acquires(RCU) __acquires(&bond->lock) diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index de87aea6d01a..4059bfc73dbf 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -422,11 +422,6 @@ static ssize_t bonding_store_arp_validate(struct device *d, bond->dev->name, arp_validate_tbl[new_value].modename, new_value); - if (!bond->params.arp_validate && new_value) - bond_register_arp(bond); - else if (bond->params.arp_validate && !new_value) - bond_unregister_arp(bond); - bond->params.arp_validate = new_value; return count; @@ -874,82 +869,28 @@ static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_store_ad_select); /* - * Show and set the number of grat ARP to send after a failover event. + * Show and set the number of peer notifications to send after a failover event. */ -static ssize_t bonding_show_n_grat_arp(struct device *d, - struct device_attribute *attr, - char *buf) +static ssize_t bonding_show_num_peer_notif(struct device *d, + struct device_attribute *attr, + char *buf) { struct bonding *bond = to_bond(d); - - return sprintf(buf, "%d\n", bond->params.num_grat_arp); + return sprintf(buf, "%d\n", bond->params.num_peer_notif); } -static ssize_t bonding_store_n_grat_arp(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t bonding_store_num_peer_notif(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { - int new_value, ret = count; struct bonding *bond = to_bond(d); - - if (sscanf(buf, "%d", &new_value) != 1) { - pr_err("%s: no num_grat_arp value specified.\n", - bond->dev->name); - ret = -EINVAL; - goto out; - } - if (new_value < 0 || new_value > 255) { - pr_err("%s: Invalid num_grat_arp value %d not in range 0-255; rejected.\n", - bond->dev->name, new_value); - ret = -EINVAL; - goto out; - } else { - bond->params.num_grat_arp = new_value; - } -out: - return ret; + int err = kstrtou8(buf, 10, &bond->params.num_peer_notif); + return err ? err : count; } static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, - bonding_show_n_grat_arp, bonding_store_n_grat_arp); - -/* - * Show and set the number of unsolicited NA's to send after a failover event. - */ -static ssize_t bonding_show_n_unsol_na(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct bonding *bond = to_bond(d); - - return sprintf(buf, "%d\n", bond->params.num_unsol_na); -} - -static ssize_t bonding_store_n_unsol_na(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int new_value, ret = count; - struct bonding *bond = to_bond(d); - - if (sscanf(buf, "%d", &new_value) != 1) { - pr_err("%s: no num_unsol_na value specified.\n", - bond->dev->name); - ret = -EINVAL; - goto out; - } - - if (new_value < 0 || new_value > 255) { - pr_err("%s: Invalid num_unsol_na value %d not in range 0-255; rejected.\n", - bond->dev->name, new_value); - ret = -EINVAL; - goto out; - } else - bond->params.num_unsol_na = new_value; -out: - return ret; -} + bonding_show_num_peer_notif, bonding_store_num_peer_notif); static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, - bonding_show_n_unsol_na, bonding_store_n_unsol_na); + bonding_show_num_peer_notif, bonding_store_num_peer_notif); /* * Show and set the MII monitor interval. There are two tricky bits @@ -1001,7 +942,6 @@ static ssize_t bonding_store_miimon(struct device *d, bond->dev->name); bond->params.arp_interval = 0; if (bond->params.arp_validate) { - bond_unregister_arp(bond); bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 90736cb4d975..ea1d005be92d 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -24,8 +24,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.7.0" -#define DRV_RELDATE "June 2, 2010" +#define DRV_VERSION "3.7.1" +#define DRV_RELDATE "April 27, 2011" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -38,16 +38,6 @@ netif_running(dev) && \ netif_carrier_ok(dev)) -/* - * Checks whether bond is ready for transmit. - * - * Caller must hold bond->lock - */ -#define BOND_IS_OK(bond) \ - (((bond)->dev->flags & IFF_UP) && \ - netif_running((bond)->dev) && \ - ((bond)->slave_cnt > 0)) - /* * Checks whether slave is ready for transmit. */ @@ -149,8 +139,7 @@ struct bond_params { int mode; int xmit_policy; int miimon; - int num_grat_arp; - int num_unsol_na; + u8 num_peer_notif; int arp_interval; int arp_validate; int use_carrier; @@ -178,9 +167,6 @@ struct vlan_entry { struct list_head vlan_list; __be32 vlan_ip; unsigned short vlan_id; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct in6_addr vlan_ipv6; -#endif }; struct slave { @@ -196,12 +182,12 @@ struct slave { u8 backup:1, /* indicates backup slave. Value corresponds with BOND_STATE_ACTIVE and BOND_STATE_BACKUP */ inactive:1; /* indicates inactive slave */ + u8 duplex; u32 original_mtu; u32 link_failure_count; - u8 perm_hwaddr[ETH_ALEN]; - u16 speed; - u8 duplex; + u32 speed; u16 queue_id; + u8 perm_hwaddr[ETH_ALEN]; struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */ struct tlb_slave_info tlb_info; #ifdef CONFIG_NET_POLL_CONTROLLER @@ -231,11 +217,12 @@ struct bonding { struct slave *primary_slave; bool force_primary; s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ + void (*recv_probe)(struct sk_buff *, struct bonding *, + struct slave *); rwlock_t lock; rwlock_t curr_slave_lock; s8 kill_timers; - s8 send_grat_arp; - s8 send_unsol_na; + u8 send_peer_notif; s8 setup_by_slave; s8 igmp_retrans; #ifdef CONFIG_PROC_FS @@ -260,9 +247,6 @@ struct bonding { struct delayed_work alb_work; struct delayed_work ad_work; struct delayed_work mcast_work; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct in6_addr master_ipv6; -#endif #ifdef CONFIG_DEBUG_FS /* debugging suport via debugfs */ struct dentry *debug_dir; @@ -409,13 +393,12 @@ void bond_set_mode_ops(struct bonding *bond, int mode); int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl); void bond_select_active_slave(struct bonding *bond); void bond_change_active_slave(struct bonding *bond, struct slave *new_active); -void bond_register_arp(struct bonding *); -void bond_unregister_arp(struct bonding *); void bond_create_debugfs(void); void bond_destroy_debugfs(void); void bond_debug_register(struct bonding *bond); void bond_debug_unregister(struct bonding *bond); void bond_debug_reregister(struct bonding *bond); +const char *bond_mode_name(int mode); struct bond_net { struct net * net; /* Associated network namespace */ @@ -459,23 +442,4 @@ extern const struct bond_parm_tbl fail_over_mac_tbl[]; extern const struct bond_parm_tbl pri_reselect_tbl[]; extern struct bond_parm_tbl ad_select_tbl[]; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -void bond_send_unsolicited_na(struct bonding *bond); -void bond_register_ipv6_notifier(void); -void bond_unregister_ipv6_notifier(void); -#else -static inline void bond_send_unsolicited_na(struct bonding *bond) -{ - return; -} -static inline void bond_register_ipv6_notifier(void) -{ - return; -} -static inline void bond_unregister_ipv6_notifier(void) -{ - return; -} -#endif - #endif /* _LINUX_BONDING_H */ diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index c0a1bc5b1435..5fedc3375562 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -247,8 +247,10 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev, } #endif /* CONFIG_PPC_MPC512x */ +static struct of_device_id mpc5xxx_can_table[]; static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct mpc5xxx_can_data *data; struct device_node *np = ofdev->dev.of_node; struct net_device *dev; @@ -258,9 +260,10 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) int irq, mscan_clksrc = 0; int err = -ENOMEM; - if (!ofdev->dev.of_match) + match = of_match_device(mpc5xxx_can_table, &ofdev->dev); + if (!match) return -EINVAL; - data = (struct mpc5xxx_can_data *)of_dev->dev.of_match->data; + data = match->data; base = of_iomap(np, 0); if (!base) { diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index a358ea9445a2..f501bba1fc6f 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -346,10 +346,10 @@ static void sja1000_rx(struct net_device *dev) | (priv->read_reg(priv, REG_ID2) >> 5); } + cf->can_dlc = get_can_dlc(fi & 0x0F); if (fi & FI_RTR) { id |= CAN_RTR_FLAG; } else { - cf->can_dlc = get_can_dlc(fi & 0x0F); for (i = 0; i < cf->can_dlc; i++) cf->data[i] = priv->read_reg(priv, dreg++); } diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index b423965a78d1..1b49df6b2470 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -583,7 +583,9 @@ static int slcan_open(struct tty_struct *tty) /* Done. We have linked the TTY line to a channel. */ rtnl_unlock(); tty->receive_room = 65536; /* We don't flow control */ - return sl->dev->base_addr; + + /* TTY layer expects 0 on success */ + return 0; err_free_chan: sl->tty = NULL; diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 143a28c666af..22ce03e55b83 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -709,10 +709,11 @@ static void cas_begin_auto_negotiation(struct cas *cp, struct ethtool_cmd *ep) if (ep->autoneg == AUTONEG_ENABLE) cp->link_cntl = BMCR_ANENABLE; else { + u32 speed = ethtool_cmd_speed(ep); cp->link_cntl = 0; - if (ep->speed == SPEED_100) + if (speed == SPEED_100) cp->link_cntl |= BMCR_SPEED100; - else if (ep->speed == SPEED_1000) + else if (speed == SPEED_1000) cp->link_cntl |= CAS_BMCR_SPEED1000; if (ep->duplex == DUPLEX_FULL) cp->link_cntl |= BMCR_FULLDPLX; @@ -4605,18 +4606,17 @@ static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (bmcr & BMCR_ANENABLE) { cmd->advertising |= ADVERTISED_Autoneg; cmd->autoneg = AUTONEG_ENABLE; - cmd->speed = ((speed == 10) ? - SPEED_10 : - ((speed == 1000) ? - SPEED_1000 : SPEED_100)); + ethtool_cmd_speed_set(cmd, ((speed == 10) ? + SPEED_10 : + ((speed == 1000) ? + SPEED_1000 : SPEED_100))); cmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; } else { cmd->autoneg = AUTONEG_DISABLE; - cmd->speed = - (bmcr & CAS_BMCR_SPEED1000) ? - SPEED_1000 : - ((bmcr & BMCR_SPEED100) ? SPEED_100: - SPEED_10); + ethtool_cmd_speed_set(cmd, ((bmcr & CAS_BMCR_SPEED1000) ? + SPEED_1000 : + ((bmcr & BMCR_SPEED100) ? + SPEED_100 : SPEED_10))); cmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; @@ -4633,14 +4633,14 @@ static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) * settings that we configured. */ if (cp->link_cntl & BMCR_ANENABLE) { - cmd->speed = 0; + ethtool_cmd_speed_set(cmd, 0); cmd->duplex = 0xff; } else { - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); if (cp->link_cntl & BMCR_SPEED100) { - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); } else if (cp->link_cntl & CAS_BMCR_SPEED1000) { - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); } cmd->duplex = (cp->link_cntl & BMCR_FULLDPLX)? DUPLEX_FULL : DUPLEX_HALF; @@ -4653,6 +4653,7 @@ static int cas_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct cas *cp = netdev_priv(dev); unsigned long flags; + u32 speed = ethtool_cmd_speed(cmd); /* Verify the settings we care about. */ if (cmd->autoneg != AUTONEG_ENABLE && @@ -4660,9 +4661,9 @@ static int cas_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EINVAL; if (cmd->autoneg == AUTONEG_DISABLE && - ((cmd->speed != SPEED_1000 && - cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || + ((speed != SPEED_1000 && + speed != SPEED_100 && + speed != SPEED_10) || (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL))) return -EINVAL; diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 092f31a126e6..c26d863e1697 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -264,11 +264,6 @@ struct adapter { enum { /* adapter flags */ FULL_INIT_DONE = 1 << 0, - TSO_CAPABLE = 1 << 2, - TCP_CSUM_CAPABLE = 1 << 3, - UDP_CSUM_CAPABLE = 1 << 4, - VLAN_ACCEL_CAPABLE = 1 << 5, - RX_CSUM_ENABLED = 1 << 6, }; struct mdio_ops; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 0f71304e0542..b422d83f5343 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -192,10 +192,8 @@ static void link_start(struct port_info *p) static void enable_hw_csum(struct adapter *adapter) { - if (adapter->flags & TSO_CAPABLE) + if (adapter->port[0].dev->hw_features & NETIF_F_TSO) t1_tp_set_ip_checksum_offload(adapter->tp, 1); /* for TSO only */ - if (adapter->flags & UDP_CSUM_CAPABLE) - t1_tp_set_udp_checksum_offload(adapter->tp, 1); t1_tp_set_tcp_checksum_offload(adapter->tp, 1); } @@ -579,10 +577,10 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = p->link_config.advertising; if (netif_carrier_ok(dev)) { - cmd->speed = p->link_config.speed; + ethtool_cmd_speed_set(cmd, p->link_config.speed); cmd->duplex = p->link_config.duplex; } else { - cmd->speed = -1; + ethtool_cmd_speed_set(cmd, -1); cmd->duplex = -1; } @@ -640,11 +638,12 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EOPNOTSUPP; /* can't change speed/duplex */ if (cmd->autoneg == AUTONEG_DISABLE) { - int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); + u32 speed = ethtool_cmd_speed(cmd); + int cap = speed_duplex_to_caps(speed, cmd->duplex); - if (!(lc->supported & cap) || cmd->speed == SPEED_1000) + if (!(lc->supported & cap) || (speed == SPEED_1000)) return -EINVAL; - lc->requested_speed = cmd->speed; + lc->requested_speed = speed; lc->requested_duplex = cmd->duplex; lc->advertising = 0; } else { @@ -705,33 +704,6 @@ static int set_pauseparam(struct net_device *dev, return 0; } -static u32 get_rx_csum(struct net_device *dev) -{ - struct adapter *adapter = dev->ml_priv; - - return (adapter->flags & RX_CSUM_ENABLED) != 0; -} - -static int set_rx_csum(struct net_device *dev, u32 data) -{ - struct adapter *adapter = dev->ml_priv; - - if (data) - adapter->flags |= RX_CSUM_ENABLED; - else - adapter->flags &= ~RX_CSUM_ENABLED; - return 0; -} - -static int set_tso(struct net_device *dev, u32 value) -{ - struct adapter *adapter = dev->ml_priv; - - if (!(adapter->flags & TSO_CAPABLE)) - return value ? -EOPNOTSUPP : 0; - return ethtool_op_set_tso(dev, value); -} - static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { struct adapter *adapter = dev->ml_priv; @@ -831,17 +803,12 @@ static const struct ethtool_ops t1_ethtool_ops = { .get_eeprom = get_eeprom, .get_pauseparam = get_pauseparam, .set_pauseparam = set_pauseparam, - .get_rx_csum = get_rx_csum, - .set_rx_csum = set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, - .set_tso = set_tso, }; static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) @@ -1105,28 +1072,28 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; netdev->ml_priv = adapter; - netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - netdev->features |= NETIF_F_LLTX; + netdev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM; + netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM | NETIF_F_LLTX; - adapter->flags |= RX_CSUM_ENABLED | TCP_CSUM_CAPABLE; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; if (vlan_tso_capable(adapter)) { #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) - adapter->flags |= VLAN_ACCEL_CAPABLE; netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; #endif /* T204: disable TSO */ if (!(is_T2(adapter)) || bi->port_number != 4) { - adapter->flags |= TSO_CAPABLE; + netdev->hw_features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO; } } netdev->netdev_ops = &cxgb_netdev_ops; - netdev->hard_header_len += (adapter->flags & TSO_CAPABLE) ? + netdev->hard_header_len += (netdev->hw_features & NETIF_F_TSO) ? sizeof(struct cpl_tx_pkt_lso) : sizeof(struct cpl_tx_pkt); netif_napi_add(netdev, &adapter->napi, t1_poll, 64); diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 8754d4473042..b948ea737550 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -929,7 +929,7 @@ void t1_sge_intr_enable(struct sge *sge) u32 en = SGE_INT_ENABLE; u32 val = readl(sge->adapter->regs + A_PL_ENABLE); - if (sge->adapter->flags & TSO_CAPABLE) + if (sge->adapter->port[0].dev->hw_features & NETIF_F_TSO) en &= ~F_PACKET_TOO_BIG; writel(en, sge->adapter->regs + A_SG_INT_ENABLE); writel(val | SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_ENABLE); @@ -952,7 +952,7 @@ int t1_sge_intr_error_handler(struct sge *sge) struct adapter *adapter = sge->adapter; u32 cause = readl(adapter->regs + A_SG_INT_CAUSE); - if (adapter->flags & TSO_CAPABLE) + if (adapter->port[0].dev->hw_features & NETIF_F_TSO) cause &= ~F_PACKET_TOO_BIG; if (cause & F_RESPQ_EXHAUSTED) sge->stats.respQ_empty++; @@ -1369,6 +1369,7 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) const struct cpl_rx_pkt *p; struct adapter *adapter = sge->adapter; struct sge_port_stats *st; + struct net_device *dev; skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad); if (unlikely(!skb)) { @@ -1384,9 +1385,10 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) __skb_pull(skb, sizeof(*p)); st = this_cpu_ptr(sge->port_stats[p->iff]); + dev = adapter->port[p->iff].dev; - skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev); - if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff && + skb->protocol = eth_type_trans(skb, dev); + if ((dev->features & NETIF_F_RXCSUM) && p->csum == 0xffff && skb->protocol == htons(ETH_P_IP) && (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) { ++st->rx_cso_good; @@ -1838,8 +1840,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - if (!(adapter->flags & UDP_CSUM_CAPABLE) && - skb->ip_summed == CHECKSUM_PARTIAL && + if (skb->ip_summed == CHECKSUM_PARTIAL && ip_hdr(skb)->protocol == IPPROTO_UDP) { if (unlikely(skb_checksum_help(skb))) { pr_debug("%s: unable to do udp checksum\n", dev->name); diff --git a/drivers/net/chelsio/tp.c b/drivers/net/chelsio/tp.c index 6222d585e447..8bed4a59e65f 100644 --- a/drivers/net/chelsio/tp.c +++ b/drivers/net/chelsio/tp.c @@ -152,11 +152,6 @@ void t1_tp_set_ip_checksum_offload(struct petp *tp, int enable) set_csum_offload(tp, F_IP_CSUM, enable); } -void t1_tp_set_udp_checksum_offload(struct petp *tp, int enable) -{ - set_csum_offload(tp, F_UDP_CSUM, enable); -} - void t1_tp_set_tcp_checksum_offload(struct petp *tp, int enable) { set_csum_offload(tp, F_TCP_CSUM, enable); diff --git a/drivers/net/chelsio/tp.h b/drivers/net/chelsio/tp.h index 32fc71e58913..dfd8ce25106a 100644 --- a/drivers/net/chelsio/tp.h +++ b/drivers/net/chelsio/tp.h @@ -65,7 +65,6 @@ void t1_tp_intr_clear(struct petp *tp); int t1_tp_intr_handler(struct petp *tp); void t1_tp_get_mib_statistics(adapter_t *adap, struct tp_mib_statistics *tps); -void t1_tp_set_udp_checksum_offload(struct petp *tp, int enable); void t1_tp_set_tcp_checksum_offload(struct petp *tp, int enable); void t1_tp_set_ip_checksum_offload(struct petp *tp, int enable); int t1_tp_set_coalescing_size(struct petp *tp, unsigned int size); diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 8cca60e43444..cde59b4e5ef8 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -2966,31 +2966,36 @@ static int cnic_service_bnx2x(void *data, void *status_blk) return 0; } +static void cnic_ulp_stop_one(struct cnic_local *cp, int if_type) +{ + struct cnic_ulp_ops *ulp_ops; + + if (if_type == CNIC_ULP_ISCSI) + cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); + + mutex_lock(&cnic_lock); + ulp_ops = rcu_dereference_protected(cp->ulp_ops[if_type], + lockdep_is_held(&cnic_lock)); + if (!ulp_ops) { + mutex_unlock(&cnic_lock); + return; + } + set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); + mutex_unlock(&cnic_lock); + + if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type])) + ulp_ops->cnic_stop(cp->ulp_handle[if_type]); + + clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); +} + static void cnic_ulp_stop(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; int if_type; - cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); - - for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { - struct cnic_ulp_ops *ulp_ops; - - mutex_lock(&cnic_lock); - ulp_ops = rcu_dereference_protected(cp->ulp_ops[if_type], - lockdep_is_held(&cnic_lock)); - if (!ulp_ops) { - mutex_unlock(&cnic_lock); - continue; - } - set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); - mutex_unlock(&cnic_lock); - - if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type])) - ulp_ops->cnic_stop(cp->ulp_handle[if_type]); - - clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); - } + for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) + cnic_ulp_stop_one(cp, if_type); } static void cnic_ulp_start(struct cnic_dev *dev) @@ -3039,6 +3044,12 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info) cnic_put(dev); break; + case CNIC_CTL_STOP_ISCSI_CMD: { + struct cnic_local *cp = dev->cnic_priv; + set_bit(CNIC_LCL_FL_STOP_ISCSI, &cp->cnic_local_flags); + queue_delayed_work(cnic_wq, &cp->delete_task, 0); + break; + } case CNIC_CTL_COMPLETION_CMD: { u32 cid = BNX2X_SW_CID(info->data.comp.cid); u32 l5_cid; @@ -3562,8 +3573,12 @@ static void cnic_init_csk_state(struct cnic_sock *csk) static int cnic_cm_connect(struct cnic_sock *csk, struct cnic_sockaddr *saddr) { + struct cnic_local *cp = csk->dev->cnic_priv; int err = 0; + if (cp->ethdev->drv_state & CNIC_DRV_STATE_NO_ISCSI) + return -EOPNOTSUPP; + if (!cnic_in_use(csk)) return -EINVAL; @@ -3965,6 +3980,15 @@ static void cnic_delete_task(struct work_struct *work) cp = container_of(work, struct cnic_local, delete_task.work); dev = cp->dev; + if (test_and_clear_bit(CNIC_LCL_FL_STOP_ISCSI, &cp->cnic_local_flags)) { + struct drv_ctl_info info; + + cnic_ulp_stop_one(cp, CNIC_ULP_ISCSI); + + info.cmd = DRV_CTL_ISCSI_STOPPED_CMD; + cp->ethdev->drv_ctl(dev->netdev, &info); + } + for (i = 0; i < cp->max_cid_space; i++) { struct cnic_context *ctx = &cp->ctx_tbl[i]; diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h index 4456260c653c..3367a6d3a774 100644 --- a/drivers/net/cnic.h +++ b/drivers/net/cnic.h @@ -226,6 +226,7 @@ struct cnic_local { #define CNIC_LCL_FL_KWQ_INIT 0x0 #define CNIC_LCL_FL_L2_WAIT 0x1 #define CNIC_LCL_FL_RINGS_INITED 0x2 +#define CNIC_LCL_FL_STOP_ISCSI 0x4 struct cnic_dev *dev; diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h index e01b49ee3591..fdd8e46a9050 100644 --- a/drivers/net/cnic_if.h +++ b/drivers/net/cnic_if.h @@ -12,8 +12,8 @@ #ifndef CNIC_IF_H #define CNIC_IF_H -#define CNIC_MODULE_VERSION "2.2.13" -#define CNIC_MODULE_RELDATE "Jan 31, 2011" +#define CNIC_MODULE_VERSION "2.2.14" +#define CNIC_MODULE_RELDATE "Mar 30, 2011" #define CNIC_ULP_RDMA 0 #define CNIC_ULP_ISCSI 1 @@ -85,6 +85,7 @@ struct kcqe { #define CNIC_CTL_STOP_CMD 1 #define CNIC_CTL_START_CMD 2 #define CNIC_CTL_COMPLETION_CMD 3 +#define CNIC_CTL_STOP_ISCSI_CMD 4 #define DRV_CTL_IO_WR_CMD 0x101 #define DRV_CTL_IO_RD_CMD 0x102 @@ -94,6 +95,7 @@ struct kcqe { #define DRV_CTL_START_L2_CMD 0x106 #define DRV_CTL_STOP_L2_CMD 0x107 #define DRV_CTL_RET_L2_SPQ_CREDIT_CMD 0x10c +#define DRV_CTL_ISCSI_STOPPED_CMD 0x10d struct cnic_ctl_completion { u32 cid; diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 9d267d3a6892..e66aceb57cef 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -491,8 +491,8 @@ e100_open(struct net_device *dev) /* allocate the irq corresponding to the receiving DMA */ - if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, - IRQF_SAMPLE_RANDOM, cardname, (void *)dev)) { + if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, 0, cardname, + (void *)dev)) { goto grace_exit0; } diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index ef67be59680f..7300de5a1426 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -50,11 +50,6 @@ struct adapter; struct sge_qset; struct port_info; -enum { /* rx_offload flags */ - T3_RX_CSUM = 1 << 0, - T3_LRO = 1 << 1, -}; - enum mac_idx_types { LAN_MAC_IDX = 0, SAN_MAC_IDX, @@ -74,7 +69,6 @@ struct port_info { struct vlan_group *vlan_grp; struct sge_qset *qs; u8 port_id; - u8 rx_offload; u8 nqsets; u8 first_qset; struct cphy phy; @@ -212,7 +206,6 @@ struct sge_qset { /* an SGE queue set */ struct sge_fl fl[SGE_RXQ_PER_SET]; struct sge_txq txq[SGE_TXQ_PER_SET]; int nomem; - int lro_enabled; void *lro_va; struct net_device *netdev; struct netdev_queue *tx_q; /* associated netdev TX queue */ diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 5ccb77d078aa..056ee8c831f1 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -317,7 +317,6 @@ struct tp_params { struct qset_params { /* SGE queue set parameters */ unsigned int polling; /* polling/interrupt service for rspq */ - unsigned int lro; /* large receive offload */ unsigned int coalesce_usecs; /* irq coalescing timer */ unsigned int rspq_size; /* # of entries in response queue */ unsigned int fl_size; /* # of entries in regular free list */ diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 910893143295..9081ce037149 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -643,26 +643,6 @@ static void enable_all_napi(struct adapter *adap) napi_enable(&adap->sge.qs[i].napi); } -/** - * set_qset_lro - Turn a queue set's LRO capability on and off - * @dev: the device the qset is attached to - * @qset_idx: the queue set index - * @val: the LRO switch - * - * Sets LRO on or off for a particular queue set. - * the device's features flag is updated to reflect the LRO - * capability when all queues belonging to the device are - * in the same state. - */ -static void set_qset_lro(struct net_device *dev, int qset_idx, int val) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - adapter->params.sge.qset[qset_idx].lro = !!val; - adapter->sge.qs[qset_idx].lro_enabled = !!val; -} - /** * setup_sge_qsets - configure SGE Tx/Rx/response queues * @adap: the adapter @@ -685,7 +665,6 @@ static int setup_sge_qsets(struct adapter *adap) pi->qs = &adap->sge.qs[pi->first_qset]; for (j = 0; j < pi->nqsets; ++j, ++qset_idx) { - set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO); err = t3_sge_alloc_qset(adap, qset_idx, 1, (adap->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, @@ -1749,23 +1728,26 @@ static int restart_autoneg(struct net_device *dev) return 0; } -static int cxgb3_phys_id(struct net_device *dev, u32 data) +static int set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct port_info *pi = netdev_priv(dev); struct adapter *adapter = pi->adapter; - int i; - if (data == 0) - data = 2; + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ - for (i = 0; i < data * 2; i++) { + case ETHTOOL_ID_OFF: + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 0); + break; + + case ETHTOOL_ID_ON: + case ETHTOOL_ID_INACTIVE: t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, - (i & 1) ? F_GPIO0_OUT_VAL : 0); - if (msleep_interruptible(500)) - break; - } - t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, F_GPIO0_OUT_VAL); + } + return 0; } @@ -1777,10 +1759,10 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = p->link_config.advertising; if (netif_carrier_ok(dev)) { - cmd->speed = p->link_config.speed; + ethtool_cmd_speed_set(cmd, p->link_config.speed); cmd->duplex = p->link_config.duplex; } else { - cmd->speed = -1; + ethtool_cmd_speed_set(cmd, -1); cmd->duplex = -1; } @@ -1839,7 +1821,8 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) * being requested. */ if (cmd->autoneg == AUTONEG_DISABLE) { - int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); + u32 speed = ethtool_cmd_speed(cmd); + int cap = speed_duplex_to_caps(speed, cmd->duplex); if (lc->supported & cap) return 0; } @@ -1847,11 +1830,12 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) } if (cmd->autoneg == AUTONEG_DISABLE) { - int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); + u32 speed = ethtool_cmd_speed(cmd); + int cap = speed_duplex_to_caps(speed, cmd->duplex); - if (!(lc->supported & cap) || cmd->speed == SPEED_1000) + if (!(lc->supported & cap) || (speed == SPEED_1000)) return -EINVAL; - lc->requested_speed = cmd->speed; + lc->requested_speed = speed; lc->requested_duplex = cmd->duplex; lc->advertising = 0; } else { @@ -1907,29 +1891,6 @@ static int set_pauseparam(struct net_device *dev, return 0; } -static u32 get_rx_csum(struct net_device *dev) -{ - struct port_info *p = netdev_priv(dev); - - return p->rx_offload & T3_RX_CSUM; -} - -static int set_rx_csum(struct net_device *dev, u32 data) -{ - struct port_info *p = netdev_priv(dev); - - if (data) { - p->rx_offload |= T3_RX_CSUM; - } else { - int i; - - p->rx_offload &= ~(T3_RX_CSUM | T3_LRO); - for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) - set_qset_lro(dev, i, 0); - } - return 0; -} - static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { struct port_info *pi = netdev_priv(dev); @@ -2101,20 +2062,15 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .set_eeprom = set_eeprom, .get_pauseparam = get_pauseparam, .set_pauseparam = set_pauseparam, - .get_rx_csum = get_rx_csum, - .set_rx_csum = set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, - .phys_id = cxgb3_phys_id, + .set_phys_id = set_phys_id, .nway_reset = restart_autoneg, .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, .get_wol = get_wol, - .set_tso = ethtool_op_set_tso, }; static int in_range(int val, int lo, int hi) @@ -2162,15 +2118,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) MAX_RSPQ_ENTRIES)) return -EINVAL; - if ((adapter->flags & FULL_INIT_DONE) && t.lro > 0) - for_each_port(adapter, i) { - pi = adap2pinfo(adapter, i); - if (t.qset_idx >= pi->first_qset && - t.qset_idx < pi->first_qset + pi->nqsets && - !(pi->rx_offload & T3_RX_CSUM)) - return -EINVAL; - } - if ((adapter->flags & FULL_INIT_DONE) && (t.rspq_size >= 0 || t.fl_size[0] >= 0 || t.fl_size[1] >= 0 || t.txq_size[0] >= 0 || @@ -2231,8 +2178,14 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) } } } - if (t.lro >= 0) - set_qset_lro(dev, t.qset_idx, t.lro); + + if (t.lro >= 0) { + if (t.lro) + dev->wanted_features |= NETIF_F_GRO; + else + dev->wanted_features &= ~NETIF_F_GRO; + netdev_update_features(dev); + } break; } @@ -2266,7 +2219,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) t.fl_size[0] = q->fl_size; t.fl_size[1] = q->jumbo_size; t.polling = q->polling; - t.lro = q->lro; + t.lro = !!(dev->features & NETIF_F_GRO); t.intr_lat = q->coalesce_usecs; t.cong_thres = q->cong_thres; t.qnum = q1; @@ -3304,18 +3257,18 @@ static int __devinit init_one(struct pci_dev *pdev, adapter->port[i] = netdev; pi = netdev_priv(netdev); pi->adapter = adapter; - pi->rx_offload = T3_RX_CSUM | T3_LRO; pi->port_id = i; netif_carrier_off(netdev); netdev->irq = pdev->irq; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; - netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; - netdev->features |= NETIF_F_GRO; + netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO | NETIF_F_RXCSUM; + netdev->features |= netdev->hw_features | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; - netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; netdev->netdev_ops = &cxgb_netdev_ops; SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); } diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index bfa2d56af1ee..cba1401377ab 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -2019,7 +2019,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, skb_pull(skb, sizeof(*p) + pad); skb->protocol = eth_type_trans(skb, adap->port[p->iff]); pi = netdev_priv(skb->dev); - if ((pi->rx_offload & T3_RX_CSUM) && p->csum_valid && + if ((skb->dev->features & NETIF_F_RXCSUM) && p->csum_valid && p->csum == htons(0xffff) && !p->fragment) { qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2120,7 +2120,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, offset = 2 + sizeof(struct cpl_rx_pkt); cpl = qs->lro_va = sd->pg_chunk.va + 2; - if ((pi->rx_offload & T3_RX_CSUM) && + if ((qs->netdev->features & NETIF_F_RXCSUM) && cpl->csum_valid && cpl->csum == htons(0xffff)) { skb->ip_summed = CHECKSUM_UNNECESSARY; qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; @@ -2285,7 +2285,8 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, q->next_holdoff = q->holdoff_tmr; while (likely(budget_left && is_new_response(r, q))) { - int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled; + int packet_complete, eth, ethpad = 2; + int lro = !!(qs->netdev->features & NETIF_F_GRO); struct sk_buff *skb = NULL; u32 len, flags; __be32 rss_hi, rss_lo; diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h index 01d49eaa44d2..bc9982a4c1f4 100644 --- a/drivers/net/cxgb4/cxgb4.h +++ b/drivers/net/cxgb4/cxgb4.h @@ -290,7 +290,6 @@ struct port_info { u8 port_id; u8 tx_chan; u8 lport; /* associated offload logical port */ - u8 rx_offload; /* CSO, etc */ u8 nqsets; /* # of qsets */ u8 first_qset; /* index of first qset */ u8 rss_mode; @@ -298,11 +297,6 @@ struct port_info { u16 *rss; }; -/* port_info.rx_offload flags */ -enum { - RX_CSO = 1 << 0, -}; - struct dentry; struct work_struct; diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c index 5352c8a23f4d..7e3cfbe89e3b 100644 --- a/drivers/net/cxgb4/cxgb4_main.c +++ b/drivers/net/cxgb4/cxgb4_main.c @@ -1336,15 +1336,20 @@ static int restart_autoneg(struct net_device *dev) return 0; } -static int identify_port(struct net_device *dev, u32 data) +static int identify_port(struct net_device *dev, + enum ethtool_phys_id_state state) { + unsigned int val; struct adapter *adap = netdev2adap(dev); - if (data == 0) - data = 2; /* default to 2 seconds */ + if (state == ETHTOOL_ID_ACTIVE) + val = 0xffff; + else if (state == ETHTOOL_ID_INACTIVE) + val = 0; + else + return -EINVAL; - return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, - data * 5); + return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, val); } static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps) @@ -1431,7 +1436,8 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported = from_fw_linkcaps(p->port_type, p->link_cfg.supported); cmd->advertising = from_fw_linkcaps(p->port_type, p->link_cfg.advertising); - cmd->speed = netif_carrier_ok(dev) ? p->link_cfg.speed : 0; + ethtool_cmd_speed_set(cmd, + netif_carrier_ok(dev) ? p->link_cfg.speed : 0); cmd->duplex = DUPLEX_FULL; cmd->autoneg = p->link_cfg.autoneg; cmd->maxtxpkt = 0; @@ -1455,6 +1461,7 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) unsigned int cap; struct port_info *p = netdev_priv(dev); struct link_config *lc = &p->link_cfg; + u32 speed = ethtool_cmd_speed(cmd); if (cmd->duplex != DUPLEX_FULL) /* only full-duplex supported */ return -EINVAL; @@ -1465,16 +1472,16 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) * being requested. */ if (cmd->autoneg == AUTONEG_DISABLE && - (lc->supported & speed_to_caps(cmd->speed))) - return 0; + (lc->supported & speed_to_caps(speed))) + return 0; return -EINVAL; } if (cmd->autoneg == AUTONEG_DISABLE) { - cap = speed_to_caps(cmd->speed); + cap = speed_to_caps(speed); - if (!(lc->supported & cap) || cmd->speed == SPEED_1000 || - cmd->speed == SPEED_10000) + if (!(lc->supported & cap) || (speed == SPEED_1000) || + (speed == SPEED_10000)) return -EINVAL; lc->requested_speed = cap; lc->advertising = 0; @@ -1526,24 +1533,6 @@ static int set_pauseparam(struct net_device *dev, return 0; } -static u32 get_rx_csum(struct net_device *dev) -{ - struct port_info *p = netdev_priv(dev); - - return p->rx_offload & RX_CSO; -} - -static int set_rx_csum(struct net_device *dev, u32 data) -{ - struct port_info *p = netdev_priv(dev); - - if (data) - p->rx_offload |= RX_CSO; - else - p->rx_offload &= ~RX_CSO; - return 0; -} - static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { const struct port_info *pi = netdev_priv(dev); @@ -1865,36 +1854,20 @@ static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return err; } -#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) - -static int set_tso(struct net_device *dev, u32 value) -{ - if (value) - dev->features |= TSO_FLAGS; - else - dev->features &= ~TSO_FLAGS; - return 0; -} - -static int set_flags(struct net_device *dev, u32 flags) +static int cxgb_set_features(struct net_device *dev, u32 features) { + const struct port_info *pi = netdev_priv(dev); + u32 changed = dev->features ^ features; int err; - unsigned long old_feat = dev->features; - err = ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH | - ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN); - if (err) - return err; + if (!(changed & NETIF_F_HW_VLAN_RX)) + return 0; - if ((old_feat ^ dev->features) & NETIF_F_HW_VLAN_RX) { - const struct port_info *pi = netdev_priv(dev); - - err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1, - -1, -1, -1, !!(flags & ETH_FLAG_RXVLAN), - true); - if (err) - dev->features = old_feat; - } + err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1, + -1, -1, -1, + !!(features & NETIF_F_HW_VLAN_RX), true); + if (unlikely(err)) + dev->features = features ^ NETIF_F_HW_VLAN_RX; return err; } @@ -2005,13 +1978,9 @@ static struct ethtool_ops cxgb_ethtool_ops = { .set_eeprom = set_eeprom, .get_pauseparam = get_pauseparam, .set_pauseparam = set_pauseparam, - .get_rx_csum = get_rx_csum, - .set_rx_csum = set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, - .phys_id = identify_port, + .set_phys_id = identify_port, .nway_reset = restart_autoneg, .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, @@ -2019,8 +1988,6 @@ static struct ethtool_ops cxgb_ethtool_ops = { .get_regs = get_regs, .get_wol = get_wol, .set_wol = set_wol, - .set_tso = set_tso, - .set_flags = set_flags, .get_rxnfc = get_rxnfc, .get_rxfh_indir = get_rss_table, .set_rxfh_indir = set_rss_table, @@ -2877,6 +2844,7 @@ static const struct net_device_ops cxgb4_netdev_ops = { .ndo_get_stats64 = cxgb_get_stats, .ndo_set_rx_mode = cxgb_set_rxmode, .ndo_set_mac_address = cxgb_set_mac_addr, + .ndo_set_features = cxgb_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = cxgb_ioctl, .ndo_change_mtu = cxgb_change_mtu, @@ -3559,6 +3527,7 @@ static void free_some_resources(struct adapter *adapter) t4_fw_bye(adapter, adapter->fn); } +#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) #define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \ NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA) @@ -3660,14 +3629,14 @@ static int __devinit init_one(struct pci_dev *pdev, pi = netdev_priv(netdev); pi->adapter = adapter; pi->xact_addr_filt = -1; - pi->rx_offload = RX_CSO; pi->port_id = i; netdev->irq = pdev->irq; - netdev->features |= NETIF_F_SG | TSO_FLAGS; - netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - netdev->features |= NETIF_F_GRO | NETIF_F_RXHASH | highdma; - netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + netdev->hw_features = NETIF_F_SG | TSO_FLAGS | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM | NETIF_F_RXHASH | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + netdev->features |= netdev->hw_features | highdma; netdev->vlan_features = netdev->features & VLAN_FEAT; netdev->netdev_ops = &cxgb4_netdev_ops; diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/cxgb4/sge.c index 311471b439a8..75a4b0fa19ee 100644 --- a/drivers/net/cxgb4/sge.c +++ b/drivers/net/cxgb4/sge.c @@ -1556,7 +1556,6 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, { bool csum_ok; struct sk_buff *skb; - struct port_info *pi; const struct cpl_rx_pkt *pkt; struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq); @@ -1584,10 +1583,9 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, if (skb->dev->features & NETIF_F_RXHASH) skb->rxhash = (__force u32)pkt->rsshdr.hash_val; - pi = netdev_priv(skb->dev); rxq->stats.pkts++; - if (csum_ok && (pi->rx_offload & RX_CSO) && + if (csum_ok && (q->netdev->features & NETIF_F_RXCSUM) && (pkt->l2info & htonl(RXF_UDP | RXF_TCP))) { if (!pkt->ip_frag) { skb->ip_summed = CHECKSUM_UNNECESSARY; diff --git a/drivers/net/cxgb4vf/adapter.h b/drivers/net/cxgb4vf/adapter.h index 4766b4116b41..4fd821aadc8a 100644 --- a/drivers/net/cxgb4vf/adapter.h +++ b/drivers/net/cxgb4vf/adapter.h @@ -97,17 +97,11 @@ struct port_info { u16 rss_size; /* size of VI's RSS table slice */ u8 pidx; /* index into adapter port[] */ u8 port_id; /* physical port ID */ - u8 rx_offload; /* CSO, etc. */ u8 nqsets; /* # of "Queue Sets" */ u8 first_qset; /* index of first "Queue Set" */ struct link_config link_cfg; /* physical port configuration */ }; -/* port_info.rx_offload flags */ -enum { - RX_CSO = 1 << 0, -}; - /* * Scatter Gather Engine resources for the "adapter". Our ingress and egress * queues are organized into "Queue Sets" with one ingress and one egress diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 4661cbbd9bd9..e71c08e547e4 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -1167,7 +1167,8 @@ static int cxgb4vf_get_settings(struct net_device *dev, cmd->supported = pi->link_cfg.supported; cmd->advertising = pi->link_cfg.advertising; - cmd->speed = netif_carrier_ok(dev) ? pi->link_cfg.speed : -1; + ethtool_cmd_speed_set(cmd, + netif_carrier_ok(dev) ? pi->link_cfg.speed : -1); cmd->duplex = DUPLEX_FULL; cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; @@ -1325,38 +1326,23 @@ static void cxgb4vf_get_pauseparam(struct net_device *dev, pauseparam->tx_pause = (pi->link_cfg.fc & PAUSE_TX) != 0; } -/* - * Return whether RX Checksum Offloading is currently enabled for the device. - */ -static u32 cxgb4vf_get_rx_csum(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - - return (pi->rx_offload & RX_CSO) != 0; -} - -/* - * Turn RX Checksum Offloading on or off for the device. - */ -static int cxgb4vf_set_rx_csum(struct net_device *dev, u32 csum) -{ - struct port_info *pi = netdev_priv(dev); - - if (csum) - pi->rx_offload |= RX_CSO; - else - pi->rx_offload &= ~RX_CSO; - return 0; -} - /* * Identify the port by blinking the port's LED. */ -static int cxgb4vf_phys_id(struct net_device *dev, u32 id) +static int cxgb4vf_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { + unsigned int val; struct port_info *pi = netdev_priv(dev); - return t4vf_identify_port(pi->adapter, pi->viid, 5); + if (state == ETHTOOL_ID_ACTIVE) + val = 0xffff; + else if (state == ETHTOOL_ID_INACTIVE) + val = 0; + else + return -EINVAL; + + return t4vf_identify_port(pi->adapter, pi->viid, val); } /* @@ -1560,18 +1546,6 @@ static void cxgb4vf_get_wol(struct net_device *dev, */ #define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) -/* - * Set TCP Segmentation Offloading feature capabilities. - */ -static int cxgb4vf_set_tso(struct net_device *dev, u32 tso) -{ - if (tso) - dev->features |= TSO_FLAGS; - else - dev->features &= ~TSO_FLAGS; - return 0; -} - static struct ethtool_ops cxgb4vf_ethtool_ops = { .get_settings = cxgb4vf_get_settings, .get_drvinfo = cxgb4vf_get_drvinfo, @@ -1582,19 +1556,14 @@ static struct ethtool_ops cxgb4vf_ethtool_ops = { .get_coalesce = cxgb4vf_get_coalesce, .set_coalesce = cxgb4vf_set_coalesce, .get_pauseparam = cxgb4vf_get_pauseparam, - .get_rx_csum = cxgb4vf_get_rx_csum, - .set_rx_csum = cxgb4vf_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = cxgb4vf_get_strings, - .phys_id = cxgb4vf_phys_id, + .set_phys_id = cxgb4vf_phys_id, .get_sset_count = cxgb4vf_get_sset_count, .get_ethtool_stats = cxgb4vf_get_ethtool_stats, .get_regs_len = cxgb4vf_get_regs_len, .get_regs = cxgb4vf_get_regs, .get_wol = cxgb4vf_get_wol, - .set_tso = cxgb4vf_set_tso, }; /* @@ -2629,19 +2598,19 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, * it. */ pi->xact_addr_filt = -1; - pi->rx_offload = RX_CSO; netif_carrier_off(netdev); netdev->irq = pdev->irq; - netdev->features = (NETIF_F_SG | TSO_FLAGS | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | - NETIF_F_GRO); + netdev->hw_features = NETIF_F_SG | TSO_FLAGS | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM; + netdev->vlan_features = NETIF_F_SG | TSO_FLAGS | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_HIGHDMA; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_RX; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; - netdev->vlan_features = - (netdev->features & - ~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX)); #ifdef HAVE_NET_DEVICE_OPS netdev->netdev_ops = &cxgb4vf_netdev_ops; diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c index bb65121f581c..5182960e29fd 100644 --- a/drivers/net/cxgb4vf/sge.c +++ b/drivers/net/cxgb4vf/sge.c @@ -1555,8 +1555,8 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, pi = netdev_priv(skb->dev); rxq->stats.pkts++; - if (csum_ok && (pi->rx_offload & RX_CSO) && !pkt->err_vec && - (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) { + if (csum_ok && (rspq->netdev->features & NETIF_F_RXCSUM) && + !pkt->err_vec && (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) { if (!pkt->ip_frag) skb->ip_summed = CHECKSUM_UNNECESSARY; else { diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 8b0084d17c8c..17654059922d 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -331,18 +331,18 @@ static struct { "DE422",\ ""} -static char* __initdata depca_signature[] = DEPCA_SIGNATURE; +static const char* const depca_signature[] __devinitconst = DEPCA_SIGNATURE; enum depca_type { DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown }; -static char depca_string[] = "depca"; +static const char depca_string[] = "depca"; static int depca_device_remove (struct device *device); #ifdef CONFIG_EISA -static struct eisa_device_id depca_eisa_ids[] = { +static const struct eisa_device_id depca_eisa_ids[] __devinitconst = { { "DEC4220", de422 }, { "" } }; @@ -367,19 +367,19 @@ static struct eisa_driver depca_eisa_driver = { #define DE210_ID 0x628d #define DE212_ID 0x6def -static short depca_mca_adapter_ids[] = { +static const short depca_mca_adapter_ids[] __devinitconst = { DE210_ID, DE212_ID, 0x0000 }; -static char *depca_mca_adapter_name[] = { +static const char *depca_mca_adapter_name[] = { "DEC EtherWORKS MC Adapter (DE210)", "DEC EtherWORKS MC Adapter (DE212)", NULL }; -static enum depca_type depca_mca_adapter_type[] = { +static const enum depca_type depca_mca_adapter_type[] = { de210, de212, 0 @@ -541,10 +541,9 @@ static void SetMulticastFilter(struct net_device *dev); static int load_packet(struct net_device *dev, struct sk_buff *skb); static void depca_dbg_open(struct net_device *dev); -static u_char de1xx_irq[] __initdata = { 2, 3, 4, 5, 7, 9, 0 }; -static u_char de2xx_irq[] __initdata = { 5, 9, 10, 11, 15, 0 }; -static u_char de422_irq[] __initdata = { 5, 9, 10, 11, 0 }; -static u_char *depca_irq; +static const u_char de1xx_irq[] __devinitconst = { 2, 3, 4, 5, 7, 9, 0 }; +static const u_char de2xx_irq[] __devinitconst = { 5, 9, 10, 11, 15, 0 }; +static const u_char de422_irq[] __devinitconst = { 5, 9, 10, 11, 0 }; static int irq; static int io; @@ -580,7 +579,7 @@ static const struct net_device_ops depca_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -static int __init depca_hw_init (struct net_device *dev, struct device *device) +static int __devinit depca_hw_init (struct net_device *dev, struct device *device) { struct depca_private *lp; int i, j, offset, netRAM, mem_len, status = 0; @@ -748,6 +747,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) if (dev->irq < 2) { unsigned char irqnum; unsigned long irq_mask, delay; + const u_char *depca_irq; irq_mask = probe_irq_on(); @@ -770,6 +770,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) break; default: + depca_irq = NULL; break; /* Not reached */ } @@ -1302,7 +1303,7 @@ static void SetMulticastFilter(struct net_device *dev) } } -static int __init depca_common_init (u_long ioaddr, struct net_device **devp) +static int __devinit depca_common_init (u_long ioaddr, struct net_device **devp) { int status = 0; @@ -1333,7 +1334,7 @@ static int __init depca_common_init (u_long ioaddr, struct net_device **devp) /* ** Microchannel bus I/O device probe */ -static int __init depca_mca_probe(struct device *device) +static int __devinit depca_mca_probe(struct device *device) { unsigned char pos[2]; unsigned char where; @@ -1457,7 +1458,7 @@ static int __init depca_mca_probe(struct device *device) ** ISA bus I/O device probe */ -static void __init depca_platform_probe (void) +static void __devinit depca_platform_probe (void) { int i; struct platform_device *pldev; @@ -1497,7 +1498,7 @@ static void __init depca_platform_probe (void) } } -static enum depca_type __init depca_shmem_probe (ulong *mem_start) +static enum depca_type __devinit depca_shmem_probe (ulong *mem_start) { u_long mem_base[] = DEPCA_RAM_BASE_ADDRESSES; enum depca_type adapter = unknown; @@ -1558,7 +1559,7 @@ static int __devinit depca_isa_probe (struct platform_device *device) */ #ifdef CONFIG_EISA -static int __init depca_eisa_probe (struct device *device) +static int __devinit depca_eisa_probe (struct device *device) { enum depca_type adapter = unknown; struct eisa_device *edev; @@ -1629,7 +1630,7 @@ static int __devexit depca_device_remove (struct device *device) ** and Boot (readb) ROM. This will also give us a clue to the network RAM ** base address. */ -static int __init DepcaSignature(char *name, u_long base_addr) +static int __devinit DepcaSignature(char *name, u_long base_addr) { u_int i, j, k; void __iomem *ptr; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index c05db6046050..c445457b66d5 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -1189,10 +1189,10 @@ static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->transceiver = XCVR_INTERNAL; } if ( np->link_status ) { - cmd->speed = np->speed; + ethtool_cmd_speed_set(cmd, np->speed); cmd->duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; } else { - cmd->speed = -1; + ethtool_cmd_speed_set(cmd, -1); cmd->duplex = -1; } if ( np->an_enable) @@ -1219,31 +1219,20 @@ static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) } else { np->an_enable = 0; if (np->speed == 1000) { - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); cmd->duplex = DUPLEX_FULL; printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manual 100Mbps, Full duplex.\n"); } - switch(cmd->speed + cmd->duplex) { - - case SPEED_10 + DUPLEX_HALF: + switch (ethtool_cmd_speed(cmd)) { + case SPEED_10: np->speed = 10; - np->full_duplex = 0; + np->full_duplex = (cmd->duplex == DUPLEX_FULL); break; - - case SPEED_10 + DUPLEX_FULL: - np->speed = 10; - np->full_duplex = 1; - break; - case SPEED_100 + DUPLEX_HALF: + case SPEED_100: np->speed = 100; - np->full_duplex = 0; + np->full_duplex = (cmd->duplex == DUPLEX_FULL); break; - case SPEED_100 + DUPLEX_FULL: - np->speed = 100; - np->full_duplex = 1; - break; - case SPEED_1000 + DUPLEX_HALF:/* not supported */ - case SPEED_1000 + DUPLEX_FULL:/* not supported */ + case SPEED_1000: /* not supported */ default: return -EINVAL; } diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index b7af5bab9937..fbaff3584bd4 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -131,8 +131,6 @@ typedef struct board_info { u32 msg_enable; u32 wake_state; - int rx_csum; - int can_csum; int ip_summed; } board_info_t; @@ -470,47 +468,20 @@ static int dm9000_nway_reset(struct net_device *dev) return mii_nway_restart(&dm->mii); } -static uint32_t dm9000_get_rx_csum(struct net_device *dev) -{ - board_info_t *dm = to_dm9000_board(dev); - return dm->rx_csum; -} - -static int dm9000_set_rx_csum_unlocked(struct net_device *dev, uint32_t data) -{ - board_info_t *dm = to_dm9000_board(dev); - - if (dm->can_csum) { - dm->rx_csum = data; - iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0); - - return 0; - } - - return -EOPNOTSUPP; -} - -static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) +static int dm9000_set_features(struct net_device *dev, u32 features) { board_info_t *dm = to_dm9000_board(dev); + u32 changed = dev->features ^ features; unsigned long flags; - int ret; + + if (!(changed & NETIF_F_RXCSUM)) + return 0; spin_lock_irqsave(&dm->lock, flags); - ret = dm9000_set_rx_csum_unlocked(dev, data); + iow(dm, DM9000_RCSR, (features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); spin_unlock_irqrestore(&dm->lock, flags); - return ret; -} - -static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data) -{ - board_info_t *dm = to_dm9000_board(dev); - int ret = -EOPNOTSUPP; - - if (dm->can_csum) - ret = ethtool_op_set_tx_csum(dev, data); - return ret; + return 0; } static u32 dm9000_get_link(struct net_device *dev) @@ -643,10 +614,6 @@ static const struct ethtool_ops dm9000_ethtool_ops = { .get_eeprom_len = dm9000_get_eeprom_len, .get_eeprom = dm9000_get_eeprom, .set_eeprom = dm9000_set_eeprom, - .get_rx_csum = dm9000_get_rx_csum, - .set_rx_csum = dm9000_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = dm9000_set_tx_csum, }; static void dm9000_show_carrier(board_info_t *db, @@ -800,7 +767,9 @@ dm9000_init_dm9000(struct net_device *dev) db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ /* Checksum mode */ - dm9000_set_rx_csum_unlocked(dev, db->rx_csum); + if (dev->hw_features & NETIF_F_RXCSUM) + iow(db, DM9000_RCSR, + (dev->features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ @@ -1049,7 +1018,7 @@ dm9000_rx(struct net_device *dev) /* Pass to upper layer */ skb->protocol = eth_type_trans(skb, dev); - if (db->rx_csum) { + if (dev->features & NETIF_F_RXCSUM) { if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0) skb->ip_summed = CHECKSUM_UNNECESSARY; else @@ -1358,6 +1327,7 @@ static const struct net_device_ops dm9000_netdev_ops = { .ndo_set_multicast_list = dm9000_hash_table, .ndo_do_ioctl = dm9000_ioctl, .ndo_change_mtu = eth_change_mtu, + .ndo_set_features = dm9000_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1551,9 +1521,8 @@ dm9000_probe(struct platform_device *pdev) /* dm9000a/b are capable of hardware checksum offload */ if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) { - db->can_csum = 1; - db->rx_csum = 1; - ndev->features |= NETIF_F_IP_CSUM; + ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM; + ndev->features |= ndev->hw_features; } /* from this point we assume that we have found a DM9000 */ diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index ff2d29b17858..39cf9b9bd673 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -168,10 +168,6 @@ static int __init dummy_init_one(void) if (!dev_dummy) return -ENOMEM; - err = dev_alloc_name(dev_dummy, dev_dummy->name); - if (err < 0) - goto err; - dev_dummy->rtnl_link_ops = &dummy_link_ops; err = register_netdevice(dev_dummy); if (err < 0) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index b0aa9e68990a..e336c7937f05 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -593,7 +593,6 @@ struct nic { enum phy phy; struct params params; struct timer_list watchdog; - struct timer_list blink_timer; struct mii_if_info mii; struct work_struct tx_timeout_task; enum loopback loopback; @@ -618,7 +617,6 @@ struct nic { u32 rx_tco_frames; u32 rx_over_length_errors; - u16 leds; u16 eeprom_wc; __le16 eeprom[256]; spinlock_t mdio_lock; @@ -1512,7 +1510,7 @@ static int e100_phy_init(struct nic *nic) static int e100_hw_init(struct nic *nic) { - int err; + int err = 0; e100_hw_reset(nic); @@ -1668,7 +1666,8 @@ static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex) static void e100_watchdog(unsigned long data) { struct nic *nic = (struct nic *)data; - struct ethtool_cmd cmd; + struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; + u32 speed; netif_printk(nic, timer, KERN_DEBUG, nic->netdev, "right now = %ld\n", jiffies); @@ -1676,10 +1675,11 @@ static void e100_watchdog(unsigned long data) /* mii library handles link maintenance tasks */ mii_ethtool_gset(&nic->mii, &cmd); + speed = ethtool_cmd_speed(&cmd); if (mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) { netdev_info(nic->netdev, "NIC Link is Up %u Mbps %s Duplex\n", - cmd.speed == SPEED_100 ? 100 : 10, + speed == SPEED_100 ? 100 : 10, cmd.duplex == DUPLEX_FULL ? "Full" : "Half"); } else if (!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) { netdev_info(nic->netdev, "NIC Link is Down\n"); @@ -1698,13 +1698,13 @@ static void e100_watchdog(unsigned long data) spin_unlock_irq(&nic->cmd_lock); e100_update_stats(nic); - e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex); + e100_adjust_adaptive_ifs(nic, speed, cmd.duplex); if (nic->mac <= mac_82557_D100_C) /* Issue a multicast command to workaround a 557 lock up */ e100_set_multicast_list(nic->netdev); - if (nic->flags & ich && cmd.speed==SPEED_10 && cmd.duplex==DUPLEX_HALF) + if (nic->flags & ich && speed == SPEED_10 && cmd.duplex == DUPLEX_HALF) /* Need SW workaround for ICH[x] 10Mbps/half duplex Tx hang. */ nic->flags |= ich_10h_workaround; else @@ -2351,30 +2351,6 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) #define E100_82552_LED_OVERRIDE 0x19 #define E100_82552_LED_ON 0x000F /* LEDTX and LED_RX both on */ #define E100_82552_LED_OFF 0x000A /* LEDTX and LED_RX both off */ -static void e100_blink_led(unsigned long data) -{ - struct nic *nic = (struct nic *)data; - enum led_state { - led_on = 0x01, - led_off = 0x04, - led_on_559 = 0x05, - led_on_557 = 0x07, - }; - u16 led_reg = MII_LED_CONTROL; - - if (nic->phy == phy_82552_v) { - led_reg = E100_82552_LED_OVERRIDE; - - nic->leds = (nic->leds == E100_82552_LED_ON) ? - E100_82552_LED_OFF : E100_82552_LED_ON; - } else { - nic->leds = (nic->leds & led_on) ? led_off : - (nic->mac < mac_82559_D101M) ? led_on_557 : - led_on_559; - } - mdio_write(nic->netdev, nic->mii.phy_id, led_reg, nic->leds); - mod_timer(&nic->blink_timer, jiffies + HZ / 4); -} static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) { @@ -2598,19 +2574,38 @@ static void e100_diag_test(struct net_device *netdev, msleep_interruptible(4 * 1000); } -static int e100_phys_id(struct net_device *netdev, u32 data) +static int e100_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct nic *nic = netdev_priv(netdev); + enum led_state { + led_on = 0x01, + led_off = 0x04, + led_on_559 = 0x05, + led_on_557 = 0x07, + }; u16 led_reg = (nic->phy == phy_82552_v) ? E100_82552_LED_OVERRIDE : - MII_LED_CONTROL; + MII_LED_CONTROL; + u16 leds = 0; - if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) - data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); - mod_timer(&nic->blink_timer, jiffies); - msleep_interruptible(data * 1000); - del_timer_sync(&nic->blink_timer); - mdio_write(netdev, nic->mii.phy_id, led_reg, 0); + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 2; + case ETHTOOL_ID_ON: + leds = (nic->phy == phy_82552_v) ? E100_82552_LED_ON : + (nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559; + break; + + case ETHTOOL_ID_OFF: + leds = (nic->phy == phy_82552_v) ? E100_82552_LED_OFF : led_off; + break; + + case ETHTOOL_ID_INACTIVE: + break; + } + + mdio_write(netdev, nic->mii.phy_id, led_reg, leds); return 0; } @@ -2691,7 +2686,7 @@ static const struct ethtool_ops e100_ethtool_ops = { .set_ringparam = e100_set_ringparam, .self_test = e100_diag_test, .get_strings = e100_get_strings, - .phys_id = e100_phys_id, + .set_phys_id = e100_set_phys_id, .get_ethtool_stats = e100_get_ethtool_stats, .get_sset_count = e100_get_sset_count, }; @@ -2832,9 +2827,6 @@ static int __devinit e100_probe(struct pci_dev *pdev, init_timer(&nic->watchdog); nic->watchdog.function = e100_watchdog; nic->watchdog.data = (unsigned long)nic; - init_timer(&nic->blink_timer); - nic->blink_timer.function = e100_blink_led; - nic->blink_timer.data = (unsigned long)nic; INIT_WORK(&nic->tx_timeout_task, e100_tx_timeout_task); diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index a881dd0093bd..8676899120c3 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -238,9 +238,6 @@ struct e1000_adapter { struct work_struct reset_task; u8 fc_autoneg; - struct timer_list blink_timer; - unsigned long led_status; - /* TX */ struct e1000_tx_ring *tx_ring; /* One per active queue */ unsigned int restart_queue; @@ -349,7 +346,7 @@ extern int e1000_up(struct e1000_adapter *adapter); extern void e1000_down(struct e1000_adapter *adapter); extern void e1000_reinit_locked(struct e1000_adapter *adapter); extern void e1000_reset(struct e1000_adapter *adapter); -extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx); +extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx); extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter); diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index dd70738eb2f4..ec0fa426cce2 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -158,7 +158,7 @@ static int e1000_get_settings(struct net_device *netdev, e1000_get_speed_and_duplex(hw, &adapter->link_speed, &adapter->link_duplex); - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); /* unfortunately FULL_DUPLEX != DUPLEX_FULL * and HALF_DUPLEX != DUPLEX_HALF */ @@ -168,7 +168,7 @@ static int e1000_get_settings(struct net_device *netdev, else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } @@ -197,11 +197,13 @@ static int e1000_set_settings(struct net_device *netdev, ADVERTISED_TP | ADVERTISED_Autoneg; ecmd->advertising = hw->autoneg_advertised; - } else - if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { + } else { + u32 speed = ethtool_cmd_speed(ecmd); + if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->flags); return -EINVAL; } + } /* reset the link */ @@ -1753,46 +1755,28 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) return 0; } -/* toggle LED 4 times per second = 2 "blinks" per second */ -#define E1000_ID_INTERVAL (HZ/4) - -/* bit defines for adapter->led_status */ -#define E1000_LED_ON 0 - -static void e1000_led_blink_callback(unsigned long data) -{ - struct e1000_adapter *adapter = (struct e1000_adapter *) data; - struct e1000_hw *hw = &adapter->hw; - - if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) - e1000_led_off(hw); - else - e1000_led_on(hw); - - mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); -} - -static int e1000_phys_id(struct net_device *netdev, u32 data) +static int e1000_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - if (!data) - data = INT_MAX; + switch (state) { + case ETHTOOL_ID_ACTIVE: + e1000_setup_led(hw); + return 2; - if (!adapter->blink_timer.function) { - init_timer(&adapter->blink_timer); - adapter->blink_timer.function = e1000_led_blink_callback; - adapter->blink_timer.data = (unsigned long)adapter; + case ETHTOOL_ID_ON: + e1000_led_on(hw); + break; + + case ETHTOOL_ID_OFF: + e1000_led_off(hw); + break; + + case ETHTOOL_ID_INACTIVE: + e1000_cleanup_led(hw); } - e1000_setup_led(hw); - mod_timer(&adapter->blink_timer, jiffies); - msleep_interruptible(data * 1000); - del_timer_sync(&adapter->blink_timer); - - e1000_led_off(hw); - clear_bit(E1000_LED_ON, &adapter->led_status); - e1000_cleanup_led(hw); return 0; } @@ -1929,7 +1913,7 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_tso = e1000_set_tso, .self_test = e1000_diag_test, .get_strings = e1000_get_strings, - .phys_id = e1000_phys_id, + .set_phys_id = e1000_set_phys_id, .get_ethtool_stats = e1000_get_ethtool_stats, .get_sset_count = e1000_get_sset_count, .get_coalesce = e1000_get_coalesce, diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 477e066a1cf0..c18cb8e883dd 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -96,7 +96,6 @@ int e1000_up(struct e1000_adapter *adapter); void e1000_down(struct e1000_adapter *adapter); void e1000_reinit_locked(struct e1000_adapter *adapter); void e1000_reset(struct e1000_adapter *adapter); -int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx); int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); void e1000_free_all_tx_resources(struct e1000_adapter *adapter); @@ -4385,7 +4384,6 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, struct mii_ioctl_data *data = if_mii(ifr); int retval; u16 mii_reg; - u16 spddplx; unsigned long flags; if (hw->media_type != e1000_media_type_copper) @@ -4424,17 +4422,18 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, hw->autoneg = 1; hw->autoneg_advertised = 0x2F; } else { + u32 speed; if (mii_reg & 0x40) - spddplx = SPEED_1000; + speed = SPEED_1000; else if (mii_reg & 0x2000) - spddplx = SPEED_100; + speed = SPEED_100; else - spddplx = SPEED_10; - spddplx += (mii_reg & 0x100) - ? DUPLEX_FULL : - DUPLEX_HALF; - retval = e1000_set_spd_dplx(adapter, - spddplx); + speed = SPEED_10; + retval = e1000_set_spd_dplx( + adapter, speed, + ((mii_reg & 0x100) + ? DUPLEX_FULL : + DUPLEX_HALF)); if (retval) return retval; } @@ -4596,20 +4595,24 @@ static void e1000_restore_vlan(struct e1000_adapter *adapter) } } -int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) +int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx) { struct e1000_hw *hw = &adapter->hw; hw->autoneg = 0; + /* Make sure dplx is at most 1 bit and lsb of speed is not set + * for the switch() below to work */ + if ((spd & 1) || (dplx & ~1)) + goto err_inval; + /* Fiber NICs only allow 1000 gbps Full duplex */ if ((hw->media_type == e1000_media_type_fiber) && - spddplx != (SPEED_1000 + DUPLEX_FULL)) { - e_err(probe, "Unsupported Speed/Duplex configuration\n"); - return -EINVAL; - } + spd != SPEED_1000 && + dplx != DUPLEX_FULL) + goto err_inval; - switch (spddplx) { + switch (spd + dplx) { case SPEED_10 + DUPLEX_HALF: hw->forced_speed_duplex = e1000_10_half; break; @@ -4628,10 +4631,13 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) break; case SPEED_1000 + DUPLEX_HALF: /* not supported */ default: - e_err(probe, "Unsupported Speed/Duplex configuration\n"); - return -EINVAL; + goto err_inval; } return 0; + +err_inval: + e_err(probe, "Unsupported Speed/Duplex configuration\n"); + return -EINVAL; } static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 89a69035e538..8295f2192439 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -300,6 +300,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) func->set_lan_id = e1000_set_lan_id_single_port; func->check_mng_mode = e1000e_check_mng_mode_generic; func->led_on = e1000e_led_on_generic; + func->blink_led = e1000e_blink_led_generic; /* FWSM register */ mac->has_fwsm = true; @@ -320,6 +321,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) default: func->check_mng_mode = e1000e_check_mng_mode_generic; func->led_on = e1000e_led_on_generic; + func->blink_led = e1000e_blink_led_generic; /* FWSM register */ mac->has_fwsm = true; @@ -431,9 +433,6 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter) case e1000_82573: case e1000_82574: case e1000_82583: - /* Disable ASPM L0s due to hardware errata */ - e1000e_disable_aspm(adapter->pdev, PCIE_LINK_STATE_L0S); - if (pdev->device == E1000_DEV_ID_82573L) { adapter->flags |= FLAG_HAS_JUMBO_FRAMES; adapter->max_hw_frame_size = DEFAULT_JUMBO; @@ -594,7 +593,7 @@ static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw) extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; - msleep(2); + usleep_range(2000, 4000); i++; } while (i < MDIO_OWNERSHIP_TIMEOUT); @@ -816,7 +815,7 @@ static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw) /* Check for pending operations. */ for (i = 0; i < E1000_FLASH_UPDATES; i++) { - msleep(1); + usleep_range(1000, 2000); if ((er32(EECD) & E1000_EECD_FLUPD) == 0) break; } @@ -840,7 +839,7 @@ static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw) ew32(EECD, eecd); for (i = 0; i < E1000_FLASH_UPDATES; i++) { - msleep(1); + usleep_range(1000, 2000); if ((er32(EECD) & E1000_EECD_FLUPD) == 0) break; } @@ -930,7 +929,7 @@ static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw) if (er32(EEMNGCTL) & E1000_NVM_CFG_DONE_PORT_0) break; - msleep(1); + usleep_range(1000, 2000); timeout--; } if (!timeout) { @@ -1037,7 +1036,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) ew32(TCTL, E1000_TCTL_PSP); e1e_flush(); - msleep(10); + usleep_range(10000, 20000); /* * Must acquire the MDIO ownership before MAC reset. @@ -2066,7 +2065,8 @@ struct e1000_info e1000_82573_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_SWSM_ON_LOAD, - .flags2 = FLAG2_DISABLE_ASPM_L1, + .flags2 = FLAG2_DISABLE_ASPM_L1 + | FLAG2_DISABLE_ASPM_L0S, .pba = 20, .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, @@ -2086,7 +2086,8 @@ 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, .pba = 32, .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, @@ -2104,6 +2105,7 @@ struct e1000_info e1000_82583_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, + .flags2 = FLAG2_DISABLE_ASPM_L0S, .pba = 32, .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 00bf595ebd67..9549879e66a0 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -31,6 +31,7 @@ #ifndef _E1000_H_ #define _E1000_H_ +#include #include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include "hw.h" @@ -280,7 +282,7 @@ struct e1000_adapter { const struct e1000_info *ei; - struct vlan_group *vlgrp; + unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; u32 bd_number; u32 rx_buffer_len; u16 mng_vlan_id; @@ -389,13 +391,10 @@ struct e1000_adapter { bool fc_autoneg; - unsigned long led_status; - unsigned int flags; unsigned int flags2; struct work_struct downshift_task; struct work_struct update_phy_task; - struct work_struct led_blink_task; struct work_struct print_hang_task; bool idle_check; @@ -456,6 +455,7 @@ struct e1000_info { #define FLAG2_HAS_PHY_STATS (1 << 4) #define FLAG2_HAS_EEE (1 << 5) #define FLAG2_DMA_BURST (1 << 6) +#define FLAG2_DISABLE_ASPM_L0S (1 << 7) #define FLAG2_DISABLE_AIM (1 << 8) #define FLAG2_CHECK_PHY_HANG (1 << 9) @@ -484,7 +484,6 @@ extern const char e1000e_driver_version[]; extern void e1000e_check_options(struct e1000_adapter *adapter); extern void e1000e_set_ethtool_ops(struct net_device *netdev); -extern void e1000e_led_blink_task(struct work_struct *work); extern int e1000e_up(struct e1000_adapter *adapter); extern void e1000e_down(struct e1000_adapter *adapter); @@ -502,7 +501,6 @@ extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter); extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); extern void e1000e_get_hw_control(struct e1000_adapter *adapter); extern void e1000e_release_hw_control(struct e1000_adapter *adapter); -extern void e1000e_disable_aspm(struct pci_dev *pdev, u16 state); extern unsigned int copybreak; @@ -573,7 +571,7 @@ extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data); extern void e1000e_config_collision_dist(struct e1000_hw *hw); extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw); extern s32 e1000e_force_mac_fc(struct e1000_hw *hw); -extern s32 e1000e_blink_led(struct e1000_hw *hw); +extern s32 e1000e_blink_led_generic(struct e1000_hw *hw); extern void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value); extern s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw); extern void e1000e_reset_adaptive(struct e1000_hw *hw); diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index 2fefa820302b..f4bbeb22f51f 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -612,7 +612,7 @@ static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw) while (timeout) { if (er32(EEMNGCTL) & mask) break; - msleep(1); + usleep_range(1000, 2000); timeout--; } if (!timeout) { @@ -802,7 +802,7 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw) ew32(TCTL, E1000_TCTL_PSP); e1e_flush(); - msleep(10); + usleep_range(10000, 20000); ctrl = er32(CTRL); @@ -1434,6 +1434,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw) static struct e1000_mac_operations es2_mac_ops = { .read_mac_addr = e1000_read_mac_addr_80003es2lan, .id_led_init = e1000e_id_led_init, + .blink_led = e1000e_blink_led_generic, .check_mng_mode = e1000e_check_mng_mode_generic, /* check_for_link dependent on media type */ .cleanup_led = e1000e_cleanup_led_generic, diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 07f09e96e453..859d0d3af6c9 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -122,6 +122,7 @@ static int e1000_get_settings(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + u32 speed; if (hw->phy.media_type == e1000_media_type_copper) { @@ -159,23 +160,23 @@ static int e1000_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_EXTERNAL; } - ecmd->speed = -1; + speed = -1; ecmd->duplex = -1; if (netif_running(netdev)) { if (netif_carrier_ok(netdev)) { - ecmd->speed = adapter->link_speed; + speed = adapter->link_speed; ecmd->duplex = adapter->link_duplex - 1; } } else { u32 status = er32(STATUS); if (status & E1000_STATUS_LU) { if (status & E1000_STATUS_SPEED_1000) - ecmd->speed = 1000; + speed = SPEED_1000; else if (status & E1000_STATUS_SPEED_100) - ecmd->speed = 100; + speed = SPEED_100; else - ecmd->speed = 10; + speed = SPEED_10; if (status & E1000_STATUS_FD) ecmd->duplex = DUPLEX_FULL; @@ -184,6 +185,7 @@ static int e1000_get_settings(struct net_device *netdev, } } + ethtool_cmd_speed_set(ecmd, speed); ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; @@ -198,20 +200,25 @@ static int e1000_get_settings(struct net_device *netdev, return 0; } -static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) +static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx) { struct e1000_mac_info *mac = &adapter->hw.mac; mac->autoneg = 0; + /* Make sure dplx is at most 1 bit and lsb of speed is not set + * for the switch() below to work */ + if ((spd & 1) || (dplx & ~1)) + goto err_inval; + /* Fiber NICs only allow 1000 gbps Full duplex */ if ((adapter->hw.phy.media_type == e1000_media_type_fiber) && - spddplx != (SPEED_1000 + DUPLEX_FULL)) { - e_err("Unsupported Speed/Duplex configuration\n"); - return -EINVAL; + spd != SPEED_1000 && + dplx != DUPLEX_FULL) { + goto err_inval; } - switch (spddplx) { + switch (spd + dplx) { case SPEED_10 + DUPLEX_HALF: mac->forced_speed_duplex = ADVERTISE_10_HALF; break; @@ -230,10 +237,13 @@ static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) break; case SPEED_1000 + DUPLEX_HALF: /* not supported */ default: - e_err("Unsupported Speed/Duplex configuration\n"); - return -EINVAL; + goto err_inval; } return 0; + +err_inval: + e_err("Unsupported Speed/Duplex configuration\n"); + return -EINVAL; } static int e1000_set_settings(struct net_device *netdev, @@ -253,7 +263,7 @@ static int e1000_set_settings(struct net_device *netdev, } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; @@ -269,7 +279,8 @@ static int e1000_set_settings(struct net_device *netdev, if (adapter->fc_autoneg) hw->fc.requested_mode = e1000_fc_default; } else { - if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { + u32 speed = ethtool_cmd_speed(ecmd); + if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->state); return -EINVAL; } @@ -317,7 +328,7 @@ static int e1000_set_pauseparam(struct net_device *netdev, adapter->fc_autoneg = pause->autoneg; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (adapter->fc_autoneg == AUTONEG_ENABLE) { hw->fc.requested_mode = e1000_fc_default; @@ -673,7 +684,7 @@ static int e1000_set_ringparam(struct net_device *netdev, return -EINVAL; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (netif_running(adapter->netdev)) e1000e_down(adapter); @@ -952,7 +963,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Test each interrupt */ for (i = 0; i < 10; i++) { @@ -984,7 +995,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, mask); ew32(ICS, mask); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr & mask) { *data = 3; @@ -1002,7 +1013,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMS, mask); ew32(ICS, mask); - msleep(10); + usleep_range(10000, 20000); if (!(adapter->test_icr & mask)) { *data = 4; @@ -1020,7 +1031,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, ~mask & 0x00007FFF); ew32(ICS, ~mask & 0x00007FFF); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr) { *data = 5; @@ -1031,7 +1042,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Unhook test interrupt handler */ free_irq(irq, netdev); @@ -1406,7 +1417,7 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter) */ #define E1000_SERDES_LB_ON 0x410 ew32(SCTL, E1000_SERDES_LB_ON); - msleep(10); + usleep_range(10000, 20000); return 0; } @@ -1501,7 +1512,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter) hw->phy.media_type == e1000_media_type_internal_serdes) { #define E1000_SERDES_LB_OFF 0x400 ew32(SCTL, E1000_SERDES_LB_OFF); - msleep(10); + usleep_range(10000, 20000); break; } /* Fall Through */ @@ -1851,64 +1862,35 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) return 0; } -/* toggle LED 4 times per second = 2 "blinks" per second */ -#define E1000_ID_INTERVAL (HZ/4) - -/* bit defines for adapter->led_status */ -#define E1000_LED_ON 0 - -void e1000e_led_blink_task(struct work_struct *work) -{ - struct e1000_adapter *adapter = container_of(work, - struct e1000_adapter, led_blink_task); - - if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) - adapter->hw.mac.ops.led_off(&adapter->hw); - else - adapter->hw.mac.ops.led_on(&adapter->hw); -} - -static void e1000_led_blink_callback(unsigned long data) -{ - struct e1000_adapter *adapter = (struct e1000_adapter *) data; - - schedule_work(&adapter->led_blink_task); - mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); -} - -static int e1000_phys_id(struct net_device *netdev, u32 data) +static int e1000_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - if (!data) - data = INT_MAX; + switch (state) { + case ETHTOOL_ID_ACTIVE: + if (!hw->mac.ops.blink_led) + return 2; /* cycle on/off twice per second */ - if ((hw->phy.type == e1000_phy_ife) || - (hw->mac.type == e1000_pchlan) || - (hw->mac.type == e1000_pch2lan) || - (hw->mac.type == e1000_82583) || - (hw->mac.type == e1000_82574)) { - if (!adapter->blink_timer.function) { - init_timer(&adapter->blink_timer); - adapter->blink_timer.function = - e1000_led_blink_callback; - adapter->blink_timer.data = (unsigned long) adapter; - } - mod_timer(&adapter->blink_timer, jiffies); - msleep_interruptible(data * 1000); - del_timer_sync(&adapter->blink_timer); + hw->mac.ops.blink_led(hw); + break; + + case ETHTOOL_ID_INACTIVE: if (hw->phy.type == e1000_phy_ife) e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); - } else { - e1000e_blink_led(hw); - msleep_interruptible(data * 1000); + hw->mac.ops.led_off(hw); + hw->mac.ops.cleanup_led(hw); + break; + + case ETHTOOL_ID_ON: + adapter->hw.mac.ops.led_on(&adapter->hw); + break; + + case ETHTOOL_ID_OFF: + adapter->hw.mac.ops.led_off(&adapter->hw); + break; } - - hw->mac.ops.led_off(hw); - clear_bit(E1000_LED_ON, &adapter->led_status); - hw->mac.ops.cleanup_led(hw); - return 0; } @@ -2020,6 +2002,31 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset, } } +static int e1000e_set_flags(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + bool need_reset = false; + int rc; + + need_reset = (data & ETH_FLAG_RXVLAN) != + (netdev->features & NETIF_F_HW_VLAN_RX); + + rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_RXVLAN | + ETH_FLAG_TXVLAN); + + if (rc) + return rc; + + if (need_reset) { + if (netif_running(netdev)) + e1000e_reinit_locked(adapter); + else + e1000e_reset(adapter); + } + + return 0; +} + static const struct ethtool_ops e1000_ethtool_ops = { .get_settings = e1000_get_settings, .set_settings = e1000_set_settings, @@ -2049,12 +2056,13 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_tso = e1000_set_tso, .self_test = e1000_diag_test, .get_strings = e1000_get_strings, - .phys_id = e1000_phys_id, + .set_phys_id = e1000_set_phys_id, .get_ethtool_stats = e1000_get_ethtool_stats, .get_sset_count = e1000e_get_sset_count, .get_coalesce = e1000_get_coalesce, .set_coalesce = e1000_set_coalesce, .get_flags = ethtool_op_get_flags, + .set_flags = e1000e_set_flags, }; void e1000e_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 307e1ec22417..6c2fa8327f5c 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -756,6 +756,7 @@ struct e1000_host_mng_command_info { /* Function pointers and static data for the MAC. */ struct e1000_mac_operations { s32 (*id_led_init)(struct e1000_hw *); + s32 (*blink_led)(struct e1000_hw *); bool (*check_mng_mode)(struct e1000_hw *); s32 (*check_for_link)(struct e1000_hw *); s32 (*cleanup_led)(struct e1000_hw *); diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index ce1dbfdca112..3369d1f6a39c 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -338,7 +338,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) /* Ungate automatic PHY configuration on non-managed 82579 */ if ((hw->mac.type == e1000_pch2lan) && !(fwsm & E1000_ICH_FWSM_FW_VALID)) { - msleep(10); + usleep_range(10000, 20000); e1000_gate_hw_phy_config_ich8lan(hw, false); } @@ -427,7 +427,7 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) phy->id = 0; while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) && (i++ < 100)) { - msleep(1); + usleep_range(1000, 2000); ret_val = e1000e_get_phy_id(hw); if (ret_val) return ret_val; @@ -564,6 +564,8 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter) mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; /* ID LED init */ mac->ops.id_led_init = e1000e_id_led_init; + /* blink LED */ + mac->ops.blink_led = e1000e_blink_led_generic; /* setup LED */ mac->ops.setup_led = e1000e_setup_led_generic; /* cleanup LED */ @@ -767,6 +769,8 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) (!(er32(CTRL_EXT) & E1000_CTRL_EXT_LSECCK)))) { adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN; + + hw->mac.ops.blink_led = NULL; } if ((adapter->hw.mac.type == e1000_ich8lan) && @@ -1704,7 +1708,7 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw) goto out; /* Allow time for h/w to get to quiescent state after reset */ - msleep(10); + usleep_range(10000, 20000); /* Perform any necessary post-reset workarounds */ switch (hw->mac.type) { @@ -1737,7 +1741,7 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw) if (hw->mac.type == e1000_pch2lan) { /* Ungate automatic PHY configuration on non-managed 82579 */ if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) { - msleep(10); + usleep_range(10000, 20000); e1000_gate_hw_phy_config_ich8lan(hw, false); } @@ -2532,7 +2536,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) */ if (!ret_val) { e1000e_reload_nvm(hw); - msleep(10); + usleep_range(10000, 20000); } out: @@ -3009,7 +3013,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ew32(TCTL, E1000_TCTL_PSP); e1e_flush(); - msleep(10); + usleep_range(10000, 20000); /* Workaround for ICH8 bit corruption issue in FIFO memory */ if (hw->mac.type == e1000_ich8lan) { diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 96921de5df2e..dd8ab05b5590 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -144,7 +144,7 @@ void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value) * @hw: pointer to the HW structure * @rar_count: receive address registers * - * Setups the receive address registers by setting the base receive address + * Setup the receive address registers by setting the base receive address * register to the devices MAC address and clearing all the other receive * address registers to 0. **/ @@ -868,7 +868,7 @@ static s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw) * milliseconds even if the other end is doing it in SW). */ for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { - msleep(10); + usleep_range(10000, 20000); status = er32(STATUS); if (status & E1000_STATUS_LU) break; @@ -930,7 +930,7 @@ s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw) ew32(CTRL, ctrl); e1e_flush(); - msleep(1); + usleep_range(1000, 2000); /* * For these adapters, the SW definable pin 1 is set when the optics @@ -1181,7 +1181,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) * 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. + * turn OFF the TRANSMISSION of PAUSE frames. */ if (hw->fc.requested_mode == e1000_fc_full) { hw->fc.current_mode = e1000_fc_full; @@ -1385,7 +1385,7 @@ s32 e1000e_get_auto_rd_done(struct e1000_hw *hw) while (i < AUTO_READ_DONE_TIMEOUT) { if (er32(EECD) & E1000_EECD_AUTO_RD) break; - msleep(1); + usleep_range(1000, 2000); i++; } @@ -1530,12 +1530,12 @@ s32 e1000e_cleanup_led_generic(struct e1000_hw *hw) } /** - * e1000e_blink_led - Blink LED + * e1000e_blink_led_generic - Blink LED * @hw: pointer to the HW structure * * Blink the LEDs which are set to be on. **/ -s32 e1000e_blink_led(struct e1000_hw *hw) +s32 e1000e_blink_led_generic(struct e1000_hw *hw) { u32 ledctl_blink = 0; u32 i; @@ -2087,8 +2087,6 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) if (ret_val) return ret_val; - msleep(10); - while (widx < words) { u8 write_opcode = NVM_WRITE_OPCODE_SPI; @@ -2132,7 +2130,7 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) } } - msleep(10); + usleep_range(10000, 20000); nvm->ops.release(hw); return 0; } diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 506a0a0043b3..0939040305fa 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -58,6 +58,8 @@ char e1000e_driver_name[] = "e1000e"; const char e1000e_driver_version[] = DRV_VERSION; +static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state); + static const struct e1000_info *e1000_info_tbl[] = { [board_82571] = &e1000_82571_info, [board_82572] = &e1000_82572_info, @@ -459,13 +461,13 @@ static void e1000_receive_skb(struct e1000_adapter *adapter, struct net_device *netdev, struct sk_buff *skb, u8 status, __le16 vlan) { + u16 tag = le16_to_cpu(vlan); skb->protocol = eth_type_trans(skb, netdev); - if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) - vlan_gro_receive(&adapter->napi, adapter->vlgrp, - le16_to_cpu(vlan), skb); - else - napi_gro_receive(&adapter->napi, skb); + if (status & E1000_RXD_STAT_VP) + __vlan_hwaccel_put_tag(skb, tag); + + napi_gro_receive(&adapter->napi, skb); } /** @@ -2433,6 +2435,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid) vfta |= (1 << (vid & 0x1F)); hw->mac.ops.write_vfta(hw, index, vfta); } + + set_bit(vid, adapter->active_vlans); } static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) @@ -2441,13 +2445,6 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) struct e1000_hw *hw = &adapter->hw; u32 vfta, index; - if (!test_bit(__E1000_DOWN, &adapter->state)) - e1000_irq_disable(adapter); - vlan_group_set_device(adapter->vlgrp, vid, NULL); - - if (!test_bit(__E1000_DOWN, &adapter->state)) - e1000_irq_enable(adapter); - if ((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && (vid == adapter->mng_vlan_id)) { @@ -2463,6 +2460,79 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) vfta &= ~(1 << (vid & 0x1F)); hw->mac.ops.write_vfta(hw, index, vfta); } + + clear_bit(vid, adapter->active_vlans); +} + +/** + * e1000e_vlan_filter_disable - helper to disable hw VLAN filtering + * @adapter: board private structure to initialize + **/ +static void e1000e_vlan_filter_disable(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + /* disable VLAN receive filtering */ + rctl = er32(RCTL); + rctl &= ~(E1000_RCTL_VFE | E1000_RCTL_CFIEN); + ew32(RCTL, rctl); + + if (adapter->mng_vlan_id != (u16)E1000_MNG_VLAN_NONE) { + e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + } + } +} + +/** + * e1000e_vlan_filter_enable - helper to enable HW VLAN filtering + * @adapter: board private structure to initialize + **/ +static void e1000e_vlan_filter_enable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + /* enable VLAN receive filtering */ + rctl = er32(RCTL); + rctl |= E1000_RCTL_VFE; + rctl &= ~E1000_RCTL_CFIEN; + ew32(RCTL, rctl); + } +} + +/** + * e1000e_vlan_strip_enable - helper to disable HW VLAN stripping + * @adapter: board private structure to initialize + **/ +static void e1000e_vlan_strip_disable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl; + + /* disable VLAN tag insert/strip */ + ctrl = er32(CTRL); + ctrl &= ~E1000_CTRL_VME; + ew32(CTRL, ctrl); +} + +/** + * e1000e_vlan_strip_enable - helper to enable HW VLAN stripping + * @adapter: board private structure to initialize + **/ +static void e1000e_vlan_strip_enable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl; + + /* enable VLAN tag insert/strip */ + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_VME; + ew32(CTRL, ctrl); } static void e1000_update_mng_vlan(struct e1000_adapter *adapter) @@ -2471,85 +2541,24 @@ static void e1000_update_mng_vlan(struct e1000_adapter *adapter) u16 vid = adapter->hw.mng_cookie.vlan_id; u16 old_vid = adapter->mng_vlan_id; - if (!adapter->vlgrp) - return; - - if (!vlan_group_get_device(adapter->vlgrp, vid)) { - adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; - if (adapter->hw.mng_cookie.status & - E1000_MNG_DHCP_COOKIE_STATUS_VLAN) { - e1000_vlan_rx_add_vid(netdev, vid); - adapter->mng_vlan_id = vid; - } - - if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && - (vid != old_vid) && - !vlan_group_get_device(adapter->vlgrp, old_vid)) - e1000_vlan_rx_kill_vid(netdev, old_vid); - } else { + if (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) { + e1000_vlan_rx_add_vid(netdev, vid); adapter->mng_vlan_id = vid; } -} - -static void e1000_vlan_rx_register(struct net_device *netdev, - struct vlan_group *grp) -{ - struct e1000_adapter *adapter = netdev_priv(netdev); - struct e1000_hw *hw = &adapter->hw; - u32 ctrl, rctl; - - if (!test_bit(__E1000_DOWN, &adapter->state)) - e1000_irq_disable(adapter); - adapter->vlgrp = grp; - - if (grp) { - /* enable VLAN tag insert/strip */ - ctrl = er32(CTRL); - ctrl |= E1000_CTRL_VME; - ew32(CTRL, ctrl); - - if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { - /* enable VLAN receive filtering */ - rctl = er32(RCTL); - rctl &= ~E1000_RCTL_CFIEN; - ew32(RCTL, rctl); - e1000_update_mng_vlan(adapter); - } - } else { - /* disable VLAN tag insert/strip */ - ctrl = er32(CTRL); - ctrl &= ~E1000_CTRL_VME; - ew32(CTRL, ctrl); - - if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { - if (adapter->mng_vlan_id != - (u16)E1000_MNG_VLAN_NONE) { - e1000_vlan_rx_kill_vid(netdev, - adapter->mng_vlan_id); - adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; - } - } - } - - if (!test_bit(__E1000_DOWN, &adapter->state)) - e1000_irq_enable(adapter); + if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && (vid != old_vid)) + e1000_vlan_rx_kill_vid(netdev, old_vid); } static void e1000_restore_vlan(struct e1000_adapter *adapter) { u16 vid; - e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp); + e1000_vlan_rx_add_vid(adapter->netdev, 0); - if (!adapter->vlgrp) - return; - - for (vid = 0; vid < VLAN_N_VID; vid++) { - if (!vlan_group_get_device(adapter->vlgrp, vid)) - continue; + for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID) e1000_vlan_rx_add_vid(adapter->netdev, vid); - } } static void e1000_init_manageability_pt(struct e1000_adapter *adapter) @@ -2902,7 +2911,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) rctl = er32(RCTL); ew32(RCTL, rctl & ~E1000_RCTL_EN); e1e_flush(); - msleep(10); + usleep_range(10000, 20000); if (adapter->flags2 & FLAG2_DMA_BURST) { /* @@ -3039,6 +3048,8 @@ static void e1000_set_multi(struct net_device *netdev) if (netdev->flags & IFF_PROMISC) { rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); rctl &= ~E1000_RCTL_VFE; + /* Do not hardware filter VLANs in promisc mode */ + e1000e_vlan_filter_disable(adapter); } else { if (netdev->flags & IFF_ALLMULTI) { rctl |= E1000_RCTL_MPE; @@ -3046,8 +3057,7 @@ static void e1000_set_multi(struct net_device *netdev) } else { rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); } - if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) - rctl |= E1000_RCTL_VFE; + e1000e_vlan_filter_enable(adapter); } ew32(RCTL, rctl); @@ -3072,6 +3082,11 @@ static void e1000_set_multi(struct net_device *netdev) */ e1000_update_mc_addr_list(hw, NULL, 0); } + + if (netdev->features & NETIF_F_HW_VLAN_RX) + e1000e_vlan_strip_enable(adapter); + else + e1000e_vlan_strip_disable(adapter); } /** @@ -3383,7 +3398,7 @@ void e1000e_down(struct e1000_adapter *adapter) ew32(TCTL, tctl); /* flush both disables and wait for them to finish */ e1e_flush(); - msleep(10); + usleep_range(10000, 20000); napi_disable(&adapter->napi); e1000_irq_disable(adapter); @@ -3418,7 +3433,7 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter) { might_sleep(); while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); e1000e_down(adapter); e1000e_up(adapter); clear_bit(__E1000_RESETTING, &adapter->state); @@ -3721,10 +3736,8 @@ static int e1000_close(struct net_device *netdev) * kill manageability vlan ID if supported, but not if a vlan with * the same ID is registered on the host OS (let 8021q kill it) */ - if ((adapter->hw.mng_cookie.status & - E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && - !(adapter->vlgrp && - vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id))) + if (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); /* @@ -4328,7 +4341,6 @@ static void e1000_watchdog_task(struct work_struct *work) link_up: spin_lock(&adapter->stats64_lock); e1000e_update_stats(adapter); - spin_unlock(&adapter->stats64_lock); mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; adapter->tpt_old = adapter->stats.tpt; @@ -4339,6 +4351,7 @@ static void e1000_watchdog_task(struct work_struct *work) adapter->gorc_old = adapter->stats.gorc; adapter->gotc = adapter->stats.gotc - adapter->gotc_old; adapter->gotc_old = adapter->stats.gotc; + spin_unlock(&adapter->stats64_lock); e1000e_update_adaptive(&adapter->hw); @@ -5028,7 +5041,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); /* e1000e_down -> e1000e_reset dependent on max_frame_size & mtu */ adapter->max_frame_size = max_frame; e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu); @@ -5373,7 +5386,7 @@ static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state) pci_write_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, reg16); } #endif -void e1000e_disable_aspm(struct pci_dev *pdev, u16 state) +static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state) { dev_info(&pdev->dev, "Disabling ASPM %s %s\n", (state & PCIE_LINK_STATE_L0S) ? "L0s" : "", @@ -5393,13 +5406,19 @@ static int __e1000_resume(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + u16 aspm_disable_flag = 0; u32 err; + if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S) + aspm_disable_flag = PCIE_LINK_STATE_L0S; + if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) + aspm_disable_flag |= PCIE_LINK_STATE_L1; + if (aspm_disable_flag) + e1000e_disable_aspm(pdev, aspm_disable_flag); + pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); pci_save_state(pdev); - if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) - e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1); e1000e_set_interrupt_capability(adapter); if (netif_running(netdev)) { @@ -5643,11 +5662,17 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + u16 aspm_disable_flag = 0; int err; pci_ers_result_t result; + if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S) + aspm_disable_flag = PCIE_LINK_STATE_L0S; if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) - e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1); + aspm_disable_flag |= PCIE_LINK_STATE_L1; + if (aspm_disable_flag) + e1000e_disable_aspm(pdev, aspm_disable_flag); + err = pci_enable_device_mem(pdev); if (err) { dev_err(&pdev->dev, @@ -5714,7 +5739,7 @@ static void e1000_print_device_info(struct e1000_adapter *adapter) u8 pba_str[E1000_PBANUM_LENGTH]; /* print bus type/speed/width info */ - e_info("(PCI Express:2.5GB/s:%s) %pM\n", + e_info("(PCI Express:2.5GT/s:%s) %pM\n", /* bus width */ ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" : "Width x1"), @@ -5759,7 +5784,6 @@ static const struct net_device_ops e1000e_netdev_ops = { .ndo_tx_timeout = e1000_tx_timeout, .ndo_validate_addr = eth_validate_addr, - .ndo_vlan_rx_register = e1000_vlan_rx_register, .ndo_vlan_rx_add_vid = e1000_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = e1000_vlan_rx_kill_vid, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -5789,12 +5813,17 @@ static int __devinit e1000_probe(struct pci_dev *pdev, resource_size_t flash_start, flash_len; static int cards_found; + u16 aspm_disable_flag = 0; int i, err, pci_using_dac; u16 eeprom_data = 0; u16 eeprom_apme_mask = E1000_EEPROM_APME; + if (ei->flags2 & FLAG2_DISABLE_ASPM_L0S) + aspm_disable_flag = PCIE_LINK_STATE_L0S; if (ei->flags2 & FLAG2_DISABLE_ASPM_L1) - e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1); + aspm_disable_flag |= PCIE_LINK_STATE_L1; + if (aspm_disable_flag) + e1000e_disable_aspm(pdev, aspm_disable_flag); err = pci_enable_device_mem(pdev); if (err) @@ -5991,7 +6020,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev, INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround); INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task); INIT_WORK(&adapter->print_hang_task, e1000_print_hw_hang); - INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task); /* Initialize link parameters. User can change them with ethtool */ adapter->hw.mac.autoneg = 1; @@ -6124,7 +6152,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev) cancel_work_sync(&adapter->watchdog_task); cancel_work_sync(&adapter->downshift_task); cancel_work_sync(&adapter->update_phy_task); - cancel_work_sync(&adapter->led_blink_task); cancel_work_sync(&adapter->print_hang_task); if (!(netdev->flags & IFF_UP)) diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index 6ae31fcfb629..484774c13c21 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -2372,7 +2372,7 @@ s32 e1000e_determine_phy_address(struct e1000_hw *hw) ret_val = 0; goto out; } - msleep(1); + usleep_range(1000, 2000); i++; } while (i < 10); } @@ -2740,7 +2740,7 @@ void e1000_power_down_phy_copper(struct e1000_hw *hw) e1e_rphy(hw, PHY_CONTROL, &mii_reg); mii_reg |= MII_CR_POWER_DOWN; e1e_wphy(hw, PHY_CONTROL, mii_reg); - msleep(1); + usleep_range(1000, 2000); } /** diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index eb35951a2442..dfeb006035df 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1703,7 +1703,7 @@ static int eepro_ethtool_get_settings(struct net_device *dev, cmd->advertising |= ADVERTISED_AUI; } - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); if (dev->if_port == TPE && lp->word[1] & ee_Duplex) { cmd->duplex = DUPLEX_FULL; diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 3e2e734fecb7..7f642aef5e82 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -34,6 +34,7 @@ static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct ehea_port *port = netdev_priv(dev); + u32 speed; int ret; ret = ehea_sense_port_attr(port); @@ -43,27 +44,44 @@ static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (netif_carrier_ok(dev)) { switch (port->port_speed) { - case EHEA_SPEED_10M: cmd->speed = SPEED_10; break; - case EHEA_SPEED_100M: cmd->speed = SPEED_100; break; - case EHEA_SPEED_1G: cmd->speed = SPEED_1000; break; - case EHEA_SPEED_10G: cmd->speed = SPEED_10000; break; + case EHEA_SPEED_10M: + speed = SPEED_10; + break; + case EHEA_SPEED_100M: + speed = SPEED_100; + break; + case EHEA_SPEED_1G: + speed = SPEED_1000; + break; + case EHEA_SPEED_10G: + speed = SPEED_10000; + break; + default: + speed = -1; + break; /* BUG */ } cmd->duplex = port->full_duplex == 1 ? DUPLEX_FULL : DUPLEX_HALF; } else { - cmd->speed = -1; + speed = ~0; cmd->duplex = -1; } + ethtool_cmd_speed_set(cmd, speed); - cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_1000baseT_Full - | SUPPORTED_100baseT_Full | SUPPORTED_100baseT_Half - | SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Half - | SUPPORTED_Autoneg | SUPPORTED_FIBRE); + if (cmd->speed == SPEED_10000) { + cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); + cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); + cmd->port = PORT_FIBRE; + } else { + cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full + | SUPPORTED_100baseT_Half | SUPPORTED_10baseT_Full + | SUPPORTED_10baseT_Half | SUPPORTED_Autoneg + | SUPPORTED_TP); + cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg + | ADVERTISED_TP); + cmd->port = PORT_TP; + } - cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_Autoneg - | ADVERTISED_FIBRE); - - cmd->port = PORT_FIBRE; cmd->autoneg = port->autoneg == 1 ? AUTONEG_ENABLE : AUTONEG_DISABLE; return 0; @@ -162,11 +180,6 @@ static void ehea_set_msglevel(struct net_device *dev, u32 value) port->msg_enable = value; } -static u32 ehea_get_rx_csum(struct net_device *dev) -{ - return 1; -} - static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = { {"sig_comp_iv"}, {"swqe_refill_th"}, @@ -263,34 +276,16 @@ static void ehea_get_ethtool_stats(struct net_device *dev, } -static int ehea_set_flags(struct net_device *dev, u32 data) -{ - /* Avoid changing the VLAN flags */ - if ((data & (ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN)) != - (ethtool_op_get_flags(dev) & (ETH_FLAG_RXVLAN | - ETH_FLAG_TXVLAN))){ - return -EINVAL; - } - - return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO - | ETH_FLAG_TXVLAN - | ETH_FLAG_RXVLAN); -} - const struct ethtool_ops ehea_ethtool_ops = { .get_settings = ehea_get_settings, .get_drvinfo = ehea_get_drvinfo, .get_msglevel = ehea_get_msglevel, .set_msglevel = ehea_set_msglevel, .get_link = ethtool_op_get_link, - .set_tso = ethtool_op_set_tso, .get_strings = ehea_get_strings, .get_sset_count = ehea_get_sset_count, .get_ethtool_stats = ehea_get_ethtool_stats, - .get_rx_csum = ehea_get_rx_csum, .set_settings = ehea_set_settings, - .get_flags = ethtool_op_get_flags, - .set_flags = ehea_set_flags, .nway_reset = ehea_nway_reset, /* Restart autonegotiation */ }; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index f75d3144b8a5..6a0a8fca62bc 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -2688,9 +2689,6 @@ static int ehea_open(struct net_device *dev) netif_start_queue(dev); } - init_waitqueue_head(&port->swqe_avail_wq); - init_waitqueue_head(&port->restart_wq); - mutex_unlock(&port->port_lock); return ret; @@ -3040,11 +3038,14 @@ static void ehea_rereg_mrs(void) if (dev->flags & IFF_UP) { mutex_lock(&port->port_lock); - port_napi_enable(port); ret = ehea_restart_qps(dev); - check_sqs(port); - if (!ret) + if (!ret) { + check_sqs(port); + port_napi_enable(port); netif_wake_queue(dev); + } else { + netdev_err(dev, "Unable to restart QPS\n"); + } mutex_unlock(&port->port_lock); } } @@ -3262,10 +3263,12 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, dev->netdev_ops = &ehea_netdev_ops; ehea_set_ethtool_ops(dev); + dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO + | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_LRO; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER - | NETIF_F_LLTX; + | NETIF_F_LLTX | NETIF_F_RXCSUM; dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT; if (use_lro) @@ -3273,6 +3276,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, INIT_WORK(&port->reset_task, ehea_reset_port); + init_waitqueue_head(&port->swqe_avail_wq); + init_waitqueue_head(&port->restart_wq); + ret = register_netdev(dev); if (ret) { pr_err("register_netdev failed. ret=%d\n", ret); diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 907b05a1c659..2837ce209cd7 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -1488,7 +1488,7 @@ enc28j60_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_TP; - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); cmd->duplex = priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; cmd->port = PORT_TP; cmd->autoneg = AUTONEG_DISABLE; @@ -1499,7 +1499,8 @@ enc28j60_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int enc28j60_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - return enc28j60_setlink(dev, cmd->autoneg, cmd->speed, cmd->duplex); + return enc28j60_setlink(dev, cmd->autoneg, + ethtool_cmd_speed(cmd), cmd->duplex); } static u32 enc28j60_get_msglevel(struct net_device *dev) diff --git a/drivers/net/enic/Makefile b/drivers/net/enic/Makefile index 2e573be16c13..9d4974bba247 100644 --- a/drivers/net/enic/Makefile +++ b/drivers/net/enic/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_ENIC) := enic.o enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \ - enic_res.o enic_dev.o vnic_dev.o vnic_rq.o vnic_vic.o + enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 3a3c3c8a3a9b..38b351c7b979 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -32,7 +32,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION "2.1.1.12" +#define DRV_VERSION "2.1.1.13" #define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 @@ -84,7 +84,6 @@ struct enic { unsigned int flags; unsigned int mc_count; unsigned int uc_count; - int csum_rx_enabled; u32 port_mtu; u32 rx_coalesce_usecs; u32 tx_coalesce_usecs; @@ -120,4 +119,6 @@ static inline struct device *enic_get_dev(struct enic *enic) return &(enic->pdev->dev); } +void enic_reset_addr_lists(struct enic *enic); + #endif /* _ENIC_H_ */ diff --git a/drivers/net/enic/enic_dev.c b/drivers/net/enic/enic_dev.c index 37ad3a1c82ee..90687b14e60f 100644 --- a/drivers/net/enic/enic_dev.c +++ b/drivers/net/enic/enic_dev.c @@ -177,24 +177,24 @@ int enic_vnic_dev_deinit(struct enic *enic) return err; } -int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp) +int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp) { int err; spin_lock(&enic->devcmd_lock); - err = vnic_dev_init_prov(enic->vdev, + err = vnic_dev_init_prov2(enic->vdev, (u8 *)vp, vic_provinfo_size(vp)); spin_unlock(&enic->devcmd_lock); return err; } -int enic_dev_init_done(struct enic *enic, int *done, int *error) +int enic_dev_deinit_done(struct enic *enic, int *status) { int err; spin_lock(&enic->devcmd_lock); - err = vnic_dev_init_done(enic->vdev, done, error); + err = vnic_dev_deinit_done(enic->vdev, status); spin_unlock(&enic->devcmd_lock); return err; @@ -219,3 +219,57 @@ void enic_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) enic_del_vlan(enic, vid); spin_unlock(&enic->devcmd_lock); } + +int enic_dev_enable2(struct enic *enic, int active) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_enable2(enic->vdev, active); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_enable2_done(struct enic *enic, int *status) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_enable2_done(enic->vdev, status); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_status_to_errno(int devcmd_status) +{ + switch (devcmd_status) { + case ERR_SUCCESS: + return 0; + case ERR_EINVAL: + return -EINVAL; + case ERR_EFAULT: + return -EFAULT; + case ERR_EPERM: + return -EPERM; + case ERR_EBUSY: + return -EBUSY; + case ERR_ECMDUNKNOWN: + case ERR_ENOTSUPPORTED: + return -EOPNOTSUPP; + case ERR_EBADSTATE: + return -EINVAL; + case ERR_ENOMEM: + return -ENOMEM; + case ERR_ETIMEDOUT: + return -ETIMEDOUT; + case ERR_ELINKDOWN: + return -ENETDOWN; + case ERR_EINPROGRESS: + return -EINPROGRESS; + case ERR_EMAXRES: + default: + return (devcmd_status < 0) ? devcmd_status : -1; + } +} diff --git a/drivers/net/enic/enic_dev.h b/drivers/net/enic/enic_dev.h index 495f57fcb887..d5f681337626 100644 --- a/drivers/net/enic/enic_dev.h +++ b/drivers/net/enic/enic_dev.h @@ -35,7 +35,10 @@ int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic); int enic_dev_enable(struct enic *enic); int enic_dev_disable(struct enic *enic); int enic_vnic_dev_deinit(struct enic *enic); -int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp); -int enic_dev_init_done(struct enic *enic, int *done, int *error); +int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp); +int enic_dev_deinit_done(struct enic *enic, int *status); +int enic_dev_enable2(struct enic *enic, int arg); +int enic_dev_enable2_done(struct enic *enic, int *status); +int enic_dev_status_to_errno(int devcmd_status); #endif /* _ENIC_DEV_H_ */ diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 8b9cad5e9712..3d99b0f1a236 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -45,6 +45,7 @@ #include "enic_res.h" #include "enic.h" #include "enic_dev.h" +#include "enic_pp.h" #define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ) #define WQ_ENET_MAX_DESC_LEN (1 << WQ_ENET_LEN_BITS) @@ -179,10 +180,10 @@ static int enic_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_EXTERNAL; if (netif_carrier_ok(netdev)) { - ecmd->speed = vnic_dev_port_speed(enic->vdev); + ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev)); ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } @@ -250,56 +251,6 @@ static void enic_get_ethtool_stats(struct net_device *netdev, *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].offset]; } -static u32 enic_get_rx_csum(struct net_device *netdev) -{ - struct enic *enic = netdev_priv(netdev); - return enic->csum_rx_enabled; -} - -static int enic_set_rx_csum(struct net_device *netdev, u32 data) -{ - struct enic *enic = netdev_priv(netdev); - - if (data && !ENIC_SETTING(enic, RXCSUM)) - return -EINVAL; - - enic->csum_rx_enabled = !!data; - - return 0; -} - -static int enic_set_tx_csum(struct net_device *netdev, u32 data) -{ - struct enic *enic = netdev_priv(netdev); - - if (data && !ENIC_SETTING(enic, TXCSUM)) - return -EINVAL; - - if (data) - netdev->features |= NETIF_F_HW_CSUM; - else - netdev->features &= ~NETIF_F_HW_CSUM; - - return 0; -} - -static int enic_set_tso(struct net_device *netdev, u32 data) -{ - struct enic *enic = netdev_priv(netdev); - - if (data && !ENIC_SETTING(enic, TSO)) - return -EINVAL; - - if (data) - netdev->features |= - NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN; - else - netdev->features &= - ~(NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN); - - return 0; -} - static u32 enic_get_msglevel(struct net_device *netdev) { struct enic *enic = netdev_priv(netdev); @@ -387,17 +338,8 @@ static const struct ethtool_ops enic_ethtool_ops = { .get_strings = enic_get_strings, .get_sset_count = enic_get_sset_count, .get_ethtool_stats = enic_get_ethtool_stats, - .get_rx_csum = enic_get_rx_csum, - .set_rx_csum = enic_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = enic_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = enic_set_tso, .get_coalesce = enic_get_coalesce, .set_coalesce = enic_set_coalesce, - .get_flags = ethtool_op_get_flags, }; static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) @@ -874,7 +816,7 @@ static struct net_device_stats *enic_get_stats(struct net_device *netdev) return net_stats; } -static void enic_reset_addr_lists(struct enic *enic) +void enic_reset_addr_lists(struct enic *enic) { enic->mc_count = 0; enic->uc_count = 0; @@ -1112,157 +1054,77 @@ static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) return -EINVAL; } -static int enic_set_port_profile(struct enic *enic, u8 *mac) -{ - struct vic_provinfo *vp; - u8 oui[3] = VIC_PROVINFO_CISCO_OUI; - u16 os_type = VIC_GENERIC_PROV_OS_TYPE_LINUX; - char uuid_str[38]; - char client_mac_str[18]; - u8 *client_mac; - int err; - - err = enic_vnic_dev_deinit(enic); - if (err) - return err; - - enic_reset_addr_lists(enic); - - switch (enic->pp.request) { - - case PORT_REQUEST_ASSOCIATE: - - if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) - return -EINVAL; - - if (!is_valid_ether_addr(mac)) - return -EADDRNOTAVAIL; - - vp = vic_provinfo_alloc(GFP_KERNEL, oui, - VIC_PROVINFO_GENERIC_TYPE); - if (!vp) - return -ENOMEM; - - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR, - strlen(enic->pp.name) + 1, enic->pp.name); - - if (!is_zero_ether_addr(enic->pp.mac_addr)) - client_mac = enic->pp.mac_addr; - else - client_mac = mac; - - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR, - ETH_ALEN, client_mac); - - sprintf(client_mac_str, "%pM", client_mac); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR, - sizeof(client_mac_str), client_mac_str); - - if (enic->pp.set & ENIC_SET_INSTANCE) { - sprintf(uuid_str, "%pUB", enic->pp.instance_uuid); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR, - sizeof(uuid_str), uuid_str); - } - - if (enic->pp.set & ENIC_SET_HOST) { - sprintf(uuid_str, "%pUB", enic->pp.host_uuid); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_HOST_UUID_STR, - sizeof(uuid_str), uuid_str); - } - - os_type = htons(os_type); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_OS_TYPE, - sizeof(os_type), &os_type); - - err = enic_dev_init_prov(enic, vp); - vic_provinfo_free(vp); - if (err) - return err; - break; - - case PORT_REQUEST_DISASSOCIATE: - break; - - default: - return -EINVAL; - } - - /* Set flag to indicate that the port assoc/disassoc - * request has been sent out to fw - */ - enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; - - return 0; -} - static int enic_set_vf_port(struct net_device *netdev, int vf, struct nlattr *port[]) { struct enic *enic = netdev_priv(netdev); - struct enic_port_profile new_pp; - int err = 0; - - memset(&new_pp, 0, sizeof(new_pp)); - - if (port[IFLA_PORT_REQUEST]) { - new_pp.set |= ENIC_SET_REQUEST; - new_pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); - } - - if (port[IFLA_PORT_PROFILE]) { - new_pp.set |= ENIC_SET_NAME; - memcpy(new_pp.name, nla_data(port[IFLA_PORT_PROFILE]), - PORT_PROFILE_MAX); - } - - if (port[IFLA_PORT_INSTANCE_UUID]) { - new_pp.set |= ENIC_SET_INSTANCE; - memcpy(new_pp.instance_uuid, - nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX); - } - - if (port[IFLA_PORT_HOST_UUID]) { - new_pp.set |= ENIC_SET_HOST; - memcpy(new_pp.host_uuid, - nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX); - } + struct enic_port_profile prev_pp; + int err = 0, restore_pp = 1; /* don't support VFs, yet */ if (vf != PORT_SELF_VF) return -EOPNOTSUPP; - if (!(new_pp.set & ENIC_SET_REQUEST)) + if (!port[IFLA_PORT_REQUEST]) return -EOPNOTSUPP; - if (new_pp.request == PORT_REQUEST_ASSOCIATE) { - /* Special case handling */ - if (!is_zero_ether_addr(enic->pp.vf_mac)) - memcpy(new_pp.mac_addr, enic->pp.vf_mac, ETH_ALEN); + memcpy(&prev_pp, &enic->pp, sizeof(enic->pp)); + memset(&enic->pp, 0, sizeof(enic->pp)); + + enic->pp.set |= ENIC_SET_REQUEST; + enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); + + if (port[IFLA_PORT_PROFILE]) { + enic->pp.set |= ENIC_SET_NAME; + memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]), + PORT_PROFILE_MAX); + } + + if (port[IFLA_PORT_INSTANCE_UUID]) { + enic->pp.set |= ENIC_SET_INSTANCE; + memcpy(enic->pp.instance_uuid, + nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX); + } + + if (port[IFLA_PORT_HOST_UUID]) { + enic->pp.set |= ENIC_SET_HOST; + memcpy(enic->pp.host_uuid, + nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX); + } + + /* Special case handling: mac came from IFLA_VF_MAC */ + if (!is_zero_ether_addr(prev_pp.vf_mac)) + memcpy(enic->pp.mac_addr, prev_pp.vf_mac, ETH_ALEN); if (is_zero_ether_addr(netdev->dev_addr)) random_ether_addr(netdev->dev_addr); + + err = enic_process_set_pp_request(enic, &prev_pp, &restore_pp); + if (err) { + if (restore_pp) { + /* Things are still the way they were: Implicit + * DISASSOCIATE failed + */ + memcpy(&enic->pp, &prev_pp, sizeof(enic->pp)); + } else { + memset(&enic->pp, 0, sizeof(enic->pp)); + memset(netdev->dev_addr, 0, ETH_ALEN); + } + } else { + /* Set flag to indicate that the port assoc/disassoc + * request has been sent out to fw + */ + enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; + + /* If DISASSOCIATE, clean up all assigned/saved macaddresses */ + if (enic->pp.request == PORT_REQUEST_DISASSOCIATE) { + memset(enic->pp.mac_addr, 0, ETH_ALEN); + memset(netdev->dev_addr, 0, ETH_ALEN); + } } - memcpy(&enic->pp, &new_pp, sizeof(struct enic_port_profile)); - - err = enic_set_port_profile(enic, netdev->dev_addr); - if (err) - goto set_port_profile_cleanup; - -set_port_profile_cleanup: memset(enic->pp.vf_mac, 0, ETH_ALEN); - if (err || enic->pp.request == PORT_REQUEST_DISASSOCIATE) { - memset(netdev->dev_addr, 0, ETH_ALEN); - memset(enic->pp.mac_addr, 0, ETH_ALEN); - } - return err; } @@ -1270,34 +1132,15 @@ static int enic_get_vf_port(struct net_device *netdev, int vf, struct sk_buff *skb) { struct enic *enic = netdev_priv(netdev); - int err, error, done; u16 response = PORT_PROFILE_RESPONSE_SUCCESS; + int err; if (!(enic->pp.set & ENIC_PORT_REQUEST_APPLIED)) return -ENODATA; - err = enic_dev_init_done(enic, &done, &error); + err = enic_process_get_pp_request(enic, enic->pp.request, &response); if (err) - error = err; - - switch (error) { - case ERR_SUCCESS: - if (!done) - response = PORT_PROFILE_RESPONSE_INPROGRESS; - break; - case ERR_EINVAL: - response = PORT_PROFILE_RESPONSE_INVALID; - break; - case ERR_EBADSTATE: - response = PORT_PROFILE_RESPONSE_BADSTATE; - break; - case ERR_ENOMEM: - response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES; - break; - default: - response = PORT_PROFILE_RESPONSE_ERROR; - break; - } + return err; NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request); NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response); @@ -1407,7 +1250,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, skb_put(skb, bytes_written); skb->protocol = eth_type_trans(skb, netdev); - if (enic->csum_rx_enabled && !csum_not_calc) { + if ((netdev->features & NETIF_F_RXCSUM) && !csum_not_calc) { skb->csum = htons(checksum); skb->ip_summed = CHECKSUM_COMPLETE; } @@ -2536,17 +2379,18 @@ static int __devinit enic_probe(struct pci_dev *pdev, dev_info(dev, "loopback tag=0x%04x\n", enic->loop_tag); } if (ENIC_SETTING(enic, TXCSUM)) - netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + netdev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM; if (ENIC_SETTING(enic, TSO)) - netdev->features |= NETIF_F_TSO | + netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN; - if (ENIC_SETTING(enic, LRO)) - netdev->features |= NETIF_F_GRO; + if (ENIC_SETTING(enic, RXCSUM)) + netdev->hw_features |= NETIF_F_RXCSUM; + + netdev->features |= netdev->hw_features; + if (using_dac) netdev->features |= NETIF_F_HIGHDMA; - enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM); - err = register_netdev(netdev); if (err) { dev_err(dev, "Cannot register net device, aborting\n"); diff --git a/drivers/net/enic/enic_pp.c b/drivers/net/enic/enic_pp.c new file mode 100644 index 000000000000..ffaa75dd1ded --- /dev/null +++ b/drivers/net/enic/enic_pp.c @@ -0,0 +1,264 @@ +/* + * Copyright 2011 Cisco Systems, Inc. All rights reserved. + * + * This program is free software; you may 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. + * + * 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 +#include +#include +#include +#include +#include + +#include "vnic_vic.h" +#include "enic_res.h" +#include "enic.h" +#include "enic_dev.h" + +static int enic_set_port_profile(struct enic *enic) +{ + struct net_device *netdev = enic->netdev; + struct vic_provinfo *vp; + const u8 oui[3] = VIC_PROVINFO_CISCO_OUI; + const u16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX); + char uuid_str[38]; + char client_mac_str[18]; + u8 *client_mac; + int err; + + if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) + return -EINVAL; + + vp = vic_provinfo_alloc(GFP_KERNEL, oui, + VIC_PROVINFO_GENERIC_TYPE); + if (!vp) + return -ENOMEM; + + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR, + strlen(enic->pp.name) + 1, enic->pp.name); + + if (!is_zero_ether_addr(enic->pp.mac_addr)) + client_mac = enic->pp.mac_addr; + else + client_mac = netdev->dev_addr; + + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR, + ETH_ALEN, client_mac); + + snprintf(client_mac_str, sizeof(client_mac_str), "%pM", client_mac); + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR, + sizeof(client_mac_str), client_mac_str); + + if (enic->pp.set & ENIC_SET_INSTANCE) { + sprintf(uuid_str, "%pUB", enic->pp.instance_uuid); + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR, + sizeof(uuid_str), uuid_str); + } + + if (enic->pp.set & ENIC_SET_HOST) { + sprintf(uuid_str, "%pUB", enic->pp.host_uuid); + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_HOST_UUID_STR, + sizeof(uuid_str), uuid_str); + } + + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_OS_TYPE, + sizeof(os_type), &os_type); + + err = enic_dev_status_to_errno(enic_dev_init_prov2(enic, vp)); + +add_tlv_failure: + vic_provinfo_free(vp); + + return err; +} + +static int enic_unset_port_profile(struct enic *enic) +{ + int err; + + err = enic_vnic_dev_deinit(enic); + if (err) + return enic_dev_status_to_errno(err); + + enic_reset_addr_lists(enic); + + return 0; +} + +static int enic_are_pp_different(struct enic_port_profile *pp1, + struct enic_port_profile *pp2) +{ + return strcmp(pp1->name, pp2->name) | !!memcmp(pp1->instance_uuid, + pp2->instance_uuid, PORT_UUID_MAX) | + !!memcmp(pp1->host_uuid, pp2->host_uuid, PORT_UUID_MAX) | + !!memcmp(pp1->mac_addr, pp2->mac_addr, ETH_ALEN); +} + +static int enic_pp_preassociate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); +static int enic_pp_disassociate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); +static int enic_pp_preassociate_rr(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); +static int enic_pp_associate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); + +static int (*enic_pp_handlers[])(struct enic *enic, + struct enic_port_profile *prev_state, int *restore_pp) = { + [PORT_REQUEST_PREASSOCIATE] = enic_pp_preassociate, + [PORT_REQUEST_PREASSOCIATE_RR] = enic_pp_preassociate_rr, + [PORT_REQUEST_ASSOCIATE] = enic_pp_associate, + [PORT_REQUEST_DISASSOCIATE] = enic_pp_disassociate, +}; + +static const int enic_pp_handlers_count = + sizeof(enic_pp_handlers)/sizeof(*enic_pp_handlers); + +static int enic_pp_preassociate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + return -EOPNOTSUPP; +} + +static int enic_pp_disassociate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + return enic_unset_port_profile(enic); +} + +static int enic_pp_preassociate_rr(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + int err; + int active = 0; + + if (enic->pp.request != PORT_REQUEST_ASSOCIATE) { + /* If pre-associate is not part of an associate. + We always disassociate first */ + err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic, + prev_pp, restore_pp); + if (err) + return err; + + *restore_pp = 0; + } + + *restore_pp = 0; + + err = enic_set_port_profile(enic); + if (err) + return err; + + /* If pre-associate is not part of an associate. */ + if (enic->pp.request != PORT_REQUEST_ASSOCIATE) + err = enic_dev_status_to_errno(enic_dev_enable2(enic, active)); + + return err; +} + +static int enic_pp_associate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + int err; + int active = 1; + + /* Check if a pre-associate was called before */ + if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR || + (prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR && + enic_are_pp_different(prev_pp, &enic->pp))) { + err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE]( + enic, prev_pp, restore_pp); + if (err) + return err; + + *restore_pp = 0; + } + + err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR]( + enic, prev_pp, restore_pp); + if (err) + return err; + + *restore_pp = 0; + + return enic_dev_status_to_errno(enic_dev_enable2(enic, active)); +} + +int enic_process_set_pp_request(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + if (enic->pp.request < enic_pp_handlers_count + && enic_pp_handlers[enic->pp.request]) + return enic_pp_handlers[enic->pp.request](enic, + prev_pp, restore_pp); + else + return -EOPNOTSUPP; +} + +int enic_process_get_pp_request(struct enic *enic, int request, + u16 *response) +{ + int err, status = ERR_SUCCESS; + + switch (request) { + + case PORT_REQUEST_PREASSOCIATE_RR: + case PORT_REQUEST_ASSOCIATE: + err = enic_dev_enable2_done(enic, &status); + break; + + case PORT_REQUEST_DISASSOCIATE: + err = enic_dev_deinit_done(enic, &status); + break; + + default: + return -EINVAL; + } + + if (err) + status = err; + + switch (status) { + case ERR_SUCCESS: + *response = PORT_PROFILE_RESPONSE_SUCCESS; + break; + case ERR_EINVAL: + *response = PORT_PROFILE_RESPONSE_INVALID; + break; + case ERR_EBADSTATE: + *response = PORT_PROFILE_RESPONSE_BADSTATE; + break; + case ERR_ENOMEM: + *response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES; + break; + case ERR_EINPROGRESS: + *response = PORT_PROFILE_RESPONSE_INPROGRESS; + break; + default: + *response = PORT_PROFILE_RESPONSE_ERROR; + break; + } + + return 0; +} diff --git a/drivers/net/enic/enic_pp.h b/drivers/net/enic/enic_pp.h new file mode 100644 index 000000000000..699e365a944d --- /dev/null +++ b/drivers/net/enic/enic_pp.h @@ -0,0 +1,27 @@ +/* + * Copyright 2011 Cisco Systems, Inc. All rights reserved. + * + * This program is free software; you may 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _ENIC_PP_H_ +#define _ENIC_PP_H_ + +int enic_process_set_pp_request(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); +int enic_process_get_pp_request(struct enic *enic, int request, + u16 *response); + +#endif /* _ENIC_PP_H_ */ diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index f111a37419ce..6e5c6356e7df 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -98,9 +98,9 @@ int enic_get_vnic_config(struct enic *enic) "vNIC MAC addr %pM wq/rq %d/%d mtu %d\n", enic->mac_addr, c->wq_desc_count, c->rq_desc_count, c->mtu); dev_info(enic_get_dev(enic), "vNIC csum tx/rx %d/%d " - "tso/lro %d/%d intr timer %d usec rss %d\n", + "tso %d intr timer %d usec rss %d\n", ENIC_SETTING(enic, TXCSUM), ENIC_SETTING(enic, RXCSUM), - ENIC_SETTING(enic, TSO), ENIC_SETTING(enic, LRO), + ENIC_SETTING(enic, TSO), c->intr_timer_usec, ENIC_SETTING(enic, RSS)); return 0; diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index c089b362a36f..68f24ae860ae 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -786,48 +786,6 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg) return r; } -int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err) -{ - u64 a0 = 0, a1 = 0; - int wait = 1000; - int ret; - - *done = 0; - - ret = vnic_dev_cmd(vdev, CMD_INIT_STATUS, &a0, &a1, wait); - if (ret) - return ret; - - *done = (a0 == 0); - - *err = (a0 == 0) ? (int)a1:0; - - return 0; -} - -int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len) -{ - u64 a0, a1 = len; - int wait = 1000; - dma_addr_t prov_pa; - void *prov_buf; - int ret; - - prov_buf = pci_alloc_consistent(vdev->pdev, len, &prov_pa); - if (!prov_buf) - return -ENOMEM; - - memcpy(prov_buf, buf, len); - - a0 = prov_pa; - - ret = vnic_dev_cmd(vdev, CMD_INIT_PROV_INFO, &a0, &a1, wait); - - pci_free_consistent(vdev->pdev, len, prov_buf, prov_pa); - - return ret; -} - int vnic_dev_deinit(struct vnic_dev *vdev) { u64 a0 = 0, a1 = 0; @@ -927,4 +885,59 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, return NULL; } +int vnic_dev_init_prov2(struct vnic_dev *vdev, u8 *buf, u32 len) +{ + u64 a0, a1 = len; + int wait = 1000; + dma_addr_t prov_pa; + void *prov_buf; + int ret; + prov_buf = pci_alloc_consistent(vdev->pdev, len, &prov_pa); + if (!prov_buf) + return -ENOMEM; + + memcpy(prov_buf, buf, len); + + a0 = prov_pa; + + ret = vnic_dev_cmd(vdev, CMD_INIT_PROV_INFO2, &a0, &a1, wait); + + pci_free_consistent(vdev->pdev, len, prov_buf, prov_pa); + + return ret; +} + +int vnic_dev_enable2(struct vnic_dev *vdev, int active) +{ + u64 a0, a1 = 0; + int wait = 1000; + + a0 = (active ? CMD_ENABLE2_ACTIVE : 0); + + return vnic_dev_cmd(vdev, CMD_ENABLE2, &a0, &a1, wait); +} + +static int vnic_dev_cmd_status(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, + int *status) +{ + u64 a0 = cmd, a1 = 0; + int wait = 1000; + int ret; + + ret = vnic_dev_cmd(vdev, CMD_STATUS, &a0, &a1, wait); + if (!ret) + *status = (int)a0; + + return ret; +} + +int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status) +{ + return vnic_dev_cmd_status(vdev, CMD_ENABLE2, status); +} + +int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status) +{ + return vnic_dev_cmd_status(vdev, CMD_DEINIT, status); +} diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index e837546213a8..cf482a2c9dd9 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h @@ -108,8 +108,6 @@ int vnic_dev_disable(struct vnic_dev *vdev); int vnic_dev_open(struct vnic_dev *vdev, int arg); int vnic_dev_open_done(struct vnic_dev *vdev, int *done); int vnic_dev_init(struct vnic_dev *vdev, int arg); -int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err); -int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len); int vnic_dev_deinit(struct vnic_dev *vdev); int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg); int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done); @@ -122,5 +120,9 @@ int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev, struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar, unsigned int num_bars); +int vnic_dev_init_prov2(struct vnic_dev *vdev, u8 *buf, u32 len); +int vnic_dev_enable2(struct vnic_dev *vdev, int active); +int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status); +int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status); #endif /* _VNIC_DEV_H_ */ diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h index d833a071bac5..c5569bfb47ac 100644 --- a/drivers/net/enic/vnic_devcmd.h +++ b/drivers/net/enic/vnic_devcmd.h @@ -267,17 +267,62 @@ enum vnic_devcmd_cmd { /* * As for BY_BDF except a0 is index of hvnlink subordinate vnic - * or SR-IOV virtual vnic */ + * or SR-IOV virtual vnic + */ CMD_PROXY_BY_INDEX = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 43), /* - * in: (u64)a0=paddr of buffer to put latest VIC VIF-CONFIG-INFO TLV in - * (u32)a1=length of buffer in a0 - * out: (u64)a0=paddr of buffer with latest VIC VIF-CONFIG-INFO TLV - * (u32)a1=actual length of latest VIC VIF-CONFIG-INFO TLV */ + * For HPP toggle: + * adapter-info-get + * in: (u64)a0=phsical address of buffer passed in from caller. + * (u16)a1=size of buffer specified in a0. + * out: (u64)a0=phsical address of buffer passed in from caller. + * (u16)a1=actual bytes from VIF-CONFIG-INFO TLV, or + * 0 if no VIF-CONFIG-INFO TLV was ever received. */ CMD_CONFIG_INFO_GET = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 44), + + /* init_prov_info2: + * Variant of CMD_INIT_PROV_INFO, where it will not try to enable + * the vnic until CMD_ENABLE2 is issued. + * (u64)a0=paddr of vnic_devcmd_provinfo + * (u32)a1=sizeof provision info */ + CMD_INIT_PROV_INFO2 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 47), + + /* enable2: + * (u32)a0=0 ==> standby + * =CMD_ENABLE2_ACTIVE ==> active + */ + CMD_ENABLE2 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 48), + + /* + * cmd_status: + * Returns the status of the specified command + * Input: + * a0 = command for which status is being queried. + * Possible values are: + * CMD_SOFT_RESET + * CMD_HANG_RESET + * CMD_OPEN + * CMD_INIT + * CMD_INIT_PROV_INFO + * CMD_DEINIT + * CMD_INIT_PROV_INFO2 + * CMD_ENABLE2 + * Output: + * if status == STAT_ERROR + * a0 = ERR_ENOTSUPPORTED - status for command in a0 is + * not supported + * if status == STAT_NONE + * a0 = status of the devcmd specified in a0 as follows. + * ERR_SUCCESS - command in a0 completed successfully + * ERR_EINPROGRESS - command in a0 is still in progress + */ + CMD_STATUS = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 49), }; +/* CMD_ENABLE2 flags */ +#define CMD_ENABLE2_ACTIVE 0x1 + /* flags for CMD_OPEN */ #define CMD_OPENF_OPROM 0x1 /* open coming from option rom */ @@ -315,6 +360,8 @@ enum vnic_devcmd_error { ERR_ETIMEDOUT = 8, ERR_ELINKDOWN = 9, ERR_EMAXRES = 10, + ERR_ENOTSUPPORTED = 11, + ERR_EINPROGRESS = 12, }; /* diff --git a/drivers/net/enic/vnic_vic.c b/drivers/net/enic/vnic_vic.c index 4725b79de0ef..24ef8cd40545 100644 --- a/drivers/net/enic/vnic_vic.c +++ b/drivers/net/enic/vnic_vic.c @@ -23,7 +23,8 @@ #include "vnic_vic.h" -struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type) +struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, const u8 *oui, + const u8 type) { struct vic_provinfo *vp; @@ -47,7 +48,7 @@ void vic_provinfo_free(struct vic_provinfo *vp) } int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length, - void *value) + const void *value) { struct vic_provinfo_tlv *tlv; diff --git a/drivers/net/enic/vnic_vic.h b/drivers/net/enic/vnic_vic.h index f700f5d9e81d..9ef81f148351 100644 --- a/drivers/net/enic/vnic_vic.h +++ b/drivers/net/enic/vnic_vic.h @@ -47,6 +47,7 @@ enum vic_generic_prov_os_type { VIC_GENERIC_PROV_OS_TYPE_ESX = 1, VIC_GENERIC_PROV_OS_TYPE_LINUX = 2, VIC_GENERIC_PROV_OS_TYPE_WINDOWS = 3, + VIC_GENERIC_PROV_OS_TYPE_SOLARIS = 4, }; struct vic_provinfo { @@ -61,14 +62,22 @@ struct vic_provinfo { } tlv[0]; } __packed; +#define VIC_PROVINFO_ADD_TLV(vp, tlvtype, tlvlen, data) \ + do { \ + err = vic_provinfo_add_tlv(vp, tlvtype, tlvlen, data); \ + if (err) \ + goto add_tlv_failure; \ + } while (0) + #define VIC_PROVINFO_MAX_DATA 1385 #define VIC_PROVINFO_MAX_TLV_DATA (VIC_PROVINFO_MAX_DATA - \ sizeof(struct vic_provinfo)) -struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type); +struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, const u8 *oui, + const u8 type); void vic_provinfo_free(struct vic_provinfo *vp); int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length, - void *value); + const void *value); size_t vic_provinfo_size(struct vic_provinfo *vp); #endif /* _VNIC_VIC_H_ */ diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 380d0614a89a..b5f6173130f4 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -1545,7 +1545,7 @@ static int ewrk3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } ecmd->supported |= SUPPORTED_10baseT_Half; - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); ecmd->duplex = DUPLEX_HALF; return 0; } @@ -1604,55 +1604,47 @@ static u32 ewrk3_get_link(struct net_device *dev) return !(cmr & CMR_LINK); } -static int ewrk3_phys_id(struct net_device *dev, u32 data) +static int ewrk3_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct ewrk3_private *lp = netdev_priv(dev); unsigned long iobase = dev->base_addr; - unsigned long flags; u8 cr; - int count; - /* Toggle LED 4x per second */ - count = data << 2; + spin_lock_irq(&lp->hw_lock); - spin_lock_irqsave(&lp->hw_lock, flags); + switch (state) { + case ETHTOOL_ID_ACTIVE: + /* Prevent ISR from twiddling the LED */ + lp->led_mask = 0; + spin_unlock_irq(&lp->hw_lock); + return 2; /* cycle on/off twice per second */ - /* Bail if a PHYS_ID is already in progress */ - if (lp->led_mask == 0) { - spin_unlock_irqrestore(&lp->hw_lock, flags); - return -EBUSY; - } - - /* Prevent ISR from twiddling the LED */ - lp->led_mask = 0; - - while (count--) { - /* Toggle the LED */ + case ETHTOOL_ID_ON: cr = inb(EWRK3_CR); - outb(cr ^ CR_LED, EWRK3_CR); + outb(cr | CR_LED, EWRK3_CR); + break; - /* Wait a little while */ - spin_unlock_irqrestore(&lp->hw_lock, flags); - msleep(250); - spin_lock_irqsave(&lp->hw_lock, flags); + case ETHTOOL_ID_OFF: + cr = inb(EWRK3_CR); + outb(cr & ~CR_LED, EWRK3_CR); + break; - /* Exit if we got a signal */ - if (signal_pending(current)) - break; + case ETHTOOL_ID_INACTIVE: + lp->led_mask = CR_LED; + cr = inb(EWRK3_CR); + outb(cr & ~CR_LED, EWRK3_CR); } + spin_unlock_irq(&lp->hw_lock); - lp->led_mask = CR_LED; - cr = inb(EWRK3_CR); - outb(cr & ~CR_LED, EWRK3_CR); - spin_unlock_irqrestore(&lp->hw_lock, flags); - return signal_pending(current) ? -ERESTARTSYS : 0; + return 0; } static const struct ethtool_ops ethtool_ops_203 = { .get_drvinfo = ewrk3_get_drvinfo, .get_settings = ewrk3_get_settings, .set_settings = ewrk3_set_settings, - .phys_id = ewrk3_phys_id, + .set_phys_id = ewrk3_set_phys_id, }; static const struct ethtool_ops ethtool_ops = { @@ -1660,7 +1652,7 @@ static const struct ethtool_ops ethtool_ops = { .get_settings = ewrk3_get_settings, .set_settings = ewrk3_set_settings, .get_link = ewrk3_get_link, - .phys_id = ewrk3_phys_id, + .set_phys_id = ewrk3_set_phys_id, }; /* diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index d5ab4dad5051..d09e8b0add01 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -774,7 +774,6 @@ struct fe_priv { u32 driver_data; u32 device_id; u32 register_size; - int rx_csum; u32 mac_in_use; int mgmt_version; int mgmt_sema; @@ -3956,6 +3955,7 @@ static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct fe_priv *np = netdev_priv(dev); + u32 speed; int adv; spin_lock_irq(&np->lock); @@ -3975,23 +3975,26 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (netif_carrier_ok(dev)) { switch (np->linkspeed & (NVREG_LINKSPEED_MASK)) { case NVREG_LINKSPEED_10: - ecmd->speed = SPEED_10; + speed = SPEED_10; break; case NVREG_LINKSPEED_100: - ecmd->speed = SPEED_100; + speed = SPEED_100; break; case NVREG_LINKSPEED_1000: - ecmd->speed = SPEED_1000; + speed = SPEED_1000; + break; + default: + speed = -1; break; } ecmd->duplex = DUPLEX_HALF; if (np->duplex) ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + speed = -1; ecmd->duplex = -1; } - + ethtool_cmd_speed_set(ecmd, speed); ecmd->autoneg = np->autoneg; ecmd->advertising = ADVERTISED_MII; @@ -4030,6 +4033,7 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct fe_priv *np = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(ecmd); if (ecmd->port != PORT_MII) return -EINVAL; @@ -4055,7 +4059,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) /* Note: autonegotiation disable, speed 1000 intentionally * forbidden - no one should need that. */ - if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) + if (speed != SPEED_10 && speed != SPEED_100) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; @@ -4139,13 +4143,13 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); - if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF) + if (speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF) adv |= ADVERTISE_10HALF; - if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL) + if (speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL) adv |= ADVERTISE_10FULL; - if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF) + if (speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF) adv |= ADVERTISE_100HALF; - if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL) + if (speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL) adv |= ADVERTISE_100FULL; np->pause_flags &= ~(NV_PAUSEFRAME_AUTONEG|NV_PAUSEFRAME_RX_ENABLE|NV_PAUSEFRAME_TX_ENABLE); if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) {/* for rx we set both advertisements but disable tx pause */ @@ -4264,16 +4268,6 @@ static int nv_nway_reset(struct net_device *dev) return ret; } -static int nv_set_tso(struct net_device *dev, u32 value) -{ - struct fe_priv *np = netdev_priv(dev); - - if ((np->driver_data & DEV_HAS_CHECKSUM)) - return ethtool_op_set_tso(dev, value); - else - return -EOPNOTSUPP; -} - static void nv_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring) { struct fe_priv *np = netdev_priv(dev); @@ -4480,58 +4474,36 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam* return 0; } -static u32 nv_get_rx_csum(struct net_device *dev) +static u32 nv_fix_features(struct net_device *dev, u32 features) { - struct fe_priv *np = netdev_priv(dev); - return np->rx_csum != 0; + /* vlan is dependent on rx checksum offload */ + if (features & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)) + features |= NETIF_F_RXCSUM; + + return features; } -static int nv_set_rx_csum(struct net_device *dev, u32 data) +static int nv_set_features(struct net_device *dev, u32 features) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - int retcode = 0; + u32 changed = dev->features ^ features; - if (np->driver_data & DEV_HAS_CHECKSUM) { - if (data) { - np->rx_csum = 1; + if (changed & NETIF_F_RXCSUM) { + spin_lock_irq(&np->lock); + + if (features & NETIF_F_RXCSUM) np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; - } else { - np->rx_csum = 0; - /* vlan is dependent on rx checksum offload */ - if (!(np->vlanctl_bits & NVREG_VLANCONTROL_ENABLE)) - np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK; - } - if (netif_running(dev)) { - spin_lock_irq(&np->lock); + else + np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK; + + if (netif_running(dev)) writel(np->txrxctl_bits, base + NvRegTxRxControl); - spin_unlock_irq(&np->lock); - } - } else { - return -EINVAL; + + spin_unlock_irq(&np->lock); } - return retcode; -} - -static int nv_set_tx_csum(struct net_device *dev, u32 data) -{ - struct fe_priv *np = netdev_priv(dev); - - if (np->driver_data & DEV_HAS_CHECKSUM) - return ethtool_op_set_tx_csum(dev, data); - else - return -EOPNOTSUPP; -} - -static int nv_set_sg(struct net_device *dev, u32 data) -{ - struct fe_priv *np = netdev_priv(dev); - - if (np->driver_data & DEV_HAS_CHECKSUM) - return ethtool_op_set_sg(dev, data); - else - return -EOPNOTSUPP; + return 0; } static int nv_get_sset_count(struct net_device *dev, int sset) @@ -4896,15 +4868,10 @@ static const struct ethtool_ops ops = { .get_regs_len = nv_get_regs_len, .get_regs = nv_get_regs, .nway_reset = nv_nway_reset, - .set_tso = nv_set_tso, .get_ringparam = nv_get_ringparam, .set_ringparam = nv_set_ringparam, .get_pauseparam = nv_get_pauseparam, .set_pauseparam = nv_set_pauseparam, - .get_rx_csum = nv_get_rx_csum, - .set_rx_csum = nv_set_rx_csum, - .set_tx_csum = nv_set_tx_csum, - .set_sg = nv_set_sg, .get_strings = nv_get_strings, .get_ethtool_stats = nv_get_ethtool_stats, .get_sset_count = nv_get_sset_count, @@ -5235,6 +5202,8 @@ static const struct net_device_ops nv_netdev_ops = { .ndo_start_xmit = nv_start_xmit, .ndo_tx_timeout = nv_tx_timeout, .ndo_change_mtu = nv_change_mtu, + .ndo_fix_features = nv_fix_features, + .ndo_set_features = nv_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = nv_set_mac_address, .ndo_set_multicast_list = nv_set_multicast, @@ -5251,6 +5220,8 @@ static const struct net_device_ops nv_netdev_ops_optimized = { .ndo_start_xmit = nv_start_xmit_optimized, .ndo_tx_timeout = nv_tx_timeout, .ndo_change_mtu = nv_change_mtu, + .ndo_fix_features = nv_fix_features, + .ndo_set_features = nv_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = nv_set_mac_address, .ndo_set_multicast_list = nv_set_multicast, @@ -5364,11 +5335,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->pkt_limit = NV_PKTLIMIT_2; if (id->driver_data & DEV_HAS_CHECKSUM) { - np->rx_csum = 1; np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - dev->features |= NETIF_F_TSO; - dev->features |= NETIF_F_GRO; + dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_RXCSUM; + dev->features |= dev->hw_features; } np->vlanctl_bits = 0; @@ -5384,7 +5354,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ; } - err = -ENOMEM; np->base = ioremap(addr, np->register_size); if (!np->base) diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 24cb953900dd..21abb5c01a56 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -956,8 +956,6 @@ static const struct ethtool_ops fs_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = fs_get_msglevel, .set_msglevel = fs_set_msglevel, - .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .set_sg = ethtool_op_set_sg, .get_regs = fs_get_regs, }; @@ -998,8 +996,10 @@ static const struct net_device_ops fs_enet_netdev_ops = { #endif }; +static struct of_device_id fs_enet_match[]; static int __devinit fs_enet_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct net_device *ndev; struct fs_enet_private *fep; struct fs_platform_info *fpi; @@ -1007,14 +1007,15 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev) const u8 *mac_addr; int privsize, len, ret = -ENODEV; - if (!ofdev->dev.of_match) + match = of_match_device(fs_enet_match, &ofdev->dev); + if (!match) return -EINVAL; fpi = kzalloc(sizeof(*fpi), GFP_KERNEL); if (!fpi) return -ENOMEM; - if (!IS_FEC(ofdev->dev.of_match)) { + if (!IS_FEC(match)) { data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len); if (!data || len != 4) goto out_free_fpi; @@ -1049,7 +1050,7 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev) fep->dev = &ofdev->dev; fep->ndev = ndev; fep->fpi = fpi; - fep->ops = ofdev->dev.of_match->data; + fep->ops = match->data; ret = fep->ops->setup_data(ndev); if (ret) diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 61035fc5599b..b9fbc83d64a7 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -226,8 +226,8 @@ static void set_multicast_finish(struct net_device *dev) } FC(fecp, r_cntrl, FEC_RCNTRL_PROM); - FW(fecp, hash_table_high, fep->fec.hthi); - FW(fecp, hash_table_low, fep->fec.htlo); + FW(fecp, grp_hash_table_high, fep->fec.hthi); + FW(fecp, grp_hash_table_low, fep->fec.htlo); } static void set_multicast_list(struct net_device *dev) @@ -273,8 +273,8 @@ static void restart(struct net_device *dev) /* * Reset all multicast. */ - FW(fecp, hash_table_high, fep->fec.hthi); - FW(fecp, hash_table_low, fep->fec.htlo); + FW(fecp, grp_hash_table_high, fep->fec.hthi); + FW(fecp, grp_hash_table_low, fep->fec.htlo); /* * Set maximum receive buffer size. diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 7e840d373ab3..6a2e150e75bb 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -101,17 +101,20 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus) return 0; } +static struct of_device_id fs_enet_mdio_fec_match[]; static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct resource res; struct mii_bus *new_bus; struct fec_info *fec; int (*get_bus_freq)(struct device_node *); int ret = -ENOMEM, clock, speed; - if (!ofdev->dev.of_match) + match = of_match_device(fs_enet_mdio_fec_match, &ofdev->dev); + if (!match) return -EINVAL; - get_bus_freq = ofdev->dev.of_match->data; + get_bus_freq = match->data; new_bus = mdiobus_alloc(); if (!new_bus) diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c index a31661948c42..9bd7746cbfcf 100644 --- a/drivers/net/ftmac100.c +++ b/drivers/net/ftmac100.c @@ -139,11 +139,11 @@ static int ftmac100_reset(struct ftmac100 *priv) * that hardware reset completed (what the f*ck). * We still need to wait for a while. */ - usleep_range(500, 1000); + udelay(500); return 0; } - usleep_range(1000, 10000); + udelay(1000); } netdev_err(netdev, "software reset failed\n"); @@ -772,7 +772,7 @@ static int ftmac100_mdio_read(struct net_device *netdev, int phy_id, int reg) if ((phycr & FTMAC100_PHYCR_MIIRD) == 0) return phycr & FTMAC100_PHYCR_MIIRDATA; - usleep_range(100, 1000); + udelay(100); } netdev_err(netdev, "mdio read timed out\n"); @@ -801,7 +801,7 @@ static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg, if ((phycr & FTMAC100_PHYCR_MIIWR) == 0) return; - usleep_range(100, 1000); + udelay(100); } netdev_err(netdev, "mdio write timed out\n"); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 2a0ad9a501bb..ff60b23a5b74 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -365,7 +365,7 @@ static void gfar_init_mac(struct net_device *ndev) gfar_write(®s->rir0, DEFAULT_RIR0); } - if (priv->rx_csum_enable) + if (ndev->features & NETIF_F_RXCSUM) rctrl |= RCTRL_CHECKSUMMING; if (priv->extended_hash) { @@ -463,6 +463,7 @@ static const struct net_device_ops gfar_netdev_ops = { .ndo_start_xmit = gfar_start_xmit, .ndo_stop = gfar_close, .ndo_change_mtu = gfar_change_mtu, + .ndo_set_features = gfar_set_features, .ndo_set_multicast_list = gfar_set_multi, .ndo_tx_timeout = gfar_timeout, .ndo_do_ioctl = gfar_ioctl, @@ -513,7 +514,7 @@ void unlock_tx_qs(struct gfar_private *priv) /* Returns 1 if incoming frames use an FCB */ static inline int gfar_uses_fcb(struct gfar_private *priv) { - return priv->vlgrp || priv->rx_csum_enable || + return priv->vlgrp || (priv->ndev->features & NETIF_F_RXCSUM) || (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER); } @@ -1030,10 +1031,11 @@ static int gfar_probe(struct platform_device *ofdev) netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll, GFAR_DEV_WEIGHT); if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { - priv->rx_csum_enable = 1; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA; - } else - priv->rx_csum_enable = 0; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM; + dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM | NETIF_F_HIGHDMA; + } priv->vlgrp = NULL; @@ -2697,7 +2699,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, if (priv->padding) skb_pull(skb, priv->padding); - if (priv->rx_csum_enable) + if (dev->features & NETIF_F_RXCSUM) gfar_rx_checksum(skb, fcb); /* Tell the skb what kind of packet this is */ diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index b2fe7edefad9..fc86f5195445 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -382,23 +382,6 @@ extern const char gfar_driver_version[]; #define BD_LFLAG(flags) ((flags) << 16) #define BD_LENGTH_MASK 0x0000ffff -#define CLASS_CODE_UNRECOG 0x00 -#define CLASS_CODE_DUMMY1 0x01 -#define CLASS_CODE_ETHERTYPE1 0x02 -#define CLASS_CODE_ETHERTYPE2 0x03 -#define CLASS_CODE_USER_PROG1 0x04 -#define CLASS_CODE_USER_PROG2 0x05 -#define CLASS_CODE_USER_PROG3 0x06 -#define CLASS_CODE_USER_PROG4 0x07 -#define CLASS_CODE_TCP_IPV4 0x08 -#define CLASS_CODE_UDP_IPV4 0x09 -#define CLASS_CODE_AH_ESP_IPV4 0x0a -#define CLASS_CODE_SCTP_IPV4 0x0b -#define CLASS_CODE_TCP_IPV6 0x0c -#define CLASS_CODE_UDP_IPV6 0x0d -#define CLASS_CODE_AH_ESP_IPV6 0x0e -#define CLASS_CODE_SCTP_IPV6 0x0f - #define FPR_FILER_MASK 0xFFFFFFFF #define MAX_FILER_IDX 0xFF @@ -1100,7 +1083,7 @@ struct gfar_private { struct device_node *phy_node; struct device_node *tbi_node; u32 device_flags; - unsigned char rx_csum_enable:1, + unsigned char extended_hash:1, bd_stash_en:1, rx_filer_enable:1, @@ -1170,6 +1153,7 @@ extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, extern void gfar_configure_coalescing(struct gfar_private *priv, unsigned long tx_mask, unsigned long rx_mask); void gfar_init_sysfs(struct net_device *dev); +int gfar_set_features(struct net_device *dev, u32 features); extern const struct ethtool_ops gfar_ethtool_ops; diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 3bc8e276ba4d..493d743839d9 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -517,15 +517,15 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva return err; } -static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) +int gfar_set_features(struct net_device *dev, u32 features) { struct gfar_private *priv = netdev_priv(dev); unsigned long flags; int err = 0, i = 0; + u32 changed = dev->features ^ features; - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) - return -EOPNOTSUPP; - + if (!(changed & NETIF_F_RXCSUM)) + return 0; if (dev->flags & IFF_UP) { /* Halt TX and RX, and process the frames which @@ -546,58 +546,15 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) /* Now we take down the rings to rebuild them */ stop_gfar(dev); - } - spin_lock_irqsave(&priv->bflock, flags); - priv->rx_csum_enable = data; - spin_unlock_irqrestore(&priv->bflock, flags); + dev->features = features; - if (dev->flags & IFF_UP) { err = startup_gfar(dev); netif_tx_wake_all_queues(dev); } return err; } -static uint32_t gfar_get_rx_csum(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) - return 0; - - return priv->rx_csum_enable; -} - -static int gfar_set_tx_csum(struct net_device *dev, uint32_t data) -{ - struct gfar_private *priv = netdev_priv(dev); - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) - return -EOPNOTSUPP; - - netif_tx_lock_bh(dev); - - if (data) - dev->features |= NETIF_F_IP_CSUM; - else - dev->features &= ~NETIF_F_IP_CSUM; - - netif_tx_unlock_bh(dev); - - return 0; -} - -static uint32_t gfar_get_tx_csum(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) - return 0; - - return (dev->features & NETIF_F_IP_CSUM) != 0; -} - static uint32_t gfar_get_msglevel(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); @@ -645,42 +602,6 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) } #endif -static int gfar_ethflow_to_class(int flow_type, u64 *class) -{ - switch (flow_type) { - case TCP_V4_FLOW: - *class = CLASS_CODE_TCP_IPV4; - break; - case UDP_V4_FLOW: - *class = CLASS_CODE_UDP_IPV4; - break; - case AH_V4_FLOW: - case ESP_V4_FLOW: - *class = CLASS_CODE_AH_ESP_IPV4; - break; - case SCTP_V4_FLOW: - *class = CLASS_CODE_SCTP_IPV4; - break; - case TCP_V6_FLOW: - *class = CLASS_CODE_TCP_IPV6; - break; - case UDP_V6_FLOW: - *class = CLASS_CODE_UDP_IPV6; - break; - case AH_V6_FLOW: - case ESP_V6_FLOW: - *class = CLASS_CODE_AH_ESP_IPV6; - break; - case SCTP_V6_FLOW: - *class = CLASS_CODE_SCTP_IPV6; - break; - default: - return 0; - } - - return 1; -} - static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow) { u32 fcr = 0x0, fpr = FPR_FILER_MASK; @@ -778,11 +699,6 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u case UDP_V6_FLOW: cmp_rqfpr = RQFPR_IPV6 |RQFPR_UDP; break; - case IPV4_FLOW: - cmp_rqfpr = RQFPR_IPV4; - case IPV6_FLOW: - cmp_rqfpr = RQFPR_IPV6; - break; default: printk(KERN_ERR "Right now this class is not supported\n"); return 0; @@ -848,18 +764,9 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd) { - u64 class; - - if (!gfar_ethflow_to_class(cmd->flow_type, &class)) - return -EINVAL; - - if (class < CLASS_CODE_USER_PROG1 || - class > CLASS_CODE_SCTP_IPV6) - return -EINVAL; - /* write the filer rules here */ if (!gfar_ethflow_to_filer_table(priv, cmd->data, cmd->flow_type)) - return -1; + return -EINVAL; return 0; } @@ -894,11 +801,6 @@ const struct ethtool_ops gfar_ethtool_ops = { .get_strings = gfar_gstrings, .get_sset_count = gfar_sset_count, .get_ethtool_stats = gfar_fill_stats, - .get_rx_csum = gfar_get_rx_csum, - .get_tx_csum = gfar_get_tx_csum, - .set_rx_csum = gfar_set_rx_csum, - .set_tx_csum = gfar_set_tx_csum, - .set_sg = ethtool_op_set_sg, .get_msglevel = gfar_get_msglevel, .set_msglevel = gfar_set_msglevel, #ifdef CONFIG_PM diff --git a/drivers/net/greth.c b/drivers/net/greth.c index 396ff7d785d1..f181304a7ab6 100644 --- a/drivers/net/greth.c +++ b/drivers/net/greth.c @@ -901,7 +901,7 @@ static int greth_rx_gbit(struct net_device *dev, int limit) skb_put(skb, pkt_len); - if (greth->flags & GRETH_FLAG_RX_CSUM && hw_checksummed(status)) + if (dev->features & NETIF_F_RXCSUM && hw_checksummed(status)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); @@ -1142,41 +1142,6 @@ static void greth_get_regs(struct net_device *dev, struct ethtool_regs *regs, vo buff[i] = greth_read_bd(&greth_regs[i]); } -static u32 greth_get_rx_csum(struct net_device *dev) -{ - struct greth_private *greth = netdev_priv(dev); - return (greth->flags & GRETH_FLAG_RX_CSUM) != 0; -} - -static int greth_set_rx_csum(struct net_device *dev, u32 data) -{ - struct greth_private *greth = netdev_priv(dev); - - spin_lock_bh(&greth->devlock); - - if (data) - greth->flags |= GRETH_FLAG_RX_CSUM; - else - greth->flags &= ~GRETH_FLAG_RX_CSUM; - - spin_unlock_bh(&greth->devlock); - - return 0; -} - -static u32 greth_get_tx_csum(struct net_device *dev) -{ - return (dev->features & NETIF_F_IP_CSUM) != 0; -} - -static int greth_set_tx_csum(struct net_device *dev, u32 data) -{ - netif_tx_lock_bh(dev); - ethtool_op_set_tx_csum(dev, data); - netif_tx_unlock_bh(dev); - return 0; -} - static const struct ethtool_ops greth_ethtool_ops = { .get_msglevel = greth_get_msglevel, .set_msglevel = greth_set_msglevel, @@ -1185,10 +1150,6 @@ static const struct ethtool_ops greth_ethtool_ops = { .get_drvinfo = greth_get_drvinfo, .get_regs_len = greth_get_regs_len, .get_regs = greth_get_regs, - .get_rx_csum = greth_get_rx_csum, - .set_rx_csum = greth_set_rx_csum, - .get_tx_csum = greth_get_tx_csum, - .set_tx_csum = greth_set_tx_csum, .get_link = ethtool_op_get_link, }; @@ -1570,9 +1531,10 @@ static int __devinit greth_of_probe(struct platform_device *ofdev) GRETH_REGSAVE(regs->status, 0xFF); if (greth->gbit_mac) { - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM; + dev->features = dev->hw_features | NETIF_F_HIGHDMA; greth_netdev_ops.ndo_start_xmit = greth_start_xmit_gbit; - greth->flags = GRETH_FLAG_RX_CSUM; } if (greth->multicast) { diff --git a/drivers/net/greth.h b/drivers/net/greth.h index be0f2062bd14..9a0040dee4da 100644 --- a/drivers/net/greth.h +++ b/drivers/net/greth.h @@ -77,9 +77,6 @@ */ #define MAX_FRAME_SIZE 1520 -/* Flags */ -#define GRETH_FLAG_RX_CSUM 0x1 - /* GRETH APB registers */ struct greth_regs { u32 control; @@ -133,7 +130,6 @@ struct greth_private { unsigned int duplex; u32 msg_enable; - u32 flags; u8 phyaddr; u8 multicast; diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 80d25ed53344..a09041aa8509 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -132,13 +132,8 @@ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* * RX_CHECKSUM turns on card-generated receive checksum generation for * TCP and UDP packets. Otherwise the upper layers do the calculation. - * TX_CHECKSUM won't do anything too useful, even if it works. There's no - * easy mechanism by which to tell the TCP/UDP stack that it need not - * generate checksums for this device. But if somebody can find a way - * to get that to work, most of the card work is in here already. * 3/10/1999 Pete Wyckoff */ -#undef TX_CHECKSUM #define RX_CHECKSUM /* Operational parameters that usually are not changed. */ @@ -630,11 +625,6 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); -#ifdef TX_CHECKSUM - printk("check that skbcopy in ip_queue_xmit isn't happening\n"); - dev->hard_header_len += 8; /* for cksum tag */ -#endif - for (i = 0; i < 6; i++) dev->dev_addr[i] = 1 ? read_eeprom(ioaddr, 4 + i) : readb(ioaddr + StationAddr + i); @@ -937,11 +927,7 @@ static int hamachi_open(struct net_device *dev) /* always 1, takes no more time to do it */ writew(0x0001, ioaddr + RxChecksum); -#ifdef TX_CHECKSUM - writew(0x0001, ioaddr + TxChecksum); -#else writew(0x0000, ioaddr + TxChecksum); -#endif writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */ writew(0x215F, ioaddr + MACCnfg); writew(0x000C, ioaddr + FrameGap0); @@ -1226,40 +1212,6 @@ static void hamachi_init_ring(struct net_device *dev) } -#ifdef TX_CHECKSUM -#define csum_add(it, val) \ -do { \ - it += (u16) (val); \ - if (it & 0xffff0000) { \ - it &= 0xffff; \ - ++it; \ - } \ -} while (0) - /* printk("add %04x --> %04x\n", val, it); \ */ - -/* uh->len already network format, do not swap */ -#define pseudo_csum_udp(sum,ih,uh) do { \ - sum = 0; \ - csum_add(sum, (ih)->saddr >> 16); \ - csum_add(sum, (ih)->saddr & 0xffff); \ - csum_add(sum, (ih)->daddr >> 16); \ - csum_add(sum, (ih)->daddr & 0xffff); \ - csum_add(sum, cpu_to_be16(IPPROTO_UDP)); \ - csum_add(sum, (uh)->len); \ -} while (0) - -/* swap len */ -#define pseudo_csum_tcp(sum,ih,len) do { \ - sum = 0; \ - csum_add(sum, (ih)->saddr >> 16); \ - csum_add(sum, (ih)->saddr & 0xffff); \ - csum_add(sum, (ih)->daddr >> 16); \ - csum_add(sum, (ih)->daddr & 0xffff); \ - csum_add(sum, cpu_to_be16(IPPROTO_TCP)); \ - csum_add(sum, htons(len)); \ -} while (0) -#endif - static netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -1292,36 +1244,6 @@ static netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, hmp->tx_skbuff[entry] = skb; -#ifdef TX_CHECKSUM - { - /* tack on checksum tag */ - u32 tagval = 0; - struct ethhdr *eh = (struct ethhdr *)skb->data; - if (eh->h_proto == cpu_to_be16(ETH_P_IP)) { - struct iphdr *ih = (struct iphdr *)((char *)eh + ETH_HLEN); - if (ih->protocol == IPPROTO_UDP) { - struct udphdr *uh - = (struct udphdr *)((char *)ih + ih->ihl*4); - u32 offset = ((unsigned char *)uh + 6) - skb->data; - u32 pseudo; - pseudo_csum_udp(pseudo, ih, uh); - pseudo = htons(pseudo); - printk("udp cksum was %04x, sending pseudo %04x\n", - uh->check, pseudo); - uh->check = 0; /* zero out uh->check before card calc */ - /* - * start at 14 (skip ethhdr), store at offset (uh->check), - * use pseudo value given. - */ - tagval = (14 << 24) | (offset << 16) | pseudo; - } else if (ih->protocol == IPPROTO_TCP) { - printk("tcp, no auto cksum\n"); - } - } - *(u32 *)skb_push(skb, 8) = tagval; - } -#endif - hmp->tx_ring[entry].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE)); diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 8931168d3e74..18d8affecd1b 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -516,10 +516,6 @@ static int bpq_new_device(struct net_device *edev) memcpy(bpq->dest_addr, bcast_addr, sizeof(bpq_eth_addr)); memcpy(bpq->acpt_addr, bcast_addr, sizeof(bpq_eth_addr)); - err = dev_alloc_name(ndev, ndev->name); - if (err < 0) - goto error; - err = register_netdevice(ndev); if (err) goto error; diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 8e10d2f6a5ad..c52a1df5d922 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -188,14 +188,14 @@ struct hp100_private { * variables */ #ifdef CONFIG_ISA -static const char *hp100_isa_tbl[] = { +static const char *const hp100_isa_tbl[] __devinitconst = { "HWPF150", /* HP J2573 rev A */ "HWP1950", /* HP J2573 */ }; #endif #ifdef CONFIG_EISA -static struct eisa_device_id hp100_eisa_tbl[] = { +static const struct eisa_device_id hp100_eisa_tbl[] __devinitconst = { { "HWPF180" }, /* HP J2577 rev A */ { "HWP1920" }, /* HP 27248B */ { "HWP1940" }, /* HP J2577 */ @@ -336,7 +336,7 @@ static __devinit const char *hp100_read_id(int ioaddr) } #ifdef CONFIG_ISA -static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr) +static __devinit int hp100_isa_probe1(struct net_device *dev, int ioaddr) { const char *sig; int i; @@ -372,7 +372,7 @@ static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr) * EISA and PCI are handled by device infrastructure. */ -static int __init hp100_isa_probe(struct net_device *dev, int addr) +static int __devinit hp100_isa_probe(struct net_device *dev, int addr) { int err = -ENODEV; @@ -396,7 +396,7 @@ static int __init hp100_isa_probe(struct net_device *dev, int addr) #endif /* CONFIG_ISA */ #if !defined(MODULE) && defined(CONFIG_ISA) -struct net_device * __init hp100_probe(int unit) +struct net_device * __devinit hp100_probe(int unit) { struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); int err; @@ -2843,7 +2843,7 @@ static void cleanup_dev(struct net_device *d) } #ifdef CONFIG_EISA -static int __init hp100_eisa_probe (struct device *gendev) +static int __devinit hp100_eisa_probe (struct device *gendev) { struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); struct eisa_device *edev = to_eisa_device(gendev); diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index c5ef62ceb840..1cd481c04202 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -98,15 +98,15 @@ static const struct net_device_ops hydra_netdev_ops = { .ndo_open = hydra_open, .ndo_stop = hydra_close, - .ndo_start_xmit = ei_start_xmit, - .ndo_tx_timeout = ei_tx_timeout, - .ndo_get_stats = ei_get_stats, - .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_start_xmit = __ei_start_xmit, + .ndo_tx_timeout = __ei_tx_timeout, + .ndo_get_stats = __ei_get_stats, + .ndo_set_multicast_list = __ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ei_poll, + .ndo_poll_controller = __ei_poll, #endif }; @@ -125,7 +125,7 @@ static int __devinit hydra_init(struct zorro_dev *z) 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; - dev = alloc_ei_netdev(); + dev = ____alloc_ei_netdev(0); if (!dev) return -ENOMEM; diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 3bb990b6651a..079450fe5e96 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2053,13 +2053,6 @@ static void emac_ethtool_get_pauseparam(struct net_device *ndev, mutex_unlock(&dev->link_lock); } -static u32 emac_ethtool_get_rx_csum(struct net_device *ndev) -{ - struct emac_instance *dev = netdev_priv(ndev); - - return dev->tah_dev != NULL; -} - static int emac_get_regs_len(struct emac_instance *dev) { if (emac_has_feature(dev, EMAC_FTR_EMAC4)) @@ -2203,15 +2196,11 @@ static const struct ethtool_ops emac_ethtool_ops = { .get_ringparam = emac_ethtool_get_ringparam, .get_pauseparam = emac_ethtool_get_pauseparam, - .get_rx_csum = emac_ethtool_get_rx_csum, - .get_strings = emac_ethtool_get_strings, .get_sset_count = emac_ethtool_get_sset_count, .get_ethtool_stats = emac_ethtool_get_ethtool_stats, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, }; static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) @@ -2859,8 +2848,10 @@ static int __devinit emac_probe(struct platform_device *ofdev) if (err != 0) goto err_detach_tah; - if (dev->tah_dev) - ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; + if (dev->tah_dev) { + ndev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG; + ndev->features |= ndev->hw_features | NETIF_F_RXCSUM; + } ndev->watchdog_timeo = 5 * HZ; if (emac_phy_supports_gige(dev->phy_mode)) { ndev->netdev_ops = &emac_gige_netdev_ops; diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 8ff68ae6b520..136d7544cc33 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -782,7 +782,8 @@ static int ibmlana_open(struct net_device *dev) /* register resources - only necessary for IRQ */ - result = request_irq(priv->realirq, irq_handler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev); + result = request_irq(priv->realirq, irq_handler, IRQF_SHARED, + dev->name, dev); if (result != 0) { printk(KERN_ERR "%s: failed to register irq %d\n", dev->name, dev->irq); return result; @@ -894,12 +895,12 @@ static int ibmlana_irq; static int ibmlana_io; static int startslot; /* counts through slots when probing multiple devices */ -static short ibmlana_adapter_ids[] __initdata = { +static const short ibmlana_adapter_ids[] __devinitconst = { IBM_LANA_ID, 0x0000 }; -static char *ibmlana_adapter_names[] __devinitdata = { +static const char *const ibmlana_adapter_names[] __devinitconst = { "IBM LAN Adapter/A", NULL }; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 5522d459654c..b388d782c7c4 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -710,7 +710,7 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) SUPPORTED_FIBRE); cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg | ADVERTISED_FIBRE); - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); cmd->duplex = DUPLEX_FULL; cmd->port = PORT_FIBRE; cmd->phy_address = 0; @@ -729,45 +729,24 @@ static void netdev_get_drvinfo(struct net_device *dev, sizeof(info->version) - 1); } -static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data) +static u32 ibmveth_fix_features(struct net_device *dev, u32 features) { - struct ibmveth_adapter *adapter = netdev_priv(dev); + /* + * Since the ibmveth firmware interface does not have the + * concept of separate tx/rx checksum offload enable, if rx + * checksum is disabled we also have to disable tx checksum + * offload. Once we disable rx checksum offload, we are no + * longer allowed to send tx buffers that are not properly + * checksummed. + */ - if (data) { - adapter->rx_csum = 1; - } else { - /* - * Since the ibmveth firmware interface does not have the - * concept of separate tx/rx checksum offload enable, if rx - * checksum is disabled we also have to disable tx checksum - * offload. Once we disable rx checksum offload, we are no - * longer allowed to send tx buffers that are not properly - * checksummed. - */ - adapter->rx_csum = 0; - dev->features &= ~NETIF_F_IP_CSUM; - dev->features &= ~NETIF_F_IPV6_CSUM; - } + if (!(features & NETIF_F_RXCSUM)) + features &= ~NETIF_F_ALL_CSUM; + + return features; } -static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data) -{ - struct ibmveth_adapter *adapter = netdev_priv(dev); - - if (data) { - if (adapter->fw_ipv4_csum_support) - dev->features |= NETIF_F_IP_CSUM; - if (adapter->fw_ipv6_csum_support) - dev->features |= NETIF_F_IPV6_CSUM; - adapter->rx_csum = 1; - } else { - dev->features &= ~NETIF_F_IP_CSUM; - dev->features &= ~NETIF_F_IPV6_CSUM; - } -} - -static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, - void (*done) (struct net_device *, u32)) +static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) { struct ibmveth_adapter *adapter = netdev_priv(dev); unsigned long set_attr, clr_attr, ret_attr; @@ -827,8 +806,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, } else adapter->fw_ipv6_csum_support = data; - if (ret == H_SUCCESS || ret6 == H_SUCCESS) - done(dev, data); + if (ret != H_SUCCESS || ret6 != H_SUCCESS) + adapter->rx_csum = data; else rc1 = -EIO; } else { @@ -844,41 +823,22 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, return rc1 ? rc1 : rc2; } -static int ibmveth_set_rx_csum(struct net_device *dev, u32 data) +static int ibmveth_set_features(struct net_device *dev, u32 features) { struct ibmveth_adapter *adapter = netdev_priv(dev); + int rx_csum = !!(features & NETIF_F_RXCSUM); + int rc; - if ((data && adapter->rx_csum) || (!data && !adapter->rx_csum)) + if (rx_csum == adapter->rx_csum) return 0; - return ibmveth_set_csum_offload(dev, data, ibmveth_set_rx_csum_flags); -} - -static int ibmveth_set_tx_csum(struct net_device *dev, u32 data) -{ - struct ibmveth_adapter *adapter = netdev_priv(dev); - int rc = 0; - - if (data && (dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) - return 0; - if (!data && !(dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) - return 0; - - if (data && !adapter->rx_csum) - rc = ibmveth_set_csum_offload(dev, data, - ibmveth_set_tx_csum_flags); - else - ibmveth_set_tx_csum_flags(dev, data); + rc = ibmveth_set_csum_offload(dev, rx_csum); + if (rc && !adapter->rx_csum) + dev->features = features & ~(NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); return rc; } -static u32 ibmveth_get_rx_csum(struct net_device *dev) -{ - struct ibmveth_adapter *adapter = netdev_priv(dev); - return adapter->rx_csum; -} - static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data) { int i; @@ -914,13 +874,9 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .get_link = ethtool_op_get_link, - .set_tx_csum = ibmveth_set_tx_csum, - .get_rx_csum = ibmveth_get_rx_csum, - .set_rx_csum = ibmveth_set_rx_csum, .get_strings = ibmveth_get_strings, .get_sset_count = ibmveth_get_sset_count, .get_ethtool_stats = ibmveth_get_ethtool_stats, - .set_sg = ethtool_op_set_sg, }; static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -1345,6 +1301,8 @@ static const struct net_device_ops ibmveth_netdev_ops = { .ndo_set_multicast_list = ibmveth_set_multicast_list, .ndo_do_ioctl = ibmveth_ioctl, .ndo_change_mtu = ibmveth_change_mtu, + .ndo_fix_features = ibmveth_fix_features, + .ndo_set_features = ibmveth_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1412,7 +1370,9 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, netdev->netdev_ops = &ibmveth_netdev_ops; netdev->ethtool_ops = &netdev_ethtool_ops; SET_NETDEV_DEV(netdev, &dev->dev); - netdev->features |= NETIF_F_SG; + netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + netdev->features |= netdev->hw_features; memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); @@ -1437,7 +1397,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, netdev_dbg(netdev, "registering netdev...\n"); - ibmveth_set_csum_offload(netdev, 1, ibmveth_set_tx_csum_flags); + ibmveth_set_features(netdev, netdev->features); rc = register_netdev(netdev); diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index e07d487f015a..4fecaed67fc4 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -233,10 +233,6 @@ static int __init ifb_init_one(int index) if (!dev_ifb) return -ENOMEM; - err = dev_alloc_name(dev_ifb, dev_ifb->name); - if (err < 0) - goto err; - dev_ifb->rtnl_link_ops = &ifb_link_ops; err = register_netdevice(dev_ifb); if (err < 0) diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 6b256c275e10..0f563c8c5ffc 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -244,6 +244,14 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) */ size += NVM_WORD_SIZE_BASE_SHIFT; + /* + * Check for invalid size + */ + if ((hw->mac.type == e1000_82576) && (size > 15)) { + printk("igb: 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; @@ -1877,7 +1885,7 @@ static s32 igb_validate_nvm_checksum_82580(struct e1000_hw *hw) } if (nvm_data & NVM_COMPATIBILITY_BIT_MASK) { - /* if chekcsums compatibility bit is set validate checksums + /* if checksums compatibility bit is set validate checksums * for all 4 ports. */ eeprom_regions_count = 4; } @@ -1988,6 +1996,7 @@ static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw) out: return ret_val; } + /** * igb_set_eee_i350 - Enable/disable EEE support * @hw: pointer to the HW structure diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 1c687e298d5e..f4fa4b1751cf 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -360,7 +360,7 @@ extern int igb_up(struct igb_adapter *); extern void igb_down(struct igb_adapter *); extern void igb_reinit_locked(struct igb_adapter *); extern void igb_reset(struct igb_adapter *); -extern int igb_set_spd_dplx(struct igb_adapter *, u16); +extern int igb_set_spd_dplx(struct igb_adapter *, u32, u8); extern int igb_setup_tx_resources(struct igb_ring *); extern int igb_setup_rx_resources(struct igb_ring *); extern void igb_free_tx_resources(struct igb_ring *); diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index d976733bbcc2..fdc895e5a3f8 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -178,11 +178,11 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) if ((status & E1000_STATUS_SPEED_1000) || hw->phy.media_type != e1000_media_type_copper) - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); else if (status & E1000_STATUS_SPEED_100) - ecmd->speed = SPEED_100; + ethtool_cmd_speed_set(ecmd, SPEED_100); else - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); if ((status & E1000_STATUS_FD) || hw->phy.media_type != e1000_media_type_copper) @@ -190,7 +190,7 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } @@ -223,7 +223,8 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) if (adapter->fc_autoneg) hw->fc.requested_mode = e1000_fc_default; } else { - if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { + u32 speed = ethtool_cmd_speed(ecmd); + if (igb_set_spd_dplx(adapter, speed, ecmd->duplex)) { clear_bit(__IGB_RESETTING, &adapter->state); return -EINVAL; } @@ -1963,27 +1964,28 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) /* bit defines for adapter->led_status */ #define IGB_LED_ON 0 -static int igb_phys_id(struct net_device *netdev, u32 data) +static int igb_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - unsigned long timeout; - timeout = data * 1000; - - /* - * msleep_interruptable only accepts unsigned int so we are limited - * in how long a duration we can wait - */ - if (!timeout || timeout > UINT_MAX) - timeout = UINT_MAX; - - igb_blink_led(hw); - msleep_interruptible(timeout); - - igb_led_off(hw); - clear_bit(IGB_LED_ON, &adapter->led_status); - igb_cleanup_led(hw); + switch (state) { + case ETHTOOL_ID_ACTIVE: + igb_blink_led(hw); + return 2; + case ETHTOOL_ID_ON: + igb_blink_led(hw); + break; + case ETHTOOL_ID_OFF: + igb_led_off(hw); + break; + case ETHTOOL_ID_INACTIVE: + igb_led_off(hw); + clear_bit(IGB_LED_ON, &adapter->led_status); + igb_cleanup_led(hw); + break; + } return 0; } @@ -2215,7 +2217,7 @@ static const struct ethtool_ops igb_ethtool_ops = { .set_tso = igb_set_tso, .self_test = igb_diag_test, .get_strings = igb_get_strings, - .phys_id = igb_phys_id, + .set_phys_id = igb_set_phys_id, .get_sset_count = igb_get_sset_count, .get_ethtool_stats = igb_get_ethtool_stats, .get_coalesce = igb_get_coalesce, diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 0dfd1b93829e..ce7838e55827 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3532,6 +3532,25 @@ bool igb_has_link(struct igb_adapter *adapter) return link_active; } +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 */ + if (hw->mac.type == e1000_i350) { + thstat = rd32(E1000_THSTAT); + ctrl_ext = rd32(E1000_CTRL_EXT); + + if ((hw->phy.media_type == e1000_media_type_copper) && + !(ctrl_ext & E1000_CTRL_EXT_LINK_MODE_SGMII)) { + ret = !!(thstat & event); + } + } + + return ret; +} + /** * igb_watchdog - Timer Call-back * @data: pointer to adapter cast into an unsigned long @@ -3550,7 +3569,7 @@ static void igb_watchdog_task(struct work_struct *work) watchdog_task); struct e1000_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; - u32 link, ctrl_ext, thstat; + u32 link; int i; link = igb_has_link(adapter); @@ -3574,25 +3593,14 @@ static void igb_watchdog_task(struct work_struct *work) ((ctrl & E1000_CTRL_RFCE) ? "RX" : ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None"))); - /* 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); - if ((hw->phy.media_type == - e1000_media_type_copper) && !(ctrl_ext & - E1000_CTRL_EXT_LINK_MODE_SGMII)) { - if (thstat & - E1000_THSTAT_LINK_THROTTLE) { - printk(KERN_INFO "igb: %s The " - "network adapter link " - "speed was downshifted " - "because it " - "overheated.\n", - netdev->name); - } - } + /* check for thermal sensor event */ + if (igb_thermal_sensor_event(hw, E1000_THSTAT_LINK_THROTTLE)) { + printk(KERN_INFO "igb: %s The network adapter " + "link speed was downshifted " + "because it overheated.\n", + netdev->name); } + /* adjust timeout factor according to speed/duplex */ adapter->tx_timeout_factor = 1; switch (adapter->link_speed) { @@ -3618,22 +3626,15 @@ static void igb_watchdog_task(struct work_struct *work) if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; - /* 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); - if ((hw->phy.media_type == - e1000_media_type_copper) && !(ctrl_ext & - E1000_CTRL_EXT_LINK_MODE_SGMII)) { - if (thstat & E1000_THSTAT_PWR_DOWN) { - printk(KERN_ERR "igb: %s The " - "network adapter was stopped " - "because it overheated.\n", + + /* check for thermal sensor event */ + if (igb_thermal_sensor_event(hw, E1000_THSTAT_PWR_DOWN)) { + printk(KERN_ERR "igb: %s The network adapter " + "was stopped because it " + "overheated.\n", netdev->name); - } - } } + /* Links status message must follow this format */ printk(KERN_INFO "igb: %s NIC Link is Down\n", netdev->name); @@ -6348,21 +6349,25 @@ static void igb_restore_vlan(struct igb_adapter *adapter) } } -int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx) +int igb_set_spd_dplx(struct igb_adapter *adapter, u32 spd, u8 dplx) { struct pci_dev *pdev = adapter->pdev; struct e1000_mac_info *mac = &adapter->hw.mac; mac->autoneg = 0; + /* Make sure dplx is at most 1 bit and lsb of speed is not set + * for the switch() below to work */ + if ((spd & 1) || (dplx & ~1)) + goto err_inval; + /* Fiber NIC's only allow 1000 Gbps Full duplex */ if ((adapter->hw.phy.media_type == e1000_media_type_internal_serdes) && - spddplx != (SPEED_1000 + DUPLEX_FULL)) { - dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n"); - return -EINVAL; - } + spd != SPEED_1000 && + dplx != DUPLEX_FULL) + goto err_inval; - switch (spddplx) { + switch (spd + dplx) { case SPEED_10 + DUPLEX_HALF: mac->forced_speed_duplex = ADVERTISE_10_HALF; break; @@ -6381,10 +6386,13 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx) break; case SPEED_1000 + DUPLEX_HALF: /* not supported */ default: - dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n"); - return -EINVAL; + goto err_inval; } return 0; + +err_inval: + dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n"); + return -EINVAL; } static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake) diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c index 1d943aa7c7a6..b0b14d63dfbf 100644 --- a/drivers/net/igbvf/ethtool.c +++ b/drivers/net/igbvf/ethtool.c @@ -90,18 +90,18 @@ static int igbvf_get_settings(struct net_device *netdev, status = er32(STATUS); if (status & E1000_STATUS_LU) { if (status & E1000_STATUS_SPEED_1000) - ecmd->speed = 1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); else if (status & E1000_STATUS_SPEED_100) - ecmd->speed = 100; + ethtool_cmd_speed_set(ecmd, SPEED_100); else - ecmd->speed = 10; + ethtool_cmd_speed_set(ecmd, SPEED_10); if (status & E1000_STATUS_FD) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } @@ -391,11 +391,6 @@ static int igbvf_set_wol(struct net_device *netdev, return -EOPNOTSUPP; } -static int igbvf_phys_id(struct net_device *netdev, u32 data) -{ - return 0; -} - static int igbvf_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) { @@ -527,7 +522,6 @@ static const struct ethtool_ops igbvf_ethtool_ops = { .self_test = igbvf_diag_test, .get_sset_count = igbvf_get_sset_count, .get_strings = igbvf_get_strings, - .phys_id = igbvf_phys_id, .get_ethtool_stats = igbvf_get_ethtool_stats, .get_coalesce = igbvf_get_coalesce, .set_coalesce = igbvf_set_coalesce, diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index c8ee8d28767b..96c95617195f 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -90,8 +90,6 @@ struct ioc3_private { u32 emcr, ehar_h, ehar_l; spinlock_t ioc3_lock; struct mii_if_info mii; - unsigned long flags; -#define IOC3_FLAG_RX_CHECKSUMS 1 struct pci_dev *pdev; @@ -609,7 +607,7 @@ static inline void ioc3_rx(struct net_device *dev) goto next; } - if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS)) + if (likely(dev->features & NETIF_F_RXCSUM)) ioc3_tcpudp_checksum(skb, w0 & ERXBUF_IPCKSUM_MASK, len); @@ -1328,6 +1326,7 @@ static int __devinit ioc3_probe(struct pci_dev *pdev, dev->watchdog_timeo = 5 * HZ; dev->netdev_ops = &ioc3_netdev_ops; dev->ethtool_ops = &ioc3_ethtool_ops; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM; dev->features = NETIF_F_IP_CSUM; sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1); @@ -1618,37 +1617,12 @@ static u32 ioc3_get_link(struct net_device *dev) return rc; } -static u32 ioc3_get_rx_csum(struct net_device *dev) -{ - struct ioc3_private *ip = netdev_priv(dev); - - return ip->flags & IOC3_FLAG_RX_CHECKSUMS; -} - -static int ioc3_set_rx_csum(struct net_device *dev, u32 data) -{ - struct ioc3_private *ip = netdev_priv(dev); - - spin_lock_bh(&ip->ioc3_lock); - if (data) - ip->flags |= IOC3_FLAG_RX_CHECKSUMS; - else - ip->flags &= ~IOC3_FLAG_RX_CHECKSUMS; - spin_unlock_bh(&ip->ioc3_lock); - - return 0; -} - static const struct ethtool_ops ioc3_ethtool_ops = { .get_drvinfo = ioc3_get_drvinfo, .get_settings = ioc3_get_settings, .set_settings = ioc3_set_settings, .nway_reset = ioc3_nway_reset, .get_link = ioc3_get_link, - .get_rx_csum = ioc3_get_rx_csum, - .set_rx_csum = ioc3_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum }; static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 8800e1fe4129..69b5707db369 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -222,19 +222,19 @@ static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 s static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self); /* Probing */ -static int __init smsc_ircc_look_for_chips(void); -static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type); -static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type); -static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); -static int __init smsc_superio_fdc(unsigned short cfg_base); -static int __init smsc_superio_lpc(unsigned short cfg_base); +static int smsc_ircc_look_for_chips(void); +static const struct smsc_chip * smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type); +static int smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type); +static int smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); +static int smsc_superio_fdc(unsigned short cfg_base); +static int smsc_superio_lpc(unsigned short cfg_base); #ifdef CONFIG_PCI -static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); -static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); -static void __init preconfigure_ali_port(struct pci_dev *dev, +static int preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); +static int preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static void preconfigure_ali_port(struct pci_dev *dev, unsigned short port); -static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); -static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, +static int preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static int smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, unsigned short ircc_fir, unsigned short ircc_sir, unsigned char ircc_dma, @@ -366,7 +366,7 @@ static inline void register_bank(int iobase, int bank) } /* PNP hotplug support */ -static const struct pnp_device_id smsc_ircc_pnp_table[] = { +static const struct pnp_device_id smsc_ircc_pnp_table[] __devinitconst = { { .id = "SMCf010", .driver_data = 0 }, /* and presumably others */ { } @@ -515,7 +515,7 @@ static const struct net_device_ops smsc_ircc_netdev_ops = { * Try to open driver instance * */ -static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq) +static int __devinit smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq) { struct smsc_ircc_cb *self; struct net_device *dev; @@ -2273,7 +2273,7 @@ static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned sho } -static int __init smsc_access(unsigned short cfg_base, unsigned char reg) +static int __devinit smsc_access(unsigned short cfg_base, unsigned char reg) { IRDA_DEBUG(1, "%s\n", __func__); @@ -2281,7 +2281,7 @@ static int __init smsc_access(unsigned short cfg_base, unsigned char reg) return inb(cfg_base) != reg ? -1 : 0; } -static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type) +static const struct smsc_chip * __devinit smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type) { u8 devid, xdevid, rev; @@ -2406,7 +2406,7 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) #ifdef CONFIG_PCI #define PCIID_VENDOR_INTEL 0x8086 #define PCIID_VENDOR_ALI 0x10b9 -static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = { +static const struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitconst = { /* * Subsystems needing entries: * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family @@ -2532,7 +2532,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini * (FIR port, SIR port, FIR DMA, FIR IRQ) * through the chip configuration port. */ -static int __init preconfigure_smsc_chip(struct +static int __devinit preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf) { @@ -2633,7 +2633,7 @@ static int __init preconfigure_smsc_chip(struct * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. * They all work the same way! */ -static int __init preconfigure_through_82801(struct pci_dev *dev, +static int __devinit preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf) @@ -2786,7 +2786,7 @@ static int __init preconfigure_through_82801(struct pci_dev *dev, * This is based on reverse-engineering since ALi does not * provide any data sheet for the 1533 chip. */ -static void __init preconfigure_ali_port(struct pci_dev *dev, +static void __devinit preconfigure_ali_port(struct pci_dev *dev, unsigned short port) { unsigned char reg; @@ -2824,7 +2824,7 @@ static void __init preconfigure_ali_port(struct pci_dev *dev, IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port); } -static int __init preconfigure_through_ali(struct pci_dev *dev, +static int __devinit preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf) @@ -2837,7 +2837,7 @@ static int __init preconfigure_through_ali(struct pci_dev *dev, return preconfigure_smsc_chip(conf); } -static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, +static int __devinit smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, unsigned short ircc_fir, unsigned short ircc_sir, unsigned char ircc_dma, @@ -2849,7 +2849,7 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, int ret = 0; for_each_pci_dev(dev) { - struct smsc_ircc_subsystem_configuration *conf; + const struct smsc_ircc_subsystem_configuration *conf; /* * Cache the subsystem vendor/device: diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index 8f3df044e81e..49e8408f05fc 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -157,9 +157,6 @@ struct ixgb_adapter { u16 link_duplex; struct work_struct tx_timeout_task; - struct timer_list blink_timer; - unsigned long led_status; - /* TX */ struct ixgb_desc_ring tx_ring ____cacheline_aligned_in_smp; unsigned int restart_queue; diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index cc53aa1541ba..6da890b9534c 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -104,10 +104,10 @@ ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->transceiver = XCVR_EXTERNAL; if (netif_carrier_ok(adapter->netdev)) { - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } @@ -129,9 +129,10 @@ static int ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct ixgb_adapter *adapter = netdev_priv(netdev); + u32 speed = ethtool_cmd_speed(ecmd); if (ecmd->autoneg == AUTONEG_ENABLE || - ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL) + (speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) return -EINVAL; if (netif_running(adapter->netdev)) { @@ -610,46 +611,24 @@ ixgb_set_ringparam(struct net_device *netdev, return err; } -/* toggle LED 4 times per second = 2 "blinks" per second */ -#define IXGB_ID_INTERVAL (HZ/4) - -/* bit defines for adapter->led_status */ -#define IXGB_LED_ON 0 - -static void -ixgb_led_blink_callback(unsigned long data) -{ - struct ixgb_adapter *adapter = (struct ixgb_adapter *)data; - - if (test_and_change_bit(IXGB_LED_ON, &adapter->led_status)) - ixgb_led_off(&adapter->hw); - else - ixgb_led_on(&adapter->hw); - - mod_timer(&adapter->blink_timer, jiffies + IXGB_ID_INTERVAL); -} - static int -ixgb_phys_id(struct net_device *netdev, u32 data) +ixgb_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) { struct ixgb_adapter *adapter = netdev_priv(netdev); - if (!data) - data = INT_MAX; + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 2; - if (!adapter->blink_timer.function) { - init_timer(&adapter->blink_timer); - adapter->blink_timer.function = ixgb_led_blink_callback; - adapter->blink_timer.data = (unsigned long)adapter; + case ETHTOOL_ID_ON: + ixgb_led_on(&adapter->hw); + break; + + case ETHTOOL_ID_OFF: + case ETHTOOL_ID_INACTIVE: + ixgb_led_off(&adapter->hw); } - mod_timer(&adapter->blink_timer, jiffies); - - msleep_interruptible(data * 1000); - del_timer_sync(&adapter->blink_timer); - ixgb_led_off(&adapter->hw); - clear_bit(IXGB_LED_ON, &adapter->led_status); - return 0; } @@ -766,7 +745,7 @@ static const struct ethtool_ops ixgb_ethtool_ops = { .set_msglevel = ixgb_set_msglevel, .set_tso = ixgb_set_tso, .get_strings = ixgb_get_strings, - .phys_id = ixgb_phys_id, + .set_phys_id = ixgb_set_phys_id, .get_sset_count = ixgb_get_sset_count, .get_ethtool_stats = ixgb_get_ethtool_stats, .get_flags = ethtool_op_get_flags, diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 8d468028bb55..e467b20ed1f0 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -106,6 +106,7 @@ #define IXGBE_MAX_VF_FUNCTIONS 64 #define IXGBE_MAX_VFTA_ENTRIES 128 #define MAX_EMULATION_MAC_ADDRS 16 +#define IXGBE_MAX_PF_MACVLANS 15 #define VMDQ_P(p) ((p) + adapter->num_vfs) struct vf_data_storage { @@ -121,6 +122,15 @@ struct vf_data_storage { u16 tx_rate; }; +struct vf_macvlans { + struct list_head l; + int vf; + int rar_entry; + bool free; + bool is_macvlan; + u8 vf_macvlan[ETH_ALEN]; +}; + /* wrapper around a pointer to a socket buffer, * so a DMA handle can be stored along with the buffer */ struct ixgbe_tx_buffer { @@ -331,10 +341,52 @@ struct ixgbe_q_vector { /* board specific private data structure */ struct ixgbe_adapter { - struct timer_list watchdog_timer; + unsigned long state; + + /* Some features need tri-state capability, + * thus the additional *_CAPABLE flags. + */ + u32 flags; +#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1) +#define IXGBE_FLAG_MSI_CAPABLE (u32)(1 << 1) +#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 2) +#define IXGBE_FLAG_MSIX_CAPABLE (u32)(1 << 3) +#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 4) +#define IXGBE_FLAG_RX_1BUF_CAPABLE (u32)(1 << 6) +#define IXGBE_FLAG_RX_PS_CAPABLE (u32)(1 << 7) +#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 8) +#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 9) +#define IXGBE_FLAG_DCA_ENABLED (u32)(1 << 10) +#define IXGBE_FLAG_DCA_CAPABLE (u32)(1 << 11) +#define IXGBE_FLAG_IMIR_ENABLED (u32)(1 << 12) +#define IXGBE_FLAG_MQ_CAPABLE (u32)(1 << 13) +#define IXGBE_FLAG_DCB_ENABLED (u32)(1 << 14) +#define IXGBE_FLAG_RSS_ENABLED (u32)(1 << 16) +#define IXGBE_FLAG_RSS_CAPABLE (u32)(1 << 17) +#define IXGBE_FLAG_VMDQ_CAPABLE (u32)(1 << 18) +#define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) +#define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20) +#define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) +#define IXGBE_FLAG_NEED_LINK_CONFIG (u32)(1 << 23) +#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 24) +#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 25) +#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 26) +#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 27) +#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 28) +#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 29) + + u32 flags2; +#define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) +#define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1) +#define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE (u32)(1 << 2) +#define IXGBE_FLAG2_TEMP_SENSOR_EVENT (u32)(1 << 3) +#define IXGBE_FLAG2_SEARCH_FOR_SFP (u32)(1 << 4) +#define IXGBE_FLAG2_SFP_NEEDS_RESET (u32)(1 << 5) +#define IXGBE_FLAG2_RESET_REQUESTED (u32)(1 << 6) +#define IXGBE_FLAG2_FDIR_REQUIRES_REINIT (u32)(1 << 7) + unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; u16 bd_number; - struct work_struct reset_task; struct ixgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; /* DCB parameters */ @@ -377,43 +429,6 @@ struct ixgbe_adapter { u32 alloc_rx_page_failed; u32 alloc_rx_buff_failed; - /* Some features need tri-state capability, - * thus the additional *_CAPABLE flags. - */ - u32 flags; -#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1) -#define IXGBE_FLAG_MSI_CAPABLE (u32)(1 << 1) -#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 2) -#define IXGBE_FLAG_MSIX_CAPABLE (u32)(1 << 3) -#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 4) -#define IXGBE_FLAG_RX_1BUF_CAPABLE (u32)(1 << 6) -#define IXGBE_FLAG_RX_PS_CAPABLE (u32)(1 << 7) -#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 8) -#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 9) -#define IXGBE_FLAG_DCA_ENABLED (u32)(1 << 10) -#define IXGBE_FLAG_DCA_CAPABLE (u32)(1 << 11) -#define IXGBE_FLAG_IMIR_ENABLED (u32)(1 << 12) -#define IXGBE_FLAG_MQ_CAPABLE (u32)(1 << 13) -#define IXGBE_FLAG_DCB_ENABLED (u32)(1 << 14) -#define IXGBE_FLAG_RSS_ENABLED (u32)(1 << 16) -#define IXGBE_FLAG_RSS_CAPABLE (u32)(1 << 17) -#define IXGBE_FLAG_VMDQ_CAPABLE (u32)(1 << 18) -#define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) -#define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20) -#define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) -#define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 23) -#define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 24) -#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 25) -#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 26) -#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 27) -#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 28) -#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 29) -#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 30) - - u32 flags2; -#define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) -#define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1) -#define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE (u32)(1 << 2) /* default to trying for four seconds */ #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) @@ -434,7 +449,6 @@ struct ixgbe_adapter { u32 rx_eitr_param; u32 tx_eitr_param; - unsigned long state; u64 tx_busy; unsigned int tx_ring_count; unsigned int rx_ring_count; @@ -443,15 +457,12 @@ struct ixgbe_adapter { bool link_up; unsigned long link_check_timeout; - struct work_struct watchdog_task; - struct work_struct sfp_task; - struct timer_list sfp_timer; - struct work_struct multispeed_fiber_task; - struct work_struct sfp_config_module_task; + struct work_struct service_task; + struct timer_list service_timer; u32 fdir_pballoc; u32 atr_sample_rate; + unsigned long fdir_overflow; /* number of times ATR was backed off */ spinlock_t fdir_perfect_lock; - struct work_struct fdir_reinit_task; #ifdef IXGBE_FCOE struct ixgbe_fcoe fcoe; #endif /* IXGBE_FCOE */ @@ -461,7 +472,7 @@ struct ixgbe_adapter { u16 eeprom_version; int node; - struct work_struct check_overtemp_task; + u32 led_reg; u32 interrupt_event; char lsc_int_name[IFNAMSIZ + 9]; @@ -470,13 +481,17 @@ struct ixgbe_adapter { unsigned int num_vfs; struct vf_data_storage *vfinfo; int vf_rate_link_speed; + struct vf_macvlans vf_mvs; + struct vf_macvlans *mv_list; + bool antispoofing_enabled; }; enum ixbge_state_t { __IXGBE_TESTING, __IXGBE_RESETTING, __IXGBE_DOWN, - __IXGBE_SFP_MODULE_NOT_FOUND + __IXGBE_SERVICE_SCHED, + __IXGBE_IN_SFP_INIT, }; struct ixgbe_rsc_cb { diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 845c679c8b87..8179e5060a18 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -37,6 +37,7 @@ #define IXGBE_82598_RAR_ENTRIES 16 #define IXGBE_82598_MC_TBL_SIZE 128 #define IXGBE_82598_VFT_TBL_SIZE 128 +#define IXGBE_82598_RX_PB_SIZE 512 static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, @@ -197,14 +198,35 @@ static s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) * @hw: pointer to hardware structure * * Starts the hardware using the generic start_hw function. - * Then set pcie completion timeout + * Disables relaxed ordering Then set pcie completion timeout + * **/ static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) { + u32 regval; + u32 i; s32 ret_val = 0; ret_val = ixgbe_start_hw_generic(hw); + /* Disable relaxed ordering */ + for (i = 0; ((i < hw->mac.max_tx_queues) && + (i < IXGBE_DCA_MAX_QUEUES_82598)); i++) { + regval = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); + regval &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), regval); + } + + for (i = 0; ((i < hw->mac.max_rx_queues) && + (i < IXGBE_DCA_MAX_QUEUES_82598)); i++) { + regval = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i)); + regval &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN | + IXGBE_DCA_RXCTRL_DESC_HSRO_EN); + IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval); + } + + hw->mac.rx_pb_size = IXGBE_82598_RX_PB_SIZE; + /* set the completion timeout for interface */ if (ret_val == 0) ixgbe_set_pcie_completion_timeout(hw); @@ -1064,7 +1086,7 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK; if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS) break; - msleep(10); + usleep_range(10000, 20000); } if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_PASS) { @@ -1188,6 +1210,38 @@ static u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) return physical_layer; } +/** + * ixgbe_set_lan_id_multi_port_pcie_82598 - Set LAN id for PCIe multiple + * port devices. + * @hw: pointer to the HW structure + * + * Calls common function and corrects issue with some single port devices + * that enable LAN1 but not LAN0. + **/ +static void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw) +{ + struct ixgbe_bus_info *bus = &hw->bus; + u16 pci_gen = 0; + u16 pci_ctrl2 = 0; + + ixgbe_set_lan_id_multi_port_pcie(hw); + + /* check if LAN0 is disabled */ + hw->eeprom.ops.read(hw, IXGBE_PCIE_GENERAL_PTR, &pci_gen); + if ((pci_gen != 0) && (pci_gen != 0xFFFF)) { + + hw->eeprom.ops.read(hw, pci_gen + IXGBE_PCIE_CTRL2, &pci_ctrl2); + + /* if LAN0 is completely disabled force function to 0 */ + if ((pci_ctrl2 & IXGBE_PCIE_CTRL2_LAN_DISABLE) && + !(pci_ctrl2 & IXGBE_PCIE_CTRL2_DISABLE_SELECT) && + !(pci_ctrl2 & IXGBE_PCIE_CTRL2_DUMMY_ENABLE)) { + + bus->func = 0; + } + } +} + static struct ixgbe_mac_operations mac_ops_82598 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82598, @@ -1199,7 +1253,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = { .get_mac_addr = &ixgbe_get_mac_addr_generic, .stop_adapter = &ixgbe_stop_adapter_generic, .get_bus_info = &ixgbe_get_bus_info_generic, - .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie, + .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie_82598, .read_analog_reg8 = &ixgbe_read_analog_reg8_82598, .write_analog_reg8 = &ixgbe_write_analog_reg8_82598, .setup_link = &ixgbe_setup_mac_link_82598, @@ -1227,6 +1281,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = { static struct ixgbe_eeprom_operations eeprom_ops_82598 = { .init_params = &ixgbe_init_eeprom_params_generic, .read = &ixgbe_read_eerd_generic, + .read_buffer = &ixgbe_read_eerd_buffer_generic, .calc_checksum = &ixgbe_calc_eeprom_checksum_generic, .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, .update_checksum = &ixgbe_update_eeprom_checksum_generic, diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 00aeba385a2f..8ee661245af3 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -38,6 +38,7 @@ #define IXGBE_82599_RAR_ENTRIES 128 #define IXGBE_82599_MC_TBL_SIZE 128 #define IXGBE_82599_VFT_TBL_SIZE 128 +#define IXGBE_82599_RX_PB_SIZE 512 static void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); static void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); @@ -61,6 +62,7 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, bool autoneg, bool autoneg_wait_to_complete); static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); +static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw); static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) { @@ -86,7 +88,8 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) if ((mac->ops.get_media_type(hw) == ixgbe_media_type_backplane) && (hw->phy.smart_speed == ixgbe_smart_speed_auto || - hw->phy.smart_speed == ixgbe_smart_speed_on)) + hw->phy.smart_speed == ixgbe_smart_speed_on) && + !ixgbe_verify_lesm_fw_enabled_82599(hw)) mac->ops.setup_link = &ixgbe_setup_mac_link_smartspeed; else mac->ops.setup_link = &ixgbe_setup_mac_link_82599; @@ -107,7 +110,6 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, &data_offset); - if (ret_val != 0) goto setup_sfp_out; @@ -127,9 +129,13 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) } /* Release the semaphore */ - ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); - /* Delay obtaining semaphore again to allow FW access */ - msleep(hw->eeprom.semaphore_delay); + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); + /* + * Delay obtaining semaphore again to allow FW access, + * semaphore_delay is in ms usleep_range needs us. + */ + usleep_range(hw->eeprom.semaphore_delay * 1000, + hw->eeprom.semaphore_delay * 2000); /* Now restart DSP by setting Restart_AN and clearing LMS */ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((IXGBE_READ_REG(hw, @@ -138,7 +144,7 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) /* Wait for AN to leave state 0 */ for (i = 0; i < 10; i++) { - msleep(4); + usleep_range(4000, 8000); reg_anlp1 = IXGBE_READ_REG(hw, IXGBE_ANLP1); if (reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK) break; @@ -353,6 +359,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82599_SFP: case IXGBE_DEV_ID_82599_SFP_FCOE: case IXGBE_DEV_ID_82599_SFP_EM: + case IXGBE_DEV_ID_82599_SFP_SF2: media_type = ixgbe_media_type_fiber; break; case IXGBE_DEV_ID_82599_CX4: @@ -361,6 +368,9 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82599_T3_LOM: media_type = ixgbe_media_type_copper; break; + case IXGBE_DEV_ID_82599_LS: + media_type = ixgbe_media_type_fiber_lco; + break; default: media_type = ixgbe_media_type_unknown; break; @@ -486,7 +496,7 @@ static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) * * Set the link speed in the AUTOC register and restarts link. **/ -s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, +static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete) @@ -1176,7 +1186,7 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc) if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & IXGBE_FDIRCTRL_INIT_DONE) break; - msleep(1); + usleep_range(1000, 2000); } if (i >= IXGBE_FDIR_INIT_DONE_POLL) hw_dbg(hw, "Flow Director Signature poll time exceeded!\n"); @@ -1271,7 +1281,7 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc) if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & IXGBE_FDIRCTRL_INIT_DONE) break; - msleep(1); + usleep_range(1000, 2000); } if (i >= IXGBE_FDIR_INIT_DONE_POLL) hw_dbg(hw, "Flow Director Perfect poll time exceeded!\n"); @@ -1740,30 +1750,29 @@ static s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) * ixgbe_start_hw_82599 - Prepare hardware for Tx/Rx * @hw: pointer to hardware structure * - * Starts the hardware using the generic start_hw function. - * Then performs device-specific: - * Clears the rate limiter registers. + * Starts the hardware using the generic start_hw function + * and the generation start_hw function. + * Then performs revision-specific operations, if any. **/ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) { - u32 q_num; - s32 ret_val; + s32 ret_val = 0; ret_val = ixgbe_start_hw_generic(hw); + if (ret_val != 0) + goto out; - /* Clear the rate limiters */ - for (q_num = 0; q_num < hw->mac.max_tx_queues; q_num++) { - IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, q_num); - IXGBE_WRITE_REG(hw, IXGBE_RTTBCNRC, 0); - } - IXGBE_WRITE_FLUSH(hw); + ret_val = ixgbe_start_hw_gen2(hw); + if (ret_val != 0) + goto out; /* We need to run link autotry after the driver loads */ hw->mac.autotry_restart = true; + hw->mac.rx_pb_size = IXGBE_82599_RX_PB_SIZE; if (ret_val == 0) ret_val = ixgbe_verify_fw_version_82599(hw); - +out: return ret_val; } @@ -1775,7 +1784,7 @@ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) * If PHY already detected, maintains current PHY type in hw struct, * otherwise executes the PHY detection routine. **/ -s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) +static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) { s32 status = IXGBE_ERR_PHY_ADDR_INVALID; @@ -1967,21 +1976,6 @@ static s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) return 0; } -/** - * ixgbe_get_device_caps_82599 - Get additional device capabilities - * @hw: pointer to hardware structure - * @device_caps: the EEPROM word with the extra device capabilities - * - * This function will read the EEPROM location for the device capabilities, - * and return the word through device_caps. - **/ -static s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) -{ - hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps); - - return 0; -} - /** * ixgbe_verify_fw_version_82599 - verify fw version for 82599 * @hw: pointer to hardware structure @@ -2030,6 +2024,110 @@ static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw) return status; } +/** + * ixgbe_verify_lesm_fw_enabled_82599 - Checks LESM FW module state. + * @hw: pointer to hardware structure + * + * Returns true if the LESM FW module is present and enabled. Otherwise + * returns false. Smart Speed must be disabled if LESM FW module is enabled. + **/ +static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw) +{ + bool lesm_enabled = false; + u16 fw_offset, fw_lesm_param_offset, fw_lesm_state; + s32 status; + + /* get the offset to the Firmware Module block */ + status = hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset); + + if ((status != 0) || + (fw_offset == 0) || (fw_offset == 0xFFFF)) + goto out; + + /* get the offset to the LESM Parameters block */ + status = hw->eeprom.ops.read(hw, (fw_offset + + IXGBE_FW_LESM_PARAMETERS_PTR), + &fw_lesm_param_offset); + + if ((status != 0) || + (fw_lesm_param_offset == 0) || (fw_lesm_param_offset == 0xFFFF)) + goto out; + + /* get the lesm state word */ + status = hw->eeprom.ops.read(hw, (fw_lesm_param_offset + + IXGBE_FW_LESM_STATE_1), + &fw_lesm_state); + + if ((status == 0) && + (fw_lesm_state & IXGBE_FW_LESM_STATE_ENABLED)) + lesm_enabled = true; + +out: + return lesm_enabled; +} + +/** + * ixgbe_read_eeprom_buffer_82599 - Read EEPROM word(s) using + * fastest available method + * + * @hw: pointer to hardware structure + * @offset: offset of word in EEPROM to read + * @words: number of words + * @data: word(s) read from the EEPROM + * + * Retrieves 16 bit word(s) read from EEPROM + **/ +static s32 ixgbe_read_eeprom_buffer_82599(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) +{ + struct ixgbe_eeprom_info *eeprom = &hw->eeprom; + s32 ret_val = IXGBE_ERR_CONFIG; + + /* + * If EEPROM is detected and can be addressed using 14 bits, + * use EERD otherwise use bit bang + */ + if ((eeprom->type == ixgbe_eeprom_spi) && + (offset + (words - 1) <= IXGBE_EERD_MAX_ADDR)) + ret_val = ixgbe_read_eerd_buffer_generic(hw, offset, words, + data); + else + ret_val = ixgbe_read_eeprom_buffer_bit_bang_generic(hw, offset, + words, + data); + + return ret_val; +} + +/** + * ixgbe_read_eeprom_82599 - Read EEPROM word using + * fastest available method + * + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM + **/ +static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw, + u16 offset, u16 *data) +{ + struct ixgbe_eeprom_info *eeprom = &hw->eeprom; + s32 ret_val = IXGBE_ERR_CONFIG; + + /* + * If EEPROM is detected and can be addressed using 14 bits, + * use EERD otherwise use bit bang + */ + if ((eeprom->type == ixgbe_eeprom_spi) && + (offset <= IXGBE_EERD_MAX_ADDR)) + ret_val = ixgbe_read_eerd_generic(hw, offset, data); + else + ret_val = ixgbe_read_eeprom_bit_bang_generic(hw, offset, data); + + return ret_val; +} + static struct ixgbe_mac_operations mac_ops_82599 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82599, @@ -2040,7 +2138,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .enable_rx_dma = &ixgbe_enable_rx_dma_82599, .get_mac_addr = &ixgbe_get_mac_addr_generic, .get_san_mac_addr = &ixgbe_get_san_mac_addr_generic, - .get_device_caps = &ixgbe_get_device_caps_82599, + .get_device_caps = &ixgbe_get_device_caps_generic, .get_wwn_prefix = &ixgbe_get_wwn_prefix_generic, .stop_adapter = &ixgbe_stop_adapter_generic, .get_bus_info = &ixgbe_get_bus_info_generic, @@ -2076,8 +2174,10 @@ static struct ixgbe_mac_operations mac_ops_82599 = { static struct ixgbe_eeprom_operations eeprom_ops_82599 = { .init_params = &ixgbe_init_eeprom_params_generic, - .read = &ixgbe_read_eerd_generic, + .read = &ixgbe_read_eeprom_82599, + .read_buffer = &ixgbe_read_eeprom_buffer_82599, .write = &ixgbe_write_eeprom_generic, + .write_buffer = &ixgbe_write_eeprom_buffer_bit_bang_generic, .calc_checksum = &ixgbe_calc_eeprom_checksum_generic, .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, .update_checksum = &ixgbe_update_eeprom_checksum_generic, diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index bcd952916eb2..b894b42a741c 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -54,6 +54,13 @@ 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); +static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data); +static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, + u16 offset); /** * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx @@ -95,6 +102,45 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) return 0; } +/** + * ixgbe_start_hw_gen2 - Init sequence for common device family + * @hw: pointer to hw structure + * + * Performs the init sequence common to the second generation + * of 10 GbE devices. + * Devices in the second generation: + * 82599 + * X540 + **/ +s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw) +{ + u32 i; + u32 regval; + + /* Clear the rate limiters */ + for (i = 0; i < hw->mac.max_tx_queues; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, i); + IXGBE_WRITE_REG(hw, IXGBE_RTTBCNRC, 0); + } + IXGBE_WRITE_FLUSH(hw); + + /* Disable relaxed ordering */ + for (i = 0; i < hw->mac.max_tx_queues; i++) { + regval = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(i)); + regval &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(i), regval); + } + + for (i = 0; i < hw->mac.max_rx_queues; i++) { + regval = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i)); + regval &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN | + IXGBE_DCA_RXCTRL_DESC_HSRO_EN); + IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval); + } + + return 0; +} + /** * ixgbe_init_hw_generic - Generic hardware initialization * @hw: pointer to hardware structure @@ -464,7 +510,7 @@ s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw) reg_val &= ~(IXGBE_RXCTRL_RXEN); IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val); IXGBE_WRITE_FLUSH(hw); - msleep(2); + usleep_range(2000, 4000); /* Clear interrupt mask to stop from interrupts being generated */ IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK); @@ -545,6 +591,8 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) /* Set default semaphore delay to 10ms which is a well * tested value */ eeprom->semaphore_delay = 10; + /* Clear EEPROM page size, it will be initialized as needed */ + eeprom->word_page_size = 0; /* * Check for EEPROM present first. @@ -577,26 +625,78 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) } /** - * ixgbe_write_eeprom_generic - Writes 16 bit value to EEPROM + * ixgbe_write_eeprom_buffer_bit_bang_generic - Write EEPROM using bit-bang + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to write + * @words: number of words + * @data: 16 bit word(s) to write to EEPROM + * + * Reads 16 bit word(s) from EEPROM through bit-bang method + **/ +s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) +{ + s32 status = 0; + u16 i, count; + + hw->eeprom.ops.init_params(hw); + + if (words == 0) { + status = IXGBE_ERR_INVALID_ARGUMENT; + goto out; + } + + if (offset + words > hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; + } + + /* + * The EEPROM page size cannot be queried from the chip. We do lazy + * initialization. It is worth to do that when we write large buffer. + */ + if ((hw->eeprom.word_page_size == 0) && + (words > IXGBE_EEPROM_PAGE_SIZE_MAX)) + ixgbe_detect_eeprom_page_size_generic(hw, offset); + + /* + * We cannot hold synchronization semaphores for too long + * to avoid other entity starvation. However it is more efficient + * to read in bursts than synchronizing access for each word. + */ + for (i = 0; i < words; i += IXGBE_EEPROM_RD_BUFFER_MAX_COUNT) { + count = (words - i) / IXGBE_EEPROM_RD_BUFFER_MAX_COUNT > 0 ? + IXGBE_EEPROM_RD_BUFFER_MAX_COUNT : (words - i); + status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset + i, + count, &data[i]); + + if (status != 0) + break; + } + +out: + return status; +} + +/** + * ixgbe_write_eeprom_buffer_bit_bang - Writes 16 bit word(s) to EEPROM * @hw: pointer to hardware structure * @offset: offset within the EEPROM to be written to - * @data: 16 bit word to be written to the EEPROM + * @words: number of word(s) + * @data: 16 bit word(s) to be written to the EEPROM * * If ixgbe_eeprom_update_checksum is not called after this function, the * EEPROM will most likely contain an invalid checksum. **/ -s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) +static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) { s32 status; + u16 word; + u16 page_size; + u16 i; u8 write_opcode = IXGBE_EEPROM_WRITE_OPCODE_SPI; - hw->eeprom.ops.init_params(hw); - - if (offset >= hw->eeprom.word_size) { - status = IXGBE_ERR_EEPROM; - goto out; - } - /* Prepare the EEPROM for writing */ status = ixgbe_acquire_eeprom(hw); @@ -608,54 +708,69 @@ s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) } if (status == 0) { - ixgbe_standby_eeprom(hw); + for (i = 0; i < words; i++) { + ixgbe_standby_eeprom(hw); - /* Send the WRITE ENABLE command (8 bit opcode ) */ - ixgbe_shift_out_eeprom_bits(hw, IXGBE_EEPROM_WREN_OPCODE_SPI, - IXGBE_EEPROM_OPCODE_BITS); + /* Send the WRITE ENABLE command (8 bit opcode ) */ + ixgbe_shift_out_eeprom_bits(hw, + IXGBE_EEPROM_WREN_OPCODE_SPI, + IXGBE_EEPROM_OPCODE_BITS); - ixgbe_standby_eeprom(hw); + ixgbe_standby_eeprom(hw); - /* - * Some SPI eeproms use the 8th address bit embedded in the - * opcode - */ - if ((hw->eeprom.address_bits == 8) && (offset >= 128)) - write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; + /* + * Some SPI eeproms use the 8th address bit embedded + * in the opcode + */ + if ((hw->eeprom.address_bits == 8) && + ((offset + i) >= 128)) + write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; - /* Send the Write command (8-bit opcode + addr) */ - ixgbe_shift_out_eeprom_bits(hw, write_opcode, - IXGBE_EEPROM_OPCODE_BITS); - ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2), - hw->eeprom.address_bits); + /* Send the Write command (8-bit opcode + addr) */ + ixgbe_shift_out_eeprom_bits(hw, write_opcode, + IXGBE_EEPROM_OPCODE_BITS); + ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2), + hw->eeprom.address_bits); - /* Send the data */ - data = (data >> 8) | (data << 8); - ixgbe_shift_out_eeprom_bits(hw, data, 16); - ixgbe_standby_eeprom(hw); + page_size = hw->eeprom.word_page_size; + /* Send the data in burst via SPI*/ + do { + word = data[i]; + word = (word >> 8) | (word << 8); + ixgbe_shift_out_eeprom_bits(hw, word, 16); + + if (page_size == 0) + break; + + /* do not wrap around page */ + if (((offset + i) & (page_size - 1)) == + (page_size - 1)) + break; + } while (++i < words); + + ixgbe_standby_eeprom(hw); + usleep_range(10000, 20000); + } /* Done with writing - release the EEPROM */ ixgbe_release_eeprom(hw); } -out: return status; } /** - * ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang + * ixgbe_write_eeprom_generic - Writes 16 bit value to EEPROM * @hw: pointer to hardware structure - * @offset: offset within the EEPROM to be read - * @data: read 16 bit value from EEPROM + * @offset: offset within the EEPROM to be written to + * @data: 16 bit word to be written to the EEPROM * - * Reads 16 bit value from EEPROM through bit-bang method + * If ixgbe_eeprom_update_checksum is not called after this function, the + * EEPROM will most likely contain an invalid checksum. **/ -s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, - u16 *data) +s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) { s32 status; - u16 word_in; - u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI; hw->eeprom.ops.init_params(hw); @@ -664,6 +779,76 @@ s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, goto out; } + status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset, 1, &data); + +out: + return status; +} + +/** + * ixgbe_read_eeprom_buffer_bit_bang_generic - Read EEPROM using bit-bang + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to be read + * @words: number of word(s) + * @data: read 16 bit words(s) from EEPROM + * + * Reads 16 bit word(s) from EEPROM through bit-bang method + **/ +s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) +{ + s32 status = 0; + u16 i, count; + + hw->eeprom.ops.init_params(hw); + + if (words == 0) { + status = IXGBE_ERR_INVALID_ARGUMENT; + goto out; + } + + if (offset + words > hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; + } + + /* + * We cannot hold synchronization semaphores for too long + * to avoid other entity starvation. However it is more efficient + * to read in bursts than synchronizing access for each word. + */ + for (i = 0; i < words; i += IXGBE_EEPROM_RD_BUFFER_MAX_COUNT) { + count = (words - i) / IXGBE_EEPROM_RD_BUFFER_MAX_COUNT > 0 ? + IXGBE_EEPROM_RD_BUFFER_MAX_COUNT : (words - i); + + status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset + i, + count, &data[i]); + + if (status != 0) + break; + } + +out: + return status; +} + +/** + * ixgbe_read_eeprom_buffer_bit_bang - Read EEPROM using bit-bang + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to be read + * @words: number of word(s) + * @data: read 16 bit word(s) from EEPROM + * + * Reads 16 bit word(s) from EEPROM through bit-bang method + **/ +static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) +{ + s32 status; + u16 word_in; + u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI; + u16 i; + /* Prepare the EEPROM for reading */ status = ixgbe_acquire_eeprom(hw); @@ -675,29 +860,145 @@ s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, } if (status == 0) { - ixgbe_standby_eeprom(hw); + for (i = 0; i < words; i++) { + ixgbe_standby_eeprom(hw); + /* + * Some SPI eeproms use the 8th address bit embedded + * in the opcode + */ + if ((hw->eeprom.address_bits == 8) && + ((offset + i) >= 128)) + read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; - /* - * Some SPI eeproms use the 8th address bit embedded in the - * opcode - */ - if ((hw->eeprom.address_bits == 8) && (offset >= 128)) - read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; + /* Send the READ command (opcode + addr) */ + ixgbe_shift_out_eeprom_bits(hw, read_opcode, + IXGBE_EEPROM_OPCODE_BITS); + ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2), + hw->eeprom.address_bits); - /* Send the READ command (opcode + addr) */ - ixgbe_shift_out_eeprom_bits(hw, read_opcode, - IXGBE_EEPROM_OPCODE_BITS); - ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2), - hw->eeprom.address_bits); - - /* Read the data. */ - word_in = ixgbe_shift_in_eeprom_bits(hw, 16); - *data = (word_in >> 8) | (word_in << 8); + /* Read the data. */ + word_in = ixgbe_shift_in_eeprom_bits(hw, 16); + data[i] = (word_in >> 8) | (word_in << 8); + } /* End this read operation */ ixgbe_release_eeprom(hw); } + return status; +} + +/** + * ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to be read + * @data: read 16 bit value from EEPROM + * + * Reads 16 bit value from EEPROM through bit-bang method + **/ +s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 *data) +{ + s32 status; + + hw->eeprom.ops.init_params(hw); + + if (offset >= hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; + } + + status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data); + +out: + return status; +} + +/** + * ixgbe_read_eerd_buffer_generic - Read EEPROM word(s) using EERD + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to read + * @words: number of word(s) + * @data: 16 bit word(s) from the EEPROM + * + * Reads a 16 bit word(s) from the EEPROM using the EERD register. + **/ +s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) +{ + u32 eerd; + s32 status = 0; + u32 i; + + hw->eeprom.ops.init_params(hw); + + if (words == 0) { + status = IXGBE_ERR_INVALID_ARGUMENT; + goto out; + } + + if (offset >= hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; + } + + for (i = 0; i < words; i++) { + eerd = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) + + IXGBE_EEPROM_RW_REG_START; + + IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd); + status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_READ); + + if (status == 0) { + data[i] = (IXGBE_READ_REG(hw, IXGBE_EERD) >> + IXGBE_EEPROM_RW_REG_DATA); + } else { + hw_dbg(hw, "Eeprom read timed out\n"); + goto out; + } + } +out: + return status; +} + +/** + * ixgbe_detect_eeprom_page_size_generic - Detect EEPROM page size + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to be used as a scratch pad + * + * Discover EEPROM page size by writing marching data at given offset. + * This function is called only when we are writing a new large buffer + * at given offset so the data would be overwritten anyway. + **/ +static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, + u16 offset) +{ + u16 data[IXGBE_EEPROM_PAGE_SIZE_MAX]; + s32 status = 0; + u16 i; + + for (i = 0; i < IXGBE_EEPROM_PAGE_SIZE_MAX; i++) + data[i] = i; + + hw->eeprom.word_page_size = IXGBE_EEPROM_PAGE_SIZE_MAX; + status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset, + IXGBE_EEPROM_PAGE_SIZE_MAX, data); + hw->eeprom.word_page_size = 0; + if (status != 0) + goto out; + + status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data); + if (status != 0) + goto out; + + /* + * When writing in burst more than the actual page size + * EEPROM address wraps around current page. + */ + hw->eeprom.word_page_size = IXGBE_EEPROM_PAGE_SIZE_MAX - data[0]; + + hw_dbg(hw, "Detected EEPROM page size = %d words.", + hw->eeprom.word_page_size); out: return status; } @@ -712,32 +1013,74 @@ s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, **/ s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) { - u32 eerd; - s32 status; + return ixgbe_read_eerd_buffer_generic(hw, offset, 1, data); +} + +/** + * ixgbe_write_eewr_buffer_generic - Write EEPROM word(s) using EEWR + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to write + * @words: number of words + * @data: word(s) write to the EEPROM + * + * Write a 16 bit word(s) to the EEPROM using the EEWR register. + **/ +s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) +{ + u32 eewr; + s32 status = 0; + u16 i; hw->eeprom.ops.init_params(hw); + if (words == 0) { + status = IXGBE_ERR_INVALID_ARGUMENT; + goto out; + } + if (offset >= hw->eeprom.word_size) { status = IXGBE_ERR_EEPROM; goto out; } - eerd = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) + - IXGBE_EEPROM_RW_REG_START; + for (i = 0; i < words; i++) { + eewr = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) | + (data[i] << IXGBE_EEPROM_RW_REG_DATA) | + IXGBE_EEPROM_RW_REG_START; - IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd); - status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_READ); + status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); + if (status != 0) { + hw_dbg(hw, "Eeprom write EEWR timed out\n"); + goto out; + } - if (status == 0) - *data = (IXGBE_READ_REG(hw, IXGBE_EERD) >> - IXGBE_EEPROM_RW_REG_DATA); - else - hw_dbg(hw, "Eeprom read timed out\n"); + IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr); + + status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); + if (status != 0) { + hw_dbg(hw, "Eeprom write EEWR timed out\n"); + goto out; + } + } out: return status; } +/** + * ixgbe_write_eewr_generic - Write EEPROM word using EEWR + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to write + * @data: word write to the EEPROM + * + * Write a 16 bit word to the EEPROM using the EEWR register. + **/ +s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data) +{ + return ixgbe_write_eewr_buffer_generic(hw, offset, 1, &data); +} + /** * ixgbe_poll_eerd_eewr_done - Poll EERD read or EEWR write status * @hw: pointer to hardware structure @@ -746,7 +1089,7 @@ s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) * Polls the status bit (bit 1) of the EERD or EEWR to determine when the * read or write is done respectively. **/ -s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) +static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) { u32 i; u32 reg; @@ -846,6 +1189,28 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) udelay(50); } + if (i == timeout) { + hw_dbg(hw, "Driver can't access the Eeprom - SMBI Semaphore " + "not granted.\n"); + /* + * this release is particularly important because our attempts + * above to get the semaphore may have succeeded, and if there + * was a timeout, we should unconditionally clear the semaphore + * bits to free the driver to make progress + */ + ixgbe_release_eeprom_semaphore(hw); + + udelay(50); + /* + * one last try + * If the SMBI bit is 0 when we read it, then the bit will be + * set and we have the semaphore + */ + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + if (!(swsm & IXGBE_SWSM_SMBI)) + status = 0; + } + /* Now get the semaphore between SW/FW through the SWESMBI bit */ if (status == 0) { for (i = 0; i < timeout; i++) { @@ -1112,8 +1477,12 @@ static void ixgbe_release_eeprom(struct ixgbe_hw *hw) hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); - /* Delay before attempt to obtain semaphore again to allow FW access */ - msleep(hw->eeprom.semaphore_delay); + /* + * Delay before attempt to obtain semaphore again to allow FW + * access. semaphore_delay is in ms we need us for usleep_range + */ + usleep_range(hw->eeprom.semaphore_delay * 1000, + hw->eeprom.semaphore_delay * 2000); } /** @@ -2189,7 +2558,7 @@ s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask) * thread currently using resource (swmask) */ ixgbe_release_eeprom_semaphore(hw); - msleep(5); + usleep_range(5000, 10000); timeout--; } @@ -2263,7 +2632,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) autoc_reg |= IXGBE_AUTOC_AN_RESTART; autoc_reg |= IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); - msleep(10); + usleep_range(10000, 20000); } led_reg &= ~IXGBE_LED_MODE_MASK(index); @@ -2883,3 +3252,18 @@ void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf) pfvfspoof &= ~(1 << vf_target_shift); IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof); } + +/** + * ixgbe_get_device_caps_generic - Get additional device capabilities + * @hw: pointer to hardware structure + * @device_caps: the EEPROM word with the extra device capabilities + * + * This function will read the EEPROM location for the device capabilities, + * and return the word through device_caps. + **/ +s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps) +{ + hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps); + + return 0; +} diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index 508f635fc2ca..46be83cfb500 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -35,6 +35,7 @@ u32 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); +s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw); s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw); s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num, u32 pba_num_size); @@ -48,14 +49,22 @@ s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index); s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw); s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data); +s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data); s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); +s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data); +s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data); +s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data); s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); +s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data); u16 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw); s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, u16 *checksum_val); s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw); -s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg); s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, u32 enable_addr); @@ -89,6 +98,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index); s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index); void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int pf); void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf); +s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps); #define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg))) diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c index 1bc57e52cee3..771d01a60d06 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82598.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c @@ -289,7 +289,7 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en) * Configure queue statistics registers, all queues belonging to same traffic * class uses a single set of queue statistics counters. */ -s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) +static s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) { u32 reg = 0; u8 i = 0; diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c index 025af8c53ddb..d50cf78c234d 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c @@ -39,36 +39,52 @@ */ static s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw, u8 rx_pba) { - s32 ret_val = 0; - u32 value = IXGBE_RXPBSIZE_64KB; + int num_tcs = IXGBE_MAX_PACKET_BUFFERS; + u32 rx_pb_size = hw->mac.rx_pb_size << IXGBE_RXPBSIZE_SHIFT; + u32 rxpktsize; + u32 txpktsize; + u32 txpbthresh; u8 i = 0; - /* Setup Rx packet buffer sizes */ - switch (rx_pba) { - case pba_80_48: - /* Setup the first four at 80KB */ - value = IXGBE_RXPBSIZE_80KB; - for (; i < 4; i++) - IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value); - /* Setup the last four at 48KB...don't re-init i */ - value = IXGBE_RXPBSIZE_48KB; - /* Fall Through */ - case pba_equal: - default: - for (; i < IXGBE_MAX_PACKET_BUFFERS; i++) - IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value); - - /* Setup Tx packet buffer sizes */ - for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) { - IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), - IXGBE_TXPBSIZE_20KB); - IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), - IXGBE_TXPBTHRESH_DCB); - } - break; + /* + * This really means configure the first half of the TCs + * (Traffic Classes) to use 5/8 of the Rx packet buffer + * space. To determine the size of the buffer for each TC, + * we are multiplying the average size by 5/4 and applying + * it to half of the traffic classes. + */ + if (rx_pba == pba_80_48) { + rxpktsize = (rx_pb_size * 5) / (num_tcs * 4); + rx_pb_size -= rxpktsize * (num_tcs / 2); + for (; i < (num_tcs / 2); i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); } - return ret_val; + /* Divide the remaining Rx packet buffer evenly among the TCs */ + rxpktsize = rx_pb_size / (num_tcs - i); + for (; i < num_tcs; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); + + /* + * Setup Tx packet buffer and threshold equally for all TCs + * TXPBTHRESH register is set in K so divide by 1024 and subtract + * 10 since the largest packet we support is just over 9K. + */ + txpktsize = IXGBE_TXPBSIZE_MAX / num_tcs; + txpbthresh = (txpktsize / 1024) - IXGBE_TXPKT_SIZE_MAX; + for (i = 0; i < num_tcs; i++) { + IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), txpktsize); + IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), txpbthresh); + } + + /* Clear unused TCs, if any, to zero buffer size*/ + for (; i < MAX_TRAFFIC_CLASS; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), 0); + } + + return 0; } /** @@ -285,12 +301,17 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en) IXGBE_WRITE_REG(hw, IXGBE_FCCFG, reg); /* * Enable Receive PFC - * We will always honor XOFF frames we receive when - * we are in PFC mode. + * 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 |= pfc_en << IXGBE_MFLCN_RPFCE_SHIFT; + IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg); } else { diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ixgbe/ixgbe_dcb_82599.h index 148fd8b477a9..2de71a503153 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.h +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.h @@ -92,8 +92,10 @@ #define IXGBE_RXPBSIZE_64KB 0x00010000 /* 64KB Packet Buffer */ #define IXGBE_RXPBSIZE_80KB 0x00014000 /* 80KB Packet Buffer */ #define IXGBE_RXPBSIZE_128KB 0x00020000 /* 128KB Packet Buffer */ +#define IXGBE_TXPBSIZE_MAX 0x00028000 /* 160KB Packet Buffer*/ #define IXGBE_TXPBTHRESH_DCB 0xA /* THRESH value for DCB mode */ +#define IXGBE_TXPKT_SIZE_MAX 0xA /* Max Tx Packet size */ /* SECTXMINIFG DCB */ #define IXGBE_SECTX_DCB 0x00001F00 /* DCB TX Buffer IFG */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 327c8614198c..5e7ed225851a 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -347,18 +347,28 @@ static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority, static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct dcb_app app = { + .selector = DCB_APP_IDTYPE_ETHTYPE, + .protocol = ETH_P_FCOE, + }; + u8 up = dcb_getapp(netdev, &app); int ret; - if (!adapter->dcb_set_bitmap || - !(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) - return DCB_NO_HW_CHG; - ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, MAX_TRAFFIC_CLASS); - if (ret) return DCB_NO_HW_CHG; + /* In IEEE mode app data must be parsed into DCBX format for + * hardware routines. + */ + if (adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) + up = (1 << up); + +#ifdef IXGBE_FCOE + if (up && (up != (1 << adapter->fcoe.up))) + adapter->dcb_set_bitmap |= BIT_APP_UPCHG; + /* * Only take down the adapter if an app change occurred. FCoE * may shuffle tx rings in this case and this can not be done @@ -366,12 +376,15 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) */ if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); + + ixgbe_fcoe_setapp(adapter, up); if (netif_running(netdev)) netdev->netdev_ops->ndo_stop(netdev); ixgbe_clear_interrupt_scheme(adapter); } +#endif if (adapter->dcb_cfg.pfc_mode_enable) { switch (adapter->hw.mac.type) { @@ -399,12 +412,14 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) } } +#ifdef IXGBE_FCOE if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { ixgbe_init_interrupt_scheme(adapter); if (netif_running(netdev)) netdev->netdev_ops->ndo_open(netdev); ret = DCB_HW_CHG_RST; } +#endif if (adapter->dcb_set_bitmap & BIT_PFC) { u8 pfc_en; @@ -558,68 +573,6 @@ static u8 ixgbe_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id) return dcb_getapp(netdev, &app); } -/** - * ixgbe_dcbnl_setapp - set the DCBX application user priority - * @netdev : the corresponding netdev - * @idtype : identifies the id as ether type or TCP/UDP port number - * @id: id is either ether type or TCP/UDP port number - * @up: the 802.1p user priority bitmap - * - * Returns : 0 on success or 1 on error - */ -static u8 ixgbe_dcbnl_setapp(struct net_device *netdev, - u8 idtype, u16 id, u8 up) -{ - struct ixgbe_adapter *adapter = netdev_priv(netdev); - u8 rval = 1; - struct dcb_app app = { - .selector = idtype, - .protocol = id, - .priority = up - }; - - if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) - return rval; - - rval = dcb_setapp(netdev, &app); - - switch (idtype) { - case DCB_APP_IDTYPE_ETHTYPE: -#ifdef IXGBE_FCOE - if (id == ETH_P_FCOE) { - u8 old_tc; - - /* Get current programmed tc */ - old_tc = adapter->fcoe.tc; - rval = ixgbe_fcoe_setapp(adapter, up); - - if (rval || - !(adapter->flags & IXGBE_FLAG_DCB_ENABLED) || - !(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) - break; - - /* The FCoE application priority may be changed multiple - * times in quick succession with switches that build up - * TLVs. To avoid creating uneeded device resets this - * checks the actual HW configuration and clears - * BIT_APP_UPCHG if a HW configuration change is not - * need - */ - if (old_tc == adapter->fcoe.tc) - adapter->dcb_set_bitmap &= ~BIT_APP_UPCHG; - else - adapter->dcb_set_bitmap |= BIT_APP_UPCHG; - } -#endif - break; - case DCB_APP_IDTYPE_PORTNUM: - break; - default: - break; - } - return rval; -} - static int ixgbe_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets) { @@ -745,25 +698,14 @@ static int ixgbe_dcbnl_ieee_setapp(struct net_device *dev, if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) return -EINVAL; -#ifdef IXGBE_FCOE - if (app->selector == 1 && app->protocol == ETH_P_FCOE) { - if (adapter->fcoe.tc == app->priority) - goto setapp; - /* In IEEE mode map up to tc 1:1 */ - adapter->fcoe.tc = app->priority; - adapter->fcoe.up = app->priority; - - /* Force hardware reset required to push FCoE - * setup on {tx|rx}_rings - */ - adapter->dcb_set_bitmap |= BIT_APP_UPCHG; - ixgbe_dcbnl_set_all(dev); - } - -setapp: -#endif dcb_setapp(dev, app); + +#ifdef IXGBE_FCOE + if (app->selector == 1 && app->protocol == ETH_P_FCOE && + adapter->fcoe.tc == app->priority) + ixgbe_dcbnl_set_all(dev); +#endif return 0; } @@ -838,7 +780,6 @@ const struct dcbnl_rtnl_ops dcbnl_ops = { .getpfcstate = ixgbe_dcbnl_getpfcstate, .setpfcstate = ixgbe_dcbnl_setpfcstate, .getapp = ixgbe_dcbnl_getapp, - .setapp = ixgbe_dcbnl_setapp, .getdcbx = ixgbe_dcbnl_getdcbx, .setdcbx = ixgbe_dcbnl_setdcbx, }; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 76380a2b35aa..cb1555bc8548 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -84,6 +84,7 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"hw_rsc_flushed", IXGBE_STAT(rsc_total_flush)}, {"fdir_match", IXGBE_STAT(stats.fdirmatch)}, {"fdir_miss", IXGBE_STAT(stats.fdirmiss)}, + {"fdir_overflow", IXGBE_STAT(fdir_overflow)}, {"rx_fifo_errors", IXGBE_NETDEV_STAT(rx_fifo_errors)}, {"rx_missed_errors", IXGBE_NETDEV_STAT(rx_missed_errors)}, {"tx_aborted_errors", IXGBE_NETDEV_STAT(tx_aborted_errors)}, @@ -102,6 +103,10 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, {"rx_no_dma_resources", IXGBE_STAT(hw_rx_no_dma_resources)}, + {"os2bmc_rx_by_bmc", IXGBE_STAT(stats.o2bgptc)}, + {"os2bmc_tx_by_bmc", IXGBE_STAT(stats.b2ospc)}, + {"os2bmc_tx_by_host", IXGBE_STAT(stats.o2bspc)}, + {"os2bmc_rx_by_host", IXGBE_STAT(stats.b2ogprc)}, #ifdef IXGBE_FCOE {"fcoe_bad_fccrc", IXGBE_STAT(stats.fccrc)}, {"rx_fcoe_dropped", IXGBE_STAT(stats.fcoerpdc)}, @@ -288,20 +293,20 @@ static int ixgbe_get_settings(struct net_device *netdev, if (link_up) { switch (link_speed) { case IXGBE_LINK_SPEED_10GB_FULL: - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); break; case IXGBE_LINK_SPEED_1GB_FULL: - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); break; case IXGBE_LINK_SPEED_100_FULL: - ecmd->speed = SPEED_100; + ethtool_cmd_speed_set(ecmd, SPEED_100); break; default: break; } ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } @@ -346,9 +351,10 @@ static int ixgbe_set_settings(struct net_device *netdev, } } else { /* in this case we currently only support 10Gb/FULL */ + u32 speed = ethtool_cmd_speed(ecmd); if ((ecmd->autoneg == AUTONEG_ENABLE) || (ecmd->advertising != ADVERTISED_10000baseT_Full) || - (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) + (speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) return -EINVAL; } @@ -846,11 +852,8 @@ static int ixgbe_get_eeprom(struct net_device *netdev, if (!eeprom_buff) return -ENOMEM; - for (i = 0; i < eeprom_len; i++) { - if ((ret_val = hw->eeprom.ops.read(hw, first_word + i, - &eeprom_buff[i]))) - break; - } + ret_val = hw->eeprom.ops.read_buffer(hw, first_word, eeprom_len, + eeprom_buff); /* Device's eeprom is always little-endian, word addressable */ for (i = 0; i < eeprom_len; i++) @@ -931,7 +934,7 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (!netif_running(adapter->netdev)) { for (i = 0; i < adapter->num_tx_queues; i++) @@ -1030,9 +1033,6 @@ static int ixgbe_get_sset_count(struct net_device *netdev, int sset) return IXGBE_TEST_LEN; case ETH_SS_STATS: return IXGBE_STATS_LEN; - case ETH_SS_NTUPLE_FILTERS: - return ETHTOOL_MAX_NTUPLE_LIST_ENTRY * - ETHTOOL_MAX_NTUPLE_STRING_PER_ENTRY; default: return -EOPNOTSUPP; } @@ -1238,46 +1238,62 @@ static const struct ixgbe_reg_test reg_test_82598[] = { { 0, 0, 0, 0 } }; -static const u32 register_test_patterns[] = { - 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF -}; +static bool reg_pattern_test(struct ixgbe_adapter *adapter, u64 *data, int reg, + u32 mask, u32 write) +{ + u32 pat, val, before; + static const u32 test_pattern[] = { + 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; -#define REG_PATTERN_TEST(R, M, W) \ -{ \ - u32 pat, val, before; \ - for (pat = 0; pat < ARRAY_SIZE(register_test_patterns); pat++) { \ - before = readl(adapter->hw.hw_addr + R); \ - writel((register_test_patterns[pat] & W), \ - (adapter->hw.hw_addr + R)); \ - val = readl(adapter->hw.hw_addr + R); \ - if (val != (register_test_patterns[pat] & W & M)) { \ - e_err(drv, "pattern test reg %04X failed: got " \ - "0x%08X expected 0x%08X\n", \ - R, val, (register_test_patterns[pat] & W & M)); \ - *data = R; \ - writel(before, adapter->hw.hw_addr + R); \ - return 1; \ - } \ - writel(before, adapter->hw.hw_addr + R); \ - } \ + for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) { + before = readl(adapter->hw.hw_addr + reg); + writel((test_pattern[pat] & write), + (adapter->hw.hw_addr + reg)); + val = readl(adapter->hw.hw_addr + reg); + if (val != (test_pattern[pat] & write & mask)) { + e_err(drv, "pattern test reg %04X failed: got " + "0x%08X expected 0x%08X\n", + reg, val, (test_pattern[pat] & write & mask)); + *data = reg; + writel(before, adapter->hw.hw_addr + reg); + return 1; + } + writel(before, adapter->hw.hw_addr + reg); + } + return 0; } -#define REG_SET_AND_CHECK(R, M, W) \ -{ \ - u32 val, before; \ - before = readl(adapter->hw.hw_addr + R); \ - writel((W & M), (adapter->hw.hw_addr + R)); \ - val = readl(adapter->hw.hw_addr + R); \ - if ((W & M) != (val & M)) { \ - e_err(drv, "set/check reg %04X test failed: got 0x%08X " \ - "expected 0x%08X\n", R, (val & M), (W & M)); \ - *data = R; \ - writel(before, (adapter->hw.hw_addr + R)); \ - return 1; \ - } \ - writel(before, (adapter->hw.hw_addr + R)); \ +static bool reg_set_and_check(struct ixgbe_adapter *adapter, u64 *data, int reg, + u32 mask, u32 write) +{ + u32 val, before; + before = readl(adapter->hw.hw_addr + reg); + writel((write & mask), (adapter->hw.hw_addr + reg)); + val = readl(adapter->hw.hw_addr + reg); + if ((write & mask) != (val & mask)) { + e_err(drv, "set/check reg %04X test failed: got 0x%08X " + "expected 0x%08X\n", reg, (val & mask), (write & mask)); + *data = reg; + writel(before, (adapter->hw.hw_addr + reg)); + return 1; + } + writel(before, (adapter->hw.hw_addr + reg)); + return 0; } +#define REG_PATTERN_TEST(reg, mask, write) \ + do { \ + if (reg_pattern_test(adapter, data, reg, mask, write)) \ + return 1; \ + } while (0) \ + + +#define REG_SET_AND_CHECK(reg, mask, write) \ + do { \ + if (reg_set_and_check(adapter, data, reg, mask, write)) \ + return 1; \ + } while (0) \ + static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) { const struct ixgbe_reg_test *test; @@ -1328,13 +1344,13 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) switch (test->test_type) { case PATTERN_TEST: REG_PATTERN_TEST(test->reg + (i * 0x40), - test->mask, - test->write); + test->mask, + test->write); break; case SET_READ_TEST: REG_SET_AND_CHECK(test->reg + (i * 0x40), - test->mask, - test->write); + test->mask, + test->write); break; case WRITE_NO_TEST: writel(test->write, @@ -1343,18 +1359,18 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) break; case TABLE32_TEST: REG_PATTERN_TEST(test->reg + (i * 4), - test->mask, - test->write); + test->mask, + test->write); break; case TABLE64_TEST_LO: REG_PATTERN_TEST(test->reg + (i * 8), - test->mask, - test->write); + test->mask, + test->write); break; case TABLE64_TEST_HI: REG_PATTERN_TEST((test->reg + 4) + (i * 8), - test->mask, - test->write); + test->mask, + test->write); break; } } @@ -1417,7 +1433,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) /* Disable all the interrupts */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Test each interrupt */ for (; i < 10; i++) { @@ -1437,7 +1453,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) ~mask & 0x00007FFF); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, ~mask & 0x00007FFF); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr & mask) { *data = 3; @@ -1454,7 +1470,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) adapter->test_icr = 0; IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); - msleep(10); + usleep_range(10000, 20000); if (!(adapter->test_icr &mask)) { *data = 4; @@ -1474,7 +1490,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) ~mask & 0x00007FFF); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, ~mask & 0x00007FFF); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr) { *data = 5; @@ -1485,7 +1501,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) /* Disable all the interrupts */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Unhook test interrupt handler */ free_irq(irq, netdev); @@ -1598,6 +1614,13 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; u32 reg_data; + /* X540 needs to set the MACC.FLU bit to force link up */ + if (adapter->hw.mac.type == ixgbe_mac_X540) { + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_MACC); + reg_data |= IXGBE_MACC_FLU; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_MACC, reg_data); + } + /* right now we only support MAC loopback in the driver */ reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); /* Setup MAC loopback */ @@ -1613,7 +1636,7 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter) reg_data |= IXGBE_AUTOC_LMS_10G_LINK_NO_AN | IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(&adapter->hw, IXGBE_AUTOC, reg_data); IXGBE_WRITE_FLUSH(&adapter->hw); - msleep(10); + usleep_range(10000, 20000); /* Disable Atlas Tx lanes; re-enabled in reset path */ if (hw->mac.type == ixgbe_mac_82598EB) { @@ -1999,25 +2022,30 @@ static int ixgbe_nway_reset(struct net_device *netdev) return 0; } -static int ixgbe_phys_id(struct net_device *netdev, u32 data) +static int ixgbe_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; - u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); - u32 i; - if (!data || data > 300) - data = 300; + switch (state) { + case ETHTOOL_ID_ACTIVE: + adapter->led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + return 2; - for (i = 0; i < (data * 1000); i += 400) { + case ETHTOOL_ID_ON: hw->mac.ops.led_on(hw, IXGBE_LED_ON); - msleep_interruptible(200); - hw->mac.ops.led_off(hw, IXGBE_LED_ON); - msleep_interruptible(200); - } + break; - /* Restore LED settings */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, led_reg); + case ETHTOOL_ID_OFF: + hw->mac.ops.led_off(hw, IXGBE_LED_ON); + break; + + case ETHTOOL_ID_INACTIVE: + /* Restore LED settings */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, adapter->led_reg); + break; + } return 0; } @@ -2230,8 +2258,13 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data) need_reset = (data & ETH_FLAG_RXVLAN) != (netdev->features & NETIF_F_HW_VLAN_RX); + if ((data & ETH_FLAG_RXHASH) && + !(adapter->flags & IXGBE_FLAG_RSS_ENABLED)) + return -EOPNOTSUPP; + rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_LRO | ETH_FLAG_NTUPLE | - ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN); + ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | + ETH_FLAG_RXHASH); if (rc) return rc; @@ -2465,7 +2498,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = { .set_tso = ixgbe_set_tso, .self_test = ixgbe_diag_test, .get_strings = ixgbe_get_strings, - .phys_id = ixgbe_phys_id, + .set_phys_id = ixgbe_set_phys_id, .get_sset_count = ixgbe_get_sset_count, .get_ethtool_stats = ixgbe_get_ethtool_stats, .get_coalesce = ixgbe_get_coalesce, diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index dba7d77588ef..05920726e824 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -416,8 +416,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, if (!ddp->udl) goto ddp_out; - ddp->err = (fcerr | fceofe); - if (ddp->err) + if (fcerr | fceofe) goto ddp_out; fcstat = (sterr & IXGBE_RXDADV_STAT_FCSTAT); @@ -428,6 +427,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_FCPRSP) { pci_unmap_sg(adapter->pdev, ddp->sgl, ddp->sgc, DMA_FROM_DEVICE); + ddp->err = (fcerr | fceofe); ddp->sgl = NULL; ddp->sgc = 0; } diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 6f8adc7f5d7c..fa01b0b03b77 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -51,8 +51,12 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; - -#define DRV_VERSION "3.2.9-k2" +#define MAJ 3 +#define MIN 3 +#define BUILD 8 +#define KFIX 2 +#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ + __stringify(BUILD) "-k" __stringify(KFIX) const char ixgbe_driver_version[] = DRV_VERSION; static const char ixgbe_copyright[] = "Copyright (c) 1999-2011 Intel Corporation."; @@ -120,6 +124,10 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = { board_82599 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T), board_X540 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2), + board_82599 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS), + board_82599 }, /* required last entry */ {0, } @@ -185,6 +193,22 @@ static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter) adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED; } +static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter) +{ + if (!test_bit(__IXGBE_DOWN, &adapter->state) && + !test_and_set_bit(__IXGBE_SERVICE_SCHED, &adapter->state)) + schedule_work(&adapter->service_task); +} + +static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter) +{ + BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state)); + + /* flush memory to make sure state is correct before next watchog */ + smp_mb__before_clear_bit(); + clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state); +} + struct ixgbe_reg_info { u32 ofs; char *name; @@ -811,7 +835,19 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_ring *tx_ring) #define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \ MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ -static void ixgbe_tx_timeout(struct net_device *netdev); +/** + * ixgbe_tx_timeout_reset - initiate reset due to Tx timeout + * @adapter: driver private struct + **/ +static void ixgbe_tx_timeout_reset(struct ixgbe_adapter *adapter) +{ + + /* Do the reset outside of interrupt context */ + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED; + ixgbe_service_event_schedule(adapter); + } +} /** * ixgbe_clean_tx_irq - Reclaim resources after transmit completes @@ -893,7 +929,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, adapter->tx_timeout_count + 1, tx_ring->queue_index); /* schedule immediate reset if we believe we hung */ - ixgbe_tx_timeout(adapter->netdev); + ixgbe_tx_timeout_reset(adapter); /* the adapter is about to reset, no point in enabling stuff */ return true; @@ -943,8 +979,6 @@ static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter, rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN; rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN; rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN); - rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN | - IXGBE_DCA_RXCTRL_DESC_HSRO_EN); IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(reg_idx), rxctrl); } @@ -962,7 +996,6 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter, txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK; txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu); txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN; - txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(reg_idx), txctrl); break; case ixgbe_mac_82599EB: @@ -972,7 +1005,6 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter, txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) << IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599); txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN; - txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(reg_idx), txctrl); break; default: @@ -1061,8 +1093,14 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) return 0; } - #endif /* CONFIG_IXGBE_DCA */ + +static inline void ixgbe_rx_hash(union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb) +{ + skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); +} + /** * ixgbe_receive_skb - Send a completed packet up the stack * @adapter: board private structure @@ -1454,6 +1492,8 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, } ixgbe_rx_checksum(adapter, rx_desc, skb); + if (adapter->netdev->features & NETIF_F_RXHASH) + ixgbe_rx_hash(rx_desc, skb); /* probably a little skewed due to removing CRC */ total_rx_bytes += skb->len; @@ -1787,35 +1827,51 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) } /** - * ixgbe_check_overtemp_task - worker thread to check over tempurature - * @work: pointer to work_struct containing our data + * ixgbe_check_overtemp_subtask - check for over tempurature + * @adapter: pointer to adapter **/ -static void ixgbe_check_overtemp_task(struct work_struct *work) +static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter) { - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - check_overtemp_task); struct ixgbe_hw *hw = &adapter->hw; u32 eicr = adapter->interrupt_event; - if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)) + if (test_bit(__IXGBE_DOWN, &adapter->state)) return; + if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && + !(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_EVENT)) + return; + + adapter->flags2 &= ~IXGBE_FLAG2_TEMP_SENSOR_EVENT; + switch (hw->device_id) { - case IXGBE_DEV_ID_82599_T3_LOM: { - u32 autoneg; - bool link_up = false; + case IXGBE_DEV_ID_82599_T3_LOM: + /* + * Since the warning interrupt is for both ports + * we don't have to check if: + * - This interrupt wasn't for our port. + * - We may have missed the interrupt so always have to + * check if we got a LSC + */ + if (!(eicr & IXGBE_EICR_GPI_SDP0) && + !(eicr & IXGBE_EICR_LSC)) + return; + + if (!(eicr & IXGBE_EICR_LSC) && hw->mac.ops.check_link) { + u32 autoneg; + bool link_up = false; - if (hw->mac.ops.check_link) hw->mac.ops.check_link(hw, &autoneg, &link_up, false); - if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) || - (eicr & IXGBE_EICR_LSC)) - /* Check if this is due to overtemp */ - if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP) - break; - return; - } + if (link_up) + return; + } + + /* Check if this is not due to overtemp */ + if (hw->phy.ops.check_overtemp(hw) != IXGBE_ERR_OVERTEMP) + return; + + break; default: if (!(eicr & IXGBE_EICR_GPI_SDP0)) return; @@ -1825,8 +1881,8 @@ static void ixgbe_check_overtemp_task(struct work_struct *work) "Network adapter has been stopped because it has over heated. " "Restart the computer. If the problem persists, " "power off the system and replace the adapter\n"); - /* write to clear the interrupt */ - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0); + + adapter->interrupt_event = 0; } static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr) @@ -1848,15 +1904,19 @@ static void ixgbe_check_sfp_event(struct ixgbe_adapter *adapter, u32 eicr) if (eicr & IXGBE_EICR_GPI_SDP2) { /* Clear the interrupt */ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2); - if (!test_bit(__IXGBE_DOWN, &adapter->state)) - schedule_work(&adapter->sfp_config_module_task); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET; + ixgbe_service_event_schedule(adapter); + } } if (eicr & IXGBE_EICR_GPI_SDP1) { /* Clear the interrupt */ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); - if (!test_bit(__IXGBE_DOWN, &adapter->state)) - schedule_work(&adapter->multispeed_fiber_task); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG; + ixgbe_service_event_schedule(adapter); + } } } @@ -1870,7 +1930,7 @@ static void ixgbe_check_lsc(struct ixgbe_adapter *adapter) if (!test_bit(__IXGBE_DOWN, &adapter->state)) { IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); IXGBE_WRITE_FLUSH(hw); - schedule_work(&adapter->watchdog_task); + ixgbe_service_event_schedule(adapter); } } @@ -1898,26 +1958,32 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) switch (hw->mac.type) { case ixgbe_mac_82599EB: - ixgbe_check_sfp_event(adapter, eicr); - if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && - ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) { - adapter->interrupt_event = eicr; - schedule_work(&adapter->check_overtemp_task); - } - /* now fallthrough to handle Flow Director */ case ixgbe_mac_X540: /* Handle Flow Director Full threshold interrupt */ if (eicr & IXGBE_EICR_FLOW_DIR) { + int reinit_count = 0; int i; - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_FLOW_DIR); - /* Disable transmits before FDIR Re-initialization */ - netif_tx_stop_all_queues(netdev); for (i = 0; i < adapter->num_tx_queues; i++) { - struct ixgbe_ring *tx_ring = - adapter->tx_ring[i]; + struct ixgbe_ring *ring = adapter->tx_ring[i]; if (test_and_clear_bit(__IXGBE_TX_FDIR_INIT_DONE, - &tx_ring->state)) - schedule_work(&adapter->fdir_reinit_task); + &ring->state)) + reinit_count++; + } + if (reinit_count) { + /* no more flow director interrupts until after init */ + IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR); + eicr &= ~IXGBE_EICR_FLOW_DIR; + adapter->flags2 |= IXGBE_FLAG2_FDIR_REQUIRES_REINIT; + ixgbe_service_event_schedule(adapter); + } + } + ixgbe_check_sfp_event(adapter, eicr); + if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && + ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) { + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->interrupt_event = eicr; + adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT; + ixgbe_service_event_schedule(adapter); } } break; @@ -1927,8 +1993,10 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) ixgbe_check_fan_failure(adapter, eicr); + /* re-enable the original interrupt state, no lsc, no queues */ if (!test_bit(__IXGBE_DOWN, &adapter->state)) - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); + IXGBE_WRITE_REG(hw, IXGBE_EIMS, eicr & + ~(IXGBE_EIMS_LSC | IXGBE_EIMS_RTX_QUEUE)); return IRQ_HANDLED; } @@ -2513,8 +2581,11 @@ static irqreturn_t ixgbe_intr(int irq, void *data) ixgbe_check_sfp_event(adapter, eicr); if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) { - adapter->interrupt_event = eicr; - schedule_work(&adapter->check_overtemp_task); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->interrupt_event = eicr; + adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT; + ixgbe_service_event_schedule(adapter); + } } break; default: @@ -2731,7 +2802,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter, /* poll to verify queue is enabled */ do { - msleep(1); + usleep_range(1000, 2000); txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx)); } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); if (!wait_loop) @@ -3023,7 +3094,7 @@ static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter, return; do { - msleep(1); + usleep_range(1000, 2000); rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx)); } while (--wait_loop && !(rxdctl & IXGBE_RXDCTL_ENABLE)); @@ -3178,7 +3249,9 @@ static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter) /* enable Tx loopback for VF/PF communication */ IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN); /* Enable MAC Anti-Spoofing */ - hw->mac.ops.set_mac_anti_spoofing(hw, (adapter->num_vfs != 0), + hw->mac.ops.set_mac_anti_spoofing(hw, + (adapter->antispoofing_enabled = + (adapter->num_vfs != 0)), adapter->num_vfs); } @@ -3487,7 +3560,7 @@ static int ixgbe_write_uc_addr_list(struct net_device *netdev) struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; unsigned int vfn = adapter->num_vfs; - unsigned int rar_entries = hw->mac.num_rar_entries - (vfn + 1); + unsigned int rar_entries = IXGBE_MAX_PF_MACVLANS; int count = 0; /* return ENOMEM indicating insufficient memory for addresses */ @@ -3760,31 +3833,16 @@ static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw) **/ static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter) { - struct ixgbe_hw *hw = &adapter->hw; + /* + * We are assuming the worst case scenerio here, and that + * is that an SFP was inserted/removed after the reset + * but before SFP detection was enabled. As such the best + * solution is to just start searching as soon as we start + */ + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP; - if (hw->phy.multispeed_fiber) { - /* - * In multispeed fiber setups, the device may not have - * had a physical connection when the driver loaded. - * If that's the case, the initial link configuration - * couldn't get the MAC into 10G or 1G mode, so we'll - * never have a link status change interrupt fire. - * We need to try and force an autonegotiation - * session, then bring up link. - */ - if (hw->mac.ops.setup_sfp) - hw->mac.ops.setup_sfp(hw); - if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)) - schedule_work(&adapter->multispeed_fiber_task); - } else { - /* - * Direct Attach Cu and non-multispeed fiber modules - * still need to be configured properly prior to - * attempting link. - */ - if (!(adapter->flags & IXGBE_FLAG_IN_SFP_MOD_TASK)) - schedule_work(&adapter->sfp_config_module_task); - } + adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET; } /** @@ -3860,9 +3918,10 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter) if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) gpie |= IXGBE_SDP1_GPIEN; - if (hw->mac.type == ixgbe_mac_82599EB) + if (hw->mac.type == ixgbe_mac_82599EB) { gpie |= IXGBE_SDP1_GPIEN; gpie |= IXGBE_SDP2_GPIEN; + } IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); } @@ -3913,17 +3972,6 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) e_crit(drv, "Fan has stopped, replace the adapter\n"); } - /* - * For hot-pluggable SFP+ devices, a new SFP+ module may have - * arrived before interrupts were enabled but after probe. Such - * devices wouldn't have their type identified yet. We need to - * kick off the SFP+ module setup first, then try to bring up link. - * If we're not hot-pluggable SFP+, we just need to configure link - * and bring it up. - */ - if (hw->phy.type == ixgbe_phy_none) - schedule_work(&adapter->sfp_config_module_task); - /* enable transmits */ netif_tx_start_all_queues(adapter->netdev); @@ -3931,7 +3979,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) * link up interrupt but shouldn't be a problem */ adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; adapter->link_check_timeout = jiffies; - mod_timer(&adapter->watchdog_timer, jiffies); + mod_timer(&adapter->service_timer, jiffies); /* Set PF Reset Done bit so PF/VF Mail Ops can work */ ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); @@ -3944,8 +3992,11 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) void ixgbe_reinit_locked(struct ixgbe_adapter *adapter) { WARN_ON(in_interrupt()); + /* put off any impending NetWatchDogTimeout */ + adapter->netdev->trans_start = jiffies; + while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); ixgbe_down(adapter); /* * If SR-IOV enabled then wait a bit before bringing the adapter @@ -3972,10 +4023,20 @@ void ixgbe_reset(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; int err; + /* lock SFP init bit to prevent race conditions with the watchdog */ + while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) + usleep_range(1000, 2000); + + /* clear all SFP and link config related flags while holding SFP_INIT */ + adapter->flags2 &= ~(IXGBE_FLAG2_SEARCH_FOR_SFP | + IXGBE_FLAG2_SFP_NEEDS_RESET); + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG; + err = hw->mac.ops.init_hw(hw); switch (err) { case 0: case IXGBE_ERR_SFP_NOT_PRESENT: + case IXGBE_ERR_SFP_NOT_SUPPORTED: break; case IXGBE_ERR_MASTER_REQUESTS_PENDING: e_dev_err("master disable timed out\n"); @@ -3993,6 +4054,8 @@ void ixgbe_reset(struct ixgbe_adapter *adapter) e_dev_err("Hardware Error: %d\n", err); } + clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); + /* reprogram the RAR[0] in case user changed it. */ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs, IXGBE_RAH_AV); @@ -4121,13 +4184,39 @@ void ixgbe_down(struct ixgbe_adapter *adapter) struct net_device *netdev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; u32 rxctrl; - u32 txdctl; int i; int num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; /* signal that we are down to the interrupt handler */ set_bit(__IXGBE_DOWN, &adapter->state); + /* disable receives */ + rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); + + /* disable all enabled rx queues */ + for (i = 0; i < adapter->num_rx_queues; i++) + /* this call also flushes the previous write */ + ixgbe_disable_rx_queue(adapter, adapter->rx_ring[i]); + + usleep_range(10000, 20000); + + netif_tx_stop_all_queues(netdev); + + /* call carrier off first to avoid false dev_watchdog timeouts */ + netif_carrier_off(netdev); + netif_tx_disable(netdev); + + ixgbe_irq_disable(adapter); + + ixgbe_napi_disable_all(adapter); + + adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT | + IXGBE_FLAG2_RESET_REQUESTED); + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; + + del_timer_sync(&adapter->service_timer); + /* disable receive for all VFs and wait one second */ if (adapter->num_vfs) { /* ping all the active vfs to let them know we are going down */ @@ -4141,31 +4230,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter) adapter->vfinfo[i].clear_to_send = 0; } - /* disable receives */ - rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); - IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); - - /* disable all enabled rx queues */ - for (i = 0; i < adapter->num_rx_queues; i++) - /* this call also flushes the previous write */ - ixgbe_disable_rx_queue(adapter, adapter->rx_ring[i]); - - msleep(10); - - netif_tx_stop_all_queues(netdev); - - clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - del_timer_sync(&adapter->sfp_timer); - del_timer_sync(&adapter->watchdog_timer); - cancel_work_sync(&adapter->watchdog_task); - - netif_carrier_off(netdev); - netif_tx_disable(netdev); - - ixgbe_irq_disable(adapter); - - ixgbe_napi_disable_all(adapter); - /* Cleanup the affinity_hint CPU mask memory and callback */ for (i = 0; i < num_q_vectors; i++) { struct ixgbe_q_vector *q_vector = adapter->q_vector[i]; @@ -4175,21 +4239,13 @@ void ixgbe_down(struct ixgbe_adapter *adapter) free_cpumask_var(q_vector->affinity_mask); } - if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || - adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) - cancel_work_sync(&adapter->fdir_reinit_task); - - if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) - cancel_work_sync(&adapter->check_overtemp_task); - /* disable transmits in the hardware now that interrupts are off */ for (i = 0; i < adapter->num_tx_queues; i++) { u8 reg_idx = adapter->tx_ring[i]->reg_idx; - txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx)); - IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), - (txdctl & ~IXGBE_TXDCTL_ENABLE)); + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), IXGBE_TXDCTL_SWFLSH); } - /* Disable the Tx DMA engine on 82599 */ + + /* Disable the Tx DMA engine on 82599 and X540 */ switch (hw->mac.type) { case ixgbe_mac_82599EB: case ixgbe_mac_X540: @@ -4201,9 +4257,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter) break; } - /* clear n-tuple filters that are cached */ - ethtool_ntuple_flush(netdev); - if (!pci_channel_offline(adapter->pdev)) ixgbe_reset(adapter); @@ -4267,25 +4320,8 @@ static void ixgbe_tx_timeout(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - adapter->tx_timeout_count++; - /* Do the reset outside of interrupt context */ - schedule_work(&adapter->reset_task); -} - -static void ixgbe_reset_task(struct work_struct *work) -{ - struct ixgbe_adapter *adapter; - adapter = container_of(work, struct ixgbe_adapter, reset_task); - - /* If we're already down or resetting, just bail */ - if (test_bit(__IXGBE_DOWN, &adapter->state) || - test_bit(__IXGBE_RESETTING, &adapter->state)) - return; - - ixgbe_dump(adapter); - netdev_err(adapter->netdev, "Reset adapter\n"); - ixgbe_reinit_locked(adapter); + ixgbe_tx_timeout_reset(adapter); } /** @@ -4567,8 +4603,8 @@ static inline bool ixgbe_cache_ring_rss(struct ixgbe_adapter *adapter) #ifdef CONFIG_IXGBE_DCB /* ixgbe_get_first_reg_idx - Return first register index associated with ring */ -void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc, - unsigned int *tx, unsigned int *rx) +static void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc, + unsigned int *tx, unsigned int *rx) { struct net_device *dev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; @@ -5100,11 +5136,6 @@ int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) return err; } -static void ring_free_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct ixgbe_ring, rcu)); -} - /** * ixgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings * @adapter: board private structure to clear interrupt scheme on @@ -5126,7 +5157,7 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter) /* ixgbe_get_stats64() might access this ring, we must wait * a grace period before freeing it. */ - call_rcu(&ring->rcu, ring_free_rcu); + kfree_rcu(ring, rcu); adapter->rx_ring[i] = NULL; } @@ -5137,57 +5168,6 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter) ixgbe_reset_interrupt_capability(adapter); } -/** - * ixgbe_sfp_timer - worker thread to find a missing module - * @data: pointer to our adapter struct - **/ -static void ixgbe_sfp_timer(unsigned long data) -{ - struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; - - /* - * Do the sfp_timer outside of interrupt context due to the - * delays that sfp+ detection requires - */ - schedule_work(&adapter->sfp_task); -} - -/** - * ixgbe_sfp_task - worker thread to find a missing module - * @work: pointer to work_struct containing our data - **/ -static void ixgbe_sfp_task(struct work_struct *work) -{ - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - sfp_task); - struct ixgbe_hw *hw = &adapter->hw; - - if ((hw->phy.type == ixgbe_phy_nl) && - (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { - s32 ret = hw->phy.ops.identify_sfp(hw); - if (ret == IXGBE_ERR_SFP_NOT_PRESENT) - goto reschedule; - ret = hw->phy.ops.reset(hw); - if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { - e_dev_err("failed to initialize because an unsupported " - "SFP+ module type was detected.\n"); - e_dev_err("Reload the driver after installing a " - "supported module.\n"); - unregister_netdev(adapter->netdev); - } else { - e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type); - } - /* don't need this routine any more */ - clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - } - return; -reschedule: - if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state)) - mod_timer(&adapter->sfp_timer, - round_jiffies(jiffies + (2 * HZ))); -} - /** * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter) * @adapter: board private structure to initialize @@ -5904,8 +5884,13 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORH); break; - case ixgbe_mac_82599EB: case ixgbe_mac_X540: + /* OS2BMC stats are X540 only*/ + hwstats->o2bgptc += IXGBE_READ_REG(hw, IXGBE_O2BGPTC); + hwstats->o2bspc += IXGBE_READ_REG(hw, IXGBE_O2BSPC); + hwstats->b2ospc += IXGBE_READ_REG(hw, IXGBE_B2OSPC); + hwstats->b2ogprc += IXGBE_READ_REG(hw, IXGBE_B2OGPRC); + case ixgbe_mac_82599EB: hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL); IXGBE_READ_REG(hw, IXGBE_GORCH); /* to clear */ hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL); @@ -5979,23 +5964,66 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) } /** - * ixgbe_watchdog - Timer Call-back - * @data: pointer to adapter cast into an unsigned long + * ixgbe_fdir_reinit_subtask - worker thread to reinit FDIR filter table + * @adapter - pointer to the device adapter structure **/ -static void ixgbe_watchdog(unsigned long data) +static void ixgbe_fdir_reinit_subtask(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + int i; + + if (!(adapter->flags2 & IXGBE_FLAG2_FDIR_REQUIRES_REINIT)) + return; + + adapter->flags2 &= ~IXGBE_FLAG2_FDIR_REQUIRES_REINIT; + + /* if interface is down do nothing */ + if (test_bit(__IXGBE_DOWN, &adapter->state)) + return; + + /* do nothing if we are not using signature filters */ + if (!(adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE)) + return; + + adapter->fdir_overflow++; + + if (ixgbe_reinit_fdir_tables_82599(hw) == 0) { + for (i = 0; i < adapter->num_tx_queues; i++) + set_bit(__IXGBE_TX_FDIR_INIT_DONE, + &(adapter->tx_ring[i]->state)); + /* re-enable flow director interrupts */ + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); + } else { + e_err(probe, "failed to finish FDIR re-initialization, " + "ignored adding FDIR ATR filters\n"); + } +} + +/** + * ixgbe_check_hang_subtask - check for hung queues and dropped interrupts + * @adapter - pointer to the device adapter structure + * + * This function serves two purposes. First it strobes the interrupt lines + * in order to make certain interrupts are occuring. Secondly it sets the + * bits needed to check for TX hangs. As a result we should immediately + * determine if a hang has occured. + */ +static void ixgbe_check_hang_subtask(struct ixgbe_adapter *adapter) { - struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; struct ixgbe_hw *hw = &adapter->hw; u64 eics = 0; int i; - /* - * Do the watchdog outside of interrupt context due to the lovely - * delays that some of the newer hardware requires - */ + /* If we're down or resetting, just bail */ + if (test_bit(__IXGBE_DOWN, &adapter->state) || + test_bit(__IXGBE_RESETTING, &adapter->state)) + return; - if (test_bit(__IXGBE_DOWN, &adapter->state)) - goto watchdog_short_circuit; + /* Force detection of hung controller */ + if (netif_carrier_ok(adapter->netdev)) { + for (i = 0; i < adapter->num_tx_queues; i++) + set_check_for_tx_hang(adapter->tx_ring[i]); + } if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { /* @@ -6005,108 +6033,172 @@ static void ixgbe_watchdog(unsigned long data) */ IXGBE_WRITE_REG(hw, IXGBE_EICS, (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); - goto watchdog_reschedule; + } else { + /* get one bit for every active tx/rx interrupt vector */ + for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { + struct ixgbe_q_vector *qv = adapter->q_vector[i]; + if (qv->rxr_count || qv->txr_count) + eics |= ((u64)1 << i); + } } - /* get one bit for every active tx/rx interrupt vector */ - for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { - struct ixgbe_q_vector *qv = adapter->q_vector[i]; - if (qv->rxr_count || qv->txr_count) - eics |= ((u64)1 << i); - } - - /* Cause software interrupt to ensure rx rings are cleaned */ + /* Cause software interrupt to ensure rings are cleaned */ ixgbe_irq_rearm_queues(adapter, eics); -watchdog_reschedule: - /* Reset the timer */ - mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ)); - -watchdog_short_circuit: - schedule_work(&adapter->watchdog_task); } /** - * ixgbe_multispeed_fiber_task - worker thread to configure multispeed fiber - * @work: pointer to work_struct containing our data + * ixgbe_watchdog_update_link - update the link status + * @adapter - pointer to the device adapter structure + * @link_speed - pointer to a u32 to store the link_speed **/ -static void ixgbe_multispeed_fiber_task(struct work_struct *work) +static void ixgbe_watchdog_update_link(struct ixgbe_adapter *adapter) { - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - multispeed_fiber_task); - struct ixgbe_hw *hw = &adapter->hw; - u32 autoneg; - bool negotiation; - - adapter->flags |= IXGBE_FLAG_IN_SFP_LINK_TASK; - autoneg = hw->phy.autoneg_advertised; - if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) - hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); - hw->mac.autotry_restart = false; - if (hw->mac.ops.setup_link) - hw->mac.ops.setup_link(hw, autoneg, negotiation, true); - adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; - adapter->flags &= ~IXGBE_FLAG_IN_SFP_LINK_TASK; -} - -/** - * ixgbe_sfp_config_module_task - worker thread to configure a new SFP+ module - * @work: pointer to work_struct containing our data - **/ -static void ixgbe_sfp_config_module_task(struct work_struct *work) -{ - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - sfp_config_module_task); - struct ixgbe_hw *hw = &adapter->hw; - u32 err; - - adapter->flags |= IXGBE_FLAG_IN_SFP_MOD_TASK; - - /* Time for electrical oscillations to settle down */ - msleep(100); - err = hw->phy.ops.identify_sfp(hw); - - if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - e_dev_err("failed to initialize because an unsupported SFP+ " - "module type was detected.\n"); - e_dev_err("Reload the driver after installing a supported " - "module.\n"); - unregister_netdev(adapter->netdev); - return; - } - if (hw->mac.ops.setup_sfp) - hw->mac.ops.setup_sfp(hw); - - if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)) - /* This will also work for DA Twinax connections */ - schedule_work(&adapter->multispeed_fiber_task); - adapter->flags &= ~IXGBE_FLAG_IN_SFP_MOD_TASK; -} - -/** - * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table - * @work: pointer to work_struct containing our data - **/ -static void ixgbe_fdir_reinit_task(struct work_struct *work) -{ - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - fdir_reinit_task); struct ixgbe_hw *hw = &adapter->hw; + u32 link_speed = adapter->link_speed; + bool link_up = adapter->link_up; int i; - if (ixgbe_reinit_fdir_tables_82599(hw) == 0) { - for (i = 0; i < adapter->num_tx_queues; i++) - set_bit(__IXGBE_TX_FDIR_INIT_DONE, - &(adapter->tx_ring[i]->state)); + if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)) + return; + + if (hw->mac.ops.check_link) { + hw->mac.ops.check_link(hw, &link_speed, &link_up, false); } else { - e_err(probe, "failed to finish FDIR re-initialization, " - "ignored adding FDIR ATR filters\n"); + /* always assume link is up, if no check link function */ + 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 (link_up || + time_after(jiffies, (adapter->link_check_timeout + + IXGBE_TRY_LINK_TIMEOUT))) { + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC); + IXGBE_WRITE_FLUSH(hw); + } + + adapter->link_up = link_up; + adapter->link_speed = link_speed; +} + +/** + * ixgbe_watchdog_link_is_up - update netif_carrier status and + * print link up message + * @adapter - pointer to the device adapter structure + **/ +static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct ixgbe_hw *hw = &adapter->hw; + u32 link_speed = adapter->link_speed; + bool flow_rx, flow_tx; + + /* only continue if link was previously down */ + if (netif_carrier_ok(netdev)) + return; + + adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP; + + switch (hw->mac.type) { + case ixgbe_mac_82598EB: { + u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); + flow_rx = !!(frctl & IXGBE_FCTRL_RFCE); + flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X); + } + break; + case ixgbe_mac_X540: + case ixgbe_mac_82599EB: { + u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN); + u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG); + flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE); + flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X); + } + break; + default: + flow_tx = false; + flow_rx = false; + break; + } + e_info(drv, "NIC Link is Up %s, Flow Control: %s\n", + (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? + "10 Gbps" : + (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? + "1 Gbps" : + (link_speed == IXGBE_LINK_SPEED_100_FULL ? + "100 Mbps" : + "unknown speed"))), + ((flow_rx && flow_tx) ? "RX/TX" : + (flow_rx ? "RX" : + (flow_tx ? "TX" : "None")))); + + netif_carrier_on(netdev); +#ifdef HAVE_IPLINK_VF_CONFIG + ixgbe_check_vf_rate_limit(adapter); +#endif /* HAVE_IPLINK_VF_CONFIG */ +} + +/** + * ixgbe_watchdog_link_is_down - update netif_carrier status and + * print link down message + * @adapter - pointer to the adapter structure + **/ +static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter* adapter) +{ + struct net_device *netdev = adapter->netdev; + struct ixgbe_hw *hw = &adapter->hw; + + adapter->link_up = false; + adapter->link_speed = 0; + + /* only continue if link was up previously */ + if (!netif_carrier_ok(netdev)) + return; + + /* poll for SFP+ cable when link is down */ + if (ixgbe_is_sfp(hw) && hw->mac.type == ixgbe_mac_82598EB) + adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP; + + e_info(drv, "NIC Link is Down\n"); + netif_carrier_off(netdev); +} + +/** + * ixgbe_watchdog_flush_tx - flush queues on link down + * @adapter - pointer to the device adapter structure + **/ +static void ixgbe_watchdog_flush_tx(struct ixgbe_adapter *adapter) +{ + int i; + int some_tx_pending = 0; + + if (!netif_carrier_ok(adapter->netdev)) { + for (i = 0; i < adapter->num_tx_queues; i++) { + struct ixgbe_ring *tx_ring = adapter->tx_ring[i]; + if (tx_ring->next_to_use != tx_ring->next_to_clean) { + some_tx_pending = 1; + break; + } + } + + if (some_tx_pending) { + /* We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). + */ + adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED; + } } - /* Done FDIR Re-initialization, enable transmits */ - netif_tx_start_all_queues(adapter->netdev); } static void ixgbe_spoof_check(struct ixgbe_adapter *adapter) @@ -6129,133 +6221,186 @@ static void ixgbe_spoof_check(struct ixgbe_adapter *adapter) e_warn(drv, "%d Spoofed packets detected\n", ssvpc); } -static DEFINE_MUTEX(ixgbe_watchdog_lock); - /** - * ixgbe_watchdog_task - worker thread to bring link up - * @work: pointer to work_struct containing our data + * ixgbe_watchdog_subtask - check and bring link up + * @adapter - pointer to the device adapter structure **/ -static void ixgbe_watchdog_task(struct work_struct *work) +static void ixgbe_watchdog_subtask(struct ixgbe_adapter *adapter) { - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - watchdog_task); - struct net_device *netdev = adapter->netdev; - struct ixgbe_hw *hw = &adapter->hw; - u32 link_speed; - bool link_up; - int i; - struct ixgbe_ring *tx_ring; - int some_tx_pending = 0; + /* if interface is down do nothing */ + if (test_bit(__IXGBE_DOWN, &adapter->state)) + return; - mutex_lock(&ixgbe_watchdog_lock); + ixgbe_watchdog_update_link(adapter); - link_up = adapter->link_up; - link_speed = adapter->link_speed; - - if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { - hw->mac.ops.check_link(hw, &link_speed, &link_up, false); - if (link_up) { -#ifdef CONFIG_DCB - 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); - } -#else - hw->mac.ops.fc_enable(hw, 0); -#endif - } - - if (link_up || - time_after(jiffies, (adapter->link_check_timeout + - IXGBE_TRY_LINK_TIMEOUT))) { - adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC); - } - adapter->link_up = link_up; - adapter->link_speed = link_speed; - } - - if (link_up) { - if (!netif_carrier_ok(netdev)) { - bool flow_rx, flow_tx; - - switch (hw->mac.type) { - case ixgbe_mac_82598EB: { - u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL); - u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); - flow_rx = !!(frctl & IXGBE_FCTRL_RFCE); - flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X); - } - break; - case ixgbe_mac_82599EB: - case ixgbe_mac_X540: { - u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN); - u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG); - flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE); - flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X); - } - break; - default: - flow_tx = false; - flow_rx = false; - break; - } - - e_info(drv, "NIC Link is Up %s, Flow Control: %s\n", - (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? - "10 Gbps" : - (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? - "1 Gbps" : - (link_speed == IXGBE_LINK_SPEED_100_FULL ? - "100 Mbps" : - "unknown speed"))), - ((flow_rx && flow_tx) ? "RX/TX" : - (flow_rx ? "RX" : - (flow_tx ? "TX" : "None")))); - - netif_carrier_on(netdev); - ixgbe_check_vf_rate_limit(adapter); - } else { - /* Force detection of hung controller */ - for (i = 0; i < adapter->num_tx_queues; i++) { - tx_ring = adapter->tx_ring[i]; - set_check_for_tx_hang(tx_ring); - } - } - } else { - adapter->link_up = false; - adapter->link_speed = 0; - if (netif_carrier_ok(netdev)) { - e_info(drv, "NIC Link is Down\n"); - netif_carrier_off(netdev); - } - } - - if (!netif_carrier_ok(netdev)) { - for (i = 0; i < adapter->num_tx_queues; i++) { - tx_ring = adapter->tx_ring[i]; - if (tx_ring->next_to_use != tx_ring->next_to_clean) { - some_tx_pending = 1; - break; - } - } - - if (some_tx_pending) { - /* We've lost link, so the controller stops DMA, - * but we've got queued Tx work that's never going - * to get done, so reset controller to flush Tx. - * (Do the reset outside of interrupt context). - */ - schedule_work(&adapter->reset_task); - } - } + if (adapter->link_up) + ixgbe_watchdog_link_is_up(adapter); + else + ixgbe_watchdog_link_is_down(adapter); ixgbe_spoof_check(adapter); ixgbe_update_stats(adapter); - mutex_unlock(&ixgbe_watchdog_lock); + + ixgbe_watchdog_flush_tx(adapter); +} + +/** + * ixgbe_sfp_detection_subtask - poll for SFP+ cable + * @adapter - the ixgbe adapter structure + **/ +static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + s32 err; + + /* not searching for SFP so there is nothing to do here */ + if (!(adapter->flags2 & IXGBE_FLAG2_SEARCH_FOR_SFP) && + !(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET)) + return; + + /* someone else is in init, wait until next service event */ + if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) + return; + + err = hw->phy.ops.identify_sfp(hw); + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) + goto sfp_out; + + if (err == IXGBE_ERR_SFP_NOT_PRESENT) { + /* If no cable is present, then we need to reset + * the next time we find a good cable. */ + adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET; + } + + /* exit on error */ + if (err) + goto sfp_out; + + /* exit if reset not needed */ + if (!(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET)) + goto sfp_out; + + adapter->flags2 &= ~IXGBE_FLAG2_SFP_NEEDS_RESET; + + /* + * A module may be identified correctly, but the EEPROM may not have + * support for that module. setup_sfp() will fail in that case, so + * we should not allow that module to load. + */ + if (hw->mac.type == ixgbe_mac_82598EB) + err = hw->phy.ops.reset(hw); + else + err = hw->mac.ops.setup_sfp(hw); + + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) + goto sfp_out; + + adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG; + e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type); + +sfp_out: + clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); + + if ((err == IXGBE_ERR_SFP_NOT_SUPPORTED) && + (adapter->netdev->reg_state == NETREG_REGISTERED)) { + e_dev_err("failed to initialize because an unsupported " + "SFP+ module type was detected.\n"); + e_dev_err("Reload the driver after installing a " + "supported module.\n"); + unregister_netdev(adapter->netdev); + } +} + +/** + * ixgbe_sfp_link_config_subtask - set up link SFP after module install + * @adapter - the ixgbe adapter structure + **/ +static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 autoneg; + bool negotiation; + + if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_CONFIG)) + return; + + /* someone else is in init, wait until next service event */ + if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) + return; + + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG; + + autoneg = hw->phy.autoneg_advertised; + if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) + hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); + hw->mac.autotry_restart = false; + if (hw->mac.ops.setup_link) + hw->mac.ops.setup_link(hw, autoneg, negotiation, true); + + adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; + adapter->link_check_timeout = jiffies; + clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); +} + +/** + * ixgbe_service_timer - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + **/ +static void ixgbe_service_timer(unsigned long data) +{ + struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; + unsigned long next_event_offset; + + /* poll faster when waiting for link */ + if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) + next_event_offset = HZ / 10; + else + next_event_offset = HZ * 2; + + /* Reset the timer */ + mod_timer(&adapter->service_timer, next_event_offset + jiffies); + + ixgbe_service_event_schedule(adapter); +} + +static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter) +{ + if (!(adapter->flags2 & IXGBE_FLAG2_RESET_REQUESTED)) + return; + + adapter->flags2 &= ~IXGBE_FLAG2_RESET_REQUESTED; + + /* If we're already down or resetting, just bail */ + if (test_bit(__IXGBE_DOWN, &adapter->state) || + test_bit(__IXGBE_RESETTING, &adapter->state)) + return; + + ixgbe_dump(adapter); + netdev_err(adapter->netdev, "Reset adapter\n"); + adapter->tx_timeout_count++; + + ixgbe_reinit_locked(adapter); +} + +/** + * ixgbe_service_task - manages and runs subtasks + * @work: pointer to work_struct containing our data + **/ +static void ixgbe_service_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter = container_of(work, + struct ixgbe_adapter, + service_task); + + ixgbe_reset_subtask(adapter); + ixgbe_sfp_detection_subtask(adapter); + ixgbe_sfp_link_config_subtask(adapter); + ixgbe_check_overtemp_subtask(adapter); + ixgbe_watchdog_subtask(adapter); + ixgbe_fdir_reinit_subtask(adapter); + ixgbe_check_hang_subtask(adapter); + + ixgbe_service_event_complete(adapter); } static int ixgbe_tso(struct ixgbe_adapter *adapter, @@ -7094,6 +7239,8 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter, #ifdef CONFIG_PCI_IOV struct ixgbe_hw *hw = &adapter->hw; int err; + int num_vf_macvlans, i; + struct vf_macvlans *mv_list; if (hw->mac.type == ixgbe_mac_82598EB || !max_vfs) return; @@ -7110,6 +7257,26 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter, e_err(probe, "Failed to enable PCI sriov: %d\n", err); goto err_novfs; } + + num_vf_macvlans = hw->mac.num_rar_entries - + (IXGBE_MAX_PF_MACVLANS + 1 + adapter->num_vfs); + + adapter->mv_list = mv_list = kcalloc(num_vf_macvlans, + sizeof(struct vf_macvlans), + GFP_KERNEL); + if (mv_list) { + /* Initialize list of VF macvlans */ + INIT_LIST_HEAD(&adapter->vf_mvs.l); + for (i = 0; i < num_vf_macvlans; i++) { + mv_list->vf = -1; + mv_list->free = true; + mv_list->rar_entry = hw->mac.num_rar_entries - + (i + adapter->num_vfs + 1); + list_add(&mv_list->l, &adapter->vf_mvs.l); + mv_list++; + } + } + /* If call to enable VFs succeeded then allocate memory * for per VF control structures. */ @@ -7280,22 +7447,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, hw->phy.mdio.mdio_read = ixgbe_mdio_read; hw->phy.mdio.mdio_write = ixgbe_mdio_write; - /* set up this timer and work struct before calling get_invariants - * which might start the timer - */ - init_timer(&adapter->sfp_timer); - adapter->sfp_timer.function = ixgbe_sfp_timer; - adapter->sfp_timer.data = (unsigned long) adapter; - - INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task); - - /* multispeed fiber has its own tasklet, called from GPI SDP1 context */ - INIT_WORK(&adapter->multispeed_fiber_task, ixgbe_multispeed_fiber_task); - - /* a new SFP+ module arrival, called from GPI SDP2 context */ - INIT_WORK(&adapter->sfp_config_module_task, - ixgbe_sfp_config_module_task); - ii->get_invariants(hw); /* setup the private structure */ @@ -7329,17 +7480,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, hw->phy.reset_if_overtemp = false; if (err == IXGBE_ERR_SFP_NOT_PRESENT && hw->mac.type == ixgbe_mac_82598EB) { - /* - * Start a kernel thread to watch for a module to arrive. - * Only do this for 82598, since 82599 will generate - * interrupts on module arrival. - */ - set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - mod_timer(&adapter->sfp_timer, - round_jiffies(jiffies + (2 * HZ))); err = 0; } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - e_dev_err("failed to initialize because an unsupported SFP+ " + e_dev_err("failed to load because an unsupported SFP+ " "module type was detected.\n"); e_dev_err("Reload the driver after installing a supported " "module.\n"); @@ -7361,9 +7504,16 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO6; netdev->features |= NETIF_F_GRO; + netdev->features |= NETIF_F_RXHASH; - if (adapter->hw.mac.type == ixgbe_mac_82599EB) + switch (adapter->hw.mac.type) { + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: netdev->features |= NETIF_F_SCTP_CSUM; + break; + default: + break; + } netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO6; @@ -7424,17 +7574,19 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, (hw->mac.type == ixgbe_mac_82599EB)))) hw->mac.ops.disable_tx_laser(hw); - init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = ixgbe_watchdog; - adapter->watchdog_timer.data = (unsigned long)adapter; + setup_timer(&adapter->service_timer, &ixgbe_service_timer, + (unsigned long) adapter); - INIT_WORK(&adapter->reset_task, ixgbe_reset_task); - INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task); + INIT_WORK(&adapter->service_task, ixgbe_service_task); + clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state); err = ixgbe_init_interrupt_scheme(adapter); if (err) goto err_sw_init; + if (!(adapter->flags & IXGBE_FLAG_RSS_ENABLED)) + netdev->features &= ~NETIF_F_RXHASH; + switch (pdev->device) { case IXGBE_DEV_ID_82599_SFP: /* Only this subdevice supports WOL */ @@ -7463,8 +7615,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* print bus type/speed/width info */ e_dev_info("(PCI Express:%s:%s) %pM\n", - (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0Gb/s" : - hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5Gb/s" : + (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0GT/s" : + hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5GT/s" : "Unknown"), (hw->bus.width == ixgbe_bus_width_pcie_x8 ? "Width x8" : hw->bus.width == ixgbe_bus_width_pcie_x4 ? "Width x4" : @@ -7513,13 +7665,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); - if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || - adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) - INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task); - - if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) - INIT_WORK(&adapter->check_overtemp_task, - ixgbe_check_overtemp_task); #ifdef CONFIG_IXGBE_DCA if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IXGBE_FLAG_DCA_ENABLED; @@ -7546,11 +7691,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, err_eeprom: if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) ixgbe_disable_sriov(adapter); - clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - del_timer_sync(&adapter->sfp_timer); - cancel_work_sync(&adapter->sfp_task); - cancel_work_sync(&adapter->multispeed_fiber_task); - cancel_work_sync(&adapter->sfp_config_module_task); + adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP; iounmap(hw->hw_addr); err_ioremap: free_netdev(netdev); @@ -7578,24 +7719,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) struct net_device *netdev = adapter->netdev; set_bit(__IXGBE_DOWN, &adapter->state); - - /* - * The timers may be rescheduled, so explicitly disable them - * from being rescheduled. - */ - clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - del_timer_sync(&adapter->watchdog_timer); - del_timer_sync(&adapter->sfp_timer); - - cancel_work_sync(&adapter->watchdog_task); - cancel_work_sync(&adapter->sfp_task); - cancel_work_sync(&adapter->multispeed_fiber_task); - cancel_work_sync(&adapter->sfp_config_module_task); - if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || - adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) - cancel_work_sync(&adapter->fdir_reinit_task); - if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) - cancel_work_sync(&adapter->check_overtemp_task); + cancel_work_sync(&adapter->service_task); #ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { diff --git a/drivers/net/ixgbe/ixgbe_mbx.h b/drivers/net/ixgbe/ixgbe_mbx.h index fe6ea81dc7f8..b239bdac38da 100644 --- a/drivers/net/ixgbe/ixgbe_mbx.h +++ b/drivers/net/ixgbe/ixgbe_mbx.h @@ -36,9 +36,6 @@ #define IXGBE_VFMAILBOX 0x002FC #define IXGBE_VFMBMEM 0x00200 -#define IXGBE_PFMAILBOX(x) (0x04B00 + (4 * x)) -#define IXGBE_PFMBMEM(vfn) (0x13000 + (64 * vfn)) - #define IXGBE_PFMAILBOX_STS 0x00000001 /* Initiate message send to VF */ #define IXGBE_PFMAILBOX_ACK 0x00000002 /* Ack message recv'd from VF */ #define IXGBE_PFMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */ @@ -70,6 +67,7 @@ #define IXGBE_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */ #define IXGBE_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */ #define IXGBE_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */ +#define IXGBE_VF_SET_MACVLAN 0x06 /* VF requests PF for unicast filter */ /* length of permanent address message returned from PF */ #define IXGBE_VF_PERMADDR_MSG_LEN 4 diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index df5b8aa4795d..735f686c3b36 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -449,7 +449,8 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) MDIO_MMD_AN, &autoneg_reg); - autoneg_reg &= ~ADVERTISE_100FULL; + autoneg_reg &= ~(ADVERTISE_100FULL | + ADVERTISE_100HALF); if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) autoneg_reg |= ADVERTISE_100FULL; @@ -656,7 +657,8 @@ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) MDIO_MMD_AN, &autoneg_reg); - autoneg_reg &= ~ADVERTISE_100FULL; + autoneg_reg &= ~(ADVERTISE_100FULL | + ADVERTISE_100HALF); if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) autoneg_reg |= ADVERTISE_100FULL; @@ -753,7 +755,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) &phy_data); if ((phy_data & MDIO_CTRL1_RESET) == 0) break; - msleep(10); + usleep_range(10000, 20000); } if ((phy_data & MDIO_CTRL1_RESET) != 0) { @@ -782,7 +784,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) case IXGBE_DELAY_NL: data_offset++; hw_dbg(hw, "DELAY: %d MS\n", edata); - msleep(edata); + usleep_range(edata * 1000, edata * 2000); break; case IXGBE_DATA_NL: hw_dbg(hw, "DATA:\n"); @@ -1220,7 +1222,7 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, swfw_mask = IXGBE_GSSR_PHY0_SM; do { - if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != 0) { + if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != 0) { status = IXGBE_ERR_SWFW_SYNC; goto read_byte_out; } @@ -1267,7 +1269,7 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, break; fail: - ixgbe_release_swfw_sync(hw, swfw_mask); + hw->mac.ops.release_swfw_sync(hw, swfw_mask); msleep(100); ixgbe_i2c_bus_clear(hw); retry++; @@ -1278,7 +1280,7 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, } while (retry < max_retry); - ixgbe_release_swfw_sync(hw, swfw_mask); + hw->mac.ops.release_swfw_sync(hw, swfw_mask); read_byte_out: return status; @@ -1306,7 +1308,7 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, else swfw_mask = IXGBE_GSSR_PHY0_SM; - if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != 0) { + if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != 0) { status = IXGBE_ERR_SWFW_SYNC; goto write_byte_out; } @@ -1350,7 +1352,7 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, hw_dbg(hw, "I2C byte write error.\n"); } while (retry < max_retry); - ixgbe_release_swfw_sync(hw, swfw_mask); + hw->mac.ops.release_swfw_sync(hw, swfw_mask); write_byte_out: return status; diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c index 6e50d8328942..ac99b0458fe2 100644 --- a/drivers/net/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ixgbe/ixgbe_sriov.c @@ -82,6 +82,21 @@ static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter, return 0; } +static void ixgbe_restore_vf_macvlans(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct list_head *pos; + struct vf_macvlans *entry; + + list_for_each(pos, &adapter->vf_mvs.l) { + entry = list_entry(pos, struct vf_macvlans, l); + if (entry->free == false) + hw->mac.ops.set_rar(hw, entry->rar_entry, + entry->vf_macvlan, + entry->vf, IXGBE_RAH_AV); + } +} + void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; @@ -102,6 +117,9 @@ void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg); } } + + /* Restore any VF macvlans */ + ixgbe_restore_vf_macvlans(adapter); } static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, @@ -110,7 +128,7 @@ static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, return adapter->hw.mac.ops.set_vfta(&adapter->hw, vid, vf, (bool)add); } -void ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf) +static void ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf) { struct ixgbe_hw *hw = &adapter->hw; int new_mtu = msgbuf[1]; @@ -200,6 +218,61 @@ static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter, return 0; } +static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter, + int vf, int index, unsigned char *mac_addr) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct list_head *pos; + struct vf_macvlans *entry; + + if (index <= 1) { + list_for_each(pos, &adapter->vf_mvs.l) { + entry = list_entry(pos, struct vf_macvlans, l); + if (entry->vf == vf) { + entry->vf = -1; + entry->free = true; + entry->is_macvlan = false; + hw->mac.ops.clear_rar(hw, entry->rar_entry); + } + } + } + + /* + * If index was zero then we were asked to clear the uc list + * for the VF. We're done. + */ + if (!index) + return 0; + + entry = NULL; + + list_for_each(pos, &adapter->vf_mvs.l) { + entry = list_entry(pos, struct vf_macvlans, l); + if (entry->free) + break; + } + + /* + * If we traversed the entire list and didn't find a free entry + * then we're out of space on the RAR table. Also entry may + * be NULL because the original memory allocation for the list + * failed, which is not fatal but does mean we can't support + * VF requests for MACVLAN because we couldn't allocate + * memory for the list management required. + */ + if (!entry || !entry->free) + return -ENOSPC; + + entry->free = false; + entry->is_macvlan = true; + entry->vf = vf; + memcpy(entry->vf_macvlan, mac_addr, ETH_ALEN); + + hw->mac.ops.set_rar(hw, entry->rar_entry, mac_addr, vf, IXGBE_RAH_AV); + + return 0; +} + int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask) { unsigned char vf_mac_addr[6]; @@ -251,12 +324,12 @@ static inline void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf) static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) { u32 mbx_size = IXGBE_VFMAILBOX_SIZE; - u32 msgbuf[mbx_size]; + u32 msgbuf[IXGBE_VFMAILBOX_SIZE]; struct ixgbe_hw *hw = &adapter->hw; s32 retval; int entries; u16 *hash_list; - int add, vid; + int add, vid, index; u8 *new_mac; retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf); @@ -345,6 +418,24 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) retval = ixgbe_set_vf_vlan(adapter, add, vid, vf); } break; + case IXGBE_VF_SET_MACVLAN: + index = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >> + IXGBE_VT_MSGINFO_SHIFT; + /* + * If the VF is allowed to set MAC filters then turn off + * anti-spoofing to avoid false positives. An index + * greater than 0 will indicate the VF is setting a + * macvlan MAC filter. + */ + if (index > 0 && adapter->antispoofing_enabled) { + hw->mac.ops.set_mac_anti_spoofing(hw, false, + adapter->num_vfs); + hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf); + adapter->antispoofing_enabled = false; + } + retval = ixgbe_set_vf_macvlan(adapter, vf, index, + (unsigned char *)(&msgbuf[1])); + break; default: e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]); retval = IXGBE_ERR_MBX; @@ -452,7 +543,8 @@ int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos) goto out; ixgbe_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf); ixgbe_set_vmolr(hw, vf, false); - hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf); + if (adapter->antispoofing_enabled) + hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf); adapter->vfinfo[vf].pf_vlan = vlan; adapter->vfinfo[vf].pf_qos = qos; dev_info(&adapter->pdev->dev, diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 25c1fb7eda06..fa43f2507f43 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -58,9 +58,11 @@ #define IXGBE_DEV_ID_82599_SFP_FCOE 0x1529 #define IXGBE_SUBDEV_ID_82599_SFP 0x11A9 #define IXGBE_DEV_ID_82599_SFP_EM 0x1507 +#define IXGBE_DEV_ID_82599_SFP_SF2 0x154D #define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC #define IXGBE_DEV_ID_82599_COMBO_BACKPLANE 0x10F8 #define IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ 0x000C +#define IXGBE_DEV_ID_82599_LS 0x154F #define IXGBE_DEV_ID_X540T 0x1528 /* General Registers */ @@ -163,6 +165,9 @@ (0x0D018 + ((_i - 64) * 0x40))) #define IXGBE_RXDCTL(_i) (((_i) < 64) ? (0x01028 + ((_i) * 0x40)) : \ (0x0D028 + ((_i - 64) * 0x40))) +#define IXGBE_RSCCTL(_i) (((_i) < 64) ? (0x0102C + ((_i) * 0x40)) : \ + (0x0D02C + ((_i - 64) * 0x40))) +#define IXGBE_RSCDBU 0x03028 #define IXGBE_RDDCC 0x02F20 #define IXGBE_RXMEMWRAP 0x03190 #define IXGBE_STARCTRL 0x03024 @@ -227,17 +232,23 @@ #define IXGBE_VLVF(_i) (0x0F100 + ((_i) * 4)) /* 64 of these (0-63) */ #define IXGBE_VLVFB(_i) (0x0F200 + ((_i) * 4)) /* 128 of these (0-127) */ #define IXGBE_VMVIR(_i) (0x08000 + ((_i) * 4)) /* 64 of these (0-63) */ -#define IXGBE_VT_CTL 0x051B0 -#define IXGBE_VFRE(_i) (0x051E0 + ((_i) * 4)) -#define IXGBE_VFTE(_i) (0x08110 + ((_i) * 4)) -#define IXGBE_VMECM(_i) (0x08790 + ((_i) * 4)) -#define IXGBE_QDE 0x2F04 -#define IXGBE_VMOLR(_i) (0x0F000 + ((_i) * 4)) /* 64 total */ -#define IXGBE_UTA(_i) (0x0F400 + ((_i) * 4)) -#define IXGBE_VMRCTL(_i) (0x0F600 + ((_i) * 4)) -#define IXGBE_VMRVLAN(_i) (0x0F610 + ((_i) * 4)) -#define IXGBE_VMRVM(_i) (0x0F630 + ((_i) * 4)) -#define IXGBE_L34T_IMIR(_i) (0x0E800 + ((_i) * 4)) /*128 of these (0-127)*/ +#define IXGBE_VT_CTL 0x051B0 +#define IXGBE_PFMAILBOX(_i) (0x04B00 + (4 * (_i))) /* 64 total */ +#define IXGBE_PFMBMEM(_i) (0x13000 + (64 * (_i))) /* 64 Mailboxes, 16 DW each */ +#define IXGBE_PFMBICR(_i) (0x00710 + (4 * (_i))) /* 4 total */ +#define IXGBE_PFMBIMR(_i) (0x00720 + (4 * (_i))) /* 4 total */ +#define IXGBE_VFRE(_i) (0x051E0 + ((_i) * 4)) +#define IXGBE_VFTE(_i) (0x08110 + ((_i) * 4)) +#define IXGBE_VMECM(_i) (0x08790 + ((_i) * 4)) +#define IXGBE_QDE 0x2F04 +#define IXGBE_VMTXSW(_i) (0x05180 + ((_i) * 4)) /* 2 total */ +#define IXGBE_VMOLR(_i) (0x0F000 + ((_i) * 4)) /* 64 total */ +#define IXGBE_UTA(_i) (0x0F400 + ((_i) * 4)) +#define IXGBE_MRCTL(_i) (0x0F600 + ((_i) * 4)) +#define IXGBE_VMRVLAN(_i) (0x0F610 + ((_i) * 4)) +#define IXGBE_VMRVM(_i) (0x0F630 + ((_i) * 4)) +#define IXGBE_L34T_IMIR(_i) (0x0E800 + ((_i) * 4)) /*128 of these (0-127)*/ +#define IXGBE_RXFECCERR0 0x051B8 #define IXGBE_LLITHRESH 0x0EC90 #define IXGBE_IMIR(_i) (0x05A80 + ((_i) * 4)) /* 8 of these (0-7) */ #define IXGBE_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* 8 of these (0-7) */ @@ -364,7 +375,7 @@ #define IXGBE_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */ #define IXGBE_WUFC_FLX_FILTERS 0x000F0000 /* Mask for 4 flex filters */ #define IXGBE_WUFC_EXT_FLX_FILTERS 0x00300000 /* Mask for Ext. flex filters */ -#define IXGBE_WUFC_ALL_FILTERS 0x003F00FF /* Mask for all 6 wakeup filters*/ +#define IXGBE_WUFC_ALL_FILTERS 0x003F00FF /* Mask for all wakeup filters */ #define IXGBE_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ /* Wake Up Status */ @@ -406,7 +417,6 @@ #define IXGBE_SECTXSTAT 0x08804 #define IXGBE_SECTXBUFFAF 0x08808 #define IXGBE_SECTXMINIFG 0x08810 -#define IXGBE_SECTXSTAT 0x08804 #define IXGBE_SECRXCTRL 0x08D00 #define IXGBE_SECRXSTAT 0x08D04 @@ -499,21 +509,6 @@ #define IXGBE_SECTXCTRL_STORE_FORWARD_ENABLE 0x4 -/* HW RSC registers */ -#define IXGBE_RSCCTL(_i) (((_i) < 64) ? (0x0102C + ((_i) * 0x40)) : \ - (0x0D02C + ((_i - 64) * 0x40))) -#define IXGBE_RSCDBU 0x03028 -#define IXGBE_RSCCTL_RSCEN 0x01 -#define IXGBE_RSCCTL_MAXDESC_1 0x00 -#define IXGBE_RSCCTL_MAXDESC_4 0x04 -#define IXGBE_RSCCTL_MAXDESC_8 0x08 -#define IXGBE_RSCCTL_MAXDESC_16 0x0C -#define IXGBE_RXDADV_RSCCNT_SHIFT 17 -#define IXGBE_GPIE_RSC_DELAY_SHIFT 11 -#define IXGBE_RXDADV_RSCCNT_MASK 0x001E0000 -#define IXGBE_RSCDBU_RSCACKDIS 0x00000080 -#define IXGBE_RDRXCTL_RSCFRSTSIZE 0x003E0000 - /* DCB registers */ #define IXGBE_RTRPCS 0x02430 #define IXGBE_RTTDCS 0x04900 @@ -522,6 +517,7 @@ #define IXGBE_RTRUP2TC 0x03020 #define IXGBE_RTTUP2TC 0x0C800 #define IXGBE_RTRPT4C(_i) (0x02140 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_TXLLQ(_i) (0x082E0 + ((_i) * 4)) /* 4 of these (0-3) */ #define IXGBE_RTRPT4S(_i) (0x02160 + ((_i) * 4)) /* 8 of these (0-7) */ #define IXGBE_RTTDT2C(_i) (0x04910 + ((_i) * 4)) /* 8 of these (0-7) */ #define IXGBE_RTTDT2S(_i) (0x04930 + ((_i) * 4)) /* 8 of these (0-7) */ @@ -540,7 +536,7 @@ (IXGBE_RTTBCNRC_RF_DEC_MASK << IXGBE_RTTBCNRC_RF_INT_SHIFT) -/* FCoE registers */ +/* FCoE DMA Context Registers */ #define IXGBE_FCPTRL 0x02410 /* FC User Desc. PTR Low */ #define IXGBE_FCPTRH 0x02414 /* FC USer Desc. PTR High */ #define IXGBE_FCBUFF 0x02418 /* FC Buffer Control */ @@ -677,6 +673,10 @@ #define IXGBE_FCOEDWRC 0x0242C /* Number of FCoE DWords Received */ #define IXGBE_FCOEPTC 0x08784 /* Number of FCoE Packets Transmitted */ #define IXGBE_FCOEDWTC 0x08788 /* Number of FCoE DWords Transmitted */ +#define IXGBE_O2BGPTC 0x041C4 +#define IXGBE_O2BSPC 0x087B0 +#define IXGBE_B2OSPC 0x041C0 +#define IXGBE_B2OGPRC 0x02F90 #define IXGBE_PCRC8ECL 0x0E810 #define IXGBE_PCRC8ECH 0x0E811 #define IXGBE_PCRC8ECH_MASK 0x1F @@ -742,17 +742,10 @@ #define IXGBE_PBACLR_82599 0x11068 #define IXGBE_CIAA_82599 0x11088 #define IXGBE_CIAD_82599 0x1108C -#define IXGBE_PCIE_DIAG_0_82599 0x11090 -#define IXGBE_PCIE_DIAG_1_82599 0x11094 -#define IXGBE_PCIE_DIAG_2_82599 0x11098 -#define IXGBE_PCIE_DIAG_3_82599 0x1109C -#define IXGBE_PCIE_DIAG_4_82599 0x110A0 -#define IXGBE_PCIE_DIAG_5_82599 0x110A4 -#define IXGBE_PCIE_DIAG_6_82599 0x110A8 -#define IXGBE_PCIE_DIAG_7_82599 0x110C0 -#define IXGBE_INTRPT_CSR_82599 0x110B0 -#define IXGBE_INTRPT_MASK_82599 0x110B8 +#define IXGBE_PICAUSE 0x110B0 +#define IXGBE_PIENA 0x110B8 #define IXGBE_CDQ_MBR_82599 0x110B4 +#define IXGBE_PCIESPARE 0x110BC #define IXGBE_MISC_REG_82599 0x110F0 #define IXGBE_ECC_CTRL_0_82599 0x11100 #define IXGBE_ECC_CTRL_1_82599 0x11104 @@ -785,7 +778,19 @@ #define IXGBE_SYSTIML 0x08C0C /* System time register Low - RO */ #define IXGBE_SYSTIMH 0x08C10 /* System time register High - RO */ #define IXGBE_TIMINCA 0x08C14 /* Increment attributes register - RW */ -#define IXGBE_RXUDP 0x08C1C /* Time Sync Rx UDP Port - RW */ +#define IXGBE_TIMADJL 0x08C18 /* Time Adjustment Offset register Low - RW */ +#define IXGBE_TIMADJH 0x08C1C /* Time Adjustment Offset register High - RW */ +#define IXGBE_TSAUXC 0x08C20 /* TimeSync Auxiliary Control register - RW */ +#define IXGBE_TRGTTIML0 0x08C24 /* Target Time Register 0 Low - RW */ +#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_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 */ +#define IXGBE_AUXSTMPH0 0x08C40 /* Auxiliary Time Stamp 0 register High - RO */ +#define IXGBE_AUXSTMPL1 0x08C44 /* Auxiliary Time Stamp 1 register Low - RO */ +#define IXGBE_AUXSTMPH1 0x08C48 /* Auxiliary Time Stamp 1 register High - RO */ /* Diagnostic Registers */ #define IXGBE_RDSTATCTL 0x02C20 @@ -829,8 +834,20 @@ #define IXGBE_TXDATARDPTR(_i) (0x0C720 + ((_i) * 4)) /* 8 of these C720-C72C*/ #define IXGBE_TXDESCRDPTR(_i) (0x0C730 + ((_i) * 4)) /* 8 of these C730-C73C*/ #define IXGBE_PCIEECCCTL 0x1106C +#define IXGBE_RXWRPTR(_i) (0x03100 + ((_i) * 4)) /* 8 of these 3100-310C*/ +#define IXGBE_RXUSED(_i) (0x03120 + ((_i) * 4)) /* 8 of these 3120-312C*/ +#define IXGBE_RXRDPTR(_i) (0x03140 + ((_i) * 4)) /* 8 of these 3140-314C*/ +#define IXGBE_RXRDWRPTR(_i) (0x03160 + ((_i) * 4)) /* 8 of these 3160-310C*/ +#define IXGBE_TXWRPTR(_i) (0x0C100 + ((_i) * 4)) /* 8 of these C100-C10C*/ +#define IXGBE_TXUSED(_i) (0x0C120 + ((_i) * 4)) /* 8 of these C120-C12C*/ +#define IXGBE_TXRDPTR(_i) (0x0C140 + ((_i) * 4)) /* 8 of these C140-C14C*/ +#define IXGBE_TXRDWRPTR(_i) (0x0C160 + ((_i) * 4)) /* 8 of these C160-C10C*/ #define IXGBE_PCIEECCCTL0 0x11100 #define IXGBE_PCIEECCCTL1 0x11104 +#define IXGBE_RXDBUECC 0x03F70 +#define IXGBE_TXDBUECC 0x0CF70 +#define IXGBE_RXDBUEST 0x03F74 +#define IXGBE_TXDBUEST 0x0CF74 #define IXGBE_PBTXECC 0x0C300 #define IXGBE_PBRXECC 0x03300 #define IXGBE_GHECCR 0x110B0 @@ -871,6 +888,7 @@ #define IXGBE_AUTOC3 0x042AC #define IXGBE_ANLP1 0x042B0 #define IXGBE_ANLP2 0x042B4 +#define IXGBE_MACC 0x04330 #define IXGBE_ATLASCTL 0x04800 #define IXGBE_MMNGC 0x042D0 #define IXGBE_ANLPNP1 0x042D4 @@ -883,14 +901,49 @@ #define IXGBE_MPVC 0x04318 #define IXGBE_SGMIIC 0x04314 +/* Statistics Registers */ +#define IXGBE_RXNFGPC 0x041B0 +#define IXGBE_RXNFGBCL 0x041B4 +#define IXGBE_RXNFGBCH 0x041B8 +#define IXGBE_RXDGPC 0x02F50 +#define IXGBE_RXDGBCL 0x02F54 +#define IXGBE_RXDGBCH 0x02F58 +#define IXGBE_RXDDGPC 0x02F5C +#define IXGBE_RXDDGBCL 0x02F60 +#define IXGBE_RXDDGBCH 0x02F64 +#define IXGBE_RXLPBKGPC 0x02F68 +#define IXGBE_RXLPBKGBCL 0x02F6C +#define IXGBE_RXLPBKGBCH 0x02F70 +#define IXGBE_RXDLPBKGPC 0x02F74 +#define IXGBE_RXDLPBKGBCL 0x02F78 +#define IXGBE_RXDLPBKGBCH 0x02F7C +#define IXGBE_TXDGPC 0x087A0 +#define IXGBE_TXDGBCL 0x087A4 +#define IXGBE_TXDGBCH 0x087A8 + +#define IXGBE_RXDSTATCTRL 0x02F40 + +/* Copper Pond 2 link timeout */ #define IXGBE_VALIDATE_LINK_READY_TIMEOUT 50 /* Omer CORECTL */ #define IXGBE_CORECTL 0x014F00 /* BARCTRL */ -#define IXGBE_BARCTRL 0x110F4 -#define IXGBE_BARCTRL_FLSIZE 0x0700 -#define IXGBE_BARCTRL_CSRSIZE 0x2000 +#define IXGBE_BARCTRL 0x110F4 +#define IXGBE_BARCTRL_FLSIZE 0x0700 +#define IXGBE_BARCTRL_FLSIZE_SHIFT 8 +#define IXGBE_BARCTRL_CSRSIZE 0x2000 + +/* RSCCTL Bit Masks */ +#define IXGBE_RSCCTL_RSCEN 0x01 +#define IXGBE_RSCCTL_MAXDESC_1 0x00 +#define IXGBE_RSCCTL_MAXDESC_4 0x04 +#define IXGBE_RSCCTL_MAXDESC_8 0x08 +#define IXGBE_RSCCTL_MAXDESC_16 0x0C + +/* RSCDBU Bit Masks */ +#define IXGBE_RSCDBU_RSCSMALDIS_MASK 0x0000007F +#define IXGBE_RSCDBU_RSCACKDIS 0x00000080 /* RDRXCTL Bit Masks */ #define IXGBE_RDRXCTL_RDMTS_1_2 0x00000000 /* Rx Desc Min Threshold Size */ @@ -898,6 +951,8 @@ #define IXGBE_RDRXCTL_MVMEN 0x00000020 #define IXGBE_RDRXCTL_DMAIDONE 0x00000008 /* DMA init cycle done */ #define IXGBE_RDRXCTL_AGGDIS 0x00010000 /* Aggregation disable */ +#define IXGBE_RDRXCTL_RSCFRSTSIZE 0x003E0000 /* RSC First packet size */ +#define IXGBE_RDRXCTL_RSCLLIDIS 0x00800000 /* Disable RSC compl on LLI */ #define IXGBE_RDRXCTL_RSCACKC 0x02000000 /* must set 1 when RSC enabled */ #define IXGBE_RDRXCTL_FCOE_WRFIX 0x04000000 /* must set 1 when RSC enabled */ @@ -969,8 +1024,8 @@ #define IXGBE_MSCA_OP_CODE_SHIFT 26 /* OP CODE shift */ #define IXGBE_MSCA_ADDR_CYCLE 0x00000000 /* OP CODE 00 (addr cycle) */ #define IXGBE_MSCA_WRITE 0x04000000 /* OP CODE 01 (write) */ -#define IXGBE_MSCA_READ 0x08000000 /* OP CODE 10 (read) */ -#define IXGBE_MSCA_READ_AUTOINC 0x0C000000 /* OP CODE 11 (read, auto inc)*/ +#define IXGBE_MSCA_READ 0x0C000000 /* OP CODE 11 (read) */ +#define IXGBE_MSCA_READ_AUTOINC 0x08000000 /* OP CODE 10 (read, auto inc)*/ #define IXGBE_MSCA_ST_CODE_MASK 0x30000000 /* ST Code mask */ #define IXGBE_MSCA_ST_CODE_SHIFT 28 /* ST Code shift */ #define IXGBE_MSCA_NEW_PROTOCOL 0x00000000 /* ST CODE 00 (new protocol) */ @@ -1057,6 +1112,7 @@ #define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */ #define IXGBE_GPIE_EIAME 0x40000000 #define IXGBE_GPIE_PBA_SUPPORT 0x80000000 +#define IXGBE_GPIE_RSC_DELAY_SHIFT 11 #define IXGBE_GPIE_VTMODE_MASK 0x0000C000 /* VT Mode Mask */ #define IXGBE_GPIE_VTMODE_16 0x00004000 /* 16 VFs 8 queues per VF */ #define IXGBE_GPIE_VTMODE_32 0x00008000 /* 32 VFs 4 queues per VF */ @@ -1291,6 +1347,11 @@ #define IXGBE_FTQF_POOL_SHIFT 8 #define IXGBE_FTQF_5TUPLE_MASK_MASK 0x0000001F #define IXGBE_FTQF_5TUPLE_MASK_SHIFT 25 +#define IXGBE_FTQF_SOURCE_ADDR_MASK 0x1E +#define IXGBE_FTQF_DEST_ADDR_MASK 0x1D +#define IXGBE_FTQF_SOURCE_PORT_MASK 0x1B +#define IXGBE_FTQF_DEST_PORT_MASK 0x17 +#define IXGBE_FTQF_PROTOCOL_COMP_MASK 0x0F #define IXGBE_FTQF_POOL_MASK_EN 0x40000000 #define IXGBE_FTQF_QUEUE_ENABLE 0x80000000 @@ -1333,11 +1394,11 @@ * * Current filters: * EAPOL 802.1x (0x888e): Filter 0 - * BCN (0x8904): Filter 1 + * FCoE (0x8906): Filter 2 * 1588 (0x88f7): Filter 3 + * FIP (0x8914): Filter 4 */ #define IXGBE_ETQF_FILTER_EAPOL 0 -#define IXGBE_ETQF_FILTER_BCN 1 #define IXGBE_ETQF_FILTER_FCOE 2 #define IXGBE_ETQF_FILTER_1588 3 #define IXGBE_ETQF_FILTER_FIP 4 @@ -1448,6 +1509,11 @@ #define IXGBE_AUTOC2_10G_XFI (0x1 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT) #define IXGBE_AUTOC2_10G_SFI (0x2 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT) +#define IXGBE_MACC_FLU 0x00000001 +#define IXGBE_MACC_FSV_10G 0x00030000 +#define IXGBE_MACC_FS 0x00040000 +#define IXGBE_MAC_RX2TX_LPBK 0x00000002 + /* LINKS Bit Masks */ #define IXGBE_LINKS_KX_AN_COMP 0x80000000 #define IXGBE_LINKS_UP 0x40000000 @@ -1501,7 +1567,6 @@ #define IXGBE_ANLP1_ASM_PAUSE 0x0800 #define IXGBE_ANLP1_AN_STATE_MASK 0x000f0000 - /* SW Semaphore Register bitmasks */ #define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ #define IXGBE_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ @@ -1514,6 +1579,10 @@ #define IXGBE_GSSR_PHY1_SM 0x0004 #define IXGBE_GSSR_MAC_CSR_SM 0x0008 #define IXGBE_GSSR_FLASH_SM 0x0010 +#define IXGBE_GSSR_SW_MNG_SM 0x0400 + +/* FW Status register bitmask */ +#define IXGBE_FWSTS_FWRI 0x00000200 /* Firmware Reset Indication */ /* EEC Register */ #define IXGBE_EEC_SK 0x00000001 /* EEPROM Clock */ @@ -1534,6 +1603,7 @@ /* EEPROM Addressing bits based on type (0-small, 1-large) */ #define IXGBE_EEC_ADDR_SIZE 0x00000400 #define IXGBE_EEC_SIZE 0x00007800 /* EEPROM Size */ +#define IXGBE_EERD_MAX_ADDR 0x00003FFF /* EERD alows 14 bits for addr. */ #define IXGBE_EEC_SIZE_SHIFT 11 #define IXGBE_EEPROM_WORD_SIZE_SHIFT 6 @@ -1563,8 +1633,10 @@ #define IXGBE_FW_PTR 0x0F #define IXGBE_PBANUM0_PTR 0x15 #define IXGBE_PBANUM1_PTR 0x16 -#define IXGBE_DEVICE_CAPS 0x2C +#define IXGBE_FREE_SPACE_PTR 0X3E #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_PCIE_MSIX_82598_CAPS 0x62 @@ -1601,6 +1673,10 @@ #define IXGBE_ETH_LENGTH_OF_ADDRESS 6 +#define IXGBE_EEPROM_PAGE_SIZE_MAX 128 +#define IXGBE_EEPROM_RD_BUFFER_MAX_COUNT 512 /* EEPROM words # read in burst */ +#define IXGBE_EEPROM_WR_BUFFER_MAX_COUNT 256 /* EEPROM words # wr in burst */ + #ifndef IXGBE_EEPROM_GRANT_ATTEMPTS #define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */ #endif @@ -1616,14 +1692,25 @@ #define IXGBE_FLUDONE_ATTEMPTS 20000 #endif +#define IXGBE_PCIE_CTRL2 0x5 /* PCIe Control 2 Offset */ +#define IXGBE_PCIE_CTRL2_DUMMY_ENABLE 0x8 /* Dummy Function Enable */ +#define IXGBE_PCIE_CTRL2_LAN_DISABLE 0x2 /* LAN PCI Disable */ +#define IXGBE_PCIE_CTRL2_DISABLE_SELECT 0x1 /* LAN Disable Select */ + #define IXGBE_SAN_MAC_ADDR_PORT0_OFFSET 0x0 #define IXGBE_SAN_MAC_ADDR_PORT1_OFFSET 0x3 #define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 #define IXGBE_DEVICE_CAPS_FCOE_OFFLOADS 0x2 +#define IXGBE_FW_LESM_PARAMETERS_PTR 0x2 +#define IXGBE_FW_LESM_STATE_1 0x1 +#define IXGBE_FW_LESM_STATE_ENABLED 0x8000 /* LESM Enable bit */ #define IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR 0x4 -#define IXGBE_FW_PATCH_VERSION_4 0x7 - -/* Alternative SAN MAC Address Block */ +#define IXGBE_FW_PATCH_VERSION_4 0x7 +#define IXGBE_FCOE_IBA_CAPS_BLK_PTR 0x33 /* iSCSI/FCOE block */ +#define IXGBE_FCOE_IBA_CAPS_FCOE 0x20 /* FCOE flags */ +#define IXGBE_ISCSI_FCOE_BLK_PTR 0x17 /* iSCSI/FCOE block */ +#define IXGBE_ISCSI_FCOE_FLAGS_OFFSET 0x0 /* FCOE flags */ +#define IXGBE_ISCSI_FCOE_FLAGS_ENABLE 0x1 /* FCOE flags enable bit */ #define IXGBE_ALT_SAN_MAC_ADDR_BLK_PTR 0x27 /* Alt. SAN MAC block */ #define IXGBE_ALT_SAN_MAC_ADDR_CAPS_OFFSET 0x0 /* Alt. SAN MAC capability */ #define IXGBE_ALT_SAN_MAC_ADDR_PORT0_OFFSET 0x1 /* Alt. SAN MAC 0 offset */ @@ -1688,6 +1775,7 @@ /* Transmit Config masks */ #define IXGBE_TXDCTL_ENABLE 0x02000000 /* Enable specific Tx Queue */ #define IXGBE_TXDCTL_SWFLSH 0x04000000 /* Tx Desc. write-back flushing */ +#define IXGBE_TXDCTL_WTHRESH_SHIFT 16 /* shift to WTHRESH bits */ /* Enable short packet padding to 64 bytes */ #define IXGBE_TX_PAD_ENABLE 0x00000400 #define IXGBE_JUMBO_FRAME_ENABLE 0x00000004 /* Allow jumbo frames */ @@ -1701,9 +1789,9 @@ #define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */ #define IXGBE_RXCTRL_DMBYPS 0x00000002 /* Descriptor Monitor Bypass */ #define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */ -#define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */ #define IXGBE_RXDCTL_RLPMLMASK 0x00003FFF /* Only supported on the X540 */ #define IXGBE_RXDCTL_RLPML_EN 0x00008000 +#define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */ #define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */ #define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/ @@ -1719,6 +1807,8 @@ #define IXGBE_MFLCN_RPFCE 0x00000004 /* Receive Priority FC Enable */ #define IXGBE_MFLCN_RFCE 0x00000008 /* Receive FC Enable */ +#define IXGBE_MFLCN_RPFCE_SHIFT 4 + /* Multiple Receive Queue Control */ #define IXGBE_MRQC_RSSEN 0x00000001 /* RSS Enable */ #define IXGBE_MRQC_MRQE_MASK 0xF /* Bits 3:0 */ @@ -1859,6 +1949,8 @@ #define IXGBE_RXDADV_PKTTYPE_MASK 0x0000FFF0 #define IXGBE_RXDADV_PKTTYPE_MASK_EX 0x0001FFF0 #define IXGBE_RXDADV_HDRBUFLEN_MASK 0x00007FE0 +#define IXGBE_RXDADV_RSCCNT_MASK 0x001E0000 +#define IXGBE_RXDADV_RSCCNT_SHIFT 17 #define IXGBE_RXDADV_HDRBUFLEN_SHIFT 5 #define IXGBE_RXDADV_SPLITHEADER_EN 0x00001000 #define IXGBE_RXDADV_SPH 0x8000 @@ -1934,15 +2026,6 @@ #define IXGBE_VFLRE(_i) (((_i & 1) ? 0x001C0 : 0x00600)) #define IXGBE_VFLREC(_i) (0x00700 + (_i * 4)) -/* Little Endian defines */ -#ifndef __le32 -#define __le32 u32 -#endif -#ifndef __le64 -#define __le64 u64 - -#endif - enum ixgbe_fdir_pballoc_type { IXGBE_FDIR_PBALLOC_64K = 0, IXGBE_FDIR_PBALLOC_128K, @@ -2141,8 +2224,6 @@ typedef u32 ixgbe_link_speed; IXGBE_LINK_SPEED_1GB_FULL | \ IXGBE_LINK_SPEED_10GB_FULL) -#define IXGBE_PCIE_DEV_CTRL_2 0xC8 -#define PCIE_COMPL_TO_VALUE 0x05 /* Physical layer type */ typedef u32 ixgbe_physical_layer; @@ -2315,6 +2396,7 @@ enum ixgbe_sfp_type { enum ixgbe_media_type { ixgbe_media_type_unknown = 0, ixgbe_media_type_fiber, + ixgbe_media_type_fiber_lco, ixgbe_media_type_copper, ixgbe_media_type_backplane, ixgbe_media_type_cx4, @@ -2478,6 +2560,10 @@ struct ixgbe_hw_stats { u64 fcoeptc; u64 fcoedwrc; u64 fcoedwtc; + u64 b2ospc; + u64 b2ogprc; + u64 o2bgptc; + u64 o2bspc; }; /* forward declaration */ @@ -2491,7 +2577,9 @@ typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr, struct ixgbe_eeprom_operations { s32 (*init_params)(struct ixgbe_hw *); s32 (*read)(struct ixgbe_hw *, u16, u16 *); + s32 (*read_buffer)(struct ixgbe_hw *, u16, u16, u16 *); s32 (*write)(struct ixgbe_hw *, u16, u16); + s32 (*write_buffer)(struct ixgbe_hw *, u16, u16, u16 *); s32 (*validate_checksum)(struct ixgbe_hw *, u16 *); s32 (*update_checksum)(struct ixgbe_hw *); u16 (*calc_checksum)(struct ixgbe_hw *); @@ -2577,6 +2665,7 @@ struct ixgbe_eeprom_info { u32 semaphore_delay; u16 word_size; u16 address_bits; + u16 word_page_size; }; #define IXGBE_FLAGS_DOUBLE_RESET_REQUIRED 0x01 @@ -2597,6 +2686,7 @@ struct ixgbe_mac_info { u32 vft_size; u32 num_rar_entries; u32 rar_highwater; + u32 rx_pb_size; u32 max_tx_queues; u32 max_rx_queues; u32 max_msix_vectors; diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index d9323c08f5c7..4ed687be2fe3 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -37,6 +37,7 @@ #define IXGBE_X540_RAR_ENTRIES 128 #define IXGBE_X540_MC_TBL_SIZE 128 #define IXGBE_X540_VFT_TBL_SIZE 128 +#define IXGBE_X540_RX_PB_SIZE 384 static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw); static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw); @@ -225,6 +226,28 @@ static s32 ixgbe_reset_hw_X540(struct ixgbe_hw *hw) return status; } +/** + * ixgbe_start_hw_X540 - Prepare hardware for Tx/Rx + * @hw: pointer to hardware structure + * + * Starts the hardware using the generic start_hw function + * and the generation start_hw function. + * Then performs revision-specific operations, if any. + **/ +static s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw) +{ + s32 ret_val = 0; + + ret_val = ixgbe_start_hw_generic(hw); + if (ret_val != 0) + goto out; + + ret_val = ixgbe_start_hw_gen2(hw); + hw->mac.rx_pb_size = IXGBE_X540_RX_PB_SIZE; +out: + return ret_val; +} + /** * ixgbe_get_supported_physical_layer_X540 - Returns physical layer type * @hw: pointer to hardware structure @@ -281,74 +304,105 @@ static s32 ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw) } /** - * ixgbe_read_eerd_X540 - Read EEPROM word using EERD - * @hw: pointer to hardware structure - * @offset: offset of word in the EEPROM to read - * @data: word read from the EERPOM + * ixgbe_read_eerd_X540- Read EEPROM word using EERD + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM using the EERD register. **/ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) { - s32 status; + s32 status = 0; - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == + 0) status = ixgbe_read_eerd_generic(hw, offset, data); else status = IXGBE_ERR_SWFW_SYNC; - ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM); + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } /** - * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR - * @hw: pointer to hardware structure - * @offset: offset of word in the EEPROM to write - * @data: word write to the EEPROM + * ixgbe_read_eerd_buffer_X540 - Read EEPROM word(s) using EERD + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to read + * @words: number of words + * @data: word(s) read from the EEPROM * - * Write a 16 bit word to the EEPROM using the EEWR register. + * Reads a 16 bit word(s) from the EEPROM using the EERD register. + **/ +static s32 ixgbe_read_eerd_buffer_X540(struct ixgbe_hw *hw, + u16 offset, u16 words, u16 *data) +{ + s32 status = 0; + + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == + 0) + status = ixgbe_read_eerd_buffer_generic(hw, offset, + words, data); + else + status = IXGBE_ERR_SWFW_SYNC; + + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + return status; +} + +/** + * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to write + * @data: word write to the EEPROM + * + * Write a 16 bit word to the EEPROM using the EEWR register. **/ static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data) { - u32 eewr; - s32 status; + s32 status = 0; - hw->eeprom.ops.init_params(hw); - - if (offset >= hw->eeprom.word_size) { - status = IXGBE_ERR_EEPROM; - goto out; - } - - eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) | - (data << IXGBE_EEPROM_RW_REG_DATA) | - IXGBE_EEPROM_RW_REG_START; - - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { - status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); - if (status != 0) { - hw_dbg(hw, "Eeprom write EEWR timed out\n"); - goto out; - } - - IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr); - - status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); - if (status != 0) { - hw_dbg(hw, "Eeprom write EEWR timed out\n"); - goto out; - } - } else { + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) + status = ixgbe_write_eewr_generic(hw, offset, data); + else status = IXGBE_ERR_SWFW_SYNC; - } -out: - ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM); + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } /** - * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum - * @hw: pointer to hardware structure + * ixgbe_write_eewr_buffer_X540 - Write EEPROM word(s) using EEWR + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to write + * @words: number of words + * @data: word(s) write to the EEPROM + * + * Write a 16 bit word(s) to the EEPROM using the EEWR register. + **/ +static s32 ixgbe_write_eewr_buffer_X540(struct ixgbe_hw *hw, + u16 offset, u16 words, u16 *data) +{ + s32 status = 0; + + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == + 0) + status = ixgbe_write_eewr_buffer_generic(hw, offset, + words, data); + else + status = IXGBE_ERR_SWFW_SYNC; + + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + return status; +} + +/** + * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum + * + * This function does not use synchronization for EERD and EEWR. It can + * be used internally by function which utilize ixgbe_acquire_swfw_sync_X540. + * + * @hw: pointer to hardware structure **/ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) { @@ -359,9 +413,15 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) u16 pointer = 0; u16 word = 0; + /* + * Do not use hw->eeprom.ops.read because we do not want to take + * the synchronization semaphores here. Instead use + * ixgbe_read_eerd_generic + */ + /* Include 0x0-0x3F in the checksum */ for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { - if (hw->eeprom.ops.read(hw, i, &word) != 0) { + if (ixgbe_read_eerd_generic(hw, i, &word) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -376,7 +436,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR) continue; - if (hw->eeprom.ops.read(hw, i, &pointer) != 0) { + if (ixgbe_read_eerd_generic(hw, i, &pointer) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -386,7 +446,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) pointer >= hw->eeprom.word_size) continue; - if (hw->eeprom.ops.read(hw, pointer, &length) != 0) { + if (ixgbe_read_eerd_generic(hw, pointer, &length) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -397,7 +457,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) continue; for (j = pointer+1; j <= pointer+length; j++) { - if (hw->eeprom.ops.read(hw, j, &word) != 0) { + if (ixgbe_read_eerd_generic(hw, j, &word) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -410,6 +470,62 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) return checksum; } +/** + * ixgbe_validate_eeprom_checksum_X540 - Validate EEPROM checksum + * @hw: pointer to hardware structure + * @checksum_val: calculated checksum + * + * Performs checksum calculation and validates the EEPROM checksum. If the + * caller does not need checksum_val, the value can be NULL. + **/ +static s32 ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw, + u16 *checksum_val) +{ + s32 status; + u16 checksum; + u16 read_checksum = 0; + + /* + * 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 + */ + status = hw->eeprom.ops.read(hw, 0, &checksum); + + if (status != 0) { + hw_dbg(hw, "EEPROM read failed\n"); + goto out; + } + + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { + checksum = hw->eeprom.ops.calc_checksum(hw); + + /* + * Do not use hw->eeprom.ops.read because we do not want to take + * the synchronization semaphores twice here. + */ + ixgbe_read_eerd_generic(hw, IXGBE_EEPROM_CHECKSUM, + &read_checksum); + + /* + * Verify read checksum from EEPROM is the same as + * calculated checksum + */ + if (read_checksum != checksum) + status = IXGBE_ERR_EEPROM_CHECKSUM; + + /* If the user cares, return the calculated checksum */ + if (checksum_val) + *checksum_val = checksum; + } else { + status = IXGBE_ERR_SWFW_SYNC; + } + + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); +out: + return status; +} + /** * ixgbe_update_eeprom_checksum_X540 - Updates the EEPROM checksum and flash * @hw: pointer to hardware structure @@ -421,11 +537,35 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) static s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw) { s32 status; + u16 checksum; - status = ixgbe_update_eeprom_checksum_generic(hw); + /* + * 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 + */ + status = hw->eeprom.ops.read(hw, 0, &checksum); - if (status) + if (status != 0) + hw_dbg(hw, "EEPROM read failed\n"); + + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { + checksum = hw->eeprom.ops.calc_checksum(hw); + + /* + * Do not use hw->eeprom.ops.write because we do not want to + * take the synchronization semaphores twice here. + */ + status = ixgbe_write_eewr_generic(hw, IXGBE_EEPROM_CHECKSUM, + checksum); + + if (status == 0) status = ixgbe_update_flash_X540(hw); + else + status = IXGBE_ERR_SWFW_SYNC; + } + + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } @@ -452,7 +592,7 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_EEC, flup); status = ixgbe_poll_flash_update_done_X540(hw); - if (status) + if (status == 0) hw_dbg(hw, "Flash update complete\n"); else hw_dbg(hw, "Flash update time out\n"); @@ -466,11 +606,10 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) } status = ixgbe_poll_flash_update_done_X540(hw); - if (status) + if (status == 0) hw_dbg(hw, "Flash update complete\n"); else hw_dbg(hw, "Flash update time out\n"); - } out: return status; @@ -542,7 +681,7 @@ static s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) * resource (swmask) */ ixgbe_release_swfw_sync_semaphore(hw); - msleep(5); + usleep_range(5000, 10000); } } @@ -564,7 +703,7 @@ static s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) } } - msleep(5); + usleep_range(5000, 10000); return 0; } @@ -588,7 +727,7 @@ static void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync); ixgbe_release_swfw_sync_semaphore(hw); - msleep(5); + usleep_range(5000, 10000); } /** @@ -658,10 +797,70 @@ static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw) IXGBE_WRITE_FLUSH(hw); } +/** + * ixgbe_blink_led_start_X540 - Blink LED based on index. + * @hw: pointer to hardware structure + * @index: led number to blink + * + * Devices that implement the version 2 interface: + * X540 + **/ +static s32 ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index) +{ + u32 macc_reg; + u32 ledctl_reg; + + /* + * In order for the blink bit in the LED control register + * to work, link and speed must be forced in the MAC. We + * will reverse this when we stop the blinking. + */ + macc_reg = IXGBE_READ_REG(hw, IXGBE_MACC); + macc_reg |= IXGBE_MACC_FLU | IXGBE_MACC_FSV_10G | IXGBE_MACC_FS; + IXGBE_WRITE_REG(hw, IXGBE_MACC, macc_reg); + + /* Set the LED to LINK_UP + BLINK. */ + ledctl_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + ledctl_reg &= ~IXGBE_LED_MODE_MASK(index); + ledctl_reg |= IXGBE_LED_BLINK(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, ledctl_reg); + IXGBE_WRITE_FLUSH(hw); + + return 0; +} + +/** + * ixgbe_blink_led_stop_X540 - Stop blinking LED based on index. + * @hw: pointer to hardware structure + * @index: led number to stop blinking + * + * Devices that implement the version 2 interface: + * X540 + **/ +static s32 ixgbe_blink_led_stop_X540(struct ixgbe_hw *hw, u32 index) +{ + u32 macc_reg; + u32 ledctl_reg; + + /* Restore the LED to its default value. */ + ledctl_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + ledctl_reg &= ~IXGBE_LED_MODE_MASK(index); + ledctl_reg |= IXGBE_LED_LINK_ACTIVE << IXGBE_LED_MODE_SHIFT(index); + ledctl_reg &= ~IXGBE_LED_BLINK(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, ledctl_reg); + + /* Unforce link and speed in the MAC. */ + macc_reg = IXGBE_READ_REG(hw, IXGBE_MACC); + macc_reg &= ~(IXGBE_MACC_FLU | IXGBE_MACC_FSV_10G | IXGBE_MACC_FS); + IXGBE_WRITE_REG(hw, IXGBE_MACC, macc_reg); + IXGBE_WRITE_FLUSH(hw); + + return 0; +} static struct ixgbe_mac_operations mac_ops_X540 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_X540, - .start_hw = &ixgbe_start_hw_generic, + .start_hw = &ixgbe_start_hw_X540, .clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic, .get_media_type = &ixgbe_get_media_type_X540, .get_supported_physical_layer = @@ -669,7 +868,7 @@ static struct ixgbe_mac_operations mac_ops_X540 = { .enable_rx_dma = &ixgbe_enable_rx_dma_generic, .get_mac_addr = &ixgbe_get_mac_addr_generic, .get_san_mac_addr = &ixgbe_get_san_mac_addr_generic, - .get_device_caps = NULL, + .get_device_caps = &ixgbe_get_device_caps_generic, .get_wwn_prefix = &ixgbe_get_wwn_prefix_generic, .stop_adapter = &ixgbe_stop_adapter_generic, .get_bus_info = &ixgbe_get_bus_info_generic, @@ -681,8 +880,8 @@ static struct ixgbe_mac_operations mac_ops_X540 = { .get_link_capabilities = &ixgbe_get_copper_link_capabilities_generic, .led_on = &ixgbe_led_on_generic, .led_off = &ixgbe_led_off_generic, - .blink_led_start = &ixgbe_blink_led_start_generic, - .blink_led_stop = &ixgbe_blink_led_stop_generic, + .blink_led_start = &ixgbe_blink_led_start_X540, + .blink_led_stop = &ixgbe_blink_led_stop_X540, .set_rar = &ixgbe_set_rar_generic, .clear_rar = &ixgbe_clear_rar_generic, .set_vmdq = &ixgbe_set_vmdq_generic, @@ -705,9 +904,11 @@ static struct ixgbe_mac_operations mac_ops_X540 = { static struct ixgbe_eeprom_operations eeprom_ops_X540 = { .init_params = &ixgbe_init_eeprom_params_X540, .read = &ixgbe_read_eerd_X540, + .read_buffer = &ixgbe_read_eerd_buffer_X540, .write = &ixgbe_write_eewr_X540, + .write_buffer = &ixgbe_write_eewr_buffer_X540, .calc_checksum = &ixgbe_calc_eeprom_checksum_X540, - .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, + .validate_checksum = &ixgbe_validate_eeprom_checksum_X540, .update_checksum = &ixgbe_update_eeprom_checksum_X540, }; diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c index 0563ab29264e..deee3754b1f7 100644 --- a/drivers/net/ixgbevf/ethtool.c +++ b/drivers/net/ixgbevf/ethtool.c @@ -104,11 +104,13 @@ static int ixgbevf_get_settings(struct net_device *netdev, hw->mac.ops.check_link(hw, &link_speed, &link_up, false); if (link_up) { - ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? - SPEED_10000 : SPEED_1000; + ethtool_cmd_speed_set( + ecmd, + (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? + SPEED_10000 : SPEED_1000); ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index 05fa7c85deed..d7ab202fb95c 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -1460,6 +1460,34 @@ static void ixgbevf_restore_vlan(struct ixgbevf_adapter *adapter) } } +static int ixgbevf_write_uc_addr_list(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + int count = 0; + + if ((netdev_uc_count(netdev)) > 10) { + printk(KERN_ERR "Too many unicast filters - No Space\n"); + return -ENOSPC; + } + + if (!netdev_uc_empty(netdev)) { + struct netdev_hw_addr *ha; + netdev_for_each_uc_addr(ha, netdev) { + hw->mac.ops.set_uc_addr(hw, ++count, ha->addr); + udelay(200); + } + } else { + /* + * If the list is empty then send message to PF driver to + * clear all macvlans on this VF. + */ + hw->mac.ops.set_uc_addr(hw, 0, NULL); + } + + return count; +} + /** * ixgbevf_set_rx_mode - Multicast set * @netdev: network interface device structure @@ -1476,6 +1504,8 @@ static void ixgbevf_set_rx_mode(struct net_device *netdev) /* reprogram multicast list */ if (hw->mac.ops.update_mc_addr_list) hw->mac.ops.update_mc_addr_list(hw, netdev); + + ixgbevf_write_uc_addr_list(netdev); } static void ixgbevf_napi_enable_all(struct ixgbevf_adapter *adapter) diff --git a/drivers/net/ixgbevf/mbx.h b/drivers/net/ixgbevf/mbx.h index b2b5bf5daa3d..ea393eb03f3a 100644 --- a/drivers/net/ixgbevf/mbx.h +++ b/drivers/net/ixgbevf/mbx.h @@ -81,6 +81,7 @@ #define IXGBE_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */ #define IXGBE_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */ #define IXGBE_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */ +#define IXGBE_VF_SET_MACVLAN 0x06 /* VF requests PF for unicast filter */ /* length of permanent address message returned from PF */ #define IXGBE_VF_PERMADDR_MSG_LEN 4 diff --git a/drivers/net/ixgbevf/vf.c b/drivers/net/ixgbevf/vf.c index eecd3bf6833f..aa3682e8c473 100644 --- a/drivers/net/ixgbevf/vf.c +++ b/drivers/net/ixgbevf/vf.c @@ -216,6 +216,39 @@ static s32 ixgbevf_get_mac_addr_vf(struct ixgbe_hw *hw, u8 *mac_addr) return 0; } +static s32 ixgbevf_set_uc_addr_vf(struct ixgbe_hw *hw, u32 index, u8 *addr) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + u32 msgbuf[3]; + u8 *msg_addr = (u8 *)(&msgbuf[1]); + s32 ret_val; + + memset(msgbuf, 0, sizeof(msgbuf)); + /* + * If index is one then this is the start of a new list and needs + * indication to the PF so it can do it's own list management. + * If it is zero then that tells the PF to just clear all of + * this VF's macvlans and there is no new list. + */ + msgbuf[0] |= index << IXGBE_VT_MSGINFO_SHIFT; + msgbuf[0] |= IXGBE_VF_SET_MACVLAN; + if (addr) + memcpy(msg_addr, addr, 6); + ret_val = mbx->ops.write_posted(hw, msgbuf, 3); + + if (!ret_val) + ret_val = mbx->ops.read_posted(hw, msgbuf, 3); + + msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS; + + if (!ret_val) + if (msgbuf[0] == + (IXGBE_VF_SET_MACVLAN | IXGBE_VT_MSGTYPE_NACK)) + ret_val = -ENOMEM; + + return ret_val; +} + /** * ixgbevf_set_rar_vf - set device MAC address * @hw: pointer to hardware structure @@ -378,6 +411,7 @@ static struct ixgbe_mac_operations ixgbevf_mac_ops = { .check_link = ixgbevf_check_mac_link_vf, .set_rar = ixgbevf_set_rar_vf, .update_mc_addr_list = ixgbevf_update_mc_addr_list_vf, + .set_uc_addr = ixgbevf_set_uc_addr_vf, .set_vfta = ixgbevf_set_vfta_vf, }; diff --git a/drivers/net/ixgbevf/vf.h b/drivers/net/ixgbevf/vf.h index 23eb114c149f..10306b492ee6 100644 --- a/drivers/net/ixgbevf/vf.h +++ b/drivers/net/ixgbevf/vf.h @@ -62,6 +62,7 @@ struct ixgbe_mac_operations { /* RAR, Multicast, VLAN */ s32 (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32); + s32 (*set_uc_addr)(struct ixgbe_hw *, u32, u8 *); s32 (*init_rx_addrs)(struct ixgbe_hw *); s32 (*update_mc_addr_list)(struct ixgbe_hw *, struct net_device *); s32 (*enable_mc)(struct ixgbe_hw *); diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 994c80939c7a..b5b174a8c149 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -2230,17 +2230,9 @@ jme_change_mtu(struct net_device *netdev, int new_mtu) jme_restart_rx_engine(jme); } - if (new_mtu > 1900) { - netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_TSO | NETIF_F_TSO6); - } else { - if (test_bit(JME_FLAG_TXCSUM, &jme->flags)) - netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - if (test_bit(JME_FLAG_TSO, &jme->flags)) - netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; - } - netdev->mtu = new_mtu; + netdev_update_features(netdev); + jme_reset_link(jme); return 0; @@ -2563,7 +2555,8 @@ jme_set_settings(struct net_device *netdev, struct jme_adapter *jme = netdev_priv(netdev); int rc, fdc = 0; - if (ecmd->speed == SPEED_1000 && ecmd->autoneg != AUTONEG_ENABLE) + if (ethtool_cmd_speed(ecmd) == SPEED_1000 + && ecmd->autoneg != AUTONEG_ENABLE) return -EINVAL; /* @@ -2640,19 +2633,20 @@ jme_set_msglevel(struct net_device *netdev, u32 value) } static u32 -jme_get_rx_csum(struct net_device *netdev) +jme_fix_features(struct net_device *netdev, u32 features) { - struct jme_adapter *jme = netdev_priv(netdev); - return jme->reg_rxmcs & RXMCS_CHECKSUM; + if (netdev->mtu > 1900) + features &= ~(NETIF_F_ALL_TSO | NETIF_F_ALL_CSUM); + return features; } static int -jme_set_rx_csum(struct net_device *netdev, u32 on) +jme_set_features(struct net_device *netdev, u32 features) { struct jme_adapter *jme = netdev_priv(netdev); spin_lock_bh(&jme->rxmcs_lock); - if (on) + if (features & NETIF_F_RXCSUM) jme->reg_rxmcs |= RXMCS_CHECKSUM; else jme->reg_rxmcs &= ~RXMCS_CHECKSUM; @@ -2662,42 +2656,6 @@ jme_set_rx_csum(struct net_device *netdev, u32 on) return 0; } -static int -jme_set_tx_csum(struct net_device *netdev, u32 on) -{ - struct jme_adapter *jme = netdev_priv(netdev); - - if (on) { - set_bit(JME_FLAG_TXCSUM, &jme->flags); - if (netdev->mtu <= 1900) - netdev->features |= - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - } else { - clear_bit(JME_FLAG_TXCSUM, &jme->flags); - netdev->features &= - ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - } - - return 0; -} - -static int -jme_set_tso(struct net_device *netdev, u32 on) -{ - struct jme_adapter *jme = netdev_priv(netdev); - - if (on) { - set_bit(JME_FLAG_TSO, &jme->flags); - if (netdev->mtu <= 1900) - netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; - } else { - clear_bit(JME_FLAG_TSO, &jme->flags); - netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - } - - return 0; -} - static int jme_nway_reset(struct net_device *netdev) { @@ -2839,11 +2797,6 @@ static const struct ethtool_ops jme_ethtool_ops = { .get_link = jme_get_link, .get_msglevel = jme_get_msglevel, .set_msglevel = jme_set_msglevel, - .get_rx_csum = jme_get_rx_csum, - .set_rx_csum = jme_set_rx_csum, - .set_tx_csum = jme_set_tx_csum, - .set_tso = jme_set_tso, - .set_sg = ethtool_op_set_sg, .nway_reset = jme_nway_reset, .get_eeprom_len = jme_get_eeprom_len, .get_eeprom = jme_get_eeprom, @@ -2903,6 +2856,8 @@ static const struct net_device_ops jme_netdev_ops = { .ndo_change_mtu = jme_change_mtu, .ndo_tx_timeout = jme_tx_timeout, .ndo_vlan_rx_register = jme_vlan_rx_register, + .ndo_fix_features = jme_fix_features, + .ndo_set_features = jme_set_features, }; static int __devinit @@ -2957,6 +2912,12 @@ jme_init_one(struct pci_dev *pdev, netdev->netdev_ops = &jme_netdev_ops; netdev->ethtool_ops = &jme_ethtool_ops; netdev->watchdog_timeo = TX_TIMEOUT; + netdev->hw_features = NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM | + NETIF_F_SG | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_RXCSUM; netdev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_SG | @@ -3040,8 +3001,9 @@ jme_init_one(struct pci_dev *pdev, jme->reg_txpfc = 0; jme->reg_pmcs = PMCS_MFEN; jme->reg_gpreg1 = GPREG1_DEFAULT; - set_bit(JME_FLAG_TXCSUM, &jme->flags); - set_bit(JME_FLAG_TSO, &jme->flags); + + if (jme->reg_rxmcs & RXMCS_CHECKSUM) + netdev->features |= NETIF_F_RXCSUM; /* * Get Max Read Req Size from PCI Config Space diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 8bf30451e821..e9aaeca96abc 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -468,8 +468,6 @@ struct jme_adapter { enum jme_flags_bits { JME_FLAG_MSI = 1, JME_FLAG_SSET = 2, - JME_FLAG_TXCSUM = 3, - JME_FLAG_TSO = 4, JME_FLAG_POLL = 5, JME_FLAG_SHUTDOWN = 6, }; diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 7f7d5708a658..41ea5920c158 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -1221,7 +1221,6 @@ struct ksz_port_info { #define LINK_INT_WORKING (1 << 0) #define SMALL_PACKET_TX_BUG (1 << 1) #define HALF_DUPLEX_SIGNAL_BUG (1 << 2) -#define IPV6_CSUM_GEN_HACK (1 << 3) #define RX_HUGE_FRAME (1 << 4) #define STP_SUPPORT (1 << 8) @@ -3748,7 +3747,6 @@ static int hw_init(struct ksz_hw *hw) if (1 == rc) hw->features |= HALF_DUPLEX_SIGNAL_BUG; } - hw->features |= IPV6_CSUM_GEN_HACK; return rc; } @@ -4887,8 +4885,7 @@ static netdev_tx_t netdev_tx(struct sk_buff *skb, struct net_device *dev) left = hw_alloc_pkt(hw, skb->len, num); if (left) { if (left < num || - ((hw->features & IPV6_CSUM_GEN_HACK) && - (CHECKSUM_PARTIAL == skb->ip_summed) && + ((CHECKSUM_PARTIAL == skb->ip_summed) && (ETH_P_IPV6 == htons(skb->protocol)))) { struct sk_buff *org_skb = skb; @@ -6001,6 +5998,7 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) struct dev_priv *priv = netdev_priv(dev); struct dev_info *hw_priv = priv->adapter; struct ksz_port *port = &priv->port; + u32 speed = ethtool_cmd_speed(cmd); int rc; /* @@ -6009,11 +6007,11 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) */ if (cmd->autoneg && priv->advertising == cmd->advertising) { cmd->advertising |= ADVERTISED_ALL; - if (10 == cmd->speed) + if (10 == speed) cmd->advertising &= ~(ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half); - else if (100 == cmd->speed) + else if (100 == speed) cmd->advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half); @@ -6035,8 +6033,8 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) port->force_link = 0; } else { port->duplex = cmd->duplex + 1; - if (cmd->speed != 1000) - port->speed = cmd->speed; + if (1000 != speed) + port->speed = speed; if (cmd->autoneg) port->force_link = 0; else @@ -6583,57 +6581,33 @@ static void netdev_get_ethtool_stats(struct net_device *dev, } /** - * netdev_get_rx_csum - get receive checksum support + * netdev_set_features - set receive checksum support * @dev: Network device. - * - * This function gets receive checksum support setting. - * - * Return true if receive checksum is enabled; false otherwise. - */ -static u32 netdev_get_rx_csum(struct net_device *dev) -{ - struct dev_priv *priv = netdev_priv(dev); - struct dev_info *hw_priv = priv->adapter; - struct ksz_hw *hw = &hw_priv->hw; - - return hw->rx_cfg & - (DMA_RX_CSUM_UDP | - DMA_RX_CSUM_TCP | - DMA_RX_CSUM_IP); -} - -/** - * netdev_set_rx_csum - set receive checksum support - * @dev: Network device. - * @data: Zero to disable receive checksum support. + * @features: New device features (offloads). * * This function sets receive checksum support setting. * * Return 0 if successful; otherwise an error code. */ -static int netdev_set_rx_csum(struct net_device *dev, u32 data) +static int netdev_set_features(struct net_device *dev, u32 features) { struct dev_priv *priv = netdev_priv(dev); struct dev_info *hw_priv = priv->adapter; struct ksz_hw *hw = &hw_priv->hw; - u32 new_setting = hw->rx_cfg; - if (data) - new_setting |= - (DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP | - DMA_RX_CSUM_IP); - else - new_setting &= - ~(DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP | - DMA_RX_CSUM_IP); - new_setting &= ~DMA_RX_CSUM_UDP; mutex_lock(&hw_priv->lock); - if (new_setting != hw->rx_cfg) { - hw->rx_cfg = new_setting; - if (hw->enabled) - writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL); - } + + /* see note in hw_setup() */ + if (features & NETIF_F_RXCSUM) + hw->rx_cfg |= DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP; + else + hw->rx_cfg &= ~(DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP); + + if (hw->enabled) + writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL); + mutex_unlock(&hw_priv->lock); + return 0; } @@ -6658,12 +6632,6 @@ static struct ethtool_ops netdev_ethtool_ops = { .get_strings = netdev_get_strings, .get_sset_count = netdev_get_sset_count, .get_ethtool_stats = netdev_get_ethtool_stats, - .get_rx_csum = netdev_get_rx_csum, - .set_rx_csum = netdev_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, }; /* @@ -6828,14 +6796,15 @@ static int __init netdev_init(struct net_device *dev) /* 500 ms timeout */ dev->watchdog_timeo = HZ / 2; - dev->features |= NETIF_F_IP_CSUM; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_RXCSUM; /* * Hardware does not really support IPv6 checksum generation, but - * driver actually runs faster with this on. Refer IPV6_CSUM_GEN_HACK. + * driver actually runs faster with this on. */ - dev->features |= NETIF_F_IPV6_CSUM; - dev->features |= NETIF_F_SG; + dev->hw_features |= NETIF_F_IPV6_CSUM; + + dev->features |= dev->hw_features; sema_init(&priv->proc_sem, 1); @@ -6860,6 +6829,7 @@ static const struct net_device_ops netdev_ops = { .ndo_start_xmit = netdev_tx, .ndo_tx_timeout = netdev_tx_timeout, .ndo_change_mtu = netdev_change_mtu, + .ndo_set_features = netdev_set_features, .ndo_set_mac_address = netdev_set_mac_address, .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = netdev_ioctl, diff --git a/drivers/net/lantiq_etop.c b/drivers/net/lantiq_etop.c new file mode 100644 index 000000000000..45f252b7da30 --- /dev/null +++ b/drivers/net/lantiq_etop.c @@ -0,0 +1,805 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2011 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define LTQ_ETOP_MDIO 0x11804 +#define MDIO_REQUEST 0x80000000 +#define MDIO_READ 0x40000000 +#define MDIO_ADDR_MASK 0x1f +#define MDIO_ADDR_OFFSET 0x15 +#define MDIO_REG_MASK 0x1f +#define MDIO_REG_OFFSET 0x10 +#define MDIO_VAL_MASK 0xffff + +#define PPE32_CGEN 0x800 +#define LQ_PPE32_ENET_MAC_CFG 0x1840 + +#define LTQ_ETOP_ENETS0 0x11850 +#define LTQ_ETOP_MAC_DA0 0x1186C +#define LTQ_ETOP_MAC_DA1 0x11870 +#define LTQ_ETOP_CFG 0x16020 +#define LTQ_ETOP_IGPLEN 0x16080 + +#define MAX_DMA_CHAN 0x8 +#define MAX_DMA_CRC_LEN 0x4 +#define MAX_DMA_DATA_LEN 0x600 + +#define ETOP_FTCU BIT(28) +#define ETOP_MII_MASK 0xf +#define ETOP_MII_NORMAL 0xd +#define ETOP_MII_REVERSE 0xe +#define ETOP_PLEN_UNDER 0x40 +#define ETOP_CGEN 0x800 + +/* use 2 static channels for TX/RX */ +#define LTQ_ETOP_TX_CHANNEL 1 +#define LTQ_ETOP_RX_CHANNEL 6 +#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL) +#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL) + +#define ltq_etop_r32(x) ltq_r32(ltq_etop_membase + (x)) +#define ltq_etop_w32(x, y) ltq_w32(x, ltq_etop_membase + (y)) +#define ltq_etop_w32_mask(x, y, z) \ + ltq_w32_mask(x, y, ltq_etop_membase + (z)) + +#define DRV_VERSION "1.0" + +static void __iomem *ltq_etop_membase; + +struct ltq_etop_chan { + int idx; + int tx_free; + struct net_device *netdev; + struct napi_struct napi; + struct ltq_dma_channel dma; + struct sk_buff *skb[LTQ_DESC_NUM]; +}; + +struct ltq_etop_priv { + struct net_device *netdev; + struct ltq_eth_data *pldata; + struct resource *res; + + struct mii_bus *mii_bus; + struct phy_device *phydev; + + struct ltq_etop_chan ch[MAX_DMA_CHAN]; + int tx_free[MAX_DMA_CHAN >> 1]; + + spinlock_t lock; +}; + +static int +ltq_etop_alloc_skb(struct ltq_etop_chan *ch) +{ + ch->skb[ch->dma.desc] = dev_alloc_skb(MAX_DMA_DATA_LEN); + if (!ch->skb[ch->dma.desc]) + return -ENOMEM; + ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL, + ch->skb[ch->dma.desc]->data, MAX_DMA_DATA_LEN, + DMA_FROM_DEVICE); + ch->dma.desc_base[ch->dma.desc].addr = + CPHYSADDR(ch->skb[ch->dma.desc]->data); + ch->dma.desc_base[ch->dma.desc].ctl = + LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) | + MAX_DMA_DATA_LEN; + skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN); + return 0; +} + +static void +ltq_etop_hw_receive(struct ltq_etop_chan *ch) +{ + struct ltq_etop_priv *priv = netdev_priv(ch->netdev); + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; + struct sk_buff *skb = ch->skb[ch->dma.desc]; + int len = (desc->ctl & LTQ_DMA_SIZE_MASK) - MAX_DMA_CRC_LEN; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (ltq_etop_alloc_skb(ch)) { + netdev_err(ch->netdev, + "failed to allocate new rx buffer, stopping DMA\n"); + ltq_dma_close(&ch->dma); + } + ch->dma.desc++; + ch->dma.desc %= LTQ_DESC_NUM; + spin_unlock_irqrestore(&priv->lock, flags); + + skb_put(skb, len); + skb->dev = ch->netdev; + skb->protocol = eth_type_trans(skb, ch->netdev); + netif_receive_skb(skb); +} + +static int +ltq_etop_poll_rx(struct napi_struct *napi, int budget) +{ + struct ltq_etop_chan *ch = container_of(napi, + struct ltq_etop_chan, napi); + int rx = 0; + int complete = 0; + + while ((rx < budget) && !complete) { + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; + + if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { + ltq_etop_hw_receive(ch); + rx++; + } else { + complete = 1; + } + } + if (complete || !rx) { + napi_complete(&ch->napi); + ltq_dma_ack_irq(&ch->dma); + } + return rx; +} + +static int +ltq_etop_poll_tx(struct napi_struct *napi, int budget) +{ + struct ltq_etop_chan *ch = + container_of(napi, struct ltq_etop_chan, napi); + struct ltq_etop_priv *priv = netdev_priv(ch->netdev); + struct netdev_queue *txq = + netdev_get_tx_queue(ch->netdev, ch->idx >> 1); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + while ((ch->dma.desc_base[ch->tx_free].ctl & + (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { + dev_kfree_skb_any(ch->skb[ch->tx_free]); + ch->skb[ch->tx_free] = NULL; + memset(&ch->dma.desc_base[ch->tx_free], 0, + sizeof(struct ltq_dma_desc)); + ch->tx_free++; + ch->tx_free %= LTQ_DESC_NUM; + } + spin_unlock_irqrestore(&priv->lock, flags); + + if (netif_tx_queue_stopped(txq)) + netif_tx_start_queue(txq); + napi_complete(&ch->napi); + ltq_dma_ack_irq(&ch->dma); + return 1; +} + +static irqreturn_t +ltq_etop_dma_irq(int irq, void *_priv) +{ + struct ltq_etop_priv *priv = _priv; + int ch = irq - LTQ_DMA_CH0_INT; + + napi_schedule(&priv->ch[ch].napi); + return IRQ_HANDLED; +} + +static void +ltq_etop_free_channel(struct net_device *dev, struct ltq_etop_chan *ch) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + + ltq_dma_free(&ch->dma); + if (ch->dma.irq) + free_irq(ch->dma.irq, priv); + if (IS_RX(ch->idx)) { + int desc; + for (desc = 0; desc < LTQ_DESC_NUM; desc++) + dev_kfree_skb_any(ch->skb[ch->dma.desc]); + } +} + +static void +ltq_etop_hw_exit(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + int i; + + ltq_pmu_disable(PMU_PPE); + for (i = 0; i < MAX_DMA_CHAN; i++) + if (IS_TX(i) || IS_RX(i)) + ltq_etop_free_channel(dev, &priv->ch[i]); +} + +static int +ltq_etop_hw_init(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + int i; + + ltq_pmu_enable(PMU_PPE); + + switch (priv->pldata->mii_mode) { + case PHY_INTERFACE_MODE_RMII: + ltq_etop_w32_mask(ETOP_MII_MASK, + ETOP_MII_REVERSE, LTQ_ETOP_CFG); + break; + + case PHY_INTERFACE_MODE_MII: + ltq_etop_w32_mask(ETOP_MII_MASK, + ETOP_MII_NORMAL, LTQ_ETOP_CFG); + break; + + default: + netdev_err(dev, "unknown mii mode %d\n", + priv->pldata->mii_mode); + return -ENOTSUPP; + } + + /* enable crc generation */ + ltq_etop_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG); + + ltq_dma_init_port(DMA_PORT_ETOP); + + for (i = 0; i < MAX_DMA_CHAN; i++) { + int irq = LTQ_DMA_CH0_INT + i; + struct ltq_etop_chan *ch = &priv->ch[i]; + + ch->idx = ch->dma.nr = i; + + if (IS_TX(i)) { + ltq_dma_alloc_tx(&ch->dma); + request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, + "etop_tx", priv); + } else if (IS_RX(i)) { + ltq_dma_alloc_rx(&ch->dma); + for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM; + ch->dma.desc++) + if (ltq_etop_alloc_skb(ch)) + return -ENOMEM; + ch->dma.desc = 0; + request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, + "etop_rx", priv); + } + ch->dma.irq = irq; + } + return 0; +} + +static void +ltq_etop_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strcpy(info->driver, "Lantiq ETOP"); + strcpy(info->bus_info, "internal"); + strcpy(info->version, DRV_VERSION); +} + +static int +ltq_etop_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + + return phy_ethtool_gset(priv->phydev, cmd); +} + +static int +ltq_etop_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + + return phy_ethtool_sset(priv->phydev, cmd); +} + +static int +ltq_etop_nway_reset(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + + return phy_start_aneg(priv->phydev); +} + +static const struct ethtool_ops ltq_etop_ethtool_ops = { + .get_drvinfo = ltq_etop_get_drvinfo, + .get_settings = ltq_etop_get_settings, + .set_settings = ltq_etop_set_settings, + .nway_reset = ltq_etop_nway_reset, +}; + +static int +ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data) +{ + u32 val = MDIO_REQUEST | + ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) | + ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET) | + phy_data; + + while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST) + ; + ltq_etop_w32(val, LTQ_ETOP_MDIO); + return 0; +} + +static int +ltq_etop_mdio_rd(struct mii_bus *bus, int phy_addr, int phy_reg) +{ + u32 val = MDIO_REQUEST | MDIO_READ | + ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) | + ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET); + + while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST) + ; + ltq_etop_w32(val, LTQ_ETOP_MDIO); + while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST) + ; + val = ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_VAL_MASK; + return val; +} + +static void +ltq_etop_mdio_link(struct net_device *dev) +{ + /* nothing to do */ +} + +static int +ltq_etop_mdio_probe(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + struct phy_device *phydev = NULL; + int phy_addr; + + for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { + if (priv->mii_bus->phy_map[phy_addr]) { + phydev = priv->mii_bus->phy_map[phy_addr]; + break; + } + } + + if (!phydev) { + netdev_err(dev, "no PHY found\n"); + return -ENODEV; + } + + phydev = phy_connect(dev, dev_name(&phydev->dev), <q_etop_mdio_link, + 0, priv->pldata->mii_mode); + + if (IS_ERR(phydev)) { + netdev_err(dev, "Could not attach to PHY\n"); + return PTR_ERR(phydev); + } + + phydev->supported &= (SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full + | SUPPORTED_Autoneg + | SUPPORTED_MII + | SUPPORTED_TP); + + phydev->advertising = phydev->supported; + priv->phydev = phydev; + pr_info("%s: attached PHY [%s] (phy_addr=%s, irq=%d)\n", + dev->name, phydev->drv->name, + dev_name(&phydev->dev), phydev->irq); + + return 0; +} + +static int +ltq_etop_mdio_init(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + int i; + int err; + + priv->mii_bus = mdiobus_alloc(); + if (!priv->mii_bus) { + netdev_err(dev, "failed to allocate mii bus\n"); + err = -ENOMEM; + goto err_out; + } + + priv->mii_bus->priv = dev; + priv->mii_bus->read = ltq_etop_mdio_rd; + priv->mii_bus->write = ltq_etop_mdio_wr; + priv->mii_bus->name = "ltq_mii"; + snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); + priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!priv->mii_bus->irq) { + err = -ENOMEM; + goto err_out_free_mdiobus; + } + + for (i = 0; i < PHY_MAX_ADDR; ++i) + priv->mii_bus->irq[i] = PHY_POLL; + + if (mdiobus_register(priv->mii_bus)) { + err = -ENXIO; + goto err_out_free_mdio_irq; + } + + if (ltq_etop_mdio_probe(dev)) { + err = -ENXIO; + goto err_out_unregister_bus; + } + return 0; + +err_out_unregister_bus: + mdiobus_unregister(priv->mii_bus); +err_out_free_mdio_irq: + kfree(priv->mii_bus->irq); +err_out_free_mdiobus: + mdiobus_free(priv->mii_bus); +err_out: + return err; +} + +static void +ltq_etop_mdio_cleanup(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + + phy_disconnect(priv->phydev); + mdiobus_unregister(priv->mii_bus); + kfree(priv->mii_bus->irq); + mdiobus_free(priv->mii_bus); +} + +static int +ltq_etop_open(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + int i; + + for (i = 0; i < MAX_DMA_CHAN; i++) { + struct ltq_etop_chan *ch = &priv->ch[i]; + + if (!IS_TX(i) && (!IS_RX(i))) + continue; + ltq_dma_open(&ch->dma); + napi_enable(&ch->napi); + } + phy_start(priv->phydev); + netif_tx_start_all_queues(dev); + return 0; +} + +static int +ltq_etop_stop(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + int i; + + netif_tx_stop_all_queues(dev); + phy_stop(priv->phydev); + for (i = 0; i < MAX_DMA_CHAN; i++) { + struct ltq_etop_chan *ch = &priv->ch[i]; + + if (!IS_RX(i) && !IS_TX(i)) + continue; + napi_disable(&ch->napi); + ltq_dma_close(&ch->dma); + } + return 0; +} + +static int +ltq_etop_tx(struct sk_buff *skb, struct net_device *dev) +{ + int queue = skb_get_queue_mapping(skb); + struct netdev_queue *txq = netdev_get_tx_queue(dev, queue); + struct ltq_etop_priv *priv = netdev_priv(dev); + struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1]; + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; + int len; + unsigned long flags; + u32 byte_offset; + + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + + if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) { + dev_kfree_skb_any(skb); + netdev_err(dev, "tx ring full\n"); + netif_tx_stop_queue(txq); + return NETDEV_TX_BUSY; + } + + /* dma needs to start on a 16 byte aligned address */ + byte_offset = CPHYSADDR(skb->data) % 16; + ch->skb[ch->dma.desc] = skb; + + dev->trans_start = jiffies; + + spin_lock_irqsave(&priv->lock, flags); + desc->addr = ((unsigned int) dma_map_single(NULL, skb->data, len, + DMA_TO_DEVICE)) - byte_offset; + wmb(); + desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP | + LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK); + ch->dma.desc++; + ch->dma.desc %= LTQ_DESC_NUM; + spin_unlock_irqrestore(&priv->lock, flags); + + if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN) + netif_tx_stop_queue(txq); + + return NETDEV_TX_OK; +} + +static int +ltq_etop_change_mtu(struct net_device *dev, int new_mtu) +{ + int ret = eth_change_mtu(dev, new_mtu); + + if (!ret) { + struct ltq_etop_priv *priv = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + ltq_etop_w32((ETOP_PLEN_UNDER << 16) | new_mtu, + LTQ_ETOP_IGPLEN); + spin_unlock_irqrestore(&priv->lock, flags); + } + return ret; +} + +static int +ltq_etop_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + + /* TODO: mii-toll reports "No MII transceiver present!." ?!*/ + return phy_mii_ioctl(priv->phydev, rq, cmd); +} + +static int +ltq_etop_set_mac_address(struct net_device *dev, void *p) +{ + int ret = eth_mac_addr(dev, p); + + if (!ret) { + struct ltq_etop_priv *priv = netdev_priv(dev); + unsigned long flags; + + /* store the mac for the unicast filter */ + spin_lock_irqsave(&priv->lock, flags); + ltq_etop_w32(*((u32 *)dev->dev_addr), LTQ_ETOP_MAC_DA0); + ltq_etop_w32(*((u16 *)&dev->dev_addr[4]) << 16, + LTQ_ETOP_MAC_DA1); + spin_unlock_irqrestore(&priv->lock, flags); + } + return ret; +} + +static void +ltq_etop_set_multicast_list(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + unsigned long flags; + + /* ensure that the unicast filter is not enabled in promiscious mode */ + spin_lock_irqsave(&priv->lock, flags); + if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI)) + ltq_etop_w32_mask(ETOP_FTCU, 0, LTQ_ETOP_ENETS0); + else + ltq_etop_w32_mask(0, ETOP_FTCU, LTQ_ETOP_ENETS0); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static u16 +ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + /* we are currently only using the first queue */ + return 0; +} + +static int +ltq_etop_init(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + struct sockaddr mac; + int err; + + ether_setup(dev); + dev->watchdog_timeo = 10 * HZ; + err = ltq_etop_hw_init(dev); + if (err) + goto err_hw; + ltq_etop_change_mtu(dev, 1500); + + memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr)); + if (!is_valid_ether_addr(mac.sa_data)) { + pr_warn("etop: invalid MAC, using random\n"); + random_ether_addr(mac.sa_data); + } + + err = ltq_etop_set_mac_address(dev, &mac); + if (err) + goto err_netdev; + ltq_etop_set_multicast_list(dev); + err = ltq_etop_mdio_init(dev); + if (err) + goto err_netdev; + return 0; + +err_netdev: + unregister_netdev(dev); + free_netdev(dev); +err_hw: + ltq_etop_hw_exit(dev); + return err; +} + +static void +ltq_etop_tx_timeout(struct net_device *dev) +{ + int err; + + ltq_etop_hw_exit(dev); + err = ltq_etop_hw_init(dev); + if (err) + goto err_hw; + dev->trans_start = jiffies; + netif_wake_queue(dev); + return; + +err_hw: + ltq_etop_hw_exit(dev); + netdev_err(dev, "failed to restart etop after TX timeout\n"); +} + +static const struct net_device_ops ltq_eth_netdev_ops = { + .ndo_open = ltq_etop_open, + .ndo_stop = ltq_etop_stop, + .ndo_start_xmit = ltq_etop_tx, + .ndo_change_mtu = ltq_etop_change_mtu, + .ndo_do_ioctl = ltq_etop_ioctl, + .ndo_set_mac_address = ltq_etop_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = ltq_etop_set_multicast_list, + .ndo_select_queue = ltq_etop_select_queue, + .ndo_init = ltq_etop_init, + .ndo_tx_timeout = ltq_etop_tx_timeout, +}; + +static int __init +ltq_etop_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct ltq_etop_priv *priv; + struct resource *res; + int err; + int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get etop resource\n"); + err = -ENOENT; + goto err_out; + } + + res = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, "failed to request etop resource\n"); + err = -EBUSY; + goto err_out; + } + + ltq_etop_membase = devm_ioremap_nocache(&pdev->dev, + res->start, resource_size(res)); + if (!ltq_etop_membase) { + dev_err(&pdev->dev, "failed to remap etop engine %d\n", + pdev->id); + err = -ENOMEM; + goto err_out; + } + + dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4); + strcpy(dev->name, "eth%d"); + dev->netdev_ops = <q_eth_netdev_ops; + dev->ethtool_ops = <q_etop_ethtool_ops; + priv = netdev_priv(dev); + priv->res = res; + priv->pldata = dev_get_platdata(&pdev->dev); + priv->netdev = dev; + spin_lock_init(&priv->lock); + + for (i = 0; i < MAX_DMA_CHAN; i++) { + if (IS_TX(i)) + netif_napi_add(dev, &priv->ch[i].napi, + ltq_etop_poll_tx, 8); + else if (IS_RX(i)) + netif_napi_add(dev, &priv->ch[i].napi, + ltq_etop_poll_rx, 32); + priv->ch[i].netdev = dev; + } + + err = register_netdev(dev); + if (err) + goto err_free; + + platform_set_drvdata(pdev, dev); + return 0; + +err_free: + kfree(dev); +err_out: + return err; +} + +static int __devexit +ltq_etop_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + + if (dev) { + netif_tx_stop_all_queues(dev); + ltq_etop_hw_exit(dev); + ltq_etop_mdio_cleanup(dev); + unregister_netdev(dev); + } + return 0; +} + +static struct platform_driver ltq_mii_driver = { + .remove = __devexit_p(ltq_etop_remove), + .driver = { + .name = "ltq_etop", + .owner = THIS_MODULE, + }, +}; + +int __init +init_ltq_etop(void) +{ + int ret = platform_driver_probe(<q_mii_driver, ltq_etop_probe); + + if (ret) + pr_err("ltq_etop: Error registering platfom driver!"); + return ret; +} + +static void __exit +exit_ltq_etop(void) +{ + platform_driver_unregister(<q_mii_driver); +} + +module_init(init_ltq_etop); +module_exit(exit_ltq_etop); + +MODULE_AUTHOR("John Crispin "); +MODULE_DESCRIPTION("Lantiq SoC ETOP"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index ea0dc451da9c..4ce9e5f2c069 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -173,7 +173,9 @@ static void loopback_setup(struct net_device *dev) | NETIF_F_RXCSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX - | NETIF_F_NETNS_LOCAL; + | NETIF_F_NETNS_LOCAL + | NETIF_F_VLAN_CHALLENGED + | NETIF_F_LOOPBACK; dev->ethtool_ops = &loopback_ethtool_ops; dev->header_ops = ð_header_ops; dev->netdev_ops = &loopback_ops; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 79ccb54ab00c..629bd2649c0c 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -576,6 +576,11 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) * add that if/when we get our hands on a full-blown MII PHY. */ + if (status & MACB_BIT(ISR_ROVR)) { + /* We missed at least one packet */ + bp->hw_stats.rx_overruns++; + } + if (status & MACB_BIT(HRESP)) { /* * TODO: Reset the hardware, and maybe move the printk @@ -1024,7 +1029,8 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev) hwstat->rx_jabbers + hwstat->rx_undersize_pkts + hwstat->rx_length_mismatch); - nstat->rx_over_errors = hwstat->rx_resource_errors; + nstat->rx_over_errors = hwstat->rx_resource_errors + + hwstat->rx_overruns; nstat->rx_crc_errors = hwstat->rx_fcs_errors; nstat->rx_frame_errors = hwstat->rx_align_errors; nstat->rx_fifo_errors = hwstat->rx_overruns; @@ -1171,8 +1177,7 @@ static int __init macb_probe(struct platform_device *pdev) } dev->irq = platform_get_irq(pdev, 0); - err = request_irq(dev->irq, macb_interrupt, IRQF_SAMPLE_RANDOM, - dev->name, dev); + err = request_irq(dev->irq, macb_interrupt, 0, dev->name, dev); if (err) { printk(KERN_ERR "%s: Unable to request IRQ %d (error %d)\n", diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 78e34e9e4f00..d72a70615c0f 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -70,16 +70,17 @@ static void macvlan_hash_add(struct macvlan_dev *vlan) hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]); } -static void macvlan_hash_del(struct macvlan_dev *vlan) +static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync) { hlist_del_rcu(&vlan->hlist); - synchronize_rcu(); + if (sync) + synchronize_rcu(); } static void macvlan_hash_change_addr(struct macvlan_dev *vlan, const unsigned char *addr) { - macvlan_hash_del(vlan); + macvlan_hash_del(vlan, true); /* Now that we are unhashed it is safe to change the device * address without confusing packet delivery. */ @@ -345,7 +346,7 @@ static int macvlan_stop(struct net_device *dev) dev_uc_del(lowerdev, dev->dev_addr); hash_del: - macvlan_hash_del(vlan); + macvlan_hash_del(vlan, !dev->dismantle); return 0; } @@ -415,7 +416,7 @@ static struct lock_class_key macvlan_netdev_addr_lock_key; #define MACVLAN_FEATURES \ (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \ - NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO) + NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM) #define MACVLAN_STATE_MASK \ ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT)) @@ -517,12 +518,6 @@ static void macvlan_ethtool_get_drvinfo(struct net_device *dev, snprintf(drvinfo->version, 32, "0.1"); } -static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev) -{ - const struct macvlan_dev *vlan = netdev_priv(dev); - return dev_ethtool_get_rx_csum(vlan->lowerdev); -} - static int macvlan_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { @@ -530,18 +525,10 @@ static int macvlan_ethtool_get_settings(struct net_device *dev, return dev_ethtool_get_settings(vlan->lowerdev, cmd); } -static u32 macvlan_ethtool_get_flags(struct net_device *dev) -{ - const struct macvlan_dev *vlan = netdev_priv(dev); - return dev_ethtool_get_flags(vlan->lowerdev); -} - static const struct ethtool_ops macvlan_ethtool_ops = { .get_link = ethtool_op_get_link, .get_settings = macvlan_ethtool_get_settings, - .get_rx_csum = macvlan_ethtool_get_rx_csum, .get_drvinfo = macvlan_ethtool_get_drvinfo, - .get_flags = macvlan_ethtool_get_flags, }; static const struct net_device_ops macvlan_netdev_ops = { @@ -598,26 +585,18 @@ static int macvlan_port_create(struct net_device *dev) err = netdev_rx_handler_register(dev, macvlan_handle_frame, port); if (err) kfree(port); - - dev->priv_flags |= IFF_MACVLAN_PORT; + else + dev->priv_flags |= IFF_MACVLAN_PORT; return err; } -static void macvlan_port_rcu_free(struct rcu_head *head) -{ - struct macvlan_port *port; - - port = container_of(head, struct macvlan_port, rcu); - kfree(port); -} - static void macvlan_port_destroy(struct net_device *dev) { struct macvlan_port *port = macvlan_port_get(dev); dev->priv_flags &= ~IFF_MACVLAN_PORT; netdev_rx_handler_unregister(dev); - call_rcu(&port->rcu, macvlan_port_rcu_free); + kfree_rcu(port, rcu); } static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -799,6 +778,7 @@ static int macvlan_device_event(struct notifier_block *unused, struct net_device *dev = ptr; struct macvlan_dev *vlan, *next; struct macvlan_port *port; + LIST_HEAD(list_kill); if (!macvlan_port_exists(dev)) return NOTIFY_DONE; @@ -824,7 +804,9 @@ static int macvlan_device_event(struct notifier_block *unused, break; list_for_each_entry_safe(vlan, next, &port->vlans, list) - vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL); + vlan->dev->rtnl_link_ops->dellink(vlan->dev, &list_kill); + unregister_netdevice_many(&list_kill); + list_del(&list_kill); break; case NETDEV_PRE_TYPE_CHANGE: /* Forbid underlaying device to change its type. */ diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index e85bf04cf813..16fbb11d92ac 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -176,6 +176,9 @@ static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr) * @npage_adv: Modes currently advertised on next pages * @npage_lpa: Modes advertised by link partner on next pages * + * The @ecmd parameter is expected to have been cleared before calling + * mdio45_ethtool_gset_npage(). + * * Since the CSRs for auto-negotiation using next pages are not fully * standardised, this function does not attempt to decode them. The * caller must pass them in. @@ -185,6 +188,7 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, u32 npage_adv, u32 npage_lpa) { int reg; + u32 speed; ecmd->transceiver = XCVR_INTERNAL; ecmd->phy_address = mdio->prtad; @@ -287,33 +291,36 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, if (modes & (ADVERTISED_10000baseT_Full | ADVERTISED_10000baseKX4_Full | ADVERTISED_10000baseKR_Full)) { - ecmd->speed = SPEED_10000; + speed = SPEED_10000; ecmd->duplex = DUPLEX_FULL; } else if (modes & (ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half | ADVERTISED_1000baseKX_Full)) { - ecmd->speed = SPEED_1000; + speed = SPEED_1000; ecmd->duplex = !(modes & ADVERTISED_1000baseT_Half); } else if (modes & (ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half)) { - ecmd->speed = SPEED_100; + speed = SPEED_100; ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full); } else { - ecmd->speed = SPEED_10; + speed = SPEED_10; ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full); } } else { /* Report forced settings */ reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, MDIO_CTRL1); - ecmd->speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) * - ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10)); + speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) + * ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10)); ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX || - ecmd->speed == SPEED_10000); + speed == SPEED_10000); } + ethtool_cmd_speed_set(ecmd, speed); + /* 10GBASE-T MDI/MDI-X */ - if (ecmd->port == PORT_TP && ecmd->speed == SPEED_10000) { + if (ecmd->port == PORT_TP + && (ethtool_cmd_speed(ecmd) == SPEED_10000)) { switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_SWAPPOL)) { case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 0a6c6a2e7550..c62e7816d548 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -49,6 +49,10 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr) result |= ADVERTISED_100baseT_Half; if (advert & ADVERTISE_100FULL) result |= ADVERTISED_100baseT_Full; + if (advert & ADVERTISE_PAUSE_CAP) + result |= ADVERTISED_Pause; + if (advert & ADVERTISE_PAUSE_ASYM) + result |= ADVERTISED_Asym_Pause; return result; } @@ -58,6 +62,9 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr) * @mii: MII interface * @ecmd: requested ethtool_cmd * + * The @ecmd parameter is expected to have been cleared before calling + * mii_ethtool_gset(). + * * Returns 0 for success, negative on error. */ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) @@ -118,22 +125,25 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) if (nego & (ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half)) { - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full); } else if (nego & (ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half)) { - ecmd->speed = SPEED_100; + ethtool_cmd_speed_set(ecmd, SPEED_100); ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full); } else { - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full); } } else { ecmd->autoneg = AUTONEG_DISABLE; - ecmd->speed = ((bmcr & BMCR_SPEED1000 && - (bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 : - (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10); + ethtool_cmd_speed_set(ecmd, + ((bmcr & BMCR_SPEED1000 && + (bmcr & BMCR_SPEED100) == 0) ? + SPEED_1000 : + ((bmcr & BMCR_SPEED100) ? + SPEED_100 : SPEED_10))); ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } @@ -154,10 +164,11 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) { struct net_device *dev = mii->dev; + u32 speed = ethtool_cmd_speed(ecmd); - if (ecmd->speed != SPEED_10 && - ecmd->speed != SPEED_100 && - ecmd->speed != SPEED_1000) + if (speed != SPEED_10 && + speed != SPEED_100 && + speed != SPEED_1000) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; @@ -169,7 +180,7 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) return -EINVAL; if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) return -EINVAL; - if ((ecmd->speed == SPEED_1000) && (!mii->supports_gmii)) + if ((speed == SPEED_1000) && (!mii->supports_gmii)) return -EINVAL; /* ignore supported, maxtxpkt, maxrxpkt */ @@ -227,9 +238,9 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_FULLDPLX); - if (ecmd->speed == SPEED_1000) + if (speed == SPEED_1000) tmp |= BMCR_SPEED1000; - else if (ecmd->speed == SPEED_100) + else if (speed == SPEED_100) tmp |= BMCR_SPEED100; if (ecmd->duplex == DUPLEX_FULL) { tmp |= BMCR_FULLDPLX; diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index d54b7abf0225..2e858e4dcf4d 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -57,37 +57,6 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) drvinfo->eedump_len = 0; } -static u32 mlx4_en_get_tso(struct net_device *dev) -{ - return (dev->features & NETIF_F_TSO) != 0; -} - -static int mlx4_en_set_tso(struct net_device *dev, u32 data) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - - if (data) { - if (!priv->mdev->LSO_support) - return -EPERM; - dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - } else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - return 0; -} - -static u32 mlx4_en_get_rx_csum(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - return priv->rx_csum; -} - -static int mlx4_en_set_rx_csum(struct net_device *dev, u32 data) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - priv->rx_csum = (data != 0); - return 0; -} - static const char main_strings[][ETH_GSTRING_LEN] = { "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", @@ -296,10 +265,10 @@ static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) trans_type = priv->port_state.transciver; if (netif_carrier_ok(dev)) { - cmd->speed = priv->port_state.link_speed; + ethtool_cmd_speed_set(cmd, priv->port_state.link_speed); cmd->duplex = DUPLEX_FULL; } else { - cmd->speed = -1; + ethtool_cmd_speed_set(cmd, -1); cmd->duplex = -1; } @@ -323,7 +292,8 @@ static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { if ((cmd->autoneg == AUTONEG_ENABLE) || - (cmd->speed != SPEED_10000) || (cmd->duplex != DUPLEX_FULL)) + (ethtool_cmd_speed(cmd) != SPEED_10000) || + (cmd->duplex != DUPLEX_FULL)) return -EINVAL; /* Nothing to change */ @@ -483,17 +453,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { .get_drvinfo = mlx4_en_get_drvinfo, .get_settings = mlx4_en_get_settings, .set_settings = mlx4_en_set_settings, -#ifdef NETIF_F_TSO - .get_tso = mlx4_en_get_tso, - .set_tso = mlx4_en_set_tso, -#endif - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, - .get_rx_csum = mlx4_en_get_rx_csum, - .set_rx_csum = mlx4_en_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, .get_strings = mlx4_en_get_strings, .get_sset_count = mlx4_en_get_sset_count, .get_ethtool_stats = mlx4_en_get_ethtool_stats, @@ -508,7 +468,6 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { .set_pauseparam = mlx4_en_set_pauseparam, .get_ringparam = mlx4_en_get_ringparam, .set_ringparam = mlx4_en_set_ringparam, - .get_flags = ethtool_op_get_flags, }; diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 77063f91c564..61850adae6f7 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -1083,7 +1083,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->prof = prof; priv->port = port; priv->port_up = false; - priv->rx_csum = 1; priv->flags = prof->flags; priv->tx_ring_num = prof->tx_ring_num; priv->rx_ring_num = prof->rx_ring_num; @@ -1141,21 +1140,16 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, /* * Set driver features */ - dev->features |= NETIF_F_SG; - dev->vlan_features |= NETIF_F_SG; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - dev->features |= NETIF_F_HIGHDMA; - dev->features |= NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER; - dev->features |= NETIF_F_GRO; - if (mdev->LSO_support) { - dev->features |= NETIF_F_TSO; - dev->features |= NETIF_F_TSO6; - dev->vlan_features |= NETIF_F_TSO; - dev->vlan_features |= NETIF_F_TSO6; - } + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + if (mdev->LSO_support) + dev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; + + dev->vlan_features = dev->hw_features; + + dev->hw_features |= NETIF_F_RXCSUM; + dev->features = dev->hw_features | NETIF_F_HIGHDMA | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER; mdev->pndev[port] = dev; diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 62dd21b06df4..277215fb9d72 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -584,7 +584,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud ring->bytes += length; ring->packets++; - if (likely(priv->rx_csum)) { + if (likely(dev->features & NETIF_F_RXCSUM)) { if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) && (cqe->checksum == cpu_to_be16(0xffff))) { priv->port_stats.rx_chksum_good++; diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index e30f6099c0de..0b5150df0585 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -451,7 +451,6 @@ struct mlx4_en_priv { int registered; int allocated; int stride; - int rx_csum; u64 mac; int mac_index; unsigned max_mtu; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 34425b94452f..a5d9b1c310b3 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1444,13 +1444,13 @@ mv643xx_eth_get_settings_phyless(struct mv643xx_eth_private *mp, cmd->advertising = ADVERTISED_MII; switch (port_status & PORT_SPEED_MASK) { case PORT_SPEED_10: - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); break; case PORT_SPEED_100: - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); break; case PORT_SPEED_1000: - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); break; default: cmd->speed = -1; @@ -1575,18 +1575,12 @@ mv643xx_eth_set_ringparam(struct net_device *dev, struct ethtool_ringparam *er) return 0; } -static u32 -mv643xx_eth_get_rx_csum(struct net_device *dev) -{ - struct mv643xx_eth_private *mp = netdev_priv(dev); - - return !!(rdlp(mp, PORT_CONFIG) & 0x02000000); -} static int -mv643xx_eth_set_rx_csum(struct net_device *dev, u32 rx_csum) +mv643xx_eth_set_features(struct net_device *dev, u32 features) { struct mv643xx_eth_private *mp = netdev_priv(dev); + u32 rx_csum = features & NETIF_F_RXCSUM; wrlp(mp, PORT_CONFIG, rx_csum ? 0x02000000 : 0x00000000); @@ -1634,11 +1628,6 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *dev, } } -static int mv643xx_eth_set_flags(struct net_device *dev, u32 data) -{ - return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO); -} - static int mv643xx_eth_get_sset_count(struct net_device *dev, int sset) { if (sset == ETH_SS_STATS) @@ -1657,14 +1646,8 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { .set_coalesce = mv643xx_eth_set_coalesce, .get_ringparam = mv643xx_eth_get_ringparam, .set_ringparam = mv643xx_eth_set_ringparam, - .get_rx_csum = mv643xx_eth_get_rx_csum, - .set_rx_csum = mv643xx_eth_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, .get_strings = mv643xx_eth_get_strings, .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, - .get_flags = ethtool_op_get_flags, - .set_flags = mv643xx_eth_set_flags, .get_sset_count = mv643xx_eth_get_sset_count, }; @@ -2264,7 +2247,7 @@ static void port_start(struct mv643xx_eth_private *mp) * frames to RX queue #0, and include the pseudo-header when * calculating receive checksums. */ - wrlp(mp, PORT_CONFIG, 0x02000000); + mv643xx_eth_set_features(mp->dev, mp->dev->features); /* * Treat BPDUs as normal multicasts, and disable partition mode. @@ -2848,6 +2831,7 @@ static const struct net_device_ops mv643xx_eth_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = mv643xx_eth_ioctl, .ndo_change_mtu = mv643xx_eth_change_mtu, + .ndo_set_features = mv643xx_eth_set_features, .ndo_tx_timeout = mv643xx_eth_tx_timeout, .ndo_get_stats = mv643xx_eth_get_stats, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -2930,7 +2914,9 @@ static int mv643xx_eth_probe(struct platform_device *pdev) dev->watchdog_timeo = 2 * HZ; dev->base_addr = 0; - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM | NETIF_F_LRO; + dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM; dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM; SET_NETDEV_DEV(dev, &pdev->dev); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 1446de59ae53..b1358f79ba0a 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -205,7 +205,6 @@ struct myri10ge_priv { int tx_boundary; /* boundary transmits cannot cross */ int num_slices; int running; /* running? */ - int csum_flag; /* rx_csums? */ int small_bytes; int big_bytes; int max_intr_slots; @@ -1386,7 +1385,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum, skb->protocol = eth_type_trans(skb, dev); skb_record_rx_queue(skb, ss - &mgp->ss[0]); - if (mgp->csum_flag) { + if (dev->features & NETIF_F_RXCSUM) { if ((skb->protocol == htons(ETH_P_IP)) || (skb->protocol == htons(ETH_P_IPV6))) { skb->csum = csum; @@ -1645,7 +1644,7 @@ myri10ge_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) int i; cmd->autoneg = AUTONEG_DISABLE; - cmd->speed = SPEED_10000; + ethtool_cmd_speed_set(cmd, SPEED_10000); cmd->duplex = DUPLEX_FULL; /* @@ -1757,43 +1756,6 @@ myri10ge_get_ringparam(struct net_device *netdev, ring->tx_pending = ring->tx_max_pending; } -static u32 myri10ge_get_rx_csum(struct net_device *netdev) -{ - struct myri10ge_priv *mgp = netdev_priv(netdev); - - if (mgp->csum_flag) - return 1; - else - return 0; -} - -static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled) -{ - struct myri10ge_priv *mgp = netdev_priv(netdev); - int err = 0; - - if (csum_enabled) - mgp->csum_flag = MXGEFW_FLAGS_CKSUM; - else { - netdev->features &= ~NETIF_F_LRO; - mgp->csum_flag = 0; - - } - return err; -} - -static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled) -{ - struct myri10ge_priv *mgp = netdev_priv(netdev); - u32 flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO); - - if (tso_enabled) - netdev->features |= flags; - else - netdev->features &= ~flags; - return 0; -} - static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = { "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", @@ -1944,11 +1906,6 @@ static u32 myri10ge_get_msglevel(struct net_device *netdev) return mgp->msg_enable; } -static int myri10ge_set_flags(struct net_device *netdev, u32 value) -{ - return ethtool_op_set_flags(netdev, value, ETH_FLAG_LRO); -} - static const struct ethtool_ops myri10ge_ethtool_ops = { .get_settings = myri10ge_get_settings, .get_drvinfo = myri10ge_get_drvinfo, @@ -1957,19 +1914,12 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { .get_pauseparam = myri10ge_get_pauseparam, .set_pauseparam = myri10ge_set_pauseparam, .get_ringparam = myri10ge_get_ringparam, - .get_rx_csum = myri10ge_get_rx_csum, - .set_rx_csum = myri10ge_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = myri10ge_set_tso, .get_link = ethtool_op_get_link, .get_strings = myri10ge_get_strings, .get_sset_count = myri10ge_get_sset_count, .get_ethtool_stats = myri10ge_get_ethtool_stats, .set_msglevel = myri10ge_set_msglevel, .get_msglevel = myri10ge_get_msglevel, - .get_flags = ethtool_op_get_flags, - .set_flags = myri10ge_set_flags }; static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) @@ -3136,6 +3086,14 @@ static int myri10ge_set_mac_address(struct net_device *dev, void *addr) return 0; } +static u32 myri10ge_fix_features(struct net_device *dev, u32 features) +{ + if (!(features & NETIF_F_RXCSUM)) + features &= ~NETIF_F_LRO; + + return features; +} + static int myri10ge_change_mtu(struct net_device *dev, int new_mtu) { struct myri10ge_priv *mgp = netdev_priv(dev); @@ -3834,6 +3792,7 @@ static const struct net_device_ops myri10ge_netdev_ops = { .ndo_get_stats = myri10ge_get_stats, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = myri10ge_change_mtu, + .ndo_fix_features = myri10ge_fix_features, .ndo_set_multicast_list = myri10ge_set_multicast_list, .ndo_set_mac_address = myri10ge_set_mac_address, }; @@ -3860,7 +3819,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mgp = netdev_priv(netdev); mgp->dev = netdev; mgp->pdev = pdev; - mgp->csum_flag = MXGEFW_FLAGS_CKSUM; mgp->pause = myri10ge_flow_control; mgp->intr_coal_delay = myri10ge_intr_coal_delay; mgp->msg_enable = netif_msg_init(myri10ge_debug, MYRI10GE_MSG_DEFAULT); @@ -3976,11 +3934,11 @@ 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->features = mgp->features; + netdev->hw_features = mgp->features | NETIF_F_LRO | NETIF_F_RXCSUM; + netdev->features = netdev->hw_features; if (dac_enabled) netdev->features |= NETIF_F_HIGHDMA; - netdev->features |= NETIF_F_LRO; netdev->vlan_features |= mgp->features; if (mgp->fw_ver_tiny < 37) diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index aa2813e06d00..b78be088c4ad 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -860,6 +860,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, prev_eedata = eedata; } + /* 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; @@ -2817,7 +2820,7 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) u32 tmp; ecmd->port = dev->if_port; - ecmd->speed = np->speed; + ethtool_cmd_speed_set(ecmd, np->speed); ecmd->duplex = np->duplex; ecmd->autoneg = np->autoneg; ecmd->advertising = 0; @@ -2875,9 +2878,9 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) tmp = mii_nway_result( np->advertising & mdio_read(dev, MII_LPA)); if (tmp == LPA_100FULL || tmp == LPA_100HALF) - ecmd->speed = SPEED_100; + ethtool_cmd_speed_set(ecmd, SPEED_100); else - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); if (tmp == LPA_100FULL || tmp == LPA_10FULL) ecmd->duplex = DUPLEX_FULL; else @@ -2905,7 +2908,8 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) return -EINVAL; } } else if (ecmd->autoneg == AUTONEG_DISABLE) { - if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) + u32 speed = ethtool_cmd_speed(ecmd); + if (speed != SPEED_10 && speed != SPEED_100) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; @@ -2953,7 +2957,7 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) if (ecmd->advertising & ADVERTISED_100baseT_Full) np->advertising |= ADVERTISE_100FULL; } else { - np->speed = ecmd->speed; + np->speed = ethtool_cmd_speed(ecmd); np->duplex = ecmd->duplex; /* user overriding the initial full duplex parm? */ if (np->duplex == DUPLEX_HALF) diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index 30be8c634ebd..7298a34bc795 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -167,7 +167,7 @@ static void cleanup_card(struct net_device *dev) #ifndef MODULE struct net_device * __init ne_probe(int unit) { - struct net_device *dev = alloc_ei_netdev(); + struct net_device *dev = ____alloc_ei_netdev(0); int err; if (!dev) @@ -197,15 +197,15 @@ static const struct net_device_ops ne_netdev_ops = { .ndo_open = ne_open, .ndo_stop = ne_close, - .ndo_start_xmit = ei_start_xmit, - .ndo_tx_timeout = ei_tx_timeout, - .ndo_get_stats = ei_get_stats, - .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_start_xmit = __ei_start_xmit, + .ndo_tx_timeout = __ei_tx_timeout, + .ndo_get_stats = __ei_get_stats, + .ndo_set_multicast_list = __ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ei_poll, + .ndo_poll_controller = __ei_poll, #endif }; @@ -637,7 +637,7 @@ int init_module(void) int err; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = alloc_ei_netdev(); + struct net_device *dev = ____alloc_ei_netdev(0); if (!dev) break; if (io[this_dev]) { diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index 243ed2aee88e..e8984b0ca521 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -80,17 +80,20 @@ static void ne3210_block_output(struct net_device *dev, int count, const unsigne #define NE3210_DEBUG 0x0 -static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3}; -static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0}; -static const char *ifmap[] __initdata = {"UTP", "?", "BNC", "AUI"}; -static int ifmap_val[] __initdata = { +static const unsigned char irq_map[] __devinitconst = + { 15, 12, 11, 10, 9, 7, 5, 3 }; +static const unsigned int shmem_map[] __devinitconst = + { 0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0 }; +static const char *const ifmap[] __devinitconst = + { "UTP", "?", "BNC", "AUI" }; +static const int ifmap_val[] __devinitconst = { IF_PORT_10BASET, IF_PORT_UNKNOWN, IF_PORT_10BASE2, IF_PORT_AUI, }; -static int __init ne3210_eisa_probe (struct device *device) +static int __devinit ne3210_eisa_probe (struct device *device) { unsigned long ioaddr, phys_mem; int i, retval, port_index; @@ -313,7 +316,7 @@ static void ne3210_block_output(struct net_device *dev, int count, memcpy_toio(shmem, buf, count); } -static struct eisa_device_id ne3210_ids[] = { +static const struct eisa_device_id ne3210_ids[] __devinitconst = { { "EGL0101" }, { "NVL1801" }, { "" }, diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index dfb67eb2a94b..a83e101440fd 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -241,34 +241,6 @@ static struct netconsole_target *to_target(struct config_item *item) NULL; } -/* - * Wrapper over simple_strtol (base 10) with sanity and range checking. - * We return (signed) long only because we may want to return errors. - * Do not use this to convert numbers that are allowed to be negative. - */ -static long strtol10_check_range(const char *cp, long min, long max) -{ - long ret; - char *p = (char *) cp; - - WARN_ON(min < 0); - WARN_ON(max < min); - - ret = simple_strtol(p, &p, 10); - - if (*p && (*p != '\n')) { - printk(KERN_ERR "netconsole: invalid input\n"); - return -EINVAL; - } - if ((ret < min) || (ret > max)) { - printk(KERN_ERR "netconsole: input %ld must be between " - "%ld and %ld\n", ret, min, max); - return -EINVAL; - } - - return ret; -} - /* * Attribute operations for netconsole_target. */ @@ -327,12 +299,14 @@ static ssize_t store_enabled(struct netconsole_target *nt, const char *buf, size_t count) { + int enabled; int err; - long enabled; - enabled = strtol10_check_range(buf, 0, 1); - if (enabled < 0) - return enabled; + err = kstrtoint(buf, 10, &enabled); + if (err < 0) + return err; + if (enabled < 0 || enabled > 1) + return -EINVAL; if (enabled) { /* 1 */ @@ -384,8 +358,7 @@ static ssize_t store_local_port(struct netconsole_target *nt, const char *buf, size_t count) { - long local_port; -#define __U16_MAX ((__u16) ~0U) + int rv; if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " @@ -394,12 +367,9 @@ static ssize_t store_local_port(struct netconsole_target *nt, return -EINVAL; } - local_port = strtol10_check_range(buf, 0, __U16_MAX); - if (local_port < 0) - return local_port; - - nt->np.local_port = local_port; - + rv = kstrtou16(buf, 10, &nt->np.local_port); + if (rv < 0) + return rv; return strnlen(buf, count); } @@ -407,8 +377,7 @@ static ssize_t store_remote_port(struct netconsole_target *nt, const char *buf, size_t count) { - long remote_port; -#define __U16_MAX ((__u16) ~0U) + int rv; if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " @@ -417,12 +386,9 @@ static ssize_t store_remote_port(struct netconsole_target *nt, return -EINVAL; } - remote_port = strtol10_check_range(buf, 0, __U16_MAX); - if (remote_port < 0) - return remote_port; - - nt->np.remote_port = remote_port; - + rv = kstrtou16(buf, 10, &nt->np.remote_port); + if (rv < 0) + return rv; return strnlen(buf, count); } @@ -463,8 +429,6 @@ static ssize_t store_remote_mac(struct netconsole_target *nt, size_t count) { u8 remote_mac[ETH_ALEN]; - char *p = (char *) buf; - int i; if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " @@ -473,23 +437,13 @@ static ssize_t store_remote_mac(struct netconsole_target *nt, return -EINVAL; } - for (i = 0; i < ETH_ALEN - 1; i++) { - remote_mac[i] = simple_strtoul(p, &p, 16); - if (*p != ':') - goto invalid; - p++; - } - remote_mac[ETH_ALEN - 1] = simple_strtoul(p, &p, 16); - if (*p && (*p != '\n')) - goto invalid; - + if (!mac_pton(buf, remote_mac)) + return -EINVAL; + if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n') + return -EINVAL; memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); return strnlen(buf, count); - -invalid: - printk(KERN_ERR "netconsole: invalid input\n"); - return -EINVAL; } /* @@ -671,6 +625,7 @@ static int netconsole_netdev_event(struct notifier_block *this, goto done; spin_lock_irqsave(&target_list_lock, flags); +restart: list_for_each_entry(nt, &target_list, list) { netconsole_target_get(nt); if (nt->np.dev == dev) { @@ -683,9 +638,16 @@ static int netconsole_netdev_event(struct notifier_block *this, * rtnl_lock already held */ if (nt->np.dev) { + spin_unlock_irqrestore( + &target_list_lock, + flags); __netpoll_cleanup(&nt->np); + spin_lock_irqsave(&target_list_lock, + flags); dev_put(nt->np.dev); nt->np.dev = NULL; + netconsole_target_put(nt); + goto restart; } /* Fall through */ case NETDEV_GOING_DOWN: diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index d7299f1a4940..77220687b92a 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -174,7 +174,7 @@ #define MAX_NUM_CARDS 4 -#define MAX_BUFFERS_PER_CMD 32 +#define NETXEN_MAX_FRAGS_PER_TX 14 #define MAX_TSO_HEADER_DESC 2 #define MGMT_CMD_DESC_RESV 4 #define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \ @@ -558,7 +558,7 @@ struct netxen_recv_crb { */ struct netxen_cmd_buffer { struct sk_buff *skb; - struct netxen_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1]; + struct netxen_skb_frag frag_array[MAX_SKB_FRAGS + 1]; u32 frag_count; }; @@ -1177,7 +1177,7 @@ struct netxen_adapter { u8 max_sds_rings; u8 driver_mismatch; u8 msix_supported; - u8 rx_csum; + u8 __pad; u8 pci_using_dac; u8 portnum; u8 physical_port; diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 3bdcc803ec68..b34fb74d07e3 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -117,7 +117,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->port = PORT_TP; - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); ecmd->duplex = adapter->link_duplex; ecmd->autoneg = adapter->link_autoneg; @@ -134,7 +134,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } if (netif_running(dev) && adapter->has_link_events) { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); ecmd->autoneg = adapter->link_autoneg; ecmd->duplex = adapter->link_duplex; goto skip; @@ -146,10 +146,10 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) u16 pcifn = adapter->ahw.pci_func; val = NXRD32(adapter, P3_LINK_SPEED_REG(pcifn)); - ecmd->speed = P3_LINK_SPEED_MHZ * - P3_LINK_SPEED_VAL(pcifn, val); + ethtool_cmd_speed_set(ecmd, P3_LINK_SPEED_MHZ * + P3_LINK_SPEED_VAL(pcifn, val)); } else - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); ecmd->duplex = DUPLEX_FULL; ecmd->autoneg = AUTONEG_DISABLE; @@ -251,6 +251,7 @@ static int netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct netxen_adapter *adapter = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(ecmd); int ret; if (adapter->ahw.port_type != NETXEN_NIC_GBE) @@ -259,14 +260,14 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (!(adapter->capabilities & NX_FW_CAPABILITY_GBE_LINK_CFG)) return -EOPNOTSUPP; - ret = nx_fw_cmd_set_gbe_port(adapter, ecmd->speed, ecmd->duplex, + ret = nx_fw_cmd_set_gbe_port(adapter, speed, ecmd->duplex, ecmd->autoneg); if (ret == NX_RCODE_NOT_SUPPORTED) return -EOPNOTSUPP; else if (ret) return -EIO; - adapter->link_speed = ecmd->speed; + adapter->link_speed = speed; adapter->link_duplex = ecmd->duplex; adapter->link_autoneg = ecmd->autoneg; @@ -676,62 +677,6 @@ netxen_nic_get_ethtool_stats(struct net_device *dev, } } -static u32 netxen_nic_get_tx_csum(struct net_device *dev) -{ - return dev->features & NETIF_F_IP_CSUM; -} - -static u32 netxen_nic_get_rx_csum(struct net_device *dev) -{ - struct netxen_adapter *adapter = netdev_priv(dev); - return adapter->rx_csum; -} - -static int netxen_nic_set_rx_csum(struct net_device *dev, u32 data) -{ - struct netxen_adapter *adapter = netdev_priv(dev); - - if (data) { - adapter->rx_csum = data; - return 0; - } - - if (dev->features & NETIF_F_LRO) { - if (netxen_config_hw_lro(adapter, NETXEN_NIC_LRO_DISABLED)) - return -EIO; - - dev->features &= ~NETIF_F_LRO; - netxen_send_lro_cleanup(adapter); - netdev_info(dev, "disabling LRO as rx_csum is off\n"); - } - adapter->rx_csum = data; - return 0; -} - -static u32 netxen_nic_get_tso(struct net_device *dev) -{ - struct netxen_adapter *adapter = netdev_priv(dev); - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0; - - return (dev->features & NETIF_F_TSO) != 0; -} - -static int netxen_nic_set_tso(struct net_device *dev, u32 data) -{ - if (data) { - struct netxen_adapter *adapter = netdev_priv(dev); - - dev->features |= NETIF_F_TSO; - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - dev->features |= NETIF_F_TSO6; - } else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - static void netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { @@ -866,43 +811,6 @@ static int netxen_get_intr_coalesce(struct net_device *netdev, return 0; } -static int netxen_nic_set_flags(struct net_device *netdev, u32 data) -{ - struct netxen_adapter *adapter = netdev_priv(netdev); - int hw_lro; - - if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) - return -EINVAL; - - if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)) - return -EINVAL; - - if (!adapter->rx_csum) { - netdev_info(netdev, "rx csum is off, cannot toggle LRO\n"); - return -EINVAL; - } - - if (!!(data & ETH_FLAG_LRO) == !!(netdev->features & NETIF_F_LRO)) - return 0; - - if (data & ETH_FLAG_LRO) { - hw_lro = NETXEN_NIC_LRO_ENABLED; - netdev->features |= NETIF_F_LRO; - } else { - hw_lro = NETXEN_NIC_LRO_DISABLED; - netdev->features &= ~NETIF_F_LRO; - } - - if (netxen_config_hw_lro(adapter, hw_lro)) - return -EIO; - - if ((hw_lro == 0) && netxen_send_lro_cleanup(adapter)) - return -EIO; - - - return 0; -} - const struct ethtool_ops netxen_nic_ethtool_ops = { .get_settings = netxen_nic_get_settings, .set_settings = netxen_nic_set_settings, @@ -916,21 +824,12 @@ const struct ethtool_ops netxen_nic_ethtool_ops = { .set_ringparam = netxen_nic_set_ringparam, .get_pauseparam = netxen_nic_get_pauseparam, .set_pauseparam = netxen_nic_set_pauseparam, - .get_tx_csum = netxen_nic_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .get_tso = netxen_nic_get_tso, - .set_tso = netxen_nic_set_tso, .get_wol = netxen_nic_get_wol, .set_wol = netxen_nic_set_wol, .self_test = netxen_nic_diag_test, .get_strings = netxen_nic_get_strings, .get_ethtool_stats = netxen_nic_get_ethtool_stats, .get_sset_count = netxen_get_sset_count, - .get_rx_csum = netxen_nic_get_rx_csum, - .set_rx_csum = netxen_nic_set_rx_csum, .get_coalesce = netxen_get_intr_coalesce, .set_coalesce = netxen_set_intr_coalesce, - .get_flags = ethtool_op_get_flags, - .set_flags = netxen_nic_set_flags, }; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 731077d8d962..7f999671c7b2 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1483,7 +1483,8 @@ static struct sk_buff *netxen_process_rxbuf(struct netxen_adapter *adapter, if (!skb) goto no_skb; - if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) { + if (likely((adapter->netdev->features & NETIF_F_RXCSUM) + && cksum == STATUS_CKSUM_OK)) { adapter->stats.csummed++; skb->ip_summed = CHECKSUM_UNNECESSARY; } else diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 83348dc4b184..b644383017f9 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -485,6 +485,37 @@ static void netxen_set_multicast_list(struct net_device *dev) adapter->set_multi(dev); } +static u32 netxen_fix_features(struct net_device *dev, u32 features) +{ + if (!(features & NETIF_F_RXCSUM)) { + netdev_info(dev, "disabling LRO as RXCSUM is off\n"); + + features &= ~NETIF_F_LRO; + } + + return features; +} + +static int netxen_set_features(struct net_device *dev, u32 features) +{ + struct netxen_adapter *adapter = netdev_priv(dev); + int hw_lro; + + if (!((dev->features ^ features) & NETIF_F_LRO)) + return 0; + + hw_lro = (features & NETIF_F_LRO) ? NETXEN_NIC_LRO_ENABLED + : NETXEN_NIC_LRO_DISABLED; + + if (netxen_config_hw_lro(adapter, hw_lro)) + return -EIO; + + if (!(features & NETIF_F_LRO) && netxen_send_lro_cleanup(adapter)) + return -EIO; + + return 0; +} + static const struct net_device_ops netxen_netdev_ops = { .ndo_open = netxen_nic_open, .ndo_stop = netxen_nic_close, @@ -495,6 +526,8 @@ static const struct net_device_ops netxen_netdev_ops = { .ndo_set_mac_address = netxen_nic_set_mac, .ndo_change_mtu = netxen_nic_change_mtu, .ndo_tx_timeout = netxen_tx_timeout, + .ndo_fix_features = netxen_fix_features, + .ndo_set_features = netxen_set_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = netxen_nic_poll_controller, #endif @@ -905,7 +938,7 @@ netxen_nic_request_irq(struct netxen_adapter *adapter) struct nx_host_sds_ring *sds_ring; int err, ring; - unsigned long flags = IRQF_SAMPLE_RANDOM; + unsigned long flags = 0; struct net_device *netdev = adapter->netdev; struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; @@ -1196,7 +1229,6 @@ netxen_setup_netdev(struct netxen_adapter *adapter, int err = 0; struct pci_dev *pdev = adapter->pdev; - adapter->rx_csum = 1; adapter->mc_enabled = 0; if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) adapter->max_mc_count = 38; @@ -1210,14 +1242,13 @@ netxen_setup_netdev(struct netxen_adapter *adapter, SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); - netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); - netdev->features |= (NETIF_F_GRO); - netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_RXCSUM; - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - } + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + netdev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + + netdev->vlan_features |= netdev->hw_features; if (adapter->pci_using_dac) { netdev->features |= NETIF_F_HIGHDMA; @@ -1225,10 +1256,12 @@ netxen_setup_netdev(struct netxen_adapter *adapter, } if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX) - netdev->features |= (NETIF_F_HW_VLAN_TX); + netdev->hw_features |= NETIF_F_HW_VLAN_TX; if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO) - netdev->features |= NETIF_F_LRO; + netdev->hw_features |= NETIF_F_LRO; + + netdev->features |= netdev->hw_features; netdev->irq = adapter->msix_entries[0].vector; @@ -1844,6 +1877,8 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct cmd_desc_type0 *hwdesc, *first_desc; struct pci_dev *pdev; int i, k; + int delta = 0; + struct skb_frag_struct *frag; u32 producer; int frag_count, no_of_desc; @@ -1851,6 +1886,21 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) frag_count = skb_shinfo(skb)->nr_frags + 1; + /* 14 frags supported for normal packet and + * 32 frags supported for TSO packet + */ + if (!skb_is_gso(skb) && frag_count > NETXEN_MAX_FRAGS_PER_TX) { + + for (i = 0; i < (frag_count - NETXEN_MAX_FRAGS_PER_TX); i++) { + frag = &skb_shinfo(skb)->frags[i]; + delta += frag->size; + } + + if (!__pskb_pull_tail(skb, delta)) + goto drop_packet; + + frag_count = 1 + skb_shinfo(skb)->nr_frags; + } /* 4 fragments per cmd des */ no_of_desc = (frag_count + 3) >> 2; diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 32678b6c6b39..cc25bff0bd3b 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -1233,7 +1233,7 @@ static int link_status_1g_rgmii(struct niu *np, int *link_up_p) bmsr = err; if (bmsr & BMSR_LSTATUS) { - u16 adv, lpa, common, estat; + u16 adv, lpa; err = mii_read(np, np->phy_addr, MII_ADVERTISE); if (err < 0) @@ -1245,12 +1245,9 @@ static int link_status_1g_rgmii(struct niu *np, int *link_up_p) goto out; lpa = err; - common = adv & lpa; - err = mii_read(np, np->phy_addr, MII_ESTATUS); if (err < 0) goto out; - estat = err; link_up = 1; current_speed = SPEED_1000; current_duplex = DUPLEX_FULL; @@ -1650,7 +1647,7 @@ static int xcvr_init_10g(struct niu *np) break; } - return 0; + return err; } static int mii_reset(struct niu *np) @@ -2381,17 +2378,14 @@ static int serdes_init_10g_serdes(struct niu *np) struct niu_link_config *lp = &np->link_config; unsigned long ctrl_reg, test_cfg_reg, pll_cfg, i; u64 ctrl_val, test_cfg_val, sig, mask, val; - u64 reset_val; switch (np->port) { case 0: - reset_val = ENET_SERDES_RESET_0; ctrl_reg = ENET_SERDES_0_CTRL_CFG; test_cfg_reg = ENET_SERDES_0_TEST_CFG; pll_cfg = ENET_SERDES_0_PLL_CFG; break; case 1: - reset_val = ENET_SERDES_RESET_1; ctrl_reg = ENET_SERDES_1_CTRL_CFG; test_cfg_reg = ENET_SERDES_1_TEST_CFG; pll_cfg = ENET_SERDES_1_PLL_CFG; @@ -6071,8 +6065,7 @@ static int niu_request_irq(struct niu *np) for (i = 0; i < np->num_ldg; i++) { struct niu_ldg *lp = &np->ldg[i]; - err = request_irq(lp->irq, niu_interrupt, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, + err = request_irq(lp->irq, niu_interrupt, IRQF_SHARED, np->irq_name[i], lp); if (err) goto out_free_irqs; @@ -6851,7 +6844,7 @@ static int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported = lp->supported; cmd->advertising = lp->active_advertising; cmd->autoneg = lp->active_autoneg; - cmd->speed = lp->active_speed; + ethtool_cmd_speed_set(cmd, lp->active_speed); cmd->duplex = lp->active_duplex; cmd->port = (np->flags & NIU_FLAGS_FIBER) ? PORT_FIBRE : PORT_TP; cmd->transceiver = (np->flags & NIU_FLAGS_XCVR_SERDES) ? @@ -6866,7 +6859,7 @@ static int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) struct niu_link_config *lp = &np->link_config; lp->advertising = cmd->advertising; - lp->speed = cmd->speed; + lp->speed = ethtool_cmd_speed(cmd); lp->duplex = cmd->duplex; lp->autoneg = cmd->autoneg; return niu_init_link(np); @@ -7023,6 +7016,7 @@ static int niu_ethflow_to_class(int flow_type, u64 *class) case UDP_V4_FLOW: *class = CLASS_CODE_UDP_IPV4; break; + case AH_ESP_V4_FLOW: case AH_V4_FLOW: case ESP_V4_FLOW: *class = CLASS_CODE_AH_ESP_IPV4; @@ -7036,6 +7030,7 @@ static int niu_ethflow_to_class(int flow_type, u64 *class) case UDP_V6_FLOW: *class = CLASS_CODE_UDP_IPV6; break; + case AH_ESP_V6_FLOW: case AH_V6_FLOW: case ESP_V6_FLOW: *class = CLASS_CODE_AH_ESP_IPV6; @@ -7889,37 +7884,35 @@ static void niu_force_led(struct niu *np, int on) nw64_mac(reg, val); } -static int niu_phys_id(struct net_device *dev, u32 data) +static int niu_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) + { struct niu *np = netdev_priv(dev); - u64 orig_led_state; - int i; if (!netif_running(dev)) return -EAGAIN; - if (data == 0) - data = 2; + switch (state) { + case ETHTOOL_ID_ACTIVE: + np->orig_led_state = niu_led_state_save(np); + return 1; /* cycle on/off once per second */ - orig_led_state = niu_led_state_save(np); - for (i = 0; i < (data * 2); i++) { - int on = ((i % 2) == 0); + case ETHTOOL_ID_ON: + niu_force_led(np, 1); + break; - niu_force_led(np, on); + case ETHTOOL_ID_OFF: + niu_force_led(np, 0); + break; - if (msleep_interruptible(500)) - break; + case ETHTOOL_ID_INACTIVE: + niu_led_state_restore(np, np->orig_led_state); } - niu_led_state_restore(np, orig_led_state); return 0; } -static int niu_set_flags(struct net_device *dev, u32 data) -{ - return ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH); -} - static const struct ethtool_ops niu_ethtool_ops = { .get_drvinfo = niu_get_drvinfo, .get_link = ethtool_op_get_link, @@ -7933,11 +7926,9 @@ static const struct ethtool_ops niu_ethtool_ops = { .get_strings = niu_get_strings, .get_sset_count = niu_get_sset_count, .get_ethtool_stats = niu_get_ethtool_stats, - .phys_id = niu_phys_id, + .set_phys_id = niu_set_phys_id, .get_rxnfc = niu_get_nfc, .set_rxnfc = niu_set_nfc, - .set_flags = niu_set_flags, - .get_flags = ethtool_op_get_flags, }; static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, @@ -8131,7 +8122,7 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np, netif_printk(np, probe, KERN_DEBUG, np->dev, "VPD_SCAN: start[%x] end[%x]\n", start, end); while (start < end) { - int len, err, instance, type, prop_len; + int len, err, prop_len; char namebuf[64]; u8 *prop_buf; int max_len; @@ -8147,8 +8138,6 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np, len = err; start += 3; - instance = niu_pci_eeprom_read(np, start); - type = niu_pci_eeprom_read(np, start + 3); prop_len = niu_pci_eeprom_read(np, start + 4); err = niu_pci_vpd_get_propname(np, start + 5, namebuf, 64); if (err < 0) @@ -9768,8 +9757,8 @@ static void __devinit niu_device_announce(struct niu *np) static void __devinit niu_set_basic_features(struct net_device *dev) { - dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM | - NETIF_F_GRO | NETIF_F_RXHASH); + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXHASH; + dev->features |= dev->hw_features | NETIF_F_RXCSUM; } static int __devinit niu_pci_init_one(struct pci_dev *pdev, diff --git a/drivers/net/niu.h b/drivers/net/niu.h index a41fa8ebe05f..51e177e1860d 100644 --- a/drivers/net/niu.h +++ b/drivers/net/niu.h @@ -3279,6 +3279,7 @@ struct niu { unsigned long xpcs_off; struct timer_list timer; + u64 orig_led_state; const struct niu_phy_ops *phy_ops; int phy_addr; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 6667e0667a88..3e4040f2f3cb 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1251,7 +1251,7 @@ static int ns83820_get_settings(struct net_device *ndev, /* * Here's the list of available ethtool commands from other drivers: * cmd->advertising = - * cmd->speed = + * ethtool_cmd_speed_set(cmd, ...) * cmd->duplex = * cmd->port = 0; * cmd->phy_address = @@ -1289,13 +1289,13 @@ static int ns83820_get_settings(struct net_device *ndev, cmd->duplex = fullduplex ? DUPLEX_FULL : DUPLEX_HALF; switch (cfg / CFG_SPDSTS0 & 3) { case 2: - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); break; case 1: - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); break; default: - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); break; } cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE) diff --git a/drivers/net/pch_gbe/pch_gbe.h b/drivers/net/pch_gbe/pch_gbe.h index bf126e76fabf..59fac77d0dbb 100644 --- a/drivers/net/pch_gbe/pch_gbe.h +++ b/drivers/net/pch_gbe/pch_gbe.h @@ -597,8 +597,6 @@ struct pch_gbe_hw_stats { * @rx_ring: Pointer of Rx descriptor ring structure * @rx_buffer_len: Receive buffer length * @tx_queue_len: Transmit queue length - * @rx_csum: Receive TCP/IP checksum enable/disable - * @tx_csum: Transmit TCP/IP checksum enable/disable * @have_msi: PCI MSI mode flag */ @@ -623,8 +621,6 @@ struct pch_gbe_adapter { struct pch_gbe_rx_ring *rx_ring; unsigned long rx_buffer_len; unsigned long tx_queue_len; - bool rx_csum; - bool tx_csum; bool have_msi; }; diff --git a/drivers/net/pch_gbe/pch_gbe_ethtool.c b/drivers/net/pch_gbe/pch_gbe_ethtool.c index d2174a40d708..ea2d8e41887a 100644 --- a/drivers/net/pch_gbe/pch_gbe_ethtool.c +++ b/drivers/net/pch_gbe/pch_gbe_ethtool.c @@ -92,7 +92,7 @@ static int pch_gbe_get_settings(struct net_device *netdev, ecmd->advertising &= ~(ADVERTISED_TP | ADVERTISED_1000baseT_Half); if (!netif_carrier_ok(adapter->netdev)) - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); return ret; } @@ -109,12 +109,15 @@ static int pch_gbe_set_settings(struct net_device *netdev, { struct pch_gbe_adapter *adapter = netdev_priv(netdev); struct pch_gbe_hw *hw = &adapter->hw; + u32 speed = ethtool_cmd_speed(ecmd); int ret; pch_gbe_hal_write_phy_reg(hw, MII_BMCR, BMCR_RESET); - if (ecmd->speed == USHRT_MAX) { - ecmd->speed = SPEED_1000; + /* when set_settings() is called with a ethtool_cmd previously + * filled by get_settings() on a down link, speed is -1: */ + if (speed == UINT_MAX) { + speed = SPEED_1000; ecmd->duplex = DUPLEX_FULL; } ret = mii_ethtool_sset(&adapter->mii, ecmd); @@ -122,7 +125,7 @@ static int pch_gbe_set_settings(struct net_device *netdev, pr_err("Error: mii_ethtool_sset\n"); return ret; } - hw->mac.link_speed = ecmd->speed; + hw->mac.link_speed = speed; hw->mac.link_duplex = ecmd->duplex; hw->phy.autoneg_advertised = ecmd->advertising; hw->mac.autoneg = ecmd->autoneg; @@ -433,57 +436,6 @@ static int pch_gbe_set_pauseparam(struct net_device *netdev, return ret; } -/** - * pch_gbe_get_rx_csum - Report whether receive checksums are turned on or off - * @netdev: Network interface device structure - * Returns - * true(1): Checksum On - * false(0): Checksum Off - */ -static u32 pch_gbe_get_rx_csum(struct net_device *netdev) -{ - struct pch_gbe_adapter *adapter = netdev_priv(netdev); - - return adapter->rx_csum; -} - -/** - * pch_gbe_set_rx_csum - Turn receive checksum on or off - * @netdev: Network interface device structure - * @data: Checksum On[true] or Off[false] - * Returns - * 0: Successful. - * Negative value: Failed. - */ -static int pch_gbe_set_rx_csum(struct net_device *netdev, u32 data) -{ - struct pch_gbe_adapter *adapter = netdev_priv(netdev); - - adapter->rx_csum = data; - if ((netif_running(netdev))) - pch_gbe_reinit_locked(adapter); - else - pch_gbe_reset(adapter); - - return 0; -} - -/** - * pch_gbe_set_tx_csum - Turn transmit checksums on or off - * @netdev: Network interface device structure - * @data: Checksum on[true] or off[false] - * Returns - * 0: Successful. - * Negative value: Failed. - */ -static int pch_gbe_set_tx_csum(struct net_device *netdev, u32 data) -{ - struct pch_gbe_adapter *adapter = netdev_priv(netdev); - - adapter->tx_csum = data; - return ethtool_op_set_tx_ipv6_csum(netdev, data); -} - /** * pch_gbe_get_strings - Return a set of strings that describe the requested * objects @@ -554,9 +506,6 @@ static const struct ethtool_ops pch_gbe_ethtool_ops = { .set_ringparam = pch_gbe_set_ringparam, .get_pauseparam = pch_gbe_get_pauseparam, .set_pauseparam = pch_gbe_set_pauseparam, - .get_rx_csum = pch_gbe_get_rx_csum, - .set_rx_csum = pch_gbe_set_rx_csum, - .set_tx_csum = pch_gbe_set_tx_csum, .get_strings = pch_gbe_get_strings, .get_ethtool_stats = pch_gbe_get_ethtool_stats, .get_sset_count = pch_gbe_get_sset_count, diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 2ef2f9cdefa6..c2476fd96573 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -34,6 +34,10 @@ const char pch_driver_version[] = DRV_VERSION; #define PCH_GBE_COPYBREAK_DEFAULT 256 #define PCH_GBE_PCI_BAR 1 +/* Macros for ML7223 */ +#define PCI_VENDOR_ID_ROHM 0x10db +#define PCI_DEVICE_ID_ROHM_ML7223_GBE 0x8013 + #define PCH_GBE_TX_WEIGHT 64 #define PCH_GBE_RX_WEIGHT 64 #define PCH_GBE_RX_BUFFER_WRITE 16 @@ -43,8 +47,7 @@ const char pch_driver_version[] = DRV_VERSION; #define PCH_GBE_MAC_RGMII_CTRL_SETTING ( \ PCH_GBE_CHIP_TYPE_INTERNAL | \ - PCH_GBE_RGMII_MODE_RGMII | \ - PCH_GBE_CRS_SEL \ + PCH_GBE_RGMII_MODE_RGMII \ ) /* Ethertype field values */ @@ -656,6 +659,7 @@ static void pch_gbe_configure_tx(struct pch_gbe_adapter *adapter) */ static void pch_gbe_setup_rctl(struct pch_gbe_adapter *adapter) { + struct net_device *netdev = adapter->netdev; struct pch_gbe_hw *hw = &adapter->hw; u32 rx_mode, tcpip; @@ -666,7 +670,7 @@ static void pch_gbe_setup_rctl(struct pch_gbe_adapter *adapter) tcpip = ioread32(&hw->reg->TCPIP_ACC); - if (adapter->rx_csum) { + if (netdev->features & NETIF_F_RXCSUM) { tcpip &= ~PCH_GBE_RX_TCPIPACC_OFF; tcpip |= PCH_GBE_RX_TCPIPACC_EN; } else { @@ -887,12 +891,12 @@ static void pch_gbe_watchdog(unsigned long data) struct pch_gbe_adapter *adapter = (struct pch_gbe_adapter *)data; struct net_device *netdev = adapter->netdev; struct pch_gbe_hw *hw = &adapter->hw; - struct ethtool_cmd cmd; pr_debug("right now = %ld\n", jiffies); pch_gbe_update_stats(adapter); if ((mii_link_ok(&adapter->mii)) && (!netif_carrier_ok(netdev))) { + struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; netdev->tx_queue_len = adapter->tx_queue_len; /* mii library handles link maintenance tasks */ if (mii_ethtool_gset(&adapter->mii, &cmd)) { @@ -902,7 +906,7 @@ static void pch_gbe_watchdog(unsigned long data) PCH_GBE_WATCHDOG_PERIOD)); return; } - hw->mac.link_speed = cmd.speed; + hw->mac.link_speed = ethtool_cmd_speed(&cmd); hw->mac.link_duplex = cmd.duplex; /* Set the RGMII control. */ pch_gbe_set_rgmii_ctrl(adapter, hw->mac.link_speed, @@ -912,7 +916,7 @@ static void pch_gbe_watchdog(unsigned long data) hw->mac.link_duplex); netdev_dbg(netdev, "Link is Up %d Mbps %s-Duplex\n", - cmd.speed, + hw->mac.link_speed, cmd.duplex == DUPLEX_FULL ? "Full" : "Half"); netif_carrier_on(netdev); netif_wake_queue(netdev); @@ -950,7 +954,7 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter, frame_ctrl = 0; if (unlikely(skb->len < PCH_GBE_SHORT_PKT)) frame_ctrl |= PCH_GBE_TXD_CTRL_APAD; - if (unlikely(!adapter->tx_csum)) + if (skb->ip_summed == CHECKSUM_NONE) frame_ctrl |= PCH_GBE_TXD_CTRL_TCPIP_ACC_OFF; /* Performs checksum processing */ @@ -958,7 +962,7 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter, * It is because the hardware accelerator does not support a checksum, * when the received data size is less than 64 bytes. */ - if ((skb->len < PCH_GBE_SHORT_PKT) && (adapter->tx_csum)) { + if (skb->len < PCH_GBE_SHORT_PKT && skb->ip_summed != CHECKSUM_NONE) { frame_ctrl |= PCH_GBE_TXD_CTRL_APAD | PCH_GBE_TXD_CTRL_TCPIP_ACC_OFF; if (skb->protocol == htons(ETH_P_IP)) { @@ -1426,7 +1430,7 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, length = (rx_desc->rx_words_eob) - 3; /* Decide the data conversion method */ - if (!adapter->rx_csum) { + if (!(netdev->features & NETIF_F_RXCSUM)) { /* [Header:14][payload] */ if (NET_IP_ALIGN) { /* Because alignment differs, @@ -1494,12 +1498,11 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, /* Write meta date of skb */ skb_put(skb, length); skb->protocol = eth_type_trans(skb, netdev); - if ((tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK) == - PCH_GBE_RXD_ACC_STAT_TCPIPOK) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else { + if (tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK) skb->ip_summed = CHECKSUM_NONE; - } + else + skb->ip_summed = CHECKSUM_UNNECESSARY; + napi_gro_receive(&adapter->napi, skb); (*work_done)++; pr_debug("Receive skb->ip_summed: %d length: %d\n", @@ -2029,6 +2032,29 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu) return 0; } +/** + * pch_gbe_set_features - Reset device after features changed + * @netdev: Network interface device structure + * @features: New features + * Returns + * 0: HW state updated successfully + */ +static int pch_gbe_set_features(struct net_device *netdev, u32 features) +{ + struct pch_gbe_adapter *adapter = netdev_priv(netdev); + u32 changed = features ^ netdev->features; + + if (!(changed & NETIF_F_RXCSUM)) + return 0; + + if (netif_running(netdev)) + pch_gbe_reinit_locked(adapter); + else + pch_gbe_reset(adapter); + + return 0; +} + /** * pch_gbe_ioctl - Controls register through a MII interface * @netdev: Network interface device structure @@ -2129,6 +2155,7 @@ static const struct net_device_ops pch_gbe_netdev_ops = { .ndo_set_mac_address = pch_gbe_set_mac, .ndo_tx_timeout = pch_gbe_tx_timeout, .ndo_change_mtu = pch_gbe_change_mtu, + .ndo_set_features = pch_gbe_set_features, .ndo_do_ioctl = pch_gbe_ioctl, .ndo_set_multicast_list = &pch_gbe_set_multi, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -2334,7 +2361,9 @@ static int pch_gbe_probe(struct pci_dev *pdev, netdev->watchdog_timeo = PCH_GBE_WATCHDOG_PERIOD; netif_napi_add(netdev, &adapter->napi, pch_gbe_napi_poll, PCH_GBE_RX_WEIGHT); - netdev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO; + netdev->hw_features = NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + netdev->features = netdev->hw_features; pch_gbe_set_ethtool_ops(netdev); pch_gbe_mac_load_mac_addr(&adapter->hw); @@ -2373,11 +2402,6 @@ static int pch_gbe_probe(struct pci_dev *pdev, pch_gbe_check_options(adapter); - if (adapter->tx_csum) - netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - else - netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - /* initialize the wol settings based on the eeprom settings */ adapter->wake_up_evt = PCH_GBE_WL_INIT_SETTING; dev_info(&pdev->dev, "MAC address : %pM\n", netdev->dev_addr); @@ -2420,6 +2444,13 @@ static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = { .class = (PCI_CLASS_NETWORK_ETHERNET << 8), .class_mask = (0xFFFF00) }, + {.vendor = PCI_VENDOR_ID_ROHM, + .device = PCI_DEVICE_ID_ROHM_ML7223_GBE, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = (PCI_CLASS_NETWORK_ETHERNET << 8), + .class_mask = (0xFFFF00) + }, /* required last entry */ {0} }; diff --git a/drivers/net/pch_gbe/pch_gbe_param.c b/drivers/net/pch_gbe/pch_gbe_param.c index ef0996a0eaaa..5b5d90a47e29 100644 --- a/drivers/net/pch_gbe/pch_gbe_param.c +++ b/drivers/net/pch_gbe/pch_gbe_param.c @@ -426,6 +426,8 @@ static void pch_gbe_check_copper_options(struct pch_gbe_adapter *adapter) void pch_gbe_check_options(struct pch_gbe_adapter *adapter) { struct pch_gbe_hw *hw = &adapter->hw; + struct net_device *dev = adapter->netdev; + int val; { /* Transmit Descriptor Count */ static const struct pch_gbe_option opt = { @@ -466,9 +468,10 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter) .err = "defaulting to Enabled", .def = PCH_GBE_DEFAULT_RX_CSUM }; - adapter->rx_csum = XsumRX; - pch_gbe_validate_option((int *)(&adapter->rx_csum), - &opt, adapter); + val = XsumRX; + pch_gbe_validate_option(&val, &opt, adapter); + if (!val) + dev->features &= ~NETIF_F_RXCSUM; } { /* Checksum Offload Enable/Disable */ static const struct pch_gbe_option opt = { @@ -477,9 +480,10 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter) .err = "defaulting to Enabled", .def = PCH_GBE_DEFAULT_TX_CSUM }; - adapter->tx_csum = XsumTX; - pch_gbe_validate_option((int *)(&adapter->tx_csum), - &opt, adapter); + val = XsumTX; + pch_gbe_validate_option(&val, &opt, adapter); + if (!val) + dev->features &= ~NETIF_F_ALL_CSUM; } { /* Flow Control */ static const struct pch_gbe_option opt = { diff --git a/drivers/net/pch_gbe/pch_gbe_phy.c b/drivers/net/pch_gbe/pch_gbe_phy.c index 923a687acd30..28bb9603d736 100644 --- a/drivers/net/pch_gbe/pch_gbe_phy.c +++ b/drivers/net/pch_gbe/pch_gbe_phy.c @@ -247,7 +247,7 @@ inline void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw) void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw) { struct pch_gbe_adapter *adapter; - struct ethtool_cmd cmd; + struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; int ret; u16 mii_reg; @@ -256,7 +256,7 @@ void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw) if (ret) pr_err("Error: mii_ethtool_gset\n"); - cmd.speed = hw->mac.link_speed; + ethtool_cmd_speed_set(&cmd, hw->mac.link_speed); cmd.duplex = hw->mac.link_duplex; cmd.advertising = hw->phy.autoneg_advertised; cmd.autoneg = hw->mac.autoneg; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 108591756440..288e4f1317ee 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1860,7 +1860,7 @@ static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) tmp = inw(ioaddr + CONFIG); ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP; ecmd->transceiver = XCVR_INTERNAL; - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); ecmd->phy_address = ioaddr + MGMT; SMC_SELECT_BANK(0); @@ -1875,8 +1875,8 @@ static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) u16 tmp; unsigned int ioaddr = dev->base_addr; - if (ecmd->speed != SPEED_10) - return -EINVAL; + if (ethtool_cmd_speed(ecmd) != SPEED_10) + return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI) diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 768037602dff..b48aba9e4227 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -295,12 +295,14 @@ struct pcnet32_private { struct net_device *next; struct mii_if_info mii_if; struct timer_list watchdog_timer; - struct timer_list blink_timer; u32 msg_enable; /* debug message level */ /* each bit indicates an available PHY */ u32 phymask; unsigned short chip_version; /* which variant this is */ + + /* saved registers during ethtool blink */ + u16 save_regs[4]; }; static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); @@ -324,8 +326,6 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits); static void pcnet32_ethtool_test(struct net_device *dev, struct ethtool_test *eth_test, u64 * data); static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1); -static int pcnet32_phys_id(struct net_device *dev, u32 data); -static void pcnet32_led_blink_callback(struct net_device *dev); static int pcnet32_get_regs_len(struct net_device *dev); static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *ptr); @@ -1022,7 +1022,8 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) return rc; } /* end pcnet32_loopback_test */ -static void pcnet32_led_blink_callback(struct net_device *dev) +static int pcnet32_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct pcnet32_private *lp = netdev_priv(dev); struct pcnet32_access *a = &lp->a; @@ -1030,50 +1031,31 @@ static void pcnet32_led_blink_callback(struct net_device *dev) unsigned long flags; int i; - spin_lock_irqsave(&lp->lock, flags); - for (i = 4; i < 8; i++) - a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000); - spin_unlock_irqrestore(&lp->lock, flags); + switch (state) { + case ETHTOOL_ID_ACTIVE: + /* Save the current value of the bcrs */ + spin_lock_irqsave(&lp->lock, flags); + for (i = 4; i < 8; i++) + lp->save_regs[i - 4] = a->read_bcr(ioaddr, i); + spin_unlock_irqrestore(&lp->lock, flags); + return 2; /* cycle on/off twice per second */ - mod_timer(&lp->blink_timer, PCNET32_BLINK_TIMEOUT); -} + case ETHTOOL_ID_ON: + case ETHTOOL_ID_OFF: + /* Blink the led */ + spin_lock_irqsave(&lp->lock, flags); + for (i = 4; i < 8; i++) + a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000); + spin_unlock_irqrestore(&lp->lock, flags); + break; -static int pcnet32_phys_id(struct net_device *dev, u32 data) -{ - struct pcnet32_private *lp = netdev_priv(dev); - struct pcnet32_access *a = &lp->a; - ulong ioaddr = dev->base_addr; - unsigned long flags; - int i, regs[4]; - - if (!lp->blink_timer.function) { - init_timer(&lp->blink_timer); - lp->blink_timer.function = (void *)pcnet32_led_blink_callback; - lp->blink_timer.data = (unsigned long)dev; + case ETHTOOL_ID_INACTIVE: + /* Restore the original value of the bcrs */ + spin_lock_irqsave(&lp->lock, flags); + for (i = 4; i < 8; i++) + a->write_bcr(ioaddr, i, lp->save_regs[i - 4]); + spin_unlock_irqrestore(&lp->lock, flags); } - - /* Save the current value of the bcrs */ - spin_lock_irqsave(&lp->lock, flags); - for (i = 4; i < 8; i++) - regs[i - 4] = a->read_bcr(ioaddr, i); - spin_unlock_irqrestore(&lp->lock, flags); - - mod_timer(&lp->blink_timer, jiffies); - set_current_state(TASK_INTERRUPTIBLE); - - /* AV: the limit here makes no sense whatsoever */ - if ((!data) || (data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ))) - data = (u32) (MAX_SCHEDULE_TIMEOUT / HZ); - - msleep_interruptible(data * 1000); - del_timer_sync(&lp->blink_timer); - - /* Restore the original value of the bcrs */ - spin_lock_irqsave(&lp->lock, flags); - for (i = 4; i < 8; i++) - a->write_bcr(ioaddr, i, regs[i - 4]); - spin_unlock_irqrestore(&lp->lock, flags); - return 0; } @@ -1450,7 +1432,7 @@ static const struct ethtool_ops pcnet32_ethtool_ops = { .set_ringparam = pcnet32_set_ringparam, .get_strings = pcnet32_get_strings, .self_test = pcnet32_ethtool_test, - .phys_id = pcnet32_phys_id, + .set_phys_id = pcnet32_set_phys_id, .get_regs_len = pcnet32_get_regs_len, .get_regs = pcnet32_get_regs, .get_sset_count = pcnet32_get_sset_count, @@ -2117,7 +2099,7 @@ static int pcnet32_open(struct net_device *dev) int first_phy = -1; u16 bmcr; u32 bcr9; - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; /* * There is really no good other way to handle multiple PHYs @@ -2133,9 +2115,9 @@ static int pcnet32_open(struct net_device *dev) ecmd.port = PORT_MII; ecmd.transceiver = XCVR_INTERNAL; ecmd.autoneg = AUTONEG_DISABLE; - ecmd.speed = - lp-> - options & PCNET32_PORT_100 ? SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(&ecmd, + (lp->options & PCNET32_PORT_100) ? + SPEED_100 : SPEED_10); bcr9 = lp->a.read_bcr(ioaddr, 9); if (lp->options & PCNET32_PORT_FD) { @@ -2781,11 +2763,11 @@ static void pcnet32_check_media(struct net_device *dev, int verbose) netif_carrier_on(dev); if (lp->mii) { if (netif_msg_link(lp)) { - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { + .cmd = ETHTOOL_GSET }; mii_ethtool_gset(&lp->mii_if, &ecmd); - netdev_info(dev, "link up, %sMbps, %s-duplex\n", - (ecmd.speed == SPEED_100) - ? "100" : "10", + netdev_info(dev, "link up, %uMbps, %s-duplex\n", + ethtool_cmd_speed(&ecmd), (ecmd.duplex == DUPLEX_FULL) ? "full" : "half"); } diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index f7670330f988..a47595760751 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -238,6 +238,8 @@ static void phy_sanitize_settings(struct phy_device *phydev) */ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) { + u32 speed = ethtool_cmd_speed(cmd); + if (cmd->phy_address != phydev->addr) return -EINVAL; @@ -253,16 +255,16 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) return -EINVAL; if (cmd->autoneg == AUTONEG_DISABLE && - ((cmd->speed != SPEED_1000 && - cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || + ((speed != SPEED_1000 && + speed != SPEED_100 && + speed != SPEED_10) || (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL))) return -EINVAL; phydev->autoneg = cmd->autoneg; - phydev->speed = cmd->speed; + phydev->speed = speed; phydev->advertising = cmd->advertising; @@ -286,7 +288,7 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) cmd->advertising = phydev->advertising; - cmd->speed = phydev->speed; + ethtool_cmd_speed_set(cmd, phydev->speed); cmd->duplex = phydev->duplex; cmd->port = PORT_MII; cmd->phy_address = phydev->addr; diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c index 51dfcf8023c7..1286fe212dc4 100644 --- a/drivers/net/pptp.c +++ b/drivers/net/pptp.c @@ -175,6 +175,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) struct pptp_opt *opt = &po->proto.pptp; struct pptp_gre_header *hdr; unsigned int header_len = sizeof(*hdr); + struct flowi4 fl4; int islcp; int len; unsigned char *data; @@ -189,7 +190,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) if (sk_pppox(po)->sk_state & PPPOX_DEAD) goto tx_error; - rt = ip_route_output_ports(&init_net, NULL, + rt = ip_route_output_ports(&init_net, &fl4, NULL, opt->dst_addr.sin_addr.s_addr, opt->src_addr.sin_addr.s_addr, 0, 0, IPPROTO_GRE, @@ -270,8 +271,8 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) iph->frag_off = 0; iph->protocol = IPPROTO_GRE; iph->tos = 0; - iph->daddr = rt->rt_dst; - iph->saddr = rt->rt_src; + iph->daddr = fl4.daddr; + iph->saddr = fl4.saddr; iph->ttl = ip4_dst_hoplimit(&rt->dst); iph->tot_len = htons(skb->len); @@ -434,6 +435,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, struct pppox_sock *po = pppox_sk(sk); struct pptp_opt *opt = &po->proto.pptp; struct rtable *rt; + struct flowi4 fl4; int error = 0; if (sp->sa_protocol != PX_PROTO_PPTP) @@ -463,7 +465,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.private = sk; po->chan.ops = &pptp_chan_ops; - rt = ip_route_output_ports(&init_net, sk, + rt = ip_route_output_ports(&init_net, &fl4, sk, opt->dst_addr.sin_addr.s_addr, opt->src_addr.sin_addr.s_addr, 0, 0, diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index ffdf7349ef7a..b1f251da1535 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -951,7 +951,7 @@ static void gelic_net_pass_skb_up(struct gelic_descr *descr, skb->protocol = eth_type_trans(skb, netdev); /* checksum offload */ - if (card->rx_csum) { + if (netdev->features & NETIF_F_RXCSUM) { if ((data_status & GELIC_DESCR_DATA_STATUS_CHK_MASK) && (!(data_error & GELIC_DESCR_DATA_ERROR_CHK_MASK))) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -1243,17 +1243,17 @@ static int gelic_ether_get_settings(struct net_device *netdev, switch (card->ether_port_status & GELIC_LV1_ETHER_SPEED_MASK) { case GELIC_LV1_ETHER_SPEED_10: - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); break; case GELIC_LV1_ETHER_SPEED_100: - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); break; case GELIC_LV1_ETHER_SPEED_1000: - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); break; default: pr_info("%s: speed unknown\n", __func__); - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); break; } @@ -1312,21 +1312,6 @@ static int gelic_ether_set_settings(struct net_device *netdev, return 0; } -u32 gelic_net_get_rx_csum(struct net_device *netdev) -{ - struct gelic_card *card = netdev_card(netdev); - - return card->rx_csum; -} - -int gelic_net_set_rx_csum(struct net_device *netdev, u32 data) -{ - struct gelic_card *card = netdev_card(netdev); - - card->rx_csum = data; - return 0; -} - static void gelic_net_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { @@ -1411,10 +1396,6 @@ static const struct ethtool_ops gelic_ether_ethtool_ops = { .get_settings = gelic_ether_get_settings, .set_settings = gelic_ether_set_settings, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_rx_csum = gelic_net_get_rx_csum, - .set_rx_csum = gelic_net_set_rx_csum, .get_wol = gelic_net_get_wol, .set_wol = gelic_net_set_wol, }; @@ -1512,7 +1493,11 @@ int __devinit gelic_net_setup_netdev(struct net_device *netdev, int status; u64 v1, v2; + netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM; + netdev->features = NETIF_F_IP_CSUM; + if (GELIC_CARD_RX_CSUM_DEFAULT) + netdev->features |= NETIF_F_RXCSUM; status = lv1_net_control(bus_id(card), dev_id(card), GELIC_LV1_GET_MAC_ADDRESS, @@ -1756,7 +1741,6 @@ static int __devinit ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) /* setup card structure */ card->irq_mask = GELIC_CARD_RXINT | GELIC_CARD_TXINT | GELIC_CARD_PORT_STATUS_CHANGED; - card->rx_csum = GELIC_CARD_RX_CSUM_DEFAULT; if (gelic_card_init_chain(card, &card->tx_chain, diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index fadadf9097a3..d9a55b93898b 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -290,7 +290,6 @@ struct gelic_card { struct gelic_descr_chain tx_chain; struct gelic_descr_chain rx_chain; int rx_dma_restart_required; - int rx_csum; /* * tx_lock guards tx descriptor list and * tx_dma_progress. @@ -377,8 +376,6 @@ extern int gelic_net_setup_netdev(struct net_device *netdev, /* shared ethtool ops */ extern void gelic_net_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info); -extern u32 gelic_net_get_rx_csum(struct net_device *netdev); -extern int gelic_net_set_rx_csum(struct net_device *netdev, u32 data); extern void gelic_net_poll_controller(struct net_device *netdev); #endif /* _GELIC_NET_H */ diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index b5ae29d20f2e..2e62938c0f82 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -2581,10 +2581,6 @@ static const struct net_device_ops gelic_wl_netdevice_ops = { static const struct ethtool_ops gelic_wl_ethtool_ops = { .get_drvinfo = gelic_net_get_drvinfo, .get_link = gelic_wl_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_rx_csum = gelic_net_get_rx_csum, - .set_rx_csum = gelic_net_set_rx_csum, }; static void __devinit gelic_wl_setup_netdev_ops(struct net_device *netdev) diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 348b4f1367c9..d495a6859fd9 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -1725,7 +1725,7 @@ static int ql_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) } ecmd->advertising = ql_supported_modes(qdev); ecmd->autoneg = ql_get_auto_cfg_status(qdev); - ecmd->speed = ql_get_speed(qdev); + ethtool_cmd_speed_set(ecmd, ql_get_speed(qdev)); ecmd->duplex = ql_get_full_dup(qdev); return 0; } @@ -3468,7 +3468,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev) { struct net_device *ndev = qdev->ndev; int err; - unsigned long irq_flags = IRQF_SAMPLE_RANDOM | IRQF_SHARED; + unsigned long irq_flags = IRQF_SHARED; unsigned long hw_flags; if (ql_alloc_mem_resources(qdev)) { diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index dc44564ef6f9..480ef5cb6ef9 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -29,13 +29,15 @@ #include #include +#include +#include #include "qlcnic_hdr.h" #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 15 -#define QLCNIC_LINUX_VERSIONID "5.0.15" +#define _QLCNIC_LINUX_SUBVERSION 18 +#define QLCNIC_LINUX_VERSIONID "5.0.18" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) @@ -93,12 +95,11 @@ #define TX_IP_PKT 0x04 #define TX_TCP_LSO 0x05 #define TX_TCP_LSO6 0x06 -#define TX_IPSEC 0x07 -#define TX_IPSEC_CMD 0x0a #define TX_TCPV6_PKT 0x0b #define TX_UDPV6_PKT 0x0c /* Tx defines */ +#define QLCNIC_MAX_FRAGS_PER_TX 14 #define MAX_TSO_HEADER_DESC 2 #define MGMT_CMD_DESC_RESV 4 #define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \ @@ -117,7 +118,6 @@ #define PHAN_PEG_RCV_INITIALIZED 0xff01 #define NUM_RCV_DESC_RINGS 3 -#define NUM_STS_DESC_RINGS 4 #define RCV_RING_NORMAL 0 #define RCV_RING_JUMBO 1 @@ -200,7 +200,7 @@ struct rcv_desc { __le16 reserved; __le32 buffer_length; /* allocated buffer length (usually 2K) */ __le64 addr_buffer; -}; +} __packed; /* opcode field in status_desc */ #define QLCNIC_SYN_OFFLOAD 0x03 @@ -292,6 +292,7 @@ struct uni_data_desc{ /* Flash Defines and Structures */ #define QLCNIC_FLT_LOCATION 0x3F1000 #define QLCNIC_FW_IMAGE_REGION 0x74 +#define QLCNIC_BOOTLD_REGION 0X72 struct qlcnic_flt_header { u16 version; u16 len; @@ -306,7 +307,7 @@ struct qlcnic_flt_entry { u8 reserved1; u32 size; u32 start_addr; - u32 end_add; + u32 end_addr; }; /* Magic number to let user know flash is programmed */ @@ -365,12 +366,6 @@ struct qlcnic_skb_frag { u64 length; }; -struct qlcnic_recv_crb { - u32 crb_rcv_producer[NUM_RCV_DESC_RINGS]; - u32 crb_sts_consumer[NUM_STS_DESC_RINGS]; - u32 sw_int_mask[NUM_STS_DESC_RINGS]; -}; - /* Following defines are for the state of the buffers */ #define QLCNIC_BUFFER_FREE 0 #define QLCNIC_BUFFER_BUSY 1 @@ -387,16 +382,58 @@ struct qlcnic_cmd_buffer { /* In rx_buffer, we do not need multiple fragments as is a single buffer */ struct qlcnic_rx_buffer { - struct list_head list; - struct sk_buff *skb; - u64 dma; u16 ref_handle; + struct sk_buff *skb; + struct list_head list; + u64 dma; }; /* Board types */ #define QLCNIC_GBE 0x01 #define QLCNIC_XGBE 0x02 +/* + * Interrupt coalescing defaults. The defaults are for 1500 MTU. It is + * adjusted based on configured MTU. + */ +#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US 3 +#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS 256 + +#define QLCNIC_INTR_DEFAULT 0x04 +#define QLCNIC_CONFIG_INTR_COALESCE 3 + +struct qlcnic_nic_intr_coalesce { + u8 type; + u8 sts_ring_mask; + u16 rx_packets; + u16 rx_time_us; + u16 flag; + u32 timer_out; +}; + +struct qlcnic_dump_template_hdr { + __le32 type; + __le32 offset; + __le32 size; + __le32 cap_mask; + __le32 num_entries; + __le32 version; + __le32 timestamp; + __le32 checksum; + __le32 drv_cap_mask; + __le32 sys_info[3]; + __le32 saved_state[16]; + __le32 cap_sizes[8]; + __le32 rsvd[0]; +}; + +struct qlcnic_fw_dump { + u8 clr; /* flag to indicate if dump is cleared */ + u32 size; /* total size of the dump */ + void *data; /* dump data area */ + struct qlcnic_dump_template_hdr *tmpl_hdr; +}; + /* * One hardware_context{} per adapter * contains interrupt info as well shared hardware info. @@ -415,6 +452,9 @@ struct qlcnic_hardware_context { u8 linkup; u16 port_type; u16 board_type; + + struct qlcnic_nic_intr_coalesce coal; + struct qlcnic_fw_dump fw_dump; }; struct qlcnic_adapter_stats { @@ -442,50 +482,49 @@ struct qlcnic_adapter_stats { * be one Rcv Descriptor for normal packets, one for jumbo and may be others. */ struct qlcnic_host_rds_ring { - u32 producer; - u32 num_desc; - u32 dma_size; - u32 skb_size; - u32 flags; void __iomem *crb_rcv_producer; struct rcv_desc *desc_head; struct qlcnic_rx_buffer *rx_buf_arr; + u32 num_desc; + u32 producer; + u32 dma_size; + u32 skb_size; + u32 flags; struct list_head free_list; spinlock_t lock; dma_addr_t phys_addr; -}; +} ____cacheline_internodealigned_in_smp; struct qlcnic_host_sds_ring { u32 consumer; u32 num_desc; void __iomem *crb_sts_consumer; - void __iomem *crb_intr_mask; struct status_desc *desc_head; struct qlcnic_adapter *adapter; struct napi_struct napi; struct list_head free_list[NUM_RCV_DESC_RINGS]; + void __iomem *crb_intr_mask; int irq; dma_addr_t phys_addr; char name[IFNAMSIZ+4]; -}; +} ____cacheline_internodealigned_in_smp; struct qlcnic_host_tx_ring { u32 producer; - __le32 *hw_consumer; u32 sw_consumer; - void __iomem *crb_cmd_producer; u32 num_desc; - - struct netdev_queue *txq; - - struct qlcnic_cmd_buffer *cmd_buf_arr; + void __iomem *crb_cmd_producer; struct cmd_desc_type0 *desc_head; + struct qlcnic_cmd_buffer *cmd_buf_arr; + __le32 *hw_consumer; + dma_addr_t phys_addr; dma_addr_t hw_cons_phys_addr; -}; + struct netdev_queue *txq; +} ____cacheline_internodealigned_in_smp; /* * Receive context. There is one such structure per instance of the @@ -494,12 +533,12 @@ struct qlcnic_host_tx_ring { * present elsewhere. */ struct qlcnic_recv_context { + struct qlcnic_host_rds_ring *rds_rings; + struct qlcnic_host_sds_ring *sds_rings; u32 state; u16 context_id; u16 virt_port; - struct qlcnic_host_rds_ring *rds_rings; - struct qlcnic_host_sds_ring *sds_rings; }; /* HW context creation */ @@ -538,9 +577,6 @@ struct qlcnic_recv_context { #define QLCNIC_CDRP_CMD_DESTROY_RX_CTX 0x00000008 #define QLCNIC_CDRP_CMD_CREATE_TX_CTX 0x00000009 #define QLCNIC_CDRP_CMD_DESTROY_TX_CTX 0x0000000a -#define QLCNIC_CDRP_CMD_SETUP_STATISTICS 0x0000000e -#define QLCNIC_CDRP_CMD_GET_STATISTICS 0x0000000f -#define QLCNIC_CDRP_CMD_DELETE_STATISTICS 0x00000010 #define QLCNIC_CDRP_CMD_SET_MTU 0x00000012 #define QLCNIC_CDRP_CMD_READ_PHY 0x00000013 #define QLCNIC_CDRP_CMD_WRITE_PHY 0x00000014 @@ -549,17 +585,11 @@ struct qlcnic_recv_context { #define QLCNIC_CDRP_CMD_SET_FLOW_CTL 0x00000017 #define QLCNIC_CDRP_CMD_READ_MAX_MTU 0x00000018 #define QLCNIC_CDRP_CMD_READ_MAX_LRO 0x00000019 -#define QLCNIC_CDRP_CMD_CONFIGURE_TOE 0x0000001a -#define QLCNIC_CDRP_CMD_FUNC_ATTRIB 0x0000001b -#define QLCNIC_CDRP_CMD_READ_PEXQ_PARAMETERS 0x0000001c -#define QLCNIC_CDRP_CMD_GET_LIC_CAPABILITIES 0x0000001d -#define QLCNIC_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e #define QLCNIC_CDRP_CMD_MAC_ADDRESS 0x0000001f #define QLCNIC_CDRP_CMD_GET_PCI_INFO 0x00000020 #define QLCNIC_CDRP_CMD_GET_NIC_INFO 0x00000021 #define QLCNIC_CDRP_CMD_SET_NIC_INFO 0x00000022 -#define QLCNIC_CDRP_CMD_RESET_NPAR 0x00000023 #define QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY 0x00000024 #define QLCNIC_CDRP_CMD_TOGGLE_ESWITCH 0x00000025 #define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS 0x00000026 @@ -567,8 +597,12 @@ struct qlcnic_recv_context { #define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH 0x00000028 #define QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG 0x00000029 #define QLCNIC_CDRP_CMD_GET_ESWITCH_STATS 0x0000002a +#define QLCNIC_CDRP_CMD_CONFIG_PORT 0x0000002E +#define QLCNIC_CDRP_CMD_TEMP_SIZE 0x0000002f +#define QLCNIC_CDRP_CMD_GET_TEMP_HDR 0x00000030 #define QLCNIC_RCODE_SUCCESS 0 +#define QLCNIC_RCODE_NOT_SUPPORTED 9 #define QLCNIC_RCODE_TIMEOUT 17 #define QLCNIC_DESTROY_CTX_RESET 0 @@ -597,14 +631,14 @@ struct qlcnic_hostrq_sds_ring { __le32 ring_size; /* Ring entries */ __le16 msi_index; __le16 rsvd; /* Padding */ -}; +} __packed; struct qlcnic_hostrq_rds_ring { __le64 host_phys_addr; /* Ring base addr */ __le64 buff_size; /* Packet buffer size */ __le32 ring_size; /* Ring entries */ __le32 ring_kind; /* Class of ring */ -}; +} __packed; struct qlcnic_hostrq_rx_ctx { __le64 host_rsp_dma_addr; /* Response dma'd here */ @@ -625,17 +659,17 @@ struct qlcnic_hostrq_rx_ctx { - N hostrq_rds_rings - N hostrq_sds_rings */ char data[0]; -}; +} __packed; struct qlcnic_cardrsp_rds_ring{ __le32 host_producer_crb; /* Crb to use */ __le32 rsvd1; /* Padding */ -}; +} __packed; struct qlcnic_cardrsp_sds_ring { __le32 host_consumer_crb; /* Crb to use */ __le32 interrupt_crb; /* Crb to use */ -}; +} __packed; struct qlcnic_cardrsp_rx_ctx { /* These ring offsets are relative to data[0] below */ @@ -654,7 +688,7 @@ struct qlcnic_cardrsp_rx_ctx { - N cardrsp_rds_rings - N cardrs_sds_rings */ char data[0]; -}; +} __packed; #define SIZEOF_HOSTRQ_RX(HOSTRQ_RX, rds_rings, sds_rings) \ (sizeof(HOSTRQ_RX) + \ @@ -674,7 +708,7 @@ struct qlcnic_hostrq_cds_ring { __le64 host_phys_addr; /* Ring base addr */ __le32 ring_size; /* Ring entries */ __le32 rsvd; /* Padding */ -}; +} __packed; struct qlcnic_hostrq_tx_ctx { __le64 host_rsp_dma_addr; /* Response dma'd here */ @@ -689,12 +723,12 @@ struct qlcnic_hostrq_tx_ctx { __le16 rsvd3; /* Padding */ struct qlcnic_hostrq_cds_ring cds_ring; /* Desc of cds ring */ u8 reserved[128]; /* future expansion */ -}; +} __packed; struct qlcnic_cardrsp_cds_ring { __le32 host_producer_crb; /* Crb to use */ __le32 interrupt_crb; /* Crb to use */ -}; +} __packed; struct qlcnic_cardrsp_tx_ctx { __le32 host_ctx_state; /* Starting state */ @@ -703,7 +737,7 @@ struct qlcnic_cardrsp_tx_ctx { u8 virt_port; /* Virtual/Logical id of port */ struct qlcnic_cardrsp_cds_ring cds_ring; /* Card cds settings */ u8 reserved[128]; /* future expansion */ -}; +} __packed; #define SIZEOF_HOSTRQ_TX(HOSTRQ_TX) (sizeof(HOSTRQ_TX)) #define SIZEOF_CARDRSP_TX(CARDRSP_TX) (sizeof(CARDRSP_TX)) @@ -737,40 +771,6 @@ struct qlcnic_mac_list_s { uint8_t mac_addr[ETH_ALEN+2]; }; -/* - * Interrupt coalescing defaults. The defaults are for 1500 MTU. It is - * adjusted based on configured MTU. - */ -#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US 3 -#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS 256 -#define QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS 64 -#define QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US 4 - -#define QLCNIC_INTR_DEFAULT 0x04 - -union qlcnic_nic_intr_coalesce_data { - struct { - u16 rx_packets; - u16 rx_time_us; - u16 tx_packets; - u16 tx_time_us; - } data; - u64 word; -}; - -struct qlcnic_nic_intr_coalesce { - u16 stats_time_us; - u16 rate_sample_time; - u16 flags; - u16 rsvd_1; - u32 low_threshold; - u32 high_threshold; - union qlcnic_nic_intr_coalesce_data normal; - union qlcnic_nic_intr_coalesce_data low; - union qlcnic_nic_intr_coalesce_data high; - union qlcnic_nic_intr_coalesce_data irq; -}; - #define QLCNIC_HOST_REQUEST 0x13 #define QLCNIC_REQUEST 0x14 @@ -782,50 +782,20 @@ struct qlcnic_nic_intr_coalesce { /* * Driver --> Firmware */ -#define QLCNIC_H2C_OPCODE_START 0 -#define QLCNIC_H2C_OPCODE_CONFIG_RSS 1 -#define QLCNIC_H2C_OPCODE_CONFIG_RSS_TBL 2 -#define QLCNIC_H2C_OPCODE_CONFIG_INTR_COALESCE 3 -#define QLCNIC_H2C_OPCODE_CONFIG_LED 4 -#define QLCNIC_H2C_OPCODE_CONFIG_PROMISCUOUS 5 -#define QLCNIC_H2C_OPCODE_CONFIG_L2_MAC 6 -#define QLCNIC_H2C_OPCODE_LRO_REQUEST 7 -#define QLCNIC_H2C_OPCODE_GET_SNMP_STATS 8 -#define QLCNIC_H2C_OPCODE_PROXY_START_REQUEST 9 -#define QLCNIC_H2C_OPCODE_PROXY_STOP_REQUEST 10 -#define QLCNIC_H2C_OPCODE_PROXY_SET_MTU 11 -#define QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE 12 -#define QLCNIC_H2C_OPCODE_GET_FINGER_PRINT_REQUEST 13 -#define QLCNIC_H2C_OPCODE_INSTALL_LICENSE_REQUEST 14 -#define QLCNIC_H2C_OPCODE_GET_LICENSE_CAPABILITY_REQUEST 15 -#define QLCNIC_H2C_OPCODE_GET_NET_STATS 16 -#define QLCNIC_H2C_OPCODE_PROXY_UPDATE_P2V 17 -#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 18 -#define QLCNIC_H2C_OPCODE_PROXY_STOP_DONE 20 -#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 21 -#define QLCNIC_C2C_OPCODE 22 -#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING 23 -#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO 24 -#define QLCNIC_H2C_OPCODE_LAST 25 +#define QLCNIC_H2C_OPCODE_CONFIG_RSS 0x1 +#define QLCNIC_H2C_OPCODE_CONFIG_INTR_COALESCE 0x3 +#define QLCNIC_H2C_OPCODE_CONFIG_LED 0x4 +#define QLCNIC_H2C_OPCODE_LRO_REQUEST 0x7 +#define QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE 0xc +#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 0x12 +#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 0x15 +#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING 0x17 +#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO 0x18 /* * Firmware --> Driver */ -#define QLCNIC_C2H_OPCODE_START 128 -#define QLCNIC_C2H_OPCODE_CONFIG_RSS_RESPONSE 129 -#define QLCNIC_C2H_OPCODE_CONFIG_RSS_TBL_RESPONSE 130 -#define QLCNIC_C2H_OPCODE_CONFIG_MAC_RESPONSE 131 -#define QLCNIC_C2H_OPCODE_CONFIG_PROMISCUOUS_RESPONSE 132 -#define QLCNIC_C2H_OPCODE_CONFIG_L2_MAC_RESPONSE 133 -#define QLCNIC_C2H_OPCODE_LRO_DELETE_RESPONSE 134 -#define QLCNIC_C2H_OPCODE_LRO_ADD_FAILURE_RESPONSE 135 -#define QLCNIC_C2H_OPCODE_GET_SNMP_STATS 136 -#define QLCNIC_C2H_OPCODE_GET_FINGER_PRINT_REPLY 137 -#define QLCNIC_C2H_OPCODE_INSTALL_LICENSE_REPLY 138 -#define QLCNIC_C2H_OPCODE_GET_LICENSE_CAPABILITIES_REPLY 139 -#define QLCNIC_C2H_OPCODE_GET_NET_STATS_RESPONSE 140 #define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE 141 -#define QLCNIC_C2H_OPCODE_LAST 142 #define VPORT_MISS_MODE_DROP 0 /* drop all unmatched */ #define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */ @@ -894,7 +864,7 @@ struct qlcnic_nic_req { __le64 qhdr; __le64 req_hdr; __le64 words[6]; -}; +} __packed; struct qlcnic_mac_req { u8 op; @@ -905,7 +875,7 @@ struct qlcnic_mac_req { struct qlcnic_vlan_req { __le16 vlan_id; __le16 rsvd[3]; -}; +} __packed; struct qlcnic_ipaddr { __be32 ipv4; @@ -928,7 +898,8 @@ struct qlcnic_ipaddr { #define QLCNIC_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) -#define MSIX_ENTRIES_PER_ADAPTER NUM_STS_DESC_RINGS +#define QLCNIC_DEF_NUM_STS_DESC_RINGS 4 +#define QLCNIC_MIN_NUM_RSS_RINGS 2 #define QLCNIC_MSIX_TBL_SPACE 8192 #define QLCNIC_PCI_REG_MSIX_TBL 0x44 #define QLCNIC_MSIX_TBL_PGSIZE 4096 @@ -941,6 +912,7 @@ struct qlcnic_ipaddr { #define __QLCNIC_RESETTING 2 #define __QLCNIC_START_FW 4 #define __QLCNIC_AER 5 +#define __QLCNIC_DIAG_RES_ALLOC 6 #define QLCNIC_INTERRUPT_TEST 1 #define QLCNIC_LOOPBACK_TEST 2 @@ -964,14 +936,14 @@ struct qlcnic_filter_hash { }; struct qlcnic_adapter { - struct qlcnic_hardware_context ahw; - + struct qlcnic_hardware_context *ahw; + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_tx_ring *tx_ring; struct net_device *netdev; struct pci_dev *pdev; - struct list_head mac_list; - spinlock_t tx_clean_lock; - spinlock_t mac_learn_lock; + unsigned long state; + u32 flags; u16 num_txd; u16 num_rxd; @@ -982,14 +954,12 @@ struct qlcnic_adapter { u8 max_rds_rings; u8 max_sds_rings; u8 msix_supported; - u8 rx_csum; u8 portnum; u8 physical_port; u8 reset_context; u8 mc_enabled; u8 max_mc_count; - u8 rss_supported; u8 fw_wait_cnt; u8 fw_fail_cnt; u8 tx_timeo_cnt; @@ -1014,7 +984,6 @@ struct qlcnic_adapter { u32 fw_hal_version; u32 capabilities; - u32 flags; u32 irq; u32 temp; @@ -1032,31 +1001,29 @@ struct qlcnic_adapter { u8 mac_addr[ETH_ALEN]; u64 dev_rst_time; + unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)]; - struct vlan_group *vlgrp; struct qlcnic_npar_info *npars; struct qlcnic_eswitch *eswitch; struct qlcnic_nic_template *nic_ops; struct qlcnic_adapter_stats stats; - - struct qlcnic_recv_context recv_ctx; - struct qlcnic_host_tx_ring *tx_ring; + struct list_head mac_list; void __iomem *tgt_mask_reg; void __iomem *tgt_status_reg; void __iomem *crb_int_state_reg; void __iomem *isr_int_vec; - struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER]; + struct msix_entry *msix_entries; struct delayed_work fw_work; - struct qlcnic_nic_intr_coalesce coal; struct qlcnic_filter_hash fhash; - unsigned long state; + spinlock_t tx_clean_lock; + spinlock_t mac_learn_lock; __le32 file_prd_off; /*File fw product offset*/ u32 fw_version; const struct firmware *fw; @@ -1078,7 +1045,7 @@ struct qlcnic_info { __le16 min_tx_bw; __le16 max_tx_bw; u8 reserved2[104]; -}; +} __packed; struct qlcnic_pci_info { __le16 id; /* pci function id */ @@ -1092,7 +1059,7 @@ struct qlcnic_pci_info { u8 mac[ETH_ALEN]; u8 reserved2[106]; -}; +} __packed; struct qlcnic_npar_info { u16 pvid; @@ -1209,15 +1176,160 @@ struct __qlcnic_esw_statistics { __le64 local_frames; __le64 numbytes; __le64 rsvd[3]; -}; +} __packed; struct qlcnic_esw_statistics { struct __qlcnic_esw_statistics rx; struct __qlcnic_esw_statistics tx; }; -int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val); -int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val); +struct qlcnic_common_entry_hdr { + __le32 type; + __le32 offset; + __le32 cap_size; + u8 mask; + u8 rsvd[2]; + u8 flags; +} __packed; + +struct __crb { + __le32 addr; + u8 stride; + u8 rsvd1[3]; + __le32 data_size; + __le32 no_ops; + __le32 rsvd2[4]; +} __packed; + +struct __ctrl { + __le32 addr; + u8 stride; + u8 index_a; + __le16 timeout; + __le32 data_size; + __le32 no_ops; + u8 opcode; + u8 index_v; + u8 shl_val; + u8 shr_val; + __le32 val1; + __le32 val2; + __le32 val3; +} __packed; + +struct __cache { + __le32 addr; + u8 stride; + u8 rsvd; + __le16 init_tag_val; + __le32 size; + __le32 no_ops; + __le32 ctrl_addr; + __le32 ctrl_val; + __le32 read_addr; + u8 read_addr_stride; + u8 read_addr_num; + u8 rsvd1[2]; +} __packed; + +struct __ocm { + u8 rsvd[8]; + __le32 size; + __le32 no_ops; + u8 rsvd1[8]; + __le32 read_addr; + __le32 read_addr_stride; +} __packed; + +struct __mem { + u8 rsvd[24]; + __le32 addr; + __le32 size; +} __packed; + +struct __mux { + __le32 addr; + u8 rsvd[4]; + __le32 size; + __le32 no_ops; + __le32 val; + __le32 val_stride; + __le32 read_addr; + u8 rsvd2[4]; +} __packed; + +struct __queue { + __le32 sel_addr; + __le16 stride; + u8 rsvd[2]; + __le32 size; + __le32 no_ops; + u8 rsvd2[8]; + __le32 read_addr; + u8 read_addr_stride; + u8 read_addr_cnt; + u8 rsvd3[2]; +} __packed; + +struct qlcnic_dump_entry { + struct qlcnic_common_entry_hdr hdr; + union { + struct __crb crb; + struct __cache cache; + struct __ocm ocm; + struct __mem mem; + struct __mux mux; + struct __queue que; + struct __ctrl ctrl; + } region; +} __packed; + +enum op_codes { + QLCNIC_DUMP_NOP = 0, + QLCNIC_DUMP_READ_CRB = 1, + QLCNIC_DUMP_READ_MUX = 2, + QLCNIC_DUMP_QUEUE = 3, + QLCNIC_DUMP_BRD_CONFIG = 4, + QLCNIC_DUMP_READ_OCM = 6, + QLCNIC_DUMP_PEG_REG = 7, + QLCNIC_DUMP_L1_DTAG = 8, + QLCNIC_DUMP_L1_ITAG = 9, + QLCNIC_DUMP_L1_DATA = 11, + QLCNIC_DUMP_L1_INST = 12, + QLCNIC_DUMP_L2_DTAG = 21, + QLCNIC_DUMP_L2_ITAG = 22, + QLCNIC_DUMP_L2_DATA = 23, + QLCNIC_DUMP_L2_INST = 24, + QLCNIC_DUMP_READ_ROM = 71, + QLCNIC_DUMP_READ_MEM = 72, + QLCNIC_DUMP_READ_CTRL = 98, + QLCNIC_DUMP_TLHDR = 99, + QLCNIC_DUMP_RDEND = 255 +}; + +#define QLCNIC_DUMP_WCRB BIT_0 +#define QLCNIC_DUMP_RWCRB BIT_1 +#define QLCNIC_DUMP_ANDCRB BIT_2 +#define QLCNIC_DUMP_ORCRB BIT_3 +#define QLCNIC_DUMP_POLLCRB BIT_4 +#define QLCNIC_DUMP_RD_SAVE BIT_5 +#define QLCNIC_DUMP_WRT_SAVED BIT_6 +#define QLCNIC_DUMP_MOD_SAVE_ST BIT_7 +#define QLCNIC_DUMP_SKIP BIT_7 + +#define QLCNIC_DUMP_MASK_MIN 3 +#define QLCNIC_DUMP_MASK_DEF 0x0f +#define QLCNIC_DUMP_MASK_MAX 0xff +#define QLCNIC_FORCE_FW_DUMP_KEY 0xdeadfeed + +struct qlcnic_dump_operations { + enum op_codes opcode; + u32 (*handler)(struct qlcnic_adapter *, + struct qlcnic_dump_entry *, u32 *); +}; + +int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter); +int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config); u32 qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off); int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *, ulong off, u32 data); @@ -1263,6 +1375,7 @@ int qlcnic_wol_supported(struct qlcnic_adapter *adapter); int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate); void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter); void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter); +int qlcnic_dump_fw(struct qlcnic_adapter *); /* Functions from qlcnic_init.c */ int qlcnic_load_firmware(struct qlcnic_adapter *adapter); @@ -1273,7 +1386,7 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter); int qlcnic_setup_idc_param(struct qlcnic_adapter *adapter); int qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter); -int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp); +int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp); int qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, u8 *bytes, size_t size); int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter); @@ -1293,7 +1406,7 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter); int qlcnic_check_fw_status(struct qlcnic_adapter *adapter); void qlcnic_watchdog_task(struct work_struct *work); -void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid, +void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, struct qlcnic_host_rds_ring *rds_ring); int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max); void qlcnic_set_multi(struct net_device *netdev); @@ -1307,6 +1420,8 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup); int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu); int qlcnic_change_mtu(struct net_device *netdev, int new_mtu); +u32 qlcnic_fix_features(struct net_device *netdev, u32 features); +int qlcnic_set_features(struct net_device *netdev, u32 features); int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable); int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable); int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter); @@ -1321,6 +1436,9 @@ u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter, void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings); int qlcnic_diag_alloc_res(struct net_device *netdev, int test); netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev); +int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val); +int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data); +void qlcnic_dev_request_reset(struct qlcnic_adapter *); /* Management functions */ int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*); @@ -1378,8 +1496,7 @@ static const struct qlcnic_brdinfo qlcnic_boards[] = { static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring) { - smp_mb(); - if (tx_ring->producer < tx_ring->sw_consumer) + if (likely(tx_ring->producer < tx_ring->sw_consumer)) return tx_ring->sw_consumer - tx_ring->producer; else return tx_ring->sw_consumer + tx_ring->num_desc - diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index 27631f23b3fd..bab041a5c758 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -64,14 +64,105 @@ qlcnic_issue_cmd(struct qlcnic_adapter *adapter, return rcode; } +static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u16 temp_size) +{ + uint64_t sum = 0; + int count = temp_size / sizeof(uint32_t); + while (count-- > 0) + sum += *temp_buffer++; + while (sum >> 32) + sum = (sum & 0xFFFFFFFF) + (sum >> 32); + return ~sum; +} + +int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter) +{ + int err, i; + u16 temp_size; + void *tmp_addr; + u32 version, csum, *template, *tmp_buf; + struct qlcnic_hardware_context *ahw; + struct qlcnic_dump_template_hdr *tmpl_hdr, *tmp_tmpl; + dma_addr_t tmp_addr_t = 0; + + ahw = adapter->ahw; + err = qlcnic_issue_cmd(adapter, + adapter->ahw->pci_func, + adapter->fw_hal_version, + 0, + 0, + 0, + QLCNIC_CDRP_CMD_TEMP_SIZE); + if (err != QLCNIC_RCODE_SUCCESS) { + err = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET); + dev_err(&adapter->pdev->dev, + "Failed to get template size %d\n", err); + err = -EIO; + return err; + } + version = QLCRD32(adapter, QLCNIC_ARG3_CRB_OFFSET); + temp_size = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET); + if (!temp_size) + return -EIO; + + tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size, + &tmp_addr_t, GFP_KERNEL); + if (!tmp_addr) { + dev_err(&adapter->pdev->dev, + "Can't get memory for FW dump template\n"); + return -ENOMEM; + } + err = qlcnic_issue_cmd(adapter, + adapter->ahw->pci_func, + adapter->fw_hal_version, + LSD(tmp_addr_t), + MSD(tmp_addr_t), + temp_size, + QLCNIC_CDRP_CMD_GET_TEMP_HDR); + + if (err != QLCNIC_RCODE_SUCCESS) { + dev_err(&adapter->pdev->dev, + "Failed to get mini dump template header %d\n", err); + err = -EIO; + goto error; + } + tmp_tmpl = (struct qlcnic_dump_template_hdr *) tmp_addr; + csum = qlcnic_temp_checksum((uint32_t *) tmp_addr, temp_size); + if (csum) { + dev_err(&adapter->pdev->dev, + "Template header checksum validation failed\n"); + err = -EIO; + goto error; + } + ahw->fw_dump.tmpl_hdr = vzalloc(temp_size); + if (!ahw->fw_dump.tmpl_hdr) { + err = -EIO; + goto error; + } + tmp_buf = (u32 *) tmp_addr; + template = (u32 *) ahw->fw_dump.tmpl_hdr; + for (i = 0; i < temp_size/sizeof(u32); i++) + *template++ = __le32_to_cpu(*tmp_buf++); + + tmpl_hdr = ahw->fw_dump.tmpl_hdr; + if (tmpl_hdr->cap_mask > QLCNIC_DUMP_MASK_DEF && + tmpl_hdr->cap_mask <= QLCNIC_DUMP_MASK_MAX) + tmpl_hdr->drv_cap_mask = tmpl_hdr->cap_mask; + else + tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF; +error: + dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t); + return err; +} + int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu) { - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) { if (qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, recv_ctx->context_id, mtu, @@ -102,12 +193,12 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) dma_addr_t hostrq_phys_addr, cardrsp_phys_addr; u64 phys_addr; - int i, nrds_rings, nsds_rings; + u8 i, nrds_rings, nsds_rings; size_t rq_size, rsp_size; u32 cap, reg, val, reg2; int err; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; nrds_rings = adapter->max_rds_rings; nsds_rings = adapter->max_sds_rings; @@ -119,14 +210,14 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) SIZEOF_CARDRSP_RX(struct qlcnic_cardrsp_rx_ctx, nrds_rings, nsds_rings); - addr = pci_alloc_consistent(adapter->pdev, - rq_size, &hostrq_phys_addr); + addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size, + &hostrq_phys_addr, GFP_KERNEL); if (addr == NULL) return -ENOMEM; prq = (struct qlcnic_hostrq_rx_ctx *)addr; - addr = pci_alloc_consistent(adapter->pdev, - rsp_size, &cardrsp_phys_addr); + addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size, + &cardrsp_phys_addr, GFP_KERNEL); if (addr == NULL) { err = -ENOMEM; goto out_free_rq; @@ -151,7 +242,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) prq->num_rds_rings = cpu_to_le16(nrds_rings); prq->num_sds_rings = cpu_to_le16(nsds_rings); - prq->rds_ring_offset = cpu_to_le32(0); + prq->rds_ring_offset = 0; val = le32_to_cpu(prq->rds_ring_offset) + (sizeof(struct qlcnic_hostrq_rds_ring) * nrds_rings); @@ -187,7 +278,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) phys_addr = hostrq_phys_addr; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, (u32)(phys_addr >> 32), (u32)(phys_addr & 0xffffffff), @@ -207,7 +298,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) rds_ring = &recv_ctx->rds_rings[i]; reg = le32_to_cpu(prsp_rds[i].host_producer_crb); - rds_ring->crb_rcv_producer = adapter->ahw.pci_base0 + reg; + rds_ring->crb_rcv_producer = adapter->ahw->pci_base0 + reg; } prsp_sds = ((struct qlcnic_cardrsp_sds_ring *) @@ -219,8 +310,8 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) reg = le32_to_cpu(prsp_sds[i].host_consumer_crb); reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb); - sds_ring->crb_sts_consumer = adapter->ahw.pci_base0 + reg; - sds_ring->crb_intr_mask = adapter->ahw.pci_base0 + reg2; + sds_ring->crb_sts_consumer = adapter->ahw->pci_base0 + reg; + sds_ring->crb_intr_mask = adapter->ahw->pci_base0 + reg2; } recv_ctx->state = le32_to_cpu(prsp->host_ctx_state); @@ -228,19 +319,20 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) recv_ctx->virt_port = prsp->virt_port; out_free_rsp: - pci_free_consistent(adapter->pdev, rsp_size, prsp, cardrsp_phys_addr); + dma_free_coherent(&adapter->pdev->dev, rsp_size, prsp, + cardrsp_phys_addr); out_free_rq: - pci_free_consistent(adapter->pdev, rq_size, prq, hostrq_phys_addr); + dma_free_coherent(&adapter->pdev->dev, rq_size, prq, hostrq_phys_addr); return err; } static void qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter) { - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, recv_ctx->context_id, QLCNIC_DESTROY_CTX_RESET, @@ -274,14 +366,14 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) *(tx_ring->hw_consumer) = 0; rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx); - rq_addr = pci_alloc_consistent(adapter->pdev, - rq_size, &rq_phys_addr); + rq_addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size, + &rq_phys_addr, GFP_KERNEL); if (!rq_addr) return -ENOMEM; rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx); - rsp_addr = pci_alloc_consistent(adapter->pdev, - rsp_size, &rsp_phys_addr); + rsp_addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size, + &rsp_phys_addr, GFP_KERNEL); if (!rsp_addr) { err = -ENOMEM; goto out_free_rq; @@ -313,7 +405,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) phys_addr = rq_phys_addr; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, (u32)(phys_addr >> 32), ((u32)phys_addr & 0xffffffff), @@ -322,7 +414,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) if (err == QLCNIC_RCODE_SUCCESS) { temp = le32_to_cpu(prsp->cds_ring.host_producer_crb); - tx_ring->crb_cmd_producer = adapter->ahw.pci_base0 + temp; + tx_ring->crb_cmd_producer = adapter->ahw->pci_base0 + temp; adapter->tx_context_id = le16_to_cpu(prsp->context_id); @@ -332,10 +424,11 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) err = -EIO; } - pci_free_consistent(adapter->pdev, rsp_size, rsp_addr, rsp_phys_addr); + dma_free_coherent(&adapter->pdev->dev, rsp_size, rsp_addr, + rsp_phys_addr); out_free_rq: - pci_free_consistent(adapter->pdev, rq_size, rq_addr, rq_phys_addr); + dma_free_coherent(&adapter->pdev->dev, rq_size, rq_addr, rq_phys_addr); return err; } @@ -344,7 +437,7 @@ static void qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter) { if (qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, adapter->tx_context_id, QLCNIC_DESTROY_CTX_RESET, @@ -357,33 +450,15 @@ qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter) } int -qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val) -{ - - if (qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, - adapter->fw_hal_version, - reg, - 0, - 0, - QLCNIC_CDRP_CMD_READ_PHY)) { - - return -EIO; - } - - return QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET); -} - -int -qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val) +qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config) { return qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, - reg, - val, + config, 0, - QLCNIC_CDRP_CMD_WRITE_PHY); + 0, + QLCNIC_CDRP_CMD_CONFIG_PORT); } int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) @@ -398,20 +473,19 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) struct pci_dev *pdev = adapter->pdev; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; tx_ring = adapter->tx_ring; - tx_ring->hw_consumer = (__le32 *)pci_alloc_consistent(pdev, sizeof(u32), - &tx_ring->hw_cons_phys_addr); + tx_ring->hw_consumer = (__le32 *) dma_alloc_coherent(&pdev->dev, + sizeof(u32), &tx_ring->hw_cons_phys_addr, GFP_KERNEL); if (tx_ring->hw_consumer == NULL) { dev_err(&pdev->dev, "failed to allocate tx consumer\n"); return -ENOMEM; } - *(tx_ring->hw_consumer) = 0; /* cmd desc ring */ - addr = pci_alloc_consistent(pdev, TX_DESC_RINGSIZE(tx_ring), - &tx_ring->phys_addr); + addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring), + &tx_ring->phys_addr, GFP_KERNEL); if (addr == NULL) { dev_err(&pdev->dev, "failed to allocate tx desc ring\n"); @@ -423,9 +497,9 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; - addr = pci_alloc_consistent(adapter->pdev, + addr = dma_alloc_coherent(&adapter->pdev->dev, RCV_DESC_RINGSIZE(rds_ring), - &rds_ring->phys_addr); + &rds_ring->phys_addr, GFP_KERNEL); if (addr == NULL) { dev_err(&pdev->dev, "failed to allocate rds ring [%d]\n", ring); @@ -439,9 +513,9 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; - addr = pci_alloc_consistent(adapter->pdev, + addr = dma_alloc_coherent(&adapter->pdev->dev, STATUS_DESC_RINGSIZE(sds_ring), - &sds_ring->phys_addr); + &sds_ring->phys_addr, GFP_KERNEL); if (addr == NULL) { dev_err(&pdev->dev, "failed to allocate sds ring [%d]\n", ring); @@ -501,11 +575,11 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) struct qlcnic_host_tx_ring *tx_ring; int ring; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; tx_ring = adapter->tx_ring; if (tx_ring->hw_consumer != NULL) { - pci_free_consistent(adapter->pdev, + dma_free_coherent(&adapter->pdev->dev, sizeof(u32), tx_ring->hw_consumer, tx_ring->hw_cons_phys_addr); @@ -513,7 +587,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) } if (tx_ring->desc_head != NULL) { - pci_free_consistent(adapter->pdev, + dma_free_coherent(&adapter->pdev->dev, TX_DESC_RINGSIZE(tx_ring), tx_ring->desc_head, tx_ring->phys_addr); tx_ring->desc_head = NULL; @@ -523,7 +597,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) rds_ring = &recv_ctx->rds_rings[ring]; if (rds_ring->desc_head != NULL) { - pci_free_consistent(adapter->pdev, + dma_free_coherent(&adapter->pdev->dev, RCV_DESC_RINGSIZE(rds_ring), rds_ring->desc_head, rds_ring->phys_addr); @@ -535,7 +609,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) sds_ring = &recv_ctx->sds_rings[ring]; if (sds_ring->desc_head != NULL) { - pci_free_consistent(adapter->pdev, + dma_free_coherent(&adapter->pdev->dev, STATUS_DESC_RINGSIZE(sds_ring), sds_ring->desc_head, sds_ring->phys_addr); @@ -551,9 +625,9 @@ int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac) int err; u32 arg1; - arg1 = adapter->ahw.pci_func | BIT_8; + arg1 = adapter->ahw->pci_func | BIT_8; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, 0, @@ -582,15 +656,15 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, void *nic_info_addr; size_t nic_size = sizeof(struct qlcnic_info); - nic_info_addr = pci_alloc_consistent(adapter->pdev, - nic_size, &nic_dma_t); + nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size, + &nic_dma_t, GFP_KERNEL); if (!nic_info_addr) return -ENOMEM; memset(nic_info_addr, 0, nic_size); nic_info = (struct qlcnic_info *) nic_info_addr; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, MSD(nic_dma_t), LSD(nic_dma_t), @@ -623,7 +697,8 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, err = -EIO; } - pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t); + dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr, + nic_dma_t); return err; } @@ -639,8 +714,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) if (adapter->op_mode != QLCNIC_MGMT_FUNC) return err; - nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size, - &nic_dma_t); + nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size, + &nic_dma_t, GFP_KERNEL); if (!nic_info_addr) return -ENOMEM; @@ -659,7 +734,7 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw); err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, MSD(nic_dma_t), LSD(nic_dma_t), @@ -672,7 +747,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) err = -EIO; } - pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t); + dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr, + nic_dma_t); return err; } @@ -687,15 +763,15 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter, size_t npar_size = sizeof(struct qlcnic_pci_info); size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC; - pci_info_addr = pci_alloc_consistent(adapter->pdev, pci_size, - &pci_info_dma_t); + pci_info_addr = dma_alloc_coherent(&adapter->pdev->dev, pci_size, + &pci_info_dma_t, GFP_KERNEL); if (!pci_info_addr) return -ENOMEM; memset(pci_info_addr, 0, pci_size); npar = (struct qlcnic_pci_info *) pci_info_addr; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, MSD(pci_info_dma_t), LSD(pci_info_dma_t), @@ -721,7 +797,7 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter, err = -EIO; } - pci_free_consistent(adapter->pdev, pci_size, pci_info_addr, + dma_free_coherent(&adapter->pdev->dev, pci_size, pci_info_addr, pci_info_dma_t); return err; } @@ -741,7 +817,7 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id, arg1 |= pci_func << 8; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, 0, @@ -775,14 +851,14 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, return -ENOMEM; if (adapter->op_mode != QLCNIC_MGMT_FUNC && - func != adapter->ahw.pci_func) { + func != adapter->ahw->pci_func) { dev_err(&adapter->pdev->dev, "Not privilege to query stats for func=%d", func); return -EIO; } - stats_addr = pci_alloc_consistent(adapter->pdev, stats_size, - &stats_dma_t); + stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size, + &stats_dma_t, GFP_KERNEL); if (!stats_addr) { dev_err(&adapter->pdev->dev, "Unable to allocate memory\n"); return -ENOMEM; @@ -793,7 +869,7 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, arg1 |= rx_tx << 15 | stats_size << 16; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, MSD(stats_dma_t), @@ -816,7 +892,7 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, esw_stats->numbytes = le64_to_cpu(stats->numbytes); } - pci_free_consistent(adapter->pdev, stats_size, stats_addr, + dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr, stats_dma_t); return err; } @@ -900,7 +976,7 @@ int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw, arg1 |= BIT_14 | rx_tx << 15; return qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, 0, @@ -921,7 +997,7 @@ __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter, u8 pci_func; pci_func = (*arg1 >> 8); err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, *arg1, 0, @@ -999,7 +1075,7 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, } err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, arg2, diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 45b2755d6cba..9efc690a289f 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -150,10 +150,10 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct qlcnic_adapter *adapter = netdev_priv(dev); int check_sfp_module = 0; - u16 pcifn = adapter->ahw.pci_func; + u16 pcifn = adapter->ahw->pci_func; /* read which mode */ - if (adapter->ahw.port_type == QLCNIC_GBE) { + if (adapter->ahw->port_type == QLCNIC_GBE) { ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | @@ -166,11 +166,11 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full); - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); ecmd->duplex = adapter->link_duplex; ecmd->autoneg = adapter->link_autoneg; - } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + } else if (adapter->ahw->port_type == QLCNIC_XGBE) { u32 val; val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR); @@ -183,15 +183,15 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } if (netif_running(dev) && adapter->has_link_events) { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); ecmd->autoneg = adapter->link_autoneg; ecmd->duplex = adapter->link_duplex; goto skip; } val = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn)); - ecmd->speed = P3P_LINK_SPEED_MHZ * - P3P_LINK_SPEED_VAL(pcifn, val); + ethtool_cmd_speed_set(ecmd, P3P_LINK_SPEED_MHZ * + P3P_LINK_SPEED_VAL(pcifn, val)); ecmd->duplex = DUPLEX_FULL; ecmd->autoneg = AUTONEG_DISABLE; } else @@ -201,7 +201,7 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->phy_address = adapter->physical_port; ecmd->transceiver = XCVR_EXTERNAL; - switch (adapter->ahw.board_type) { + switch (adapter->ahw->board_type) { case QLCNIC_BRDTYPE_P3P_REF_QG: case QLCNIC_BRDTYPE_P3P_4_GB: case QLCNIC_BRDTYPE_P3P_4_GB_MM: @@ -238,7 +238,7 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->autoneg = AUTONEG_DISABLE; break; case QLCNIC_BRDTYPE_P3P_10G_TP: - if (adapter->ahw.port_type == QLCNIC_XGBE) { + if (adapter->ahw->port_type == QLCNIC_XGBE) { ecmd->autoneg = AUTONEG_DISABLE; ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP); ecmd->advertising |= @@ -256,7 +256,7 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) break; default: dev_err(&adapter->pdev->dev, "Unsupported board model %d\n", - adapter->ahw.board_type); + adapter->ahw->board_type); return -EIO; } @@ -284,50 +284,44 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { + u32 config = 0; + u32 ret = 0; struct qlcnic_adapter *adapter = netdev_priv(dev); - __u32 status; + + if (adapter->ahw->port_type != QLCNIC_GBE) + return -EOPNOTSUPP; /* read which mode */ - if (adapter->ahw.port_type == QLCNIC_GBE) { - /* autonegotiation */ - if (qlcnic_fw_cmd_set_phy(adapter, - QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG, - ecmd->autoneg) != 0) - return -EIO; - else - adapter->link_autoneg = ecmd->autoneg; + if (ecmd->duplex) + config |= 0x1; - if (qlcnic_fw_cmd_query_phy(adapter, - QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - &status) != 0) - return -EIO; + if (ecmd->autoneg) + config |= 0x2; - switch (ecmd->speed) { - case SPEED_10: - qlcnic_set_phy_speed(status, 0); - break; - case SPEED_100: - qlcnic_set_phy_speed(status, 1); - break; - case SPEED_1000: - qlcnic_set_phy_speed(status, 2); - break; - } + switch (ethtool_cmd_speed(ecmd)) { + case SPEED_10: + config |= (0 << 8); + break; + case SPEED_100: + config |= (1 << 8); + break; + case SPEED_1000: + config |= (10 << 8); + break; + default: + return -EIO; + } - if (ecmd->duplex == DUPLEX_HALF) - qlcnic_clear_phy_duplex(status); - if (ecmd->duplex == DUPLEX_FULL) - qlcnic_set_phy_duplex(status); - if (qlcnic_fw_cmd_set_phy(adapter, - QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - *((int *)&status)) != 0) - return -EIO; - else { - adapter->link_speed = ecmd->speed; - adapter->link_duplex = ecmd->duplex; - } - } else + ret = qlcnic_fw_cmd_set_port(adapter, config); + + if (ret == QLCNIC_RCODE_NOT_SUPPORTED) return -EOPNOTSUPP; + else if (ret) + return -EIO; + + adapter->link_speed = ethtool_cmd_speed(ecmd); + adapter->link_duplex = ecmd->duplex; + adapter->link_autoneg = ecmd->autoneg; if (!netif_running(dev)) return 0; @@ -340,14 +334,14 @@ static void qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) { struct qlcnic_adapter *adapter = netdev_priv(dev); - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; struct qlcnic_host_sds_ring *sds_ring; u32 *regs_buff = p; int ring, i = 0, j = 0; memset(p, 0, qlcnic_get_regs_len(dev)); regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) | - (adapter->ahw.revision_id << 16) | (adapter->pdev)->device; + (adapter->ahw->revision_id << 16) | (adapter->pdev)->device; regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff)); regs_buff[1] = QLCNIC_MGMT_API_VERSION; @@ -382,7 +376,7 @@ static u32 qlcnic_test_link(struct net_device *dev) u32 val; val = QLCRD32(adapter, CRB_XG_STATE_P3P); - val = XG_LINK_STATE_P3P(adapter->ahw.pci_func, val); + val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val); return (val == XG_LINK_UP_P3P) ? 0 : 1; } @@ -474,6 +468,39 @@ qlcnic_set_ringparam(struct net_device *dev, return qlcnic_reset_context(adapter); } +static void qlcnic_get_channels(struct net_device *dev, + struct ethtool_channels *channel) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + + channel->max_rx = rounddown_pow_of_two(min_t(int, + adapter->max_rx_ques, num_online_cpus())); + channel->max_tx = adapter->max_tx_ques; + + channel->rx_count = adapter->max_sds_rings; + channel->tx_count = adapter->max_tx_ques; +} + +static int qlcnic_set_channels(struct net_device *dev, + struct ethtool_channels *channel) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + int err; + + if (channel->other_count || channel->combined_count || + channel->tx_count != channel->max_tx) + return -EINVAL; + + err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count); + if (err) + return err; + + err = qlcnic_set_max_rss(adapter, channel->rx_count); + netdev_info(dev, "allocated 0x%x sds rings\n", + adapter->max_sds_rings); + return err; +} + static void qlcnic_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) @@ -482,7 +509,7 @@ qlcnic_get_pauseparam(struct net_device *netdev, int port = adapter->physical_port; __u32 val; - if (adapter->ahw.port_type == QLCNIC_GBE) { + if (adapter->ahw->port_type == QLCNIC_GBE) { if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) return; /* get flow control settings */ @@ -504,7 +531,7 @@ qlcnic_get_pauseparam(struct net_device *netdev, pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val)); break; } - } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + } else if (adapter->ahw->port_type == QLCNIC_XGBE) { if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) return; pause->rx_pause = 1; @@ -515,7 +542,7 @@ qlcnic_get_pauseparam(struct net_device *netdev, pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val)); } else { dev_err(&netdev->dev, "Unknown board type: %x\n", - adapter->ahw.port_type); + adapter->ahw->port_type); } } @@ -528,7 +555,7 @@ qlcnic_set_pauseparam(struct net_device *netdev, __u32 val; /* read mode */ - if (adapter->ahw.port_type == QLCNIC_GBE) { + if (adapter->ahw->port_type == QLCNIC_GBE) { if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) return -EIO; /* set flow control */ @@ -571,7 +598,7 @@ qlcnic_set_pauseparam(struct net_device *netdev, break; } QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val); - } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + } else if (adapter->ahw->port_type == QLCNIC_XGBE) { if (!pause->rx_pause || pause->autoneg) return -EOPNOTSUPP; @@ -593,7 +620,7 @@ qlcnic_set_pauseparam(struct net_device *netdev, QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val); } else { dev_err(&netdev->dev, "Unknown board type: %x\n", - adapter->ahw.port_type); + adapter->ahw->port_type); } return 0; } @@ -639,8 +666,8 @@ static int qlcnic_irq_test(struct net_device *netdev) goto clear_it; adapter->diag_cnt = 0; - ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func, - adapter->fw_hal_version, adapter->portnum, + ret = qlcnic_issue_cmd(adapter, adapter->ahw->pci_func, + adapter->fw_hal_version, adapter->ahw->pci_func, 0, 0, 0x00000011); if (ret) goto done; @@ -749,14 +776,14 @@ qlcnic_get_ethtool_stats(struct net_device *dev, return; memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics)); - ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func, + ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func, QLCNIC_QUERY_RX_COUNTER, &port_stats.rx); if (ret) return; qlcnic_fill_device_stats(&index, data, &port_stats.rx); - ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func, + ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func, QLCNIC_QUERY_TX_COUNTER, &port_stats.tx); if (ret) return; @@ -764,115 +791,49 @@ qlcnic_get_ethtool_stats(struct net_device *dev, qlcnic_fill_device_stats(&index, data, &port_stats.tx); } -static int qlcnic_set_tx_csum(struct net_device *dev, u32 data) -{ - struct qlcnic_adapter *adapter = netdev_priv(dev); - - if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) - return -EOPNOTSUPP; - if (data) - dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - else - dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - - return 0; - -} -static u32 qlcnic_get_tx_csum(struct net_device *dev) -{ - return dev->features & NETIF_F_IP_CSUM; -} - -static u32 qlcnic_get_rx_csum(struct net_device *dev) -{ - struct qlcnic_adapter *adapter = netdev_priv(dev); - return adapter->rx_csum; -} - -static int qlcnic_set_rx_csum(struct net_device *dev, u32 data) -{ - struct qlcnic_adapter *adapter = netdev_priv(dev); - - if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) - return -EOPNOTSUPP; - if (!!data) { - adapter->rx_csum = !!data; - return 0; - } - - if (dev->features & NETIF_F_LRO) { - if (qlcnic_config_hw_lro(adapter, QLCNIC_LRO_DISABLED)) - return -EIO; - - dev->features &= ~NETIF_F_LRO; - qlcnic_send_lro_cleanup(adapter); - dev_info(&adapter->pdev->dev, - "disabling LRO as rx_csum is off\n"); - } - adapter->rx_csum = !!data; - return 0; -} - -static u32 qlcnic_get_tso(struct net_device *dev) -{ - return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0; -} - -static int qlcnic_set_tso(struct net_device *dev, u32 data) -{ - struct qlcnic_adapter *adapter = netdev_priv(dev); - if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)) - return -EOPNOTSUPP; - if (data) - dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - -static int qlcnic_blink_led(struct net_device *dev, u32 val) +static int qlcnic_set_led(struct net_device *dev, + enum ethtool_phys_id_state state) { struct qlcnic_adapter *adapter = netdev_priv(dev); int max_sds_rings = adapter->max_sds_rings; - int dev_down = 0; - int ret; - if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { - dev_down = 1; - if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) - return -EIO; + switch (state) { + case ETHTOOL_ID_ACTIVE: + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return -EIO; - ret = qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST); - if (ret) { - clear_bit(__QLCNIC_RESETTING, &adapter->state); - return ret; + if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST)) { + clear_bit(__QLCNIC_RESETTING, &adapter->state); + return -EIO; + } + set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state); } - } - ret = adapter->nic_ops->config_led(adapter, 1, 0xf); - if (ret) { + if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) + return 0; + dev_err(&adapter->pdev->dev, "Failed to set LED blink state.\n"); - goto done; + break; + + case ETHTOOL_ID_INACTIVE: + if (adapter->nic_ops->config_led(adapter, 0, 0xf)) + dev_err(&adapter->pdev->dev, + "Failed to reset LED blink state.\n"); + + break; + + default: + return -EINVAL; } - msleep_interruptible(val * 1000); - - ret = adapter->nic_ops->config_led(adapter, 0, 0xf); - if (ret) { - dev_err(&adapter->pdev->dev, - "Failed to reset LED blink state.\n"); - goto done; - } - -done: - if (dev_down) { + if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) { qlcnic_diag_free_res(dev, max_sds_rings); clear_bit(__QLCNIC_RESETTING, &adapter->state); } - return ret; + return -EIO; } static void @@ -936,8 +897,8 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev, */ if (ethcoal->rx_coalesce_usecs > 0xffff || ethcoal->rx_max_coalesced_frames > 0xffff || - ethcoal->tx_coalesce_usecs > 0xffff || - ethcoal->tx_max_coalesced_frames > 0xffff || + ethcoal->tx_coalesce_usecs || + ethcoal->tx_max_coalesced_frames || ethcoal->rx_coalesce_usecs_irq || ethcoal->rx_max_coalesced_frames_irq || ethcoal->tx_coalesce_usecs_irq || @@ -959,21 +920,17 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev, if (!ethcoal->rx_coalesce_usecs || !ethcoal->rx_max_coalesced_frames) { - adapter->coal.flags = QLCNIC_INTR_DEFAULT; - adapter->coal.normal.data.rx_time_us = + adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT; + adapter->ahw->coal.rx_time_us = QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; - adapter->coal.normal.data.rx_packets = + adapter->ahw->coal.rx_packets = QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; } else { - adapter->coal.flags = 0; - adapter->coal.normal.data.rx_time_us = - ethcoal->rx_coalesce_usecs; - adapter->coal.normal.data.rx_packets = - ethcoal->rx_max_coalesced_frames; + adapter->ahw->coal.flag = 0; + adapter->ahw->coal.rx_time_us = ethcoal->rx_coalesce_usecs; + adapter->ahw->coal.rx_packets = + ethcoal->rx_max_coalesced_frames; } - adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs; - adapter->coal.normal.data.tx_packets = - ethcoal->tx_max_coalesced_frames; qlcnic_config_intr_coalesce(adapter); @@ -988,50 +945,8 @@ static int qlcnic_get_intr_coalesce(struct net_device *netdev, if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) return -EINVAL; - ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us; - ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us; - ethcoal->rx_max_coalesced_frames = - adapter->coal.normal.data.rx_packets; - ethcoal->tx_max_coalesced_frames = - adapter->coal.normal.data.tx_packets; - - return 0; -} - -static int qlcnic_set_flags(struct net_device *netdev, u32 data) -{ - struct qlcnic_adapter *adapter = netdev_priv(netdev); - int hw_lro; - - if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) - return -EINVAL; - - if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) - return -EINVAL; - - if (!adapter->rx_csum) { - dev_info(&adapter->pdev->dev, "rx csum is off, " - "cannot toggle lro\n"); - return -EINVAL; - } - - if ((data & ETH_FLAG_LRO) && (netdev->features & NETIF_F_LRO)) - return 0; - - if (data & ETH_FLAG_LRO) { - hw_lro = QLCNIC_LRO_ENABLED; - netdev->features |= NETIF_F_LRO; - } else { - hw_lro = 0; - netdev->features &= ~NETIF_F_LRO; - } - - if (qlcnic_config_hw_lro(adapter, hw_lro)) - return -EIO; - - if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter)) - return -EIO; - + ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us; + ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets; return 0; } @@ -1050,6 +965,84 @@ static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl) adapter->msg_enable = msglvl; } +static int +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; + + dump->len = fw_dump->tmpl_hdr->size + fw_dump->size; + dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; + dump->version = adapter->fw_version; + return 0; +} + +static int +qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, + void *buffer) +{ + int i, copy_sz; + u32 *hdr_ptr, *data; + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; + + if (qlcnic_api_lock(adapter)) + return -EIO; + if (!fw_dump->clr) { + netdev_info(netdev, "Dump not available\n"); + qlcnic_api_unlock(adapter); + return -EINVAL; + } + /* Copy template header first */ + copy_sz = fw_dump->tmpl_hdr->size; + hdr_ptr = (u32 *) fw_dump->tmpl_hdr; + data = (u32 *) buffer; + for (i = 0; i < copy_sz/sizeof(u32); i++) + *data++ = cpu_to_le32(*hdr_ptr++); + + /* Copy captured dump data */ + memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size); + dump->len = copy_sz + fw_dump->size; + dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; + + /* Free dump area once data has been captured */ + vfree(fw_dump->data); + fw_dump->data = NULL; + fw_dump->clr = 0; + qlcnic_api_unlock(adapter); + + return 0; +} + +static int +qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val) +{ + int ret = 0; + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; + + if (val->flag == QLCNIC_FORCE_FW_DUMP_KEY) { + netdev_info(netdev, "Forcing a FW dump\n"); + qlcnic_dev_request_reset(adapter); + } else { + 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 (qlcnic_api_lock(adapter)) + return -EIO; + fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff; + qlcnic_api_unlock(adapter); + netdev_info(netdev, "Driver mask changed to: 0x%x\n", + fw_dump->tmpl_hdr->drv_cap_mask); + } +out: + return ret; +} + const struct ethtool_ops qlcnic_ethtool_ops = { .get_settings = qlcnic_get_settings, .set_settings = qlcnic_set_settings, @@ -1061,26 +1054,22 @@ const struct ethtool_ops qlcnic_ethtool_ops = { .get_eeprom = qlcnic_get_eeprom, .get_ringparam = qlcnic_get_ringparam, .set_ringparam = qlcnic_set_ringparam, + .get_channels = qlcnic_get_channels, + .set_channels = qlcnic_set_channels, .get_pauseparam = qlcnic_get_pauseparam, .set_pauseparam = qlcnic_set_pauseparam, - .get_tx_csum = qlcnic_get_tx_csum, - .set_tx_csum = qlcnic_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .get_tso = qlcnic_get_tso, - .set_tso = qlcnic_set_tso, .get_wol = qlcnic_get_wol, .set_wol = qlcnic_set_wol, .self_test = qlcnic_diag_test, .get_strings = qlcnic_get_strings, .get_ethtool_stats = qlcnic_get_ethtool_stats, .get_sset_count = qlcnic_get_sset_count, - .get_rx_csum = qlcnic_get_rx_csum, - .set_rx_csum = qlcnic_set_rx_csum, .get_coalesce = qlcnic_get_intr_coalesce, .set_coalesce = qlcnic_set_intr_coalesce, - .get_flags = ethtool_op_get_flags, - .set_flags = qlcnic_set_flags, - .phys_id = qlcnic_blink_led, + .set_phys_id = qlcnic_set_led, .set_msglevel = qlcnic_set_msglevel, .get_msglevel = qlcnic_get_msglevel, + .get_dump_flag = qlcnic_get_dump_flag, + .get_dump_data = qlcnic_get_dump_data, + .set_dump = qlcnic_set_dump, }; diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h index 726ef555b6bc..d14506f764e0 100644 --- a/drivers/net/qlcnic/qlcnic_hdr.h +++ b/drivers/net/qlcnic/qlcnic_hdr.h @@ -492,10 +492,10 @@ enum { #define TEST_AGT_CTRL (0x00) -#define TA_CTL_START 1 -#define TA_CTL_ENABLE 2 -#define TA_CTL_WRITE 4 -#define TA_CTL_BUSY 8 +#define TA_CTL_START BIT_0 +#define TA_CTL_ENABLE BIT_1 +#define TA_CTL_WRITE BIT_2 +#define TA_CTL_BUSY BIT_3 /* * Register offsets for MN @@ -765,6 +765,38 @@ struct qlcnic_legacy_intr_set { #define QLCNIC_MAX_PCI_FUNC 8 #define QLCNIC_MAX_VLAN_FILTERS 64 +/* FW dump defines */ +#define MIU_TEST_CTR 0x41000090 +#define MIU_TEST_ADDR_LO 0x41000094 +#define MIU_TEST_ADDR_HI 0x41000098 +#define FLASH_ROM_WINDOW 0x42110030 +#define FLASH_ROM_DATA 0x42150000 + +static const u32 MIU_TEST_READ_DATA[] = { + 0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC, }; + +#define QLCNIC_FW_DUMP_REG1 0x00130060 +#define QLCNIC_FW_DUMP_REG2 0x001e0000 +#define QLCNIC_FLASH_SEM2_LK 0x0013C010 +#define QLCNIC_FLASH_SEM2_ULK 0x0013C014 +#define QLCNIC_FLASH_LOCK_ID 0x001B2100 + +#define QLCNIC_RD_DUMP_REG(addr, bar0, data) do { \ + writel((addr & 0xFFFF0000), (void *) (bar0 + \ + QLCNIC_FW_DUMP_REG1)); \ + readl((void *) (bar0 + QLCNIC_FW_DUMP_REG1)); \ + *data = readl((void *) (bar0 + QLCNIC_FW_DUMP_REG2 + \ + LSW(addr))); \ +} while (0) + +#define QLCNIC_WR_DUMP_REG(addr, bar0, data) do { \ + writel((addr & 0xFFFF0000), (void *) (bar0 + \ + QLCNIC_FW_DUMP_REG1)); \ + readl((void *) (bar0 + QLCNIC_FW_DUMP_REG1)); \ + writel(data, (void *) (bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr)));\ + readl((void *) (bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr))); \ +} while (0) + /* PCI function operational mode */ enum { QLCNIC_MGMT_FUNC = 0, diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index 616940f0a8d0..e9656616f2a2 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -9,6 +9,7 @@ #include #include +#include #define MASK(n) ((1ULL<<(n))-1) #define OCM_WIN_P3P(addr) (addr & 0xffc0000) @@ -457,7 +458,7 @@ int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); - word = QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE | + word = QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE | ((u64)adapter->portnum << 16); req.req_hdr = cpu_to_le64(word); @@ -532,33 +533,31 @@ void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter) } } -#define QLCNIC_CONFIG_INTR_COALESCE 3 - /* * Send the interrupt coalescing parameter set by ethtool to the card. */ int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter) { struct qlcnic_nic_req req; - u64 word[6]; - int rv, i; + int rv; memset(&req, 0, sizeof(struct qlcnic_nic_req)); req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); - word[0] = QLCNIC_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); - req.req_hdr = cpu_to_le64(word[0]); - - memcpy(&word[0], &adapter->coal, sizeof(adapter->coal)); - for (i = 0; i < 6; i++) - req.words[i] = cpu_to_le64(word[i]); + req.req_hdr = cpu_to_le64(QLCNIC_CONFIG_INTR_COALESCE | + ((u64) adapter->portnum << 16)); + req.words[0] = cpu_to_le64(((u64) adapter->ahw->coal.flag) << 32); + req.words[2] = cpu_to_le64(adapter->ahw->coal.rx_packets | + ((u64) adapter->ahw->coal.rx_time_us) << 16); + req.words[5] = cpu_to_le64(adapter->ahw->coal.timer_out | + ((u64) adapter->ahw->coal.type) << 32 | + ((u64) adapter->ahw->coal.sts_ring_mask) << 40); rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); if (rv != 0) dev_err(&adapter->netdev->dev, "Could not send interrupt coalescing parameters\n"); - return rv; } @@ -568,6 +567,9 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable) u64 word; int rv; + if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) + return 0; + memset(&req, 0, sizeof(struct qlcnic_nic_req)); req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); @@ -713,6 +715,9 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter) u64 word; int rv; + if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) + return 0; + memset(&req, 0, sizeof(struct qlcnic_nic_req)); req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); @@ -754,6 +759,43 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu) return rc; } + +u32 qlcnic_fix_features(struct net_device *netdev, u32 features) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) { + u32 changed = features ^ netdev->features; + features ^= changed & (NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); + } + + if (!(features & NETIF_F_RXCSUM)) + features &= ~NETIF_F_LRO; + + return features; +} + + +int qlcnic_set_features(struct net_device *netdev, u32 features) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + u32 changed = netdev->features ^ features; + int hw_lro = (features & NETIF_F_LRO) ? QLCNIC_LRO_ENABLED : 0; + + if (!(changed & NETIF_F_LRO)) + return 0; + + netdev->features = features ^ NETIF_F_LRO; + + if (qlcnic_config_hw_lro(adapter, hw_lro)) + return -EIO; + + if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter)) + return -EIO; + + return 0; +} + /* * Changes the CRB window to the specified window. */ @@ -780,7 +822,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter, m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)]; if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) { - *addr = adapter->ahw.pci_base0 + m->start_2M + + *addr = adapter->ahw->pci_base0 + m->start_2M + (off - m->start_128M); return 0; } @@ -788,7 +830,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter, /* * Not in direct map, use crb window */ - *addr = adapter->ahw.pci_base0 + CRB_INDIRECT_2M + (off & MASK(16)); + *addr = adapter->ahw->pci_base0 + CRB_INDIRECT_2M + (off & MASK(16)); return 1; } @@ -801,7 +843,7 @@ static int qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off) { u32 window; - void __iomem *addr = adapter->ahw.pci_base0 + CRB_WINDOW_2M; + void __iomem *addr = adapter->ahw->pci_base0 + CRB_WINDOW_2M; off -= QLCNIC_PCI_CRBSPACE; @@ -838,13 +880,13 @@ qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data) if (rv > 0) { /* indirect access */ - write_lock_irqsave(&adapter->ahw.crb_lock, flags); + write_lock_irqsave(&adapter->ahw->crb_lock, flags); crb_win_lock(adapter); rv = qlcnic_pci_set_crbwindow_2M(adapter, off); if (!rv) writel(data, addr); crb_win_unlock(adapter); - write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); + write_unlock_irqrestore(&adapter->ahw->crb_lock, flags); return rv; } @@ -869,12 +911,12 @@ qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off) if (rv > 0) { /* indirect access */ - write_lock_irqsave(&adapter->ahw.crb_lock, flags); + write_lock_irqsave(&adapter->ahw->crb_lock, flags); crb_win_lock(adapter); if (!qlcnic_pci_set_crbwindow_2M(adapter, off)) data = readl(addr); crb_win_unlock(adapter); - write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); + write_unlock_irqrestore(&adapter->ahw->crb_lock, flags); return data; } @@ -904,9 +946,9 @@ qlcnic_pci_set_window_2M(struct qlcnic_adapter *adapter, window = OCM_WIN_P3P(addr); - writel(window, adapter->ahw.ocm_win_crb); + writel(window, adapter->ahw->ocm_win_crb); /* read back to flush */ - readl(adapter->ahw.ocm_win_crb); + readl(adapter->ahw->ocm_win_crb); *start = QLCNIC_PCI_OCM0_2M + GET_MEM_OFFS_2M(addr); return 0; @@ -920,13 +962,13 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off, int ret; u32 start; - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); ret = qlcnic_pci_set_window_2M(adapter, off, &start); if (ret != 0) goto unlock; - addr = adapter->ahw.pci_base0 + start; + addr = adapter->ahw->pci_base0 + start; if (op == 0) /* read */ *data = readq(addr); @@ -934,7 +976,7 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off, writeq(*data, addr); unlock: - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); return ret; } @@ -942,23 +984,23 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off, void qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data) { - void __iomem *addr = adapter->ahw.pci_base0 + + void __iomem *addr = adapter->ahw->pci_base0 + QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM); - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); *data = readq(addr); - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); } void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data) { - void __iomem *addr = adapter->ahw.pci_base0 + + void __iomem *addr = adapter->ahw->pci_base0 + QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM); - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); writeq(data, addr); - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); } #define MAX_CTL_CHECK 1000 @@ -997,7 +1039,7 @@ qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter, correct: off8 = off & ~0xf; - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); @@ -1049,7 +1091,7 @@ qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter, ret = 0; done: - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); return ret; } @@ -1091,7 +1133,7 @@ qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, correct: off8 = off & ~0xf; - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); @@ -1121,7 +1163,7 @@ qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, ret = 0; } - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); return ret; } @@ -1145,7 +1187,7 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter) if (qlcnic_rom_fast_read(adapter, offset, &board_type)) return -EIO; - adapter->ahw.board_type = board_type; + adapter->ahw->board_type = board_type; if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) { u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I); @@ -1164,20 +1206,20 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter) case QLCNIC_BRDTYPE_P3P_10G_SFP_QT: case QLCNIC_BRDTYPE_P3P_10G_XFP: case QLCNIC_BRDTYPE_P3P_10000_BASE_T: - adapter->ahw.port_type = QLCNIC_XGBE; + adapter->ahw->port_type = QLCNIC_XGBE; break; case QLCNIC_BRDTYPE_P3P_REF_QG: case QLCNIC_BRDTYPE_P3P_4_GB: case QLCNIC_BRDTYPE_P3P_4_GB_MM: - adapter->ahw.port_type = QLCNIC_GBE; + adapter->ahw->port_type = QLCNIC_GBE; break; case QLCNIC_BRDTYPE_P3P_10G_TP: - adapter->ahw.port_type = (adapter->portnum < 2) ? + adapter->ahw->port_type = (adapter->portnum < 2) ? QLCNIC_XGBE : QLCNIC_GBE; break; default: dev_err(&pdev->dev, "unknown board type %x\n", board_type); - adapter->ahw.port_type = QLCNIC_XGBE; + adapter->ahw->port_type = QLCNIC_XGBE; break; } @@ -1220,3 +1262,461 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) return rv; } + +/* FW dump related functions */ +static u32 +qlcnic_dump_crb(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, + u32 *buffer) +{ + int i; + u32 addr, data; + struct __crb *crb = &entry->region.crb; + void __iomem *base = adapter->ahw->pci_base0; + + addr = crb->addr; + + for (i = 0; i < crb->no_ops; i++) { + QLCNIC_RD_DUMP_REG(addr, base, &data); + *buffer++ = cpu_to_le32(addr); + *buffer++ = cpu_to_le32(data); + addr += crb->stride; + } + return crb->no_ops * 2 * sizeof(u32); +} + +static u32 +qlcnic_dump_ctrl(struct qlcnic_adapter *adapter, + struct qlcnic_dump_entry *entry, u32 *buffer) +{ + int i, k, timeout = 0; + void __iomem *base = adapter->ahw->pci_base0; + u32 addr, data; + u8 opcode, no_ops; + struct __ctrl *ctr = &entry->region.ctrl; + struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr; + + addr = ctr->addr; + no_ops = ctr->no_ops; + + for (i = 0; i < no_ops; i++) { + k = 0; + opcode = 0; + for (k = 0; k < 8; k++) { + if (!(ctr->opcode & (1 << k))) + continue; + switch (1 << k) { + case QLCNIC_DUMP_WCRB: + QLCNIC_WR_DUMP_REG(addr, base, ctr->val1); + break; + case QLCNIC_DUMP_RWCRB: + QLCNIC_RD_DUMP_REG(addr, base, &data); + QLCNIC_WR_DUMP_REG(addr, base, data); + break; + case QLCNIC_DUMP_ANDCRB: + QLCNIC_RD_DUMP_REG(addr, base, &data); + QLCNIC_WR_DUMP_REG(addr, base, + (data & ctr->val2)); + break; + case QLCNIC_DUMP_ORCRB: + QLCNIC_RD_DUMP_REG(addr, base, &data); + QLCNIC_WR_DUMP_REG(addr, base, + (data | ctr->val3)); + break; + case QLCNIC_DUMP_POLLCRB: + while (timeout <= ctr->timeout) { + QLCNIC_RD_DUMP_REG(addr, base, &data); + if ((data & ctr->val2) == ctr->val1) + break; + msleep(1); + timeout++; + } + if (timeout > ctr->timeout) { + dev_info(&adapter->pdev->dev, + "Timed out, aborting poll CRB\n"); + return -EINVAL; + } + break; + case QLCNIC_DUMP_RD_SAVE: + if (ctr->index_a) + addr = t_hdr->saved_state[ctr->index_a]; + QLCNIC_RD_DUMP_REG(addr, base, &data); + t_hdr->saved_state[ctr->index_v] = data; + break; + case QLCNIC_DUMP_WRT_SAVED: + if (ctr->index_v) + data = t_hdr->saved_state[ctr->index_v]; + else + data = ctr->val1; + if (ctr->index_a) + addr = t_hdr->saved_state[ctr->index_a]; + QLCNIC_WR_DUMP_REG(addr, base, data); + break; + case QLCNIC_DUMP_MOD_SAVE_ST: + data = t_hdr->saved_state[ctr->index_v]; + data <<= ctr->shl_val; + data >>= ctr->shr_val; + if (ctr->val2) + data &= ctr->val2; + data |= ctr->val3; + data += ctr->val1; + t_hdr->saved_state[ctr->index_v] = data; + break; + default: + dev_info(&adapter->pdev->dev, + "Unknown opcode\n"); + break; + } + } + addr += ctr->stride; + } + return 0; +} + +static u32 +qlcnic_dump_mux(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, + u32 *buffer) +{ + int loop; + u32 val, data = 0; + struct __mux *mux = &entry->region.mux; + void __iomem *base = adapter->ahw->pci_base0; + + val = mux->val; + for (loop = 0; loop < mux->no_ops; loop++) { + QLCNIC_WR_DUMP_REG(mux->addr, base, val); + QLCNIC_RD_DUMP_REG(mux->read_addr, base, &data); + *buffer++ = cpu_to_le32(val); + *buffer++ = cpu_to_le32(data); + val += mux->val_stride; + } + return 2 * mux->no_ops * sizeof(u32); +} + +static u32 +qlcnic_dump_que(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, + u32 *buffer) +{ + int i, loop; + u32 cnt, addr, data, que_id = 0; + void __iomem *base = adapter->ahw->pci_base0; + struct __queue *que = &entry->region.que; + + addr = que->read_addr; + cnt = que->read_addr_cnt; + + for (loop = 0; loop < que->no_ops; loop++) { + QLCNIC_WR_DUMP_REG(que->sel_addr, base, que_id); + for (i = 0; i < cnt; i++) { + QLCNIC_RD_DUMP_REG(addr, base, &data); + *buffer++ = cpu_to_le32(data); + addr += que->read_addr_stride; + } + que_id += que->stride; + } + return que->no_ops * cnt * sizeof(u32); +} + +static u32 +qlcnic_dump_ocm(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, + u32 *buffer) +{ + int i; + u32 data; + void __iomem *addr; + struct __ocm *ocm = &entry->region.ocm; + + addr = adapter->ahw->pci_base0 + ocm->read_addr; + for (i = 0; i < ocm->no_ops; i++) { + data = readl(addr); + *buffer++ = cpu_to_le32(data); + addr += ocm->read_addr_stride; + } + return ocm->no_ops * sizeof(u32); +} + +static u32 +qlcnic_read_rom(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, + u32 *buffer) +{ + int i, count = 0; + u32 fl_addr, size, val, lck_val, addr; + struct __mem *rom = &entry->region.mem; + void __iomem *base = adapter->ahw->pci_base0; + + fl_addr = rom->addr; + size = rom->size/4; +lock_try: + lck_val = readl(base + QLCNIC_FLASH_SEM2_LK); + if (!lck_val && count < MAX_CTL_CHECK) { + msleep(10); + count++; + goto lock_try; + } + writel(adapter->ahw->pci_func, (base + QLCNIC_FLASH_LOCK_ID)); + for (i = 0; i < size; i++) { + addr = fl_addr & 0xFFFF0000; + QLCNIC_WR_DUMP_REG(FLASH_ROM_WINDOW, base, addr); + addr = LSW(fl_addr) + FLASH_ROM_DATA; + QLCNIC_RD_DUMP_REG(addr, base, &val); + fl_addr += 4; + *buffer++ = cpu_to_le32(val); + } + readl(base + QLCNIC_FLASH_SEM2_ULK); + return rom->size; +} + +static u32 +qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter, + struct qlcnic_dump_entry *entry, u32 *buffer) +{ + int i; + u32 cnt, val, data, addr; + void __iomem *base = adapter->ahw->pci_base0; + struct __cache *l1 = &entry->region.cache; + + val = l1->init_tag_val; + + for (i = 0; i < l1->no_ops; i++) { + QLCNIC_WR_DUMP_REG(l1->addr, base, val); + QLCNIC_WR_DUMP_REG(l1->ctrl_addr, base, LSW(l1->ctrl_val)); + addr = l1->read_addr; + cnt = l1->read_addr_num; + while (cnt) { + QLCNIC_RD_DUMP_REG(addr, base, &data); + *buffer++ = cpu_to_le32(data); + addr += l1->read_addr_stride; + cnt--; + } + val += l1->stride; + } + return l1->no_ops * l1->read_addr_num * sizeof(u32); +} + +static u32 +qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter, + struct qlcnic_dump_entry *entry, u32 *buffer) +{ + int i; + u32 cnt, val, data, addr; + u8 poll_mask, poll_to, time_out = 0; + void __iomem *base = adapter->ahw->pci_base0; + struct __cache *l2 = &entry->region.cache; + + val = l2->init_tag_val; + poll_mask = LSB(MSW(l2->ctrl_val)); + poll_to = MSB(MSW(l2->ctrl_val)); + + for (i = 0; i < l2->no_ops; i++) { + QLCNIC_WR_DUMP_REG(l2->addr, base, val); + do { + QLCNIC_WR_DUMP_REG(l2->ctrl_addr, base, + LSW(l2->ctrl_val)); + QLCNIC_RD_DUMP_REG(l2->ctrl_addr, base, &data); + if (!(data & poll_mask)) + break; + msleep(1); + time_out++; + } while (time_out <= poll_to); + if (time_out > poll_to) + return -EINVAL; + + addr = l2->read_addr; + cnt = l2->read_addr_num; + while (cnt) { + QLCNIC_RD_DUMP_REG(addr, base, &data); + *buffer++ = cpu_to_le32(data); + addr += l2->read_addr_stride; + cnt--; + } + val += l2->stride; + } + return l2->no_ops * l2->read_addr_num * sizeof(u32); +} + +static u32 +qlcnic_read_memory(struct qlcnic_adapter *adapter, + struct qlcnic_dump_entry *entry, u32 *buffer) +{ + u32 addr, data, test, ret = 0; + int i, reg_read; + struct __mem *mem = &entry->region.mem; + void __iomem *base = adapter->ahw->pci_base0; + + reg_read = mem->size; + addr = mem->addr; + /* check for data size of multiple of 16 and 16 byte alignment */ + if ((addr & 0xf) || (reg_read%16)) { + dev_info(&adapter->pdev->dev, + "Unaligned memory addr:0x%x size:0x%x\n", + addr, reg_read); + return -EINVAL; + } + + mutex_lock(&adapter->ahw->mem_lock); + + while (reg_read != 0) { + QLCNIC_WR_DUMP_REG(MIU_TEST_ADDR_LO, base, addr); + QLCNIC_WR_DUMP_REG(MIU_TEST_ADDR_HI, base, 0); + QLCNIC_WR_DUMP_REG(MIU_TEST_CTR, base, + TA_CTL_ENABLE | TA_CTL_START); + + for (i = 0; i < MAX_CTL_CHECK; i++) { + QLCNIC_RD_DUMP_REG(MIU_TEST_CTR, base, &test); + if (!(test & TA_CTL_BUSY)) + break; + } + if (i == MAX_CTL_CHECK) { + if (printk_ratelimit()) { + dev_err(&adapter->pdev->dev, + "failed to read through agent\n"); + ret = -EINVAL; + goto out; + } + } + for (i = 0; i < 4; i++) { + QLCNIC_RD_DUMP_REG(MIU_TEST_READ_DATA[i], base, &data); + *buffer++ = cpu_to_le32(data); + } + addr += 16; + reg_read -= 16; + ret += 16; + } +out: + mutex_unlock(&adapter->ahw->mem_lock); + return mem->size; +} + +static u32 +qlcnic_dump_nop(struct qlcnic_adapter *adapter, + struct qlcnic_dump_entry *entry, u32 *buffer) +{ + entry->hdr.flags |= QLCNIC_DUMP_SKIP; + return 0; +} + +struct qlcnic_dump_operations fw_dump_ops[] = { + { QLCNIC_DUMP_NOP, qlcnic_dump_nop }, + { QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb }, + { QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux }, + { QLCNIC_DUMP_QUEUE, qlcnic_dump_que }, + { QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom }, + { QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm }, + { QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl }, + { QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache }, + { QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache }, + { QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache }, + { QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache }, + { QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache }, + { QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache }, + { QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache }, + { QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache }, + { QLCNIC_DUMP_READ_ROM, qlcnic_read_rom }, + { QLCNIC_DUMP_READ_MEM, qlcnic_read_memory }, + { QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl }, + { QLCNIC_DUMP_TLHDR, qlcnic_dump_nop }, + { QLCNIC_DUMP_RDEND, qlcnic_dump_nop }, +}; + +/* Walk the template and collect dump for each entry in the dump template */ +static int +qlcnic_valid_dump_entry(struct device *dev, struct qlcnic_dump_entry *entry, + u32 size) +{ + int ret = 1; + if (size != entry->hdr.cap_size) { + dev_info(dev, + "Invalidate dump, Type:%d\tMask:%d\tSize:%dCap_size:%d\n", + entry->hdr.type, entry->hdr.mask, size, entry->hdr.cap_size); + dev_info(dev, "Aborting further dump capture\n"); + ret = 0; + } + return ret; +} + +int qlcnic_dump_fw(struct qlcnic_adapter *adapter) +{ + u32 *buffer; + char mesg[64]; + char *msg[] = {mesg, NULL}; + int i, k, ops_cnt, ops_index, dump_size = 0; + u32 entry_offset, dump, no_entries, buf_offset = 0; + struct qlcnic_dump_entry *entry; + struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; + struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr; + + if (fw_dump->clr) { + dev_info(&adapter->pdev->dev, + "Previous dump not cleared, not capturing dump\n"); + return -EIO; + } + /* Calculate the size for dump data area only */ + for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++) + if (i & tmpl_hdr->drv_cap_mask) + dump_size += tmpl_hdr->cap_sizes[k]; + if (!dump_size) + return -EIO; + + fw_dump->data = vzalloc(dump_size); + if (!fw_dump->data) { + dev_info(&adapter->pdev->dev, + "Unable to allocate (%d KB) for fw dump\n", + dump_size/1024); + return -ENOMEM; + } + buffer = fw_dump->data; + fw_dump->size = dump_size; + no_entries = tmpl_hdr->num_entries; + ops_cnt = ARRAY_SIZE(fw_dump_ops); + entry_offset = tmpl_hdr->offset; + tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION; + tmpl_hdr->sys_info[1] = adapter->fw_version; + + for (i = 0; i < no_entries; i++) { + entry = (struct qlcnic_dump_entry *) ((void *) tmpl_hdr + + entry_offset); + if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) { + entry->hdr.flags |= QLCNIC_DUMP_SKIP; + entry_offset += entry->hdr.offset; + continue; + } + /* Find the handler for this entry */ + ops_index = 0; + while (ops_index < ops_cnt) { + if (entry->hdr.type == fw_dump_ops[ops_index].opcode) + break; + ops_index++; + } + if (ops_index == ops_cnt) { + dev_info(&adapter->pdev->dev, + "Invalid entry type %d, exiting dump\n", + entry->hdr.type); + goto error; + } + /* Collect dump for this entry */ + dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer); + if (dump && !qlcnic_valid_dump_entry(&adapter->pdev->dev, entry, + dump)) + entry->hdr.flags |= QLCNIC_DUMP_SKIP; + buf_offset += entry->hdr.cap_size; + entry_offset += entry->hdr.offset; + buffer = fw_dump->data + buf_offset; + } + if (dump_size != buf_offset) { + dev_info(&adapter->pdev->dev, + "Captured(%d) and expected size(%d) do not match\n", + buf_offset, dump_size); + goto error; + } else { + fw_dump->clr = 1; + snprintf(mesg, sizeof(mesg), "FW dump for device: %d\n", + adapter->pdev->devfn); + dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n", + fw_dump->size); + /* Send a udev event to notify availability of FW dump */ + kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg); + return 0; + } +error: + vfree(fw_dump->data); + return -EINVAL; +} diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index a7f1d5b7e811..5b8bbcf904d5 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -94,7 +94,7 @@ void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter) struct qlcnic_rx_buffer *rx_buf; int i, ring; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; for (i = 0; i < rds_ring->num_desc; ++i) { @@ -119,7 +119,7 @@ void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter) struct qlcnic_rx_buffer *rx_buf; int i, ring; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; @@ -173,7 +173,7 @@ void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter) struct qlcnic_host_tx_ring *tx_ring; int ring; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; if (recv_ctx->rds_rings == NULL) goto skip_rds; @@ -226,7 +226,7 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter) } tx_ring->cmd_buf_arr = cmd_buf_arr; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; size = adapter->max_rds_rings * sizeof(struct qlcnic_host_rds_ring); rds_ring = kzalloc(size, GFP_KERNEL); @@ -345,7 +345,7 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter) } static int do_rom_fast_read(struct qlcnic_adapter *adapter, - int addr, int *valp) + u32 addr, u32 *valp) { QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr); QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); @@ -398,7 +398,7 @@ qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, return ret; } -int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp) +int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp) { int ret; @@ -864,7 +864,7 @@ qlcnic_validate_product_offs(struct qlcnic_adapter *adapter) for (i = 0; i < entries; i++) { __le32 flags, file_chiprev, offs; - u8 chiprev = adapter->ahw.revision_id; + u8 chiprev = adapter->ahw->revision_id; u32 flagbit; offs = cpu_to_le32(ptab_descr->findex) + @@ -1130,9 +1130,20 @@ qlcnic_load_firmware(struct qlcnic_adapter *adapter) } else { u64 data; u32 hi, lo; + int ret; + struct qlcnic_flt_entry bootld_entry; - size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8; - flashaddr = QLCNIC_BOOTLD_START; + ret = qlcnic_get_flt_entry(adapter, QLCNIC_BOOTLD_REGION, + &bootld_entry); + if (!ret) { + size = bootld_entry.size / 8; + flashaddr = bootld_entry.start_addr; + } else { + size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8; + flashaddr = QLCNIC_BOOTLD_START; + dev_info(&pdev->dev, + "using legacy method to get flash fw region"); + } for (i = 0; i < size; i++) { if (qlcnic_rom_fast_read(adapter, @@ -1379,8 +1390,8 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, skb = buffer->skb; - if (likely(adapter->rx_csum && (cksum == STATUS_CKSUM_OK || - cksum == STATUS_CKSUM_LOOP))) { + if (likely((adapter->netdev->features & NETIF_F_RXCSUM) && + (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) { adapter->stats.csummed++; skb->ip_summed = CHECKSUM_UNNECESSARY; } else { @@ -1394,7 +1405,7 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, return skb; } -static int +static inline int qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb, u16 *vlan_tag) { @@ -1425,7 +1436,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter, int ring, u64 sts_data0) { struct net_device *netdev = adapter->netdev; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; struct qlcnic_rx_buffer *buffer; struct sk_buff *skb; struct qlcnic_host_rds_ring *rds_ring; @@ -1467,10 +1478,10 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter, skb->protocol = eth_type_trans(skb, netdev); - if ((vid != 0xffff) && adapter->vlgrp) - vlan_gro_receive(&sds_ring->napi, adapter->vlgrp, vid, skb); - else - napi_gro_receive(&sds_ring->napi, skb); + if (vid != 0xffff) + __vlan_hwaccel_put_tag(skb, vid); + + napi_gro_receive(&sds_ring->napi, skb); adapter->stats.rx_pkts++; adapter->stats.rxbytes += length; @@ -1488,7 +1499,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, int ring, u64 sts_data0, u64 sts_data1) { struct net_device *netdev = adapter->netdev; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; struct qlcnic_rx_buffer *buffer; struct sk_buff *skb; struct qlcnic_host_rds_ring *rds_ring; @@ -1552,10 +1563,9 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, length = skb->len; - if ((vid != 0xffff) && adapter->vlgrp) - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vid); - else - netif_receive_skb(skb); + if (vid != 0xffff) + __vlan_hwaccel_put_tag(skb, vid); + netif_receive_skb(skb); adapter->stats.lro_pkts++; adapter->stats.lrobytes += length; @@ -1625,7 +1635,7 @@ qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max) for (ring = 0; ring < adapter->max_rds_rings; ring++) { struct qlcnic_host_rds_ring *rds_ring = - &adapter->recv_ctx.rds_rings[ring]; + &adapter->recv_ctx->rds_rings[ring]; if (!list_empty(&sds_ring->free_list[ring])) { list_for_each(cur, &sds_ring->free_list[ring]) { @@ -1651,12 +1661,13 @@ qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max) } void -qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid, +qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, struct qlcnic_host_rds_ring *rds_ring) { struct rcv_desc *pdesc; struct qlcnic_rx_buffer *buffer; - int producer, count = 0; + int count = 0; + u32 producer; struct list_head *head; producer = rds_ring->producer; @@ -1696,7 +1707,8 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, { struct rcv_desc *pdesc; struct qlcnic_rx_buffer *buffer; - int producer, count = 0; + int count = 0; + uint32_t producer; struct list_head *head; if (!spin_trylock(&rds_ring->lock)) diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index cd88c7e1bfa9..3ab7d2c7baf2 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -13,12 +13,12 @@ #include #include -#include #include #include #include #include #include +#include MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver"); MODULE_LICENSE("GPL"); @@ -98,6 +98,9 @@ static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32); static int qlcnicvf_start_firmware(struct qlcnic_adapter *); static void qlcnic_set_netdev_features(struct qlcnic_adapter *, struct qlcnic_esw_func_cfg *); +static void qlcnic_vlan_rx_add(struct net_device *, u16); +static void qlcnic_vlan_rx_del(struct net_device *, u16); + /* PCI Device ID Table */ #define ENTRY(device) \ {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \ @@ -113,7 +116,7 @@ static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = { MODULE_DEVICE_TABLE(pci, qlcnic_pci_tbl); -void +inline void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter, struct qlcnic_host_tx_ring *tx_ring) { @@ -169,7 +172,7 @@ qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev) { int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) return -ENOMEM; @@ -193,14 +196,14 @@ qlcnic_napi_del(struct qlcnic_adapter *adapter) { int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; netif_napi_del(&sds_ring->napi); } - qlcnic_free_sds_rings(&adapter->recv_ctx); + qlcnic_free_sds_rings(adapter->recv_ctx); } static void @@ -208,7 +211,7 @@ qlcnic_napi_enable(struct qlcnic_adapter *adapter) { int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) return; @@ -225,7 +228,7 @@ qlcnic_napi_disable(struct qlcnic_adapter *adapter) { int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) return; @@ -317,13 +320,6 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p) return 0; } -static void qlcnic_vlan_rx_register(struct net_device *netdev, - struct vlan_group *grp) -{ - struct qlcnic_adapter *adapter = netdev_priv(netdev); - adapter->vlgrp = grp; -} - static const struct net_device_ops qlcnic_netdev_ops = { .ndo_open = qlcnic_open, .ndo_stop = qlcnic_close, @@ -333,8 +329,11 @@ static const struct net_device_ops qlcnic_netdev_ops = { .ndo_set_multicast_list = qlcnic_set_multi, .ndo_set_mac_address = qlcnic_set_mac, .ndo_change_mtu = qlcnic_change_mtu, + .ndo_fix_features = qlcnic_fix_features, + .ndo_set_features = qlcnic_set_features, .ndo_tx_timeout = qlcnic_tx_timeout, - .ndo_vlan_rx_register = qlcnic_vlan_rx_register, + .ndo_vlan_rx_add_vid = qlcnic_vlan_rx_add, + .ndo_vlan_rx_kill_vid = qlcnic_vlan_rx_del, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = qlcnic_poll_controller, #endif @@ -352,24 +351,53 @@ static struct qlcnic_nic_template qlcnic_vf_ops = { .start_firmware = qlcnicvf_start_firmware }; -static void -qlcnic_setup_intr(struct qlcnic_adapter *adapter) +static int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) +{ + struct pci_dev *pdev = adapter->pdev; + int err = -1; + + adapter->max_sds_rings = 1; + adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED); + qlcnic_set_msix_bit(pdev, 0); + + if (adapter->msix_supported) { + enable_msix: + qlcnic_init_msix_entries(adapter, num_msix); + err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); + if (err == 0) { + adapter->flags |= QLCNIC_MSIX_ENABLED; + qlcnic_set_msix_bit(pdev, 1); + + adapter->max_sds_rings = num_msix; + + dev_info(&pdev->dev, "using msi-x interrupts\n"); + return err; + } + if (err > 0) { + num_msix = rounddown_pow_of_two(err); + if (num_msix) + goto enable_msix; + } + } + return err; +} + + +static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter) { const struct qlcnic_legacy_intr_set *legacy_intrp; struct pci_dev *pdev = adapter->pdev; - int err, num_msix; - if (adapter->rss_supported) { - num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ? - MSIX_ENTRIES_PER_ADAPTER : 2; - } else - num_msix = 1; + if (use_msi && !pci_enable_msi(pdev)) { + adapter->flags |= QLCNIC_MSI_ENABLED; + adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, + msi_tgt_status[adapter->ahw->pci_func]); + dev_info(&pdev->dev, "using msi interrupts\n"); + adapter->msix_entries[0].vector = pdev->irq; + return; + } - adapter->max_sds_rings = 1; - - adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED); - - legacy_intrp = &legacy_intr[adapter->ahw.pci_func]; + legacy_intrp = &legacy_intr[adapter->ahw->pci_func]; adapter->int_vec_bit = legacy_intrp->int_vec_bit; adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, @@ -380,43 +408,29 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter) adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter, ISR_INT_STATE_REG); - - qlcnic_set_msix_bit(pdev, 0); - - if (adapter->msix_supported) { - - qlcnic_init_msix_entries(adapter, num_msix); - err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); - if (err == 0) { - adapter->flags |= QLCNIC_MSIX_ENABLED; - qlcnic_set_msix_bit(pdev, 1); - - if (adapter->rss_supported) - adapter->max_sds_rings = num_msix; - - dev_info(&pdev->dev, "using msi-x interrupts\n"); - return; - } - - if (err > 0) - pci_disable_msix(pdev); - - /* fall through for msi */ - } - - if (use_msi && !pci_enable_msi(pdev)) { - adapter->flags |= QLCNIC_MSI_ENABLED; - adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, - msi_tgt_status[adapter->ahw.pci_func]); - dev_info(&pdev->dev, "using msi interrupts\n"); - adapter->msix_entries[0].vector = pdev->irq; - return; - } - dev_info(&pdev->dev, "using legacy interrupts\n"); adapter->msix_entries[0].vector = pdev->irq; } +static void +qlcnic_setup_intr(struct qlcnic_adapter *adapter) +{ + int num_msix; + + if (adapter->msix_supported) { + num_msix = (num_online_cpus() >= + QLCNIC_DEF_NUM_STS_DESC_RINGS) ? + QLCNIC_DEF_NUM_STS_DESC_RINGS : + QLCNIC_MIN_NUM_RSS_RINGS; + } else + num_msix = 1; + + if (!qlcnic_enable_msix(adapter, num_msix)) + return; + + qlcnic_enable_msi_legacy(adapter); +} + static void qlcnic_teardown_intr(struct qlcnic_adapter *adapter) { @@ -429,8 +443,8 @@ qlcnic_teardown_intr(struct qlcnic_adapter *adapter) static void qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter) { - if (adapter->ahw.pci_base0 != NULL) - iounmap(adapter->ahw.pci_base0); + if (adapter->ahw->pci_base0 != NULL) + iounmap(adapter->ahw->pci_base0); } static int @@ -464,8 +478,10 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter) for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { pfn = pci_info[i].id; - if (pfn > QLCNIC_MAX_PCI_FUNC) - return QL_STATUS_INVALID_PARAM; + if (pfn > QLCNIC_MAX_PCI_FUNC) { + ret = QL_STATUS_INVALID_PARAM; + goto err_eswitch; + } adapter->npars[pfn].active = (u8)pci_info[i].active; adapter->npars[pfn].type = (u8)pci_info[i].type; adapter->npars[pfn].phy_port = (u8)pci_info[i].default_port; @@ -498,7 +514,7 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter) u32 ref_count; int i, ret = 1; u32 data = QLCNIC_MGMT_FUNC; - void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE; + void __iomem *priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE; /* If other drivers are not in use set their privilege level */ ref_count = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE); @@ -510,16 +526,16 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter) for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { id = i; if (adapter->npars[i].type != QLCNIC_TYPE_NIC || - id == adapter->ahw.pci_func) + id == adapter->ahw->pci_func) continue; data |= (qlcnic_config_npars & QLC_DEV_SET_DRV(0xf, id)); } } else { data = readl(priv_op); - data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw.pci_func)) | + data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw->pci_func)) | (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC, - adapter->ahw.pci_func)); + adapter->ahw->pci_func)); } writel(data, priv_op); qlcnic_api_unlock(adapter); @@ -537,22 +553,23 @@ qlcnic_check_vf(struct qlcnic_adapter *adapter) u32 op_mode, priv_level; /* Determine FW API version */ - adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API); + adapter->fw_hal_version = readl(adapter->ahw->pci_base0 + + QLCNIC_FW_API); /* Find PCI function number */ pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func); - msix_base_addr = adapter->ahw.pci_base0 + QLCNIC_MSIX_BASE; + msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE; msix_base = readl(msix_base_addr); func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE; - adapter->ahw.pci_func = func; + adapter->ahw->pci_func = func; /* Determine function privilege level */ - priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE; + priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE; op_mode = readl(priv_op); if (op_mode == QLC_DEV_DRV_DEFAULT) priv_level = QLCNIC_MGMT_FUNC; else - priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func); + priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func); if (priv_level == QLCNIC_NON_PRIV_FUNC) { adapter->op_mode = QLCNIC_NON_PRIV_FUNC; @@ -591,13 +608,14 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter) dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20)); - adapter->ahw.pci_base0 = mem_ptr0; - adapter->ahw.pci_len0 = pci_len0; + adapter->ahw->pci_base0 = mem_ptr0; + adapter->ahw->pci_len0 = pci_len0; qlcnic_check_vf(adapter); - adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter, - QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func))); + adapter->ahw->ocm_win_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG( + adapter->ahw->pci_func))); return 0; } @@ -639,7 +657,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) dev_info(&pdev->dev, "firmware v%d.%d.%d\n", fw_major, fw_minor, fw_build); - if (adapter->ahw.port_type == QLCNIC_XGBE) { + if (adapter->ahw->port_type == QLCNIC_XGBE) { if (adapter->flags & QLCNIC_ESWITCH_ENABLED) { adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF; adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF; @@ -651,7 +669,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; - } else if (adapter->ahw.port_type == QLCNIC_GBE) { + } else if (adapter->ahw->port_type == QLCNIC_GBE) { adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G; adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; @@ -659,7 +677,6 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) } adapter->msix_supported = !!use_msi_x; - adapter->rss_supported = !!use_msi_x; adapter->num_txd = MAX_CMD_DESCRIPTORS; @@ -672,7 +689,7 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter) int err; struct qlcnic_info nic_info; - err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func); + err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw->pci_func); if (err) return err; @@ -707,6 +724,22 @@ qlcnic_set_vlan_config(struct qlcnic_adapter *adapter, adapter->pvid = 0; } +static void +qlcnic_vlan_rx_add(struct net_device *netdev, u16 vid) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + set_bit(vid, adapter->vlans); +} + +static void +qlcnic_vlan_rx_del(struct net_device *netdev, u16 vid) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + qlcnic_restore_indev_addr(netdev, NETDEV_DOWN); + clear_bit(vid, adapter->vlans); +} + static void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter, struct qlcnic_esw_func_cfg *esw_cfg) @@ -734,7 +767,7 @@ qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter) if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return 0; - esw_cfg.pci_func = adapter->ahw.pci_func; + esw_cfg.pci_func = adapter->ahw->pci_func; if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg)) return -EIO; qlcnic_set_vlan_config(adapter, &esw_cfg); @@ -750,28 +783,27 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter, struct net_device *netdev = adapter->netdev; unsigned long features, vlan_features; - features = (NETIF_F_SG | NETIF_F_IP_CSUM | + features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO); vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM); + NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_FILTER); if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) { features |= (NETIF_F_TSO | NETIF_F_TSO6); vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6); } - if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) + + if (netdev->features & NETIF_F_LRO) features |= NETIF_F_LRO; if (esw_cfg->offload_flags & BIT_0) { netdev->features |= features; - adapter->rx_csum = 1; if (!(esw_cfg->offload_flags & BIT_1)) netdev->features &= ~NETIF_F_TSO; if (!(esw_cfg->offload_flags & BIT_2)) netdev->features &= ~NETIF_F_TSO6; } else { netdev->features &= ~features; - adapter->rx_csum = 0; } netdev->vlan_features = (features & vlan_features); @@ -791,14 +823,14 @@ qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter) if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED) return 0; - priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE; + priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE; op_mode = readl(priv_op); - priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func); + priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func); if (op_mode == QLC_DEV_DRV_DEFAULT) priv_level = QLCNIC_MGMT_FUNC; else - priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func); + priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func); if (adapter->flags & QLCNIC_ESWITCH_ENABLED) { if (priv_level == QLCNIC_MGMT_FUNC) { @@ -1038,7 +1070,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter) unsigned long flags = 0; struct net_device *netdev = adapter->netdev; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { handler = qlcnic_tmp_intr; @@ -1075,7 +1107,7 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter) int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; @@ -1083,20 +1115,6 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter) } } -static void -qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter) -{ - adapter->coal.flags = QLCNIC_INTR_DEFAULT; - adapter->coal.normal.data.rx_time_us = - QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; - adapter->coal.normal.data.rx_packets = - QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; - adapter->coal.normal.data.tx_time_us = - QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US; - adapter->coal.normal.data.tx_packets = - QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS; -} - static int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) { @@ -1115,14 +1133,14 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) return -EIO; for (ring = 0; ring < adapter->max_rds_rings; ring++) { - rds_ring = &adapter->recv_ctx.rds_rings[ring]; - qlcnic_post_rx_buffers(adapter, ring, rds_ring); + rds_ring = &adapter->recv_ctx->rds_rings[ring]; + qlcnic_post_rx_buffers(adapter, rds_ring); } qlcnic_set_multi(netdev); qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu); - adapter->ahw.linkup = 0; + adapter->ahw->linkup = 0; if (adapter->max_sds_rings > 1) qlcnic_config_rss(adapter, 1); @@ -1230,8 +1248,6 @@ qlcnic_attach(struct qlcnic_adapter *adapter) goto err_out_free_hw; } - qlcnic_init_coalesce_defaults(adapter); - qlcnic_create_sysfs_entries(adapter); adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC; @@ -1272,7 +1288,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) clear_bit(__QLCNIC_DEV_UP, &adapter->state); if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->max_sds_rings; ring++) { - sds_ring = &adapter->recv_ctx.sds_rings[ring]; + sds_ring = &adapter->recv_ctx->sds_rings[ring]; qlcnic_disable_int(sds_ring); } } @@ -1293,6 +1309,48 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) netif_device_attach(netdev); } +static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter) +{ + int err = 0; + adapter->ahw = kzalloc(sizeof(struct qlcnic_hardware_context), + GFP_KERNEL); + if (!adapter->ahw) { + dev_err(&adapter->pdev->dev, + "Failed to allocate recv ctx resources for adapter\n"); + err = -ENOMEM; + goto err_out; + } + adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context), + GFP_KERNEL); + if (!adapter->recv_ctx) { + dev_err(&adapter->pdev->dev, + "Failed to allocate recv ctx resources for adapter\n"); + kfree(adapter->ahw); + adapter->ahw = NULL; + err = -ENOMEM; + goto err_out; + } + /* Initialize interrupt coalesce parameters */ + adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT; + adapter->ahw->coal.rx_time_us = QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; + adapter->ahw->coal.rx_packets = QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; +err_out: + return err; +} + +static void qlcnic_free_adapter_resources(struct qlcnic_adapter *adapter) +{ + kfree(adapter->recv_ctx); + adapter->recv_ctx = NULL; + + if (adapter->ahw->fw_dump.tmpl_hdr) { + vfree(adapter->ahw->fw_dump.tmpl_hdr); + adapter->ahw->fw_dump.tmpl_hdr = NULL; + } + kfree(adapter->ahw); + adapter->ahw = NULL; +} + int qlcnic_diag_alloc_res(struct net_device *netdev, int test) { struct qlcnic_adapter *adapter = netdev_priv(netdev); @@ -1325,13 +1383,13 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) } for (ring = 0; ring < adapter->max_rds_rings; ring++) { - rds_ring = &adapter->recv_ctx.rds_rings[ring]; - qlcnic_post_rx_buffers(adapter, ring, rds_ring); + rds_ring = &adapter->recv_ctx->rds_rings[ring]; + qlcnic_post_rx_buffers(adapter, rds_ring); } if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->max_sds_rings; ring++) { - sds_ring = &adapter->recv_ctx.sds_rings[ring]; + sds_ring = &adapter->recv_ctx->sds_rings[ring]; qlcnic_enable_int(sds_ring); } } @@ -1399,7 +1457,6 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, int err; struct pci_dev *pdev = adapter->pdev; - adapter->rx_csum = 1; adapter->mc_enabled = 0; adapter->max_mc_count = 38; @@ -1410,26 +1467,24 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops); - netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_HW_VLAN_RX); - netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM); + netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; - if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) { - netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6); - } + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) + netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; + if (pci_using_dac) + netdev->hw_features |= NETIF_F_HIGHDMA; - if (pci_using_dac) { - netdev->features |= NETIF_F_HIGHDMA; - netdev->vlan_features |= NETIF_F_HIGHDMA; - } + netdev->vlan_features = netdev->hw_features; if (adapter->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX) - netdev->features |= (NETIF_F_HW_VLAN_TX); - + netdev->hw_features |= NETIF_F_HW_VLAN_TX; if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) - netdev->features |= NETIF_F_LRO; + netdev->hw_features |= NETIF_F_LRO; + + netdev->features |= netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; + netdev->irq = adapter->msix_entries[0].vector; netif_carrier_off(netdev); @@ -1459,6 +1514,19 @@ static int qlcnic_set_dma_mask(struct pci_dev *pdev, u8 *pci_using_dac) return 0; } +static int +qlcnic_alloc_msix_entries(struct qlcnic_adapter *adapter, u16 count) +{ + adapter->msix_entries = kcalloc(count, sizeof(struct msix_entry), + GFP_KERNEL); + + if (adapter->msix_entries) + return 0; + + dev_err(&adapter->pdev->dev, "failed allocating msix_entries\n"); + return -ENOMEM; +} + static int __devinit qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1501,23 +1569,30 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter = netdev_priv(netdev); adapter->netdev = netdev; adapter->pdev = pdev; + + if (qlcnic_alloc_adapter_resources(adapter)) + goto err_out_free_netdev; + adapter->dev_rst_time = jiffies; - revision_id = pdev->revision; - adapter->ahw.revision_id = revision_id; + adapter->ahw->revision_id = revision_id; - rwlock_init(&adapter->ahw.crb_lock); - mutex_init(&adapter->ahw.mem_lock); + rwlock_init(&adapter->ahw->crb_lock); + mutex_init(&adapter->ahw->mem_lock); spin_lock_init(&adapter->tx_clean_lock); INIT_LIST_HEAD(&adapter->mac_list); err = qlcnic_setup_pci_map(adapter); if (err) - goto err_out_free_netdev; + goto err_out_free_hw; /* This will be reset for mezz cards */ - adapter->portnum = adapter->ahw.pci_func; + adapter->portnum = adapter->ahw->pci_func; + + /* Get FW dump template and store it */ + if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC) + qlcnic_fw_cmd_get_minidump_temp(adapter); err = qlcnic_get_board_info(adapter); if (err) { @@ -1545,11 +1620,15 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pr_info("%s: %s Board Chip rev 0x%x\n", module_name(THIS_MODULE), - brd_name, adapter->ahw.revision_id); + brd_name, adapter->ahw->revision_id); } qlcnic_clear_stats(adapter); + err = qlcnic_alloc_msix_entries(adapter, adapter->max_rx_ques); + if (err) + goto err_out_decr_ref; + qlcnic_setup_intr(adapter); err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac); @@ -1560,7 +1639,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); - switch (adapter->ahw.port_type) { + switch (adapter->ahw->port_type) { case QLCNIC_GBE: dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n", adapter->netdev->name); @@ -1578,6 +1657,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_out_disable_msi: qlcnic_teardown_intr(adapter); + kfree(adapter->msix_entries); err_out_decr_ref: qlcnic_clr_all_drv_state(adapter, 0); @@ -1585,6 +1665,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_out_iounmap: qlcnic_cleanup_pci_map(adapter); +err_out_free_hw: + qlcnic_free_adapter_resources(adapter); + err_out_free_netdev: free_netdev(netdev); @@ -1626,6 +1709,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev) qlcnic_free_lb_filters_mem(adapter); qlcnic_teardown_intr(adapter); + kfree(adapter->msix_entries); qlcnic_remove_diag_entries(adapter); @@ -1638,6 +1722,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev) pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); + qlcnic_free_adapter_resources(adapter); free_netdev(netdev); } static int __qlcnic_shutdown(struct pci_dev *pdev) @@ -1819,6 +1904,7 @@ static void qlcnic_change_filter(struct qlcnic_adapter *adapter, vlan_req->vlan_id = vlan_id; tx_ring->producer = get_next_index(producer, tx_ring->num_desc); + smp_mb(); } #define QLCNIC_MAC_HASH(MAC)\ @@ -1879,58 +1965,122 @@ qlcnic_send_filter(struct qlcnic_adapter *adapter, spin_unlock(&adapter->mac_learn_lock); } -static void -qlcnic_tso_check(struct net_device *netdev, - struct qlcnic_host_tx_ring *tx_ring, +static int +qlcnic_tx_pkt(struct qlcnic_adapter *adapter, struct cmd_desc_type0 *first_desc, struct sk_buff *skb) { - u8 opcode = TX_ETHER_PKT; - __be16 protocol = skb->protocol; - u16 flags = 0; - int copied, offset, copy_len, hdr_len = 0, tso = 0; + u8 opcode = 0, hdr_len = 0; + u16 flags = 0, vlan_tci = 0; + int copied, offset, copy_len; struct cmd_desc_type0 *hwdesc; struct vlan_ethhdr *vh; - struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; + u16 protocol = ntohs(skb->protocol); u32 producer = tx_ring->producer; - __le16 vlan_oob = first_desc->flags_opcode & - cpu_to_le16(FLAGS_VLAN_OOB); + + if (protocol == ETH_P_8021Q) { + vh = (struct vlan_ethhdr *)skb->data; + flags = FLAGS_VLAN_TAGGED; + vlan_tci = vh->h_vlan_TCI; + } else if (vlan_tx_tag_present(skb)) { + flags = FLAGS_VLAN_OOB; + vlan_tci = vlan_tx_tag_get(skb); + } + if (unlikely(adapter->pvid)) { + if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED)) + return -EIO; + if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED)) + goto set_flags; + + flags = FLAGS_VLAN_OOB; + vlan_tci = adapter->pvid; + } +set_flags: + qlcnic_set_tx_vlan_tci(first_desc, vlan_tci); + qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); if (*(skb->data) & BIT_0) { flags |= BIT_0; memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN); } - - if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && + opcode = TX_ETHER_PKT; + if ((adapter->netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && skb_shinfo(skb)->gso_size > 0) { hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); first_desc->total_hdr_length = hdr_len; - if (vlan_oob) { + + opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO; + + /* For LSO, we need to copy the MAC/IP/TCP headers into + * the descriptor ring */ + copied = 0; + offset = 2; + + if (flags & FLAGS_VLAN_OOB) { first_desc->total_hdr_length += VLAN_HLEN; first_desc->tcp_hdr_offset = VLAN_HLEN; first_desc->ip_hdr_offset = VLAN_HLEN; /* Only in case of TSO on vlan device */ flags |= FLAGS_VLAN_TAGGED; + + /* Create a TSO vlan header template for firmware */ + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + copy_len = min((int)sizeof(struct cmd_desc_type0) - + offset, hdr_len + VLAN_HLEN); + + vh = (struct vlan_ethhdr *)((char *) hwdesc + 2); + skb_copy_from_linear_data(skb, vh, 12); + vh->h_vlan_proto = htons(ETH_P_8021Q); + vh->h_vlan_TCI = htons(vlan_tci); + + skb_copy_from_linear_data_offset(skb, 12, + (char *)vh + 16, copy_len - 16); + + copied = copy_len - VLAN_HLEN; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); } - opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ? - TX_TCP_LSO6 : TX_TCP_LSO; - tso = 1; + while (copied < hdr_len) { + + copy_len = min((int)sizeof(struct cmd_desc_type0) - + offset, (hdr_len - copied)); + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + skb_copy_from_linear_data_offset(skb, copied, + (char *) hwdesc + offset, copy_len); + + copied += copy_len; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); + } + + tx_ring->producer = producer; + smp_mb(); + adapter->stats.lso_frames++; } else if (skb->ip_summed == CHECKSUM_PARTIAL) { u8 l4proto; - if (protocol == cpu_to_be16(ETH_P_IP)) { + if (protocol == ETH_P_IP) { l4proto = ip_hdr(skb)->protocol; if (l4proto == IPPROTO_TCP) opcode = TX_TCP_PKT; else if (l4proto == IPPROTO_UDP) opcode = TX_UDP_PKT; - } else if (protocol == cpu_to_be16(ETH_P_IPV6)) { + } else if (protocol == ETH_P_IPV6) { l4proto = ipv6_hdr(skb)->nexthdr; if (l4proto == IPPROTO_TCP) @@ -1939,63 +2089,11 @@ qlcnic_tso_check(struct net_device *netdev, opcode = TX_UDPV6_PKT; } } - first_desc->tcp_hdr_offset += skb_transport_offset(skb); first_desc->ip_hdr_offset += skb_network_offset(skb); qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); - if (!tso) - return; - - /* For LSO, we need to copy the MAC/IP/TCP headers into - * the descriptor ring - */ - copied = 0; - offset = 2; - - if (vlan_oob) { - /* Create a TSO vlan header template for firmware */ - - hwdesc = &tx_ring->desc_head[producer]; - tx_ring->cmd_buf_arr[producer].skb = NULL; - - copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, - hdr_len + VLAN_HLEN); - - vh = (struct vlan_ethhdr *)((char *)hwdesc + 2); - skb_copy_from_linear_data(skb, vh, 12); - vh->h_vlan_proto = htons(ETH_P_8021Q); - vh->h_vlan_TCI = (__be16)swab16((u16)first_desc->vlan_TCI); - - skb_copy_from_linear_data_offset(skb, 12, - (char *)vh + 16, copy_len - 16); - - copied = copy_len - VLAN_HLEN; - offset = 0; - - producer = get_next_index(producer, tx_ring->num_desc); - } - - while (copied < hdr_len) { - - copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, - (hdr_len - copied)); - - hwdesc = &tx_ring->desc_head[producer]; - tx_ring->cmd_buf_arr[producer].skb = NULL; - - skb_copy_from_linear_data_offset(skb, copied, - (char *)hwdesc + offset, copy_len); - - copied += copy_len; - offset = 0; - - producer = get_next_index(producer, tx_ring->num_desc); - } - - tx_ring->producer = producer; - barrier(); - adapter->stats.lso_frames++; + return 0; } static int @@ -2046,39 +2144,21 @@ qlcnic_map_tx_skb(struct pci_dev *pdev, return -ENOMEM; } -static int -qlcnic_check_tx_tagging(struct qlcnic_adapter *adapter, - struct sk_buff *skb, - struct cmd_desc_type0 *first_desc) +static void +qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb, + struct qlcnic_cmd_buffer *pbuf) { - u8 opcode = 0; - u16 flags = 0; - __be16 protocol = skb->protocol; - struct vlan_ethhdr *vh; + struct qlcnic_skb_frag *nf = &pbuf->frag_array[0]; + int nr_frags = skb_shinfo(skb)->nr_frags; + int i; - if (protocol == cpu_to_be16(ETH_P_8021Q)) { - vh = (struct vlan_ethhdr *)skb->data; - protocol = vh->h_vlan_encapsulated_proto; - flags = FLAGS_VLAN_TAGGED; - qlcnic_set_tx_vlan_tci(first_desc, ntohs(vh->h_vlan_TCI)); - } else if (vlan_tx_tag_present(skb)) { - flags = FLAGS_VLAN_OOB; - qlcnic_set_tx_vlan_tci(first_desc, vlan_tx_tag_get(skb)); + for (i = 0; i < nr_frags; i++) { + nf = &pbuf->frag_array[i+1]; + pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE); } - if (unlikely(adapter->pvid)) { - if (first_desc->vlan_TCI && - !(adapter->flags & QLCNIC_TAGGING_ENABLED)) - return -EIO; - if (first_desc->vlan_TCI && - (adapter->flags & QLCNIC_TAGGING_ENABLED)) - goto set_flags; - flags = FLAGS_VLAN_OOB; - qlcnic_set_tx_vlan_tci(first_desc, adapter->pvid); - } -set_flags: - qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); - return 0; + nf = &pbuf->frag_array[0]; + pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE); } static inline void @@ -2099,10 +2179,11 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct cmd_desc_type0 *hwdesc, *first_desc; struct pci_dev *pdev; struct ethhdr *phdr; + int delta = 0; int i, k; u32 producer; - int frag_count, no_of_desc; + int frag_count; u32 num_txd = tx_ring->num_desc; if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { @@ -2118,13 +2199,22 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } frag_count = skb_shinfo(skb)->nr_frags + 1; + /* 14 frags supported for normal packet and + * 32 frags supported for TSO packet + */ + if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) { - /* 4 fragments per cmd des */ - no_of_desc = (frag_count + 3) >> 2; + for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++) + delta += skb_shinfo(skb)->frags[i].size; + + if (!__pskb_pull_tail(skb, delta)) + goto drop_packet; + + frag_count = 1 + skb_shinfo(skb)->nr_frags; + } if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) { netif_stop_queue(netdev); - smp_mb(); if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) netif_start_queue(netdev); else { @@ -2141,9 +2231,6 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) first_desc = hwdesc = &tx_ring->desc_head[producer]; qlcnic_clear_cmddesc((u64 *)hwdesc); - if (qlcnic_check_tx_tagging(adapter, skb, first_desc)) - goto drop_packet; - if (qlcnic_map_tx_skb(pdev, skb, pbuf)) { adapter->stats.tx_dma_map_error++; goto drop_packet; @@ -2187,8 +2274,10 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } tx_ring->producer = get_next_index(producer, num_txd); + smp_mb(); - qlcnic_tso_check(netdev, tx_ring, first_desc, skb); + if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb))) + goto unwind_buff; if (qlcnic_mac_learn) qlcnic_send_filter(adapter, tx_ring, first_desc, skb); @@ -2200,6 +2289,8 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; +unwind_buff: + qlcnic_unmap_buffers(pdev, skb, pbuf); drop_packet: adapter->stats.txdropped++; dev_kfree_skb_any(skb); @@ -2246,16 +2337,16 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup) { struct net_device *netdev = adapter->netdev; - if (adapter->ahw.linkup && !linkup) { + if (adapter->ahw->linkup && !linkup) { netdev_info(netdev, "NIC Link is down\n"); - adapter->ahw.linkup = 0; + adapter->ahw->linkup = 0; if (netif_running(netdev)) { netif_carrier_off(netdev); netif_stop_queue(netdev); } - } else if (!adapter->ahw.linkup && linkup) { + } else if (!adapter->ahw->linkup && linkup) { netdev_info(netdev, "NIC Link is up\n"); - adapter->ahw.linkup = 1; + adapter->ahw->linkup = 1; if (netif_running(netdev)) { netif_carrier_on(netdev); netif_wake_queue(netdev); @@ -2491,7 +2582,7 @@ static void qlcnic_poll_controller(struct net_device *netdev) int ring; struct qlcnic_host_sds_ring *sds_ring; struct qlcnic_adapter *adapter = netdev_priv(netdev); - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; disable_irq(adapter->irq); for (ring = 0; ring < adapter->max_sds_rings; ring++) { @@ -2742,6 +2833,8 @@ qlcnic_fwinit_work(struct work_struct *work) set_bit(__QLCNIC_START_FW, &adapter->state); QLCDB(adapter, DRV, "Restarting fw\n"); qlcnic_idc_debug_info(adapter, 0); + QLCDB(adapter, DRV, "Take FW dump\n"); + qlcnic_dump_fw(adapter); } qlcnic_api_unlock(adapter); @@ -2840,7 +2933,7 @@ qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter) } /*Transit to RESET state from READY state only */ -static void +void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) { u32 state; @@ -3252,6 +3345,56 @@ static struct device_attribute dev_attr_diag_mode = { .store = qlcnic_store_diag_mode, }; +int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val) +{ + if (!use_msi_x && !use_msi) { + netdev_info(netdev, "no msix or msi support, hence no rss\n"); + return -EINVAL; + } + + if ((val > max_hw) || (val < 2) || !is_power_of_2(val)) { + netdev_info(netdev, "rss_ring valid range [2 - %x] in " + " powers of 2\n", max_hw); + return -EINVAL; + } + return 0; + +} + +int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data) +{ + struct net_device *netdev = adapter->netdev; + int err = 0; + + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return -EBUSY; + + netif_device_detach(netdev); + if (netif_running(netdev)) + __qlcnic_down(adapter, netdev); + qlcnic_detach(adapter); + qlcnic_teardown_intr(adapter); + + if (qlcnic_enable_msix(adapter, data)) { + netdev_info(netdev, "failed setting max_rss; rss disabled\n"); + qlcnic_enable_msi_legacy(adapter); + } + + if (netif_running(netdev)) { + err = qlcnic_attach(adapter); + if (err) + goto done; + err = __qlcnic_up(adapter, netdev); + if (err) + goto done; + qlcnic_restore_indev_addr(netdev, NETDEV_UP); + } + done: + netif_device_attach(netdev); + clear_bit(__QLCNIC_RESETTING, &adapter->state); + return err; +} + static int qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter, loff_t offset, size_t size) @@ -3382,7 +3525,6 @@ qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj, return size; } - static struct bin_attribute bin_attr_crb = { .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)}, .size = 0, @@ -3501,7 +3643,7 @@ validate_esw_config(struct qlcnic_adapter *adapter, u8 pci_func; int i; - op_mode = readl(adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE); + op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE); for (i = 0; i < count; i++) { pci_func = esw_cfg[i].pci_func; @@ -3567,13 +3709,13 @@ qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj, if (qlcnic_config_switch_port(adapter, &esw_cfg[i])) return QL_STATUS_INVALID_PARAM; - if (adapter->ahw.pci_func != esw_cfg[i].pci_func) + if (adapter->ahw->pci_func != esw_cfg[i].pci_func) continue; op_mode = esw_cfg[i].op_mode; qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]); esw_cfg[i].op_mode = op_mode; - esw_cfg[i].pci_func = adapter->ahw.pci_func; + esw_cfg[i].pci_func = adapter->ahw->pci_func; switch (esw_cfg[i].op_mode) { case QLCNIC_PORT_DEFAULTS: @@ -3954,14 +4096,14 @@ qlcnic_create_diag_entries(struct qlcnic_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_pci_config)) + dev_info(dev, "failed to create pci config sysfs entry"); if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; if (device_create_bin_file(dev, &bin_attr_esw_config)) dev_info(dev, "failed to create esw config sysfs entry"); if (adapter->op_mode != QLCNIC_MGMT_FUNC) return; - if (device_create_bin_file(dev, &bin_attr_pci_config)) - dev_info(dev, "failed to create pci config sysfs entry"); if (device_create_bin_file(dev, &bin_attr_npar_config)) dev_info(dev, "failed to create npar config sysfs entry"); if (device_create_bin_file(dev, &bin_attr_pm_config)) @@ -3982,12 +4124,12 @@ qlcnic_remove_diag_entries(struct qlcnic_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_pci_config); if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; device_remove_bin_file(dev, &bin_attr_esw_config); if (adapter->op_mode != QLCNIC_MGMT_FUNC) return; - device_remove_bin_file(dev, &bin_attr_pci_config); device_remove_bin_file(dev, &bin_attr_npar_config); device_remove_bin_file(dev, &bin_attr_pm_config); device_remove_bin_file(dev, &bin_attr_esw_stats); @@ -4034,14 +4176,10 @@ qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event) qlcnic_config_indev_addr(adapter, netdev, event); - if (!adapter->vlgrp) - return; - - for (vid = 0; vid < VLAN_N_VID; vid++) { - dev = vlan_group_get_device(adapter->vlgrp, vid); + for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) { + dev = vlan_find_dev(netdev, vid); if (!dev) continue; - qlcnic_config_indev_addr(adapter, dev, event); } } diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 4757c59a07a2..d32850715f5c 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -2134,7 +2134,7 @@ struct ql_adapter { struct delayed_work mpi_idc_work; struct delayed_work mpi_core_to_log; struct completion ide_completion; - struct nic_operations *nic_ops; + const struct nic_operations *nic_ops; u16 device_id; struct timer_list timer; atomic_t lb_count; diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 8149cc9de4ca..19b00fa0eaf0 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -356,7 +356,7 @@ static int ql_get_settings(struct net_device *ndev, ecmd->port = PORT_FIBRE; } - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); ecmd->duplex = DUPLEX_FULL; return 0; @@ -412,31 +412,31 @@ static int ql_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) return 0; } -static int ql_phys_id(struct net_device *ndev, u32 data) +static int ql_set_phys_id(struct net_device *ndev, + enum ethtool_phys_id_state state) + { struct ql_adapter *qdev = netdev_priv(ndev); - u32 led_reg, i; - int status; - /* Save the current LED settings */ - status = ql_mb_get_led_cfg(qdev); - if (status) - return status; - led_reg = qdev->led_config; + switch (state) { + case ETHTOOL_ID_ACTIVE: + /* Save the current LED settings */ + if (ql_mb_get_led_cfg(qdev)) + return -EIO; - /* Start blinking the led */ - if (!data || data > 300) - data = 300; - - for (i = 0; i < (data * 10); i++) + /* Start blinking */ ql_mb_set_led_cfg(qdev, QL_LED_BLINK); + return 0; - /* Restore LED settings */ - status = ql_mb_set_led_cfg(qdev, led_reg); - if (status) - return status; + case ETHTOOL_ID_INACTIVE: + /* Restore LED settings */ + if (ql_mb_set_led_cfg(qdev, qdev->led_config)) + return -EIO; + return 0; - return 0; + default: + return -EINVAL; + } } static int ql_start_loopback(struct ql_adapter *qdev) @@ -655,32 +655,6 @@ static int ql_set_pauseparam(struct net_device *netdev, return status; } -static u32 ql_get_rx_csum(struct net_device *netdev) -{ - struct ql_adapter *qdev = netdev_priv(netdev); - return qdev->rx_csum; -} - -static int ql_set_rx_csum(struct net_device *netdev, uint32_t data) -{ - struct ql_adapter *qdev = netdev_priv(netdev); - qdev->rx_csum = data; - return 0; -} - -static int ql_set_tso(struct net_device *ndev, uint32_t data) -{ - - if (data) { - ndev->features |= NETIF_F_TSO; - ndev->features |= NETIF_F_TSO6; - } else { - ndev->features &= ~NETIF_F_TSO; - ndev->features &= ~NETIF_F_TSO6; - } - return 0; -} - static u32 ql_get_msglevel(struct net_device *ndev) { struct ql_adapter *qdev = netdev_priv(ndev); @@ -703,18 +677,10 @@ const struct ethtool_ops qlge_ethtool_ops = { .get_msglevel = ql_get_msglevel, .set_msglevel = ql_set_msglevel, .get_link = ethtool_op_get_link, - .phys_id = ql_phys_id, + .set_phys_id = ql_set_phys_id, .self_test = ql_self_test, .get_pauseparam = ql_get_pauseparam, .set_pauseparam = ql_set_pauseparam, - .get_rx_csum = ql_get_rx_csum, - .set_rx_csum = ql_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = ql_set_tso, .get_coalesce = ql_get_coalesce, .set_coalesce = ql_set_coalesce, .get_sset_count = ql_get_sset_count, diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 5bb311945436..6c9d124cfc76 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1571,7 +1571,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev, skb->protocol = eth_type_trans(skb, ndev); skb_checksum_none_assert(skb); - if (qdev->rx_csum && + if ((ndev->features & NETIF_F_RXCSUM) && !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { @@ -1684,7 +1684,7 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev, /* If rx checksum is on, and there are no * csum or frame errors. */ - if (qdev->rx_csum && + if ((ndev->features & NETIF_F_RXCSUM) && !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { @@ -2004,7 +2004,7 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev, /* If rx checksum is on, and there are no * csum or frame errors. */ - if (qdev->rx_csum && + if ((ndev->features & NETIF_F_RXCSUM) && !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { @@ -4412,12 +4412,12 @@ static void ql_asic_reset_work(struct work_struct *work) rtnl_unlock(); } -static struct nic_operations qla8012_nic_ops = { +static const struct nic_operations qla8012_nic_ops = { .get_flash = ql_get_8012_flash_params, .port_initialize = ql_8012_port_initialize, }; -static struct nic_operations qla8000_nic_ops = { +static const struct nic_operations qla8000_nic_ops = { .get_flash = ql_get_8000_flash_params, .port_initialize = ql_8000_port_initialize, }; @@ -4621,7 +4621,6 @@ static int __devinit ql_init_device(struct pci_dev *pdev, /* * Set up the operating parameters. */ - qdev->rx_csum = 1; qdev->workqueue = create_singlethread_workqueue(ndev->name); INIT_DELAYED_WORK(&qdev->asic_reset_work, ql_asic_reset_work); INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work); @@ -4695,15 +4694,11 @@ static int __devinit qlge_probe(struct pci_dev *pdev, qdev = netdev_priv(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); - ndev->features = (0 - | NETIF_F_IP_CSUM - | NETIF_F_SG - | NETIF_F_TSO - | NETIF_F_TSO6 - | NETIF_F_TSO_ECN - | NETIF_F_HW_VLAN_TX - | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER); - ndev->features |= NETIF_F_GRO; + ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN | + NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM; + ndev->features = ndev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; if (test_bit(QL_DMA64, &qdev->flags)) ndev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 493b0de3848b..04f4e6086cd0 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -37,6 +37,8 @@ #define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw" #define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw" +#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw" +#define FIRMWARE_8168E_2 "rtl_nic/rtl8168e-2.fw" #define FIRMWARE_8105E_1 "rtl_nic/rtl8105e-1.fw" #ifdef RTL8169_DEBUG @@ -96,77 +98,123 @@ static const int multicast_filter_limit = 32; #define RTL_R32(reg) readl (ioaddr + (reg)) enum mac_version { - RTL_GIGA_MAC_NONE = 0x00, - RTL_GIGA_MAC_VER_01 = 0x01, // 8169 - RTL_GIGA_MAC_VER_02 = 0x02, // 8169S - RTL_GIGA_MAC_VER_03 = 0x03, // 8110S - RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB - RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd - RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe - RTL_GIGA_MAC_VER_07 = 0x07, // 8102e - RTL_GIGA_MAC_VER_08 = 0x08, // 8102e - RTL_GIGA_MAC_VER_09 = 0x09, // 8102e - RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e - RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb - RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be - RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb - RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ? - RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ? - RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec - RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf - RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP - RTL_GIGA_MAC_VER_19 = 0x13, // 8168C - RTL_GIGA_MAC_VER_20 = 0x14, // 8168C - RTL_GIGA_MAC_VER_21 = 0x15, // 8168C - RTL_GIGA_MAC_VER_22 = 0x16, // 8168C - RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP - RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP - RTL_GIGA_MAC_VER_25 = 0x19, // 8168D - RTL_GIGA_MAC_VER_26 = 0x1a, // 8168D - RTL_GIGA_MAC_VER_27 = 0x1b, // 8168DP - RTL_GIGA_MAC_VER_28 = 0x1c, // 8168DP - RTL_GIGA_MAC_VER_29 = 0x1d, // 8105E - RTL_GIGA_MAC_VER_30 = 0x1e, // 8105E + RTL_GIGA_MAC_VER_01 = 0, + RTL_GIGA_MAC_VER_02, + RTL_GIGA_MAC_VER_03, + RTL_GIGA_MAC_VER_04, + RTL_GIGA_MAC_VER_05, + RTL_GIGA_MAC_VER_06, + RTL_GIGA_MAC_VER_07, + RTL_GIGA_MAC_VER_08, + RTL_GIGA_MAC_VER_09, + RTL_GIGA_MAC_VER_10, + RTL_GIGA_MAC_VER_11, + RTL_GIGA_MAC_VER_12, + RTL_GIGA_MAC_VER_13, + RTL_GIGA_MAC_VER_14, + RTL_GIGA_MAC_VER_15, + RTL_GIGA_MAC_VER_16, + RTL_GIGA_MAC_VER_17, + RTL_GIGA_MAC_VER_18, + RTL_GIGA_MAC_VER_19, + RTL_GIGA_MAC_VER_20, + RTL_GIGA_MAC_VER_21, + RTL_GIGA_MAC_VER_22, + RTL_GIGA_MAC_VER_23, + RTL_GIGA_MAC_VER_24, + RTL_GIGA_MAC_VER_25, + RTL_GIGA_MAC_VER_26, + RTL_GIGA_MAC_VER_27, + RTL_GIGA_MAC_VER_28, + RTL_GIGA_MAC_VER_29, + RTL_GIGA_MAC_VER_30, + RTL_GIGA_MAC_VER_31, + RTL_GIGA_MAC_VER_32, + RTL_GIGA_MAC_VER_33, + RTL_GIGA_MAC_NONE = 0xff, }; -#define _R(NAME,MAC,MASK) \ - { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK } +enum rtl_tx_desc_version { + RTL_TD_0 = 0, + RTL_TD_1 = 1, +}; + +#define _R(NAME,TD,FW) \ + { .name = NAME, .txd_version = TD, .fw_name = FW } static const struct { const char *name; - u8 mac_version; - u32 RxConfigMask; /* Clears the bits supported by this chip */ -} rtl_chip_info[] = { - _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169 - _R("RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S - _R("RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S - _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB - _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd - _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe - _R("RTL8102e", RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E - _R("RTL8102e", RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E - _R("RTL8102e", RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139 - _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139 - _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139 - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E - _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880), // PCI-E - _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_26, 0xff7e1880), // PCI-E - _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, 0xff7e1880), // PCI-E - _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_28, 0xff7e1880), // PCI-E - _R("RTL8105e", RTL_GIGA_MAC_VER_29, 0xff7e1880), // PCI-E - _R("RTL8105e", RTL_GIGA_MAC_VER_30, 0xff7e1880) // PCI-E + enum rtl_tx_desc_version txd_version; + const char *fw_name; +} rtl_chip_infos[] = { + /* PCI devices. */ + [RTL_GIGA_MAC_VER_01] = + _R("RTL8169", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_02] = + _R("RTL8169s", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_03] = + _R("RTL8110s", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_04] = + _R("RTL8169sb/8110sb", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_05] = + _R("RTL8169sc/8110sc", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_06] = + _R("RTL8169sc/8110sc", RTL_TD_0, NULL), + /* PCI-E devices. */ + [RTL_GIGA_MAC_VER_07] = + _R("RTL8102e", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_08] = + _R("RTL8102e", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_09] = + _R("RTL8102e", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_10] = + _R("RTL8101e", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_11] = + _R("RTL8168b/8111b", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_12] = + _R("RTL8168b/8111b", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_13] = + _R("RTL8101e", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_14] = + _R("RTL8100e", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_15] = + _R("RTL8100e", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_16] = + _R("RTL8101e", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_17] = + _R("RTL8168b/8111b", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_18] = + _R("RTL8168cp/8111cp", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_19] = + _R("RTL8168c/8111c", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_20] = + _R("RTL8168c/8111c", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_21] = + _R("RTL8168c/8111c", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_22] = + _R("RTL8168c/8111c", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_23] = + _R("RTL8168cp/8111cp", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_24] = + _R("RTL8168cp/8111cp", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_25] = + _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_1), + [RTL_GIGA_MAC_VER_26] = + _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_2), + [RTL_GIGA_MAC_VER_27] = + _R("RTL8168dp/8111dp", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_28] = + _R("RTL8168dp/8111dp", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_29] = + _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1), + [RTL_GIGA_MAC_VER_30] = + _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1), + [RTL_GIGA_MAC_VER_31] = + _R("RTL8168dp/8111dp", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_32] = + _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_1), + [RTL_GIGA_MAC_VER_33] = + _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_2) }; #undef _R @@ -222,6 +270,9 @@ enum rtl_registers { IntrStatus = 0x3e, TxConfig = 0x40, RxConfig = 0x44, + +#define RTL_RX_CONFIG_MASK 0xff7e1880u + RxMissed = 0x4c, Cfg9346 = 0x50, Config0 = 0x51, @@ -315,7 +366,9 @@ enum rtl8168_registers { #define OCPAR_FLAG 0x80000000 #define OCPAR_GPHY_WRITE_CMD 0x8000f060 #define OCPAR_GPHY_READ_CMD 0x0000f060 - RDSAR1 = 0xd0 /* 8168c only. Undocumented on 8168dp */ + RDSAR1 = 0xd0, /* 8168c only. Undocumented on 8168dp */ + MISC = 0xf0, /* 8168e only. */ +#define TXPLA_RST (1 << 29) }; enum rtl_register_content { @@ -393,6 +446,7 @@ enum rtl_register_content { BWF = (1 << 6), /* Accept Broadcast wakeup frame */ MWF = (1 << 5), /* Accept Multicast wakeup frame */ UWF = (1 << 4), /* Accept Unicast wakeup frame */ + Spi_en = (1 << 3), LanWake = (1 << 1), /* LanWake enable/disable */ PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ @@ -441,21 +495,69 @@ enum rtl_register_content { CounterDump = 0x8, }; -enum desc_status_bit { +enum rtl_desc_bit { + /* First doubleword. */ DescOwn = (1 << 31), /* Descriptor is owned by NIC */ RingEnd = (1 << 30), /* End of descriptor ring */ FirstFrag = (1 << 29), /* First segment of a packet */ LastFrag = (1 << 28), /* Final segment of a packet */ +}; - /* Tx private */ - LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */ - MSSShift = 16, /* MSS value position */ - MSSMask = 0xfff, /* MSS value + LargeSend bit: 12 bits */ - IPCS = (1 << 18), /* Calculate IP checksum */ - UDPCS = (1 << 17), /* Calculate UDP/IP checksum */ - TCPCS = (1 << 16), /* Calculate TCP/IP checksum */ - TxVlanTag = (1 << 17), /* Add VLAN tag */ +/* Generic case. */ +enum rtl_tx_desc_bit { + /* First doubleword. */ + TD_LSO = (1 << 27), /* Large Send Offload */ +#define TD_MSS_MAX 0x07ffu /* MSS value */ + /* Second doubleword. */ + TxVlanTag = (1 << 17), /* Add VLAN tag */ +}; + +/* 8169, 8168b and 810x except 8102e. */ +enum rtl_tx_desc_bit_0 { + /* First doubleword. */ +#define TD0_MSS_SHIFT 16 /* MSS position (11 bits) */ + TD0_TCP_CS = (1 << 16), /* Calculate TCP/IP checksum */ + TD0_UDP_CS = (1 << 17), /* Calculate UDP/IP checksum */ + TD0_IP_CS = (1 << 18), /* Calculate IP checksum */ +}; + +/* 8102e, 8168c and beyond. */ +enum rtl_tx_desc_bit_1 { + /* Second doubleword. */ +#define TD1_MSS_SHIFT 18 /* MSS position (11 bits) */ + TD1_IP_CS = (1 << 29), /* Calculate IP checksum */ + TD1_TCP_CS = (1 << 30), /* Calculate TCP/IP checksum */ + TD1_UDP_CS = (1 << 31), /* Calculate UDP/IP checksum */ +}; + +static const struct rtl_tx_desc_info { + struct { + u32 udp; + u32 tcp; + } checksum; + u16 mss_shift; + u16 opts_offset; +} tx_desc_info [] = { + [RTL_TD_0] = { + .checksum = { + .udp = TD0_IP_CS | TD0_UDP_CS, + .tcp = TD0_IP_CS | TD0_TCP_CS + }, + .mss_shift = TD0_MSS_SHIFT, + .opts_offset = 0 + }, + [RTL_TD_1] = { + .checksum = { + .udp = TD1_IP_CS | TD1_UDP_CS, + .tcp = TD1_IP_CS | TD1_TCP_CS + }, + .mss_shift = TD1_MSS_SHIFT, + .opts_offset = 1 + } +}; + +enum rtl_rx_desc_bit { /* Rx private */ PID1 = (1 << 18), /* Protocol ID bit 1/2 */ PID0 = (1 << 17), /* Protocol ID bit 2/2 */ @@ -515,13 +617,13 @@ struct rtl8169_counters { struct rtl8169_private { void __iomem *mmio_addr; /* memory map physical address */ - struct pci_dev *pci_dev; /* Index of PCI device */ + struct pci_dev *pci_dev; struct net_device *dev; struct napi_struct napi; - spinlock_t lock; /* spin lock flag */ + spinlock_t lock; u32 msg_enable; - int chipset; - int mac_version; + u16 txd_version; + u16 mac_version; u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ u32 dirty_rx; @@ -537,7 +639,6 @@ struct rtl8169_private { u16 intr_event; u16 napi_event; u16 intr_mask; - int phy_1000_ctrl_reg; struct mdio_ops { void (*write)(void __iomem *, int, int); @@ -565,6 +666,7 @@ struct rtl8169_private { u32 saved_wolopts; const struct firmware *fw; +#define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN); }; MODULE_AUTHOR("Realtek and the Linux r8169 crew "); @@ -577,6 +679,8 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(RTL8169_VERSION); MODULE_FIRMWARE(FIRMWARE_8168D_1); MODULE_FIRMWARE(FIRMWARE_8168D_2); +MODULE_FIRMWARE(FIRMWARE_8168E_1); +MODULE_FIRMWARE(FIRMWARE_8168E_2); MODULE_FIRMWARE(FIRMWARE_8105E_1); static int rtl8169_open(struct net_device *dev); @@ -648,32 +752,49 @@ static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd) #define OOB_CMD_DRIVER_START 0x05 #define OOB_CMD_DRIVER_STOP 0x06 +static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp) +{ + return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10; +} + static void rtl8168_driver_start(struct rtl8169_private *tp) { + u16 reg; int i; rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START); + reg = rtl8168_get_ocp_reg(tp); + for (i = 0; i < 10; i++) { msleep(10); - if (ocp_read(tp, 0x0f, 0x0010) & 0x00000800) + if (ocp_read(tp, 0x0f, reg) & 0x00000800) break; } } static void rtl8168_driver_stop(struct rtl8169_private *tp) { + u16 reg; int i; rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP); + reg = rtl8168_get_ocp_reg(tp); + for (i = 0; i < 10; i++) { msleep(10); - if ((ocp_read(tp, 0x0f, 0x0010) & 0x00000800) == 0) + if ((ocp_read(tp, 0x0f, reg) & 0x00000800) == 0) break; } } +static int r8168dp_check_dash(struct rtl8169_private *tp) +{ + u16 reg = rtl8168_get_ocp_reg(tp); + + return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0; +} static void r8169_mdio_write(void __iomem *ioaddr, int reg_addr, int value) { @@ -972,9 +1093,8 @@ static void rtl8169_xmii_reset_enable(struct rtl8169_private *tp) } static void __rtl8169_check_link_status(struct net_device *dev, - struct rtl8169_private *tp, - void __iomem *ioaddr, - bool pm) + struct rtl8169_private *tp, + void __iomem *ioaddr, bool pm) { unsigned long flags; @@ -1091,6 +1211,11 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return 0; } +static const char *rtl_lookup_firmware_name(struct rtl8169_private *tp) +{ + return rtl_chip_infos[tp->mac_version].fw_name; +} + static void rtl8169_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { @@ -1099,6 +1224,8 @@ static void rtl8169_get_drvinfo(struct net_device *dev, strcpy(info->driver, MODULENAME); strcpy(info->version, RTL8169_VERSION); strcpy(info->bus_info, pci_name(tp->pci_dev)); + strncpy(info->fw_version, IS_ERR_OR_NULL(tp->fw) ? "N/A" : + rtl_lookup_firmware_name(tp), sizeof(info->fw_version) - 1); } static int rtl8169_get_regs_len(struct net_device *dev) @@ -1160,16 +1287,7 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); /* The 8100e/8101e/8102e do Fast Ethernet only. */ - if ((tp->mac_version != RTL_GIGA_MAC_VER_07) && - (tp->mac_version != RTL_GIGA_MAC_VER_08) && - (tp->mac_version != RTL_GIGA_MAC_VER_09) && - (tp->mac_version != RTL_GIGA_MAC_VER_10) && - (tp->mac_version != RTL_GIGA_MAC_VER_13) && - (tp->mac_version != RTL_GIGA_MAC_VER_14) && - (tp->mac_version != RTL_GIGA_MAC_VER_15) && - (tp->mac_version != RTL_GIGA_MAC_VER_16) && - (tp->mac_version != RTL_GIGA_MAC_VER_29) && - (tp->mac_version != RTL_GIGA_MAC_VER_30)) { + if (tp->mii.supports_gmii) { if (adv & ADVERTISED_1000baseT_Half) giga_ctrl |= ADVERTISE_1000HALF; if (adv & ADVERTISED_1000baseT_Full) @@ -1199,12 +1317,10 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, bmcr |= BMCR_FULLDPLX; } - tp->phy_1000_ctrl_reg = giga_ctrl; - rtl_writephy(tp, MII_BMCR, bmcr); - if ((tp->mac_version == RTL_GIGA_MAC_VER_02) || - (tp->mac_version == RTL_GIGA_MAC_VER_03)) { + if (tp->mac_version == RTL_GIGA_MAC_VER_02 || + tp->mac_version == RTL_GIGA_MAC_VER_03) { if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) { rtl_writephy(tp, 0x17, 0x2138); rtl_writephy(tp, 0x0e, 0x0260); @@ -1226,10 +1342,14 @@ static int rtl8169_set_speed(struct net_device *dev, int ret; ret = tp->set_speed(dev, autoneg, speed, duplex, advertising); + if (ret < 0) + goto out; - if (netif_running(dev) && (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL)) + if (netif_running(dev) && (autoneg == AUTONEG_ENABLE) && + (advertising & ADVERTISED_1000baseT_Full)) { mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT); - + } +out: return ret; } @@ -1239,22 +1359,25 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) unsigned long flags; int ret; + del_timer_sync(&tp->timer); + spin_lock_irqsave(&tp->lock, flags); - ret = rtl8169_set_speed(dev, - cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising); + ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd), + cmd->duplex, cmd->advertising); spin_unlock_irqrestore(&tp->lock, flags); return ret; } -static u32 rtl8169_get_rx_csum(struct net_device *dev) +static u32 rtl8169_fix_features(struct net_device *dev, u32 features) { - struct rtl8169_private *tp = netdev_priv(dev); + if (dev->mtu > TD_MSS_MAX) + features &= ~NETIF_F_ALL_TSO; - return tp->cp_cmd & RxChkSum; + return features; } -static int rtl8169_set_rx_csum(struct net_device *dev, u32 data) +static int rtl8169_set_features(struct net_device *dev, u32 features) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; @@ -1262,11 +1385,16 @@ static int rtl8169_set_rx_csum(struct net_device *dev, u32 data) spin_lock_irqsave(&tp->lock, flags); - if (data) + if (features & NETIF_F_RXCSUM) tp->cp_cmd |= RxChkSum; else tp->cp_cmd &= ~RxChkSum; + if (dev->features & NETIF_F_HW_VLAN_RX) + tp->cp_cmd |= RxVlan; + else + tp->cp_cmd &= ~RxVlan; + RTL_W16(CPlusCmd, tp->cp_cmd); RTL_R16(CPlusCmd); @@ -1282,27 +1410,6 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp, TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; } -#define NETIF_F_HW_VLAN_TX_RX (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX) - -static void rtl8169_vlan_mode(struct net_device *dev) -{ - struct rtl8169_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->mmio_addr; - unsigned long flags; - - spin_lock_irqsave(&tp->lock, flags); - if (dev->features & NETIF_F_HW_VLAN_RX) - tp->cp_cmd |= RxVlan; - else - tp->cp_cmd &= ~RxVlan; - RTL_W16(CPlusCmd, tp->cp_cmd); - /* PCI commit */ - RTL_R16(CPlusCmd); - spin_unlock_irqrestore(&tp->lock, flags); - - dev->vlan_features = dev->features &~ NETIF_F_HW_VLAN_TX_RX; -} - static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb) { u32 opts2 = le32_to_cpu(desc->opts2); @@ -1328,7 +1435,7 @@ static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0; cmd->autoneg = !!(status & TBINwEnable); - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); cmd->duplex = DUPLEX_FULL; /* Always set */ return 0; @@ -1413,11 +1520,11 @@ static void rtl8169_update_counters(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; + struct device *d = &tp->pci_dev->dev; struct rtl8169_counters *counters; dma_addr_t paddr; u32 cmd; int wait = 1000; - struct device *d = &tp->pci_dev->dev; /* * Some chips are unable to dump tally counters when the receiver @@ -1437,7 +1544,6 @@ static void rtl8169_update_counters(struct net_device *dev) while (wait--) { if ((RTL_R32(CounterAddrLow) & CounterDump) == 0) { - /* copy updated counters */ memcpy(&tp->counters, counters, sizeof(*counters)); break; } @@ -1483,28 +1589,6 @@ static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) } } -static int rtl8169_set_flags(struct net_device *dev, u32 data) -{ - struct rtl8169_private *tp = netdev_priv(dev); - unsigned long old_feat = dev->features; - int rc; - - if ((tp->mac_version == RTL_GIGA_MAC_VER_05) && - !(data & ETH_FLAG_RXVLAN)) { - netif_info(tp, drv, dev, "8110SCd requires hardware Rx VLAN\n"); - return -EINVAL; - } - - rc = ethtool_op_set_flags(dev, data, ETH_FLAG_TXVLAN | ETH_FLAG_RXVLAN); - if (rc) - return rc; - - if ((old_feat ^ dev->features) & NETIF_F_HW_VLAN_RX) - rtl8169_vlan_mode(dev); - - return 0; -} - static const struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, .get_regs_len = rtl8169_get_regs_len, @@ -1513,24 +1597,18 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .set_settings = rtl8169_set_settings, .get_msglevel = rtl8169_get_msglevel, .set_msglevel = rtl8169_set_msglevel, - .get_rx_csum = rtl8169_get_rx_csum, - .set_rx_csum = rtl8169_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, .get_regs = rtl8169_get_regs, .get_wol = rtl8169_get_wol, .set_wol = rtl8169_set_wol, .get_strings = rtl8169_get_strings, .get_sset_count = rtl8169_get_sset_count, .get_ethtool_stats = rtl8169_get_ethtool_stats, - .set_flags = rtl8169_set_flags, - .get_flags = ethtool_op_get_flags, }; static void rtl8169_get_mac_version(struct rtl8169_private *tp, - void __iomem *ioaddr) + struct net_device *dev, u8 default_version) { + void __iomem *ioaddr = tp->mmio_addr; /* * The driver currently handles the 8168Bf and the 8168Be identically * but they can be identified more specifically through the test below @@ -1547,6 +1625,11 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, u32 val; int mac_version; } mac_info[] = { + /* 8168E family. */ + { 0x7cf00000, 0x2c200000, RTL_GIGA_MAC_VER_33 }, + { 0x7cf00000, 0x2c100000, RTL_GIGA_MAC_VER_32 }, + { 0x7c800000, 0x2c000000, RTL_GIGA_MAC_VER_33 }, + /* 8168D family. */ { 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 }, { 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 }, @@ -1555,6 +1638,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, /* 8168DP family. */ { 0x7cf00000, 0x28800000, RTL_GIGA_MAC_VER_27 }, { 0x7cf00000, 0x28a00000, RTL_GIGA_MAC_VER_28 }, + { 0x7cf00000, 0x28b00000, RTL_GIGA_MAC_VER_31 }, /* 8168C family. */ { 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 }, @@ -1574,6 +1658,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, /* 8101 family. */ + { 0x7cf00000, 0x40b00000, RTL_GIGA_MAC_VER_30 }, { 0x7cf00000, 0x40a00000, RTL_GIGA_MAC_VER_30 }, { 0x7cf00000, 0x40900000, RTL_GIGA_MAC_VER_29 }, { 0x7c800000, 0x40800000, RTL_GIGA_MAC_VER_30 }, @@ -1610,6 +1695,12 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, while ((reg & p->mask) != p->val) p++; tp->mac_version = p->mac_version; + + if (tp->mac_version == RTL_GIGA_MAC_NONE) { + netif_notice(tp, probe, dev, + "unknown MAC, using family default\n"); + tp->mac_version = default_version; + } } static void rtl8169_print_mac_version(struct rtl8169_private *tp) @@ -1679,14 +1770,14 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw) case PHY_BJMPN: if (regno > index) { netif_err(tp, probe, tp->dev, - "Out of range of firmware\n"); + "Out of range of firmware\n"); return; } break; case PHY_READCOUNT_EQ_SKIP: if (index + 2 >= fw_size) { netif_err(tp, probe, tp->dev, - "Out of range of firmware\n"); + "Out of range of firmware\n"); return; } break; @@ -1695,7 +1786,7 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw) case PHY_SKIPN: if (index + 1 + regno >= fw_size) { netif_err(tp, probe, tp->dev, - "Out of range of firmware\n"); + "Out of range of firmware\n"); return; } break; @@ -1751,10 +1842,7 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw) index++; break; case PHY_READCOUNT_EQ_SKIP: - if (count == data) - index += 2; - else - index += 1; + index += (count == data) ? 2 : 1; break; case PHY_COMP_EQ_SKIPN: if (predata == data) @@ -1789,25 +1877,26 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw) static void rtl_release_firmware(struct rtl8169_private *tp) { - release_firmware(tp->fw); - tp->fw = NULL; + if (!IS_ERR_OR_NULL(tp->fw)) + release_firmware(tp->fw); + tp->fw = RTL_FIRMWARE_UNKNOWN; } -static int rtl_apply_firmware(struct rtl8169_private *tp, const char *fw_name) +static void rtl_apply_firmware(struct rtl8169_private *tp) { - const struct firmware **fw = &tp->fw; - int rc = !*fw; - - if (rc) { - rc = request_firmware(fw, fw_name, &tp->pci_dev->dev); - if (rc < 0) - goto out; - } + const struct firmware *fw = tp->fw; /* TODO: release firmware once rtl_phy_write_fw signals failures. */ - rtl_phy_write_fw(tp, *fw); -out: - return rc; + if (!IS_ERR_OR_NULL(fw)) + rtl_phy_write_fw(tp, fw); +} + +static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val) +{ + if (rtl_readphy(tp, reg) != val) + netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n"); + else + rtl_apply_firmware(tp); } static void rtl8169s_hw_phy_config(struct rtl8169_private *tp) @@ -2164,7 +2253,7 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) /* * Tx Error Issue - * enhance line driver power + * Enhance line driver power */ { 0x1f, 0x0002 }, { 0x06, 0x5561 }, @@ -2246,10 +2335,8 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x001b); - if ((rtl_readphy(tp, 0x06) != 0xbf00) || - (rtl_apply_firmware(tp, FIRMWARE_8168D_1) < 0)) { - netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); - } + + rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xbf00); rtl_writephy(tp, 0x1f, 0x0000); } @@ -2278,7 +2365,7 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp) /* * Tx Error Issue - * enhance line driver power + * Enhance line driver power */ { 0x1f, 0x0002 }, { 0x06, 0x5561 }, @@ -2351,10 +2438,8 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x001b); - if ((rtl_readphy(tp, 0x06) != 0xb300) || - (rtl_apply_firmware(tp, FIRMWARE_8168D_2) < 0)) { - netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); - } + + rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xb300); rtl_writephy(tp, 0x1f, 0x0000); } @@ -2436,6 +2521,79 @@ static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp) rtl_patchphy(tp, 0x0d, 1 << 5); } +static void rtl8168e_hw_phy_config(struct rtl8169_private *tp) +{ + static const struct phy_reg phy_reg_init[] = { + /* Enable Delay cap */ + { 0x1f, 0x0005 }, + { 0x05, 0x8b80 }, + { 0x06, 0xc896 }, + { 0x1f, 0x0000 }, + + /* Channel estimation fine tune */ + { 0x1f, 0x0001 }, + { 0x0b, 0x6c20 }, + { 0x07, 0x2872 }, + { 0x1c, 0xefff }, + { 0x1f, 0x0003 }, + { 0x14, 0x6420 }, + { 0x1f, 0x0000 }, + + /* Update PFM & 10M TX idle timer */ + { 0x1f, 0x0007 }, + { 0x1e, 0x002f }, + { 0x15, 0x1919 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0007 }, + { 0x1e, 0x00ac }, + { 0x18, 0x0006 }, + { 0x1f, 0x0000 } + }; + + rtl_apply_firmware(tp); + + rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + /* DCO enable for 10M IDLE Power */ + rtl_writephy(tp, 0x1f, 0x0007); + rtl_writephy(tp, 0x1e, 0x0023); + rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); + + /* For impedance matching */ + rtl_writephy(tp, 0x1f, 0x0002); + rtl_w1w0_phy(tp, 0x08, 0x8000, 0x7f00); + rtl_writephy(tp, 0x1f, 0x0000); + + /* PHY auto speed down */ + rtl_writephy(tp, 0x1f, 0x0007); + rtl_writephy(tp, 0x1e, 0x002d); + rtl_w1w0_phy(tp, 0x18, 0x0050, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); + rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000); + + rtl_writephy(tp, 0x1f, 0x0005); + rtl_writephy(tp, 0x05, 0x8b86); + rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); + + rtl_writephy(tp, 0x1f, 0x0005); + rtl_writephy(tp, 0x05, 0x8b85); + rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000); + rtl_writephy(tp, 0x1f, 0x0007); + rtl_writephy(tp, 0x1e, 0x0020); + rtl_w1w0_phy(tp, 0x15, 0x0000, 0x1100); + rtl_writephy(tp, 0x1f, 0x0006); + rtl_writephy(tp, 0x00, 0x5a00); + 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); +} + static void rtl8102e_hw_phy_config(struct rtl8169_private *tp) { static const struct phy_reg phy_reg_init[] = { @@ -2474,8 +2632,7 @@ static void rtl8105e_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x18, 0x0310); msleep(100); - if (rtl_apply_firmware(tp, FIRMWARE_8105E_1) < 0) - netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); + rtl_apply_firmware(tp); rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } @@ -2551,6 +2708,13 @@ static void rtl_hw_phy_config(struct net_device *dev) case RTL_GIGA_MAC_VER_30: rtl8105e_hw_phy_config(tp); break; + case RTL_GIGA_MAC_VER_31: + /* None. */ + break; + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: + rtl8168e_hw_phy_config(tp); + break; default: break; @@ -2567,9 +2731,6 @@ static void rtl8169_phy_timer(unsigned long __opaque) assert(tp->mac_version > RTL_GIGA_MAC_VER_01); - if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL)) - return; - spin_lock_irq(&tp->lock); if (tp->phy_reset_pending(tp)) { @@ -2594,28 +2755,6 @@ static void rtl8169_phy_timer(unsigned long __opaque) spin_unlock_irq(&tp->lock); } -static inline void rtl8169_delete_timer(struct net_device *dev) -{ - struct rtl8169_private *tp = netdev_priv(dev); - struct timer_list *timer = &tp->timer; - - if (tp->mac_version <= RTL_GIGA_MAC_VER_01) - return; - - del_timer_sync(timer); -} - -static inline void rtl8169_request_timer(struct net_device *dev) -{ - struct rtl8169_private *tp = netdev_priv(dev); - struct timer_list *timer = &tp->timer; - - if (tp->mac_version <= RTL_GIGA_MAC_VER_01) - return; - - mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT); -} - #ifdef CONFIG_NET_POLL_CONTROLLER /* * Polling 'interrupt' - used by things like netconsole to send skbs @@ -2683,11 +2822,11 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) rtl8169_phy_reset(dev, tp); rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL, - ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | - (tp->mii.supports_gmii ? - ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full : 0)); + ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | + (tp->mii.supports_gmii ? + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full : 0)); if (RTL_R8(PHYstatus) & TBI_Enable) netif_info(tp, link, dev, "TBI auto-negotiating\n"); @@ -2740,7 +2879,8 @@ static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV; } -static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd) +static int rtl_xmii_ioctl(struct rtl8169_private *tp, + struct mii_ioctl_data *data, int cmd) { switch (cmd) { case SIOCGMIIPHY: @@ -2840,6 +2980,8 @@ static const struct net_device_ops rtl8169_netdev_ops = { .ndo_tx_timeout = rtl8169_tx_timeout, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = rtl8169_change_mtu, + .ndo_fix_features = rtl8169_fix_features, + .ndo_set_features = rtl8169_set_features, .ndo_set_mac_address = rtl_set_mac_address, .ndo_do_ioctl = rtl8169_ioctl, .ndo_set_multicast_list = rtl_set_rx_mode, @@ -2859,6 +3001,7 @@ static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp) ops->read = r8168dp_1_mdio_read; break; case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: ops->write = r8168dp_2_mdio_write; ops->read = r8168dp_2_mdio_read; break; @@ -2900,33 +3043,82 @@ static void r810x_pll_power_up(struct rtl8169_private *tp) static void r8168_phy_power_up(struct rtl8169_private *tp) { rtl_writephy(tp, 0x1f, 0x0000); - rtl_writephy(tp, 0x0e, 0x0000); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_11: + case RTL_GIGA_MAC_VER_12: + case RTL_GIGA_MAC_VER_17: + case RTL_GIGA_MAC_VER_18: + case RTL_GIGA_MAC_VER_19: + case RTL_GIGA_MAC_VER_20: + case RTL_GIGA_MAC_VER_21: + case RTL_GIGA_MAC_VER_22: + case RTL_GIGA_MAC_VER_23: + case RTL_GIGA_MAC_VER_24: + case RTL_GIGA_MAC_VER_25: + case RTL_GIGA_MAC_VER_26: + case RTL_GIGA_MAC_VER_27: + case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + rtl_writephy(tp, 0x0e, 0x0000); + break; + default: + break; + } rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE); } static void r8168_phy_power_down(struct rtl8169_private *tp) { rtl_writephy(tp, 0x1f, 0x0000); - rtl_writephy(tp, 0x0e, 0x0200); - rtl_writephy(tp, MII_BMCR, BMCR_PDOWN); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: + rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_PDOWN); + break; + + case RTL_GIGA_MAC_VER_11: + case RTL_GIGA_MAC_VER_12: + case RTL_GIGA_MAC_VER_17: + case RTL_GIGA_MAC_VER_18: + case RTL_GIGA_MAC_VER_19: + case RTL_GIGA_MAC_VER_20: + case RTL_GIGA_MAC_VER_21: + case RTL_GIGA_MAC_VER_22: + case RTL_GIGA_MAC_VER_23: + case RTL_GIGA_MAC_VER_24: + case RTL_GIGA_MAC_VER_25: + case RTL_GIGA_MAC_VER_26: + case RTL_GIGA_MAC_VER_27: + case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + rtl_writephy(tp, 0x0e, 0x0200); + default: + rtl_writephy(tp, MII_BMCR, BMCR_PDOWN); + break; + } } static void r8168_pll_power_down(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)) && - (ocp_read(tp, 0x0f, 0x0010) & 0x00008000)) { + 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; } - if (((tp->mac_version == RTL_GIGA_MAC_VER_23) || - (tp->mac_version == RTL_GIGA_MAC_VER_24)) && + if ((tp->mac_version == RTL_GIGA_MAC_VER_23 || + tp->mac_version == RTL_GIGA_MAC_VER_24) && (RTL_R16(CPlusCmd) & ASF)) { return; } + if (tp->mac_version == RTL_GIGA_MAC_VER_32 || + tp->mac_version == RTL_GIGA_MAC_VER_33) + rtl_ephy_write(ioaddr, 0x19, 0xff64); + if (__rtl8169_get_wol(tp) & WAKE_ANY) { rtl_writephy(tp, 0x1f, 0x0000); rtl_writephy(tp, MII_BMCR, 0x0000); @@ -2943,6 +3135,9 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80); break; } @@ -2952,9 +3147,10 @@ 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)) && - (ocp_read(tp, 0x0f, 0x0010) & 0x00008000)) { + 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; } @@ -2963,6 +3159,9 @@ static void r8168_pll_power_up(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: RTL_W8(PMCH, RTL_R8(PMCH) | 0x80); break; } @@ -3017,6 +3216,9 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: ops->down = r8168_pll_power_down; ops->up = r8168_pll_power_up; break; @@ -3028,6 +3230,22 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp) } } +static void rtl_hw_reset(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + int i; + + /* Soft reset the chip. */ + RTL_W8(ChipCmd, CmdReset); + + /* Check that the chip has finished the reset. */ + for (i = 0; i < 100; i++) { + if ((RTL_R8(ChipCmd) & CmdReset) == 0) + break; + msleep_interruptible(1); + } +} + static int __devinit rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -3037,7 +3255,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct mii_if_info *mii; struct net_device *dev; void __iomem *ioaddr; - unsigned int i; + int chipset, i; int rc; if (netif_msg_drv(&debug)) { @@ -3127,6 +3345,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = -EIO; goto err_out_free_res_3; } + tp->mmio_addr = ioaddr; tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); if (!tp->pcie_cap) @@ -3134,22 +3353,14 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) RTL_W16(IntrMask, 0x0000); - /* Soft reset the chip. */ - RTL_W8(ChipCmd, CmdReset); - - /* Check that the chip has finished the reset. */ - for (i = 0; i < 100; i++) { - if ((RTL_R8(ChipCmd) & CmdReset) == 0) - break; - msleep_interruptible(1); - } + rtl_hw_reset(tp); RTL_W16(IntrStatus, 0xffff); pci_set_master(pdev); /* Identify chip attached to board */ - rtl8169_get_mac_version(tp, ioaddr); + rtl8169_get_mac_version(tp, dev, cfg->default_ver); /* * Pretend we are using VLANs; This bypasses a nasty bug where @@ -3161,25 +3372,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl_init_mdio_ops(tp); rtl_init_pll_power_ops(tp); - /* Use appropriate default if unknown */ - if (tp->mac_version == RTL_GIGA_MAC_NONE) { - netif_notice(tp, probe, dev, - "unknown MAC, using family default\n"); - tp->mac_version = cfg->default_ver; - } - rtl8169_print_mac_version(tp); - for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) { - if (tp->mac_version == rtl_chip_info[i].mac_version) - break; - } - if (i == ARRAY_SIZE(rtl_chip_info)) { - dev_err(&pdev->dev, - "driver bug, MAC version not found in rtl_chip_info\n"); - goto err_out_msi_4; - } - tp->chipset = i; + chipset = tp->mac_version; + tp->txd_version = rtl_chip_infos[chipset].txd_version; RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(Config1, RTL_R8(Config1) | PMEnable); @@ -3199,8 +3395,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->phy_reset_pending = rtl8169_tbi_reset_pending; tp->link_ok = rtl8169_tbi_link_ok; tp->do_ioctl = rtl_tbi_ioctl; - - tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */ } else { tp->set_speed = rtl8169_set_speed_xmii; tp->get_settings = rtl8169_gset_xmii; @@ -3212,8 +3406,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&tp->lock); - tp->mmio_addr = ioaddr; - /* Get MAC address */ for (i = 0; i < MAC_ADDR_LEN; i++) dev->dev_addr[i] = RTL_R8(MAC0 + i); @@ -3226,7 +3418,19 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT); - dev->features |= NETIF_F_HW_VLAN_TX_RX | NETIF_F_GRO; + /* don't enable SG, IP_CSUM and TSO by default - it might not work + * properly for all devices */ + dev->features |= NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_RXCSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_HIGHDMA; + + if (tp->mac_version == RTL_GIGA_MAC_VER_05) + /* 8110SCd requires hardware Rx VLAN - disallow toggling */ + dev->hw_features &= ~NETIF_F_HW_VLAN_RX; tp->intr_mask = 0xffff; tp->hw_start = cfg->hw_start; @@ -3237,6 +3441,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->timer.data = (unsigned long) dev; tp->timer.function = rtl8169_phy_timer; + tp->fw = RTL_FIRMWARE_UNKNOWN; + rc = register_netdev(dev); if (rc < 0) goto err_out_msi_4; @@ -3244,12 +3450,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); netif_info(tp, probe, dev, "%s at 0x%lx, %pM, XID %08x IRQ %d\n", - rtl_chip_info[tp->chipset].name, - dev->base_addr, dev->dev_addr, + rtl_chip_infos[chipset].name, dev->base_addr, dev->dev_addr, (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq); - if ((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28)) { + 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) { rtl8168_driver_start(tp); } @@ -3281,17 +3487,18 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct rtl8169_private *tp = netdev_priv(dev); - if ((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28)) { + 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) { rtl8168_driver_stop(tp); } cancel_delayed_work_sync(&tp->task); - rtl_release_firmware(tp); - unregister_netdev(dev); + rtl_release_firmware(tp); + if (pci_dev_run_wake(pdev)) pm_runtime_get_noresume(&pdev->dev); @@ -3303,6 +3510,27 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +static void rtl_request_firmware(struct rtl8169_private *tp) +{ + /* Return early if the firmware is already loaded / cached. */ + if (IS_ERR(tp->fw)) { + const char *name; + + name = rtl_lookup_firmware_name(tp); + if (name) { + int rc; + + rc = request_firmware(&tp->fw, name, &tp->pci_dev->dev); + if (rc >= 0) + return; + + netif_warn(tp, ifup, tp->dev, "unable to load " + "firmware patch %s (%d)\n", name, rc); + } + tp->fw = NULL; + } +} + static int rtl8169_open(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -3334,24 +3562,24 @@ static int rtl8169_open(struct net_device *dev) smp_mb(); + rtl_request_firmware(tp); + retval = request_irq(dev->irq, rtl8169_interrupt, (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED, dev->name, dev); if (retval < 0) - goto err_release_ring_2; + goto err_release_fw_2; napi_enable(&tp->napi); rtl8169_init_phy(dev, tp); - rtl8169_vlan_mode(dev); + rtl8169_set_features(dev, dev->features); rtl_pll_power_up(tp); rtl_hw_start(dev); - rtl8169_request_timer(dev); - tp->saved_wolopts = 0; pm_runtime_put_noidle(&pdev->dev); @@ -3359,7 +3587,8 @@ static int rtl8169_open(struct net_device *dev) out: return retval; -err_release_ring_2: +err_release_fw_2: + rtl_release_firmware(tp); rtl8169_rx_clear(tp); err_free_rx_1: dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, @@ -3382,7 +3611,8 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp) rtl8169_irq_mask_and_ack(ioaddr); if (tp->mac_version == RTL_GIGA_MAC_VER_27 || - tp->mac_version == RTL_GIGA_MAC_VER_28) { + tp->mac_version == RTL_GIGA_MAC_VER_28 || + tp->mac_version == RTL_GIGA_MAC_VER_31) { while (RTL_R8(TxPoll) & NPQ) udelay(20); @@ -3400,7 +3630,7 @@ static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp) void __iomem *ioaddr = tp->mmio_addr; u32 cfg = rtl8169_rx_config; - cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); + cfg |= (RTL_R32(RxConfig) & RTL_RX_CONFIG_MASK); RTL_W32(RxConfig, cfg); /* Set DMA burst size and Interframe Gap Time */ @@ -3411,25 +3641,14 @@ static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp) static void rtl_hw_start(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->mmio_addr; - unsigned int i; - /* Soft reset the chip. */ - RTL_W8(ChipCmd, CmdReset); - - /* Check that the chip has finished the reset. */ - for (i = 0; i < 100; i++) { - if ((RTL_R8(ChipCmd) & CmdReset) == 0) - break; - msleep_interruptible(1); - } + rtl_hw_reset(tp); tp->hw_start(dev); netif_start_queue(dev); } - static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp, void __iomem *ioaddr) { @@ -3495,26 +3714,26 @@ static void rtl_hw_start_8169(struct net_device *dev) } RTL_W8(Cfg9346, Cfg9346_Unlock); - if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || - (tp->mac_version == RTL_GIGA_MAC_VER_02) || - (tp->mac_version == RTL_GIGA_MAC_VER_03) || - (tp->mac_version == RTL_GIGA_MAC_VER_04)) + if (tp->mac_version == RTL_GIGA_MAC_VER_01 || + tp->mac_version == RTL_GIGA_MAC_VER_02 || + tp->mac_version == RTL_GIGA_MAC_VER_03 || + tp->mac_version == RTL_GIGA_MAC_VER_04) RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); RTL_W8(EarlyTxThres, NoEarlyTx); rtl_set_rx_max_size(ioaddr, rx_buf_sz); - if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || - (tp->mac_version == RTL_GIGA_MAC_VER_02) || - (tp->mac_version == RTL_GIGA_MAC_VER_03) || - (tp->mac_version == RTL_GIGA_MAC_VER_04)) + if (tp->mac_version == RTL_GIGA_MAC_VER_01 || + tp->mac_version == RTL_GIGA_MAC_VER_02 || + tp->mac_version == RTL_GIGA_MAC_VER_03 || + tp->mac_version == RTL_GIGA_MAC_VER_04) rtl_set_rx_tx_config_registers(tp); tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; - if ((tp->mac_version == RTL_GIGA_MAC_VER_02) || - (tp->mac_version == RTL_GIGA_MAC_VER_03)) { + if (tp->mac_version == RTL_GIGA_MAC_VER_02 || + tp->mac_version == RTL_GIGA_MAC_VER_03) { dprintk("Set MAC Reg C+CR Offset 0xE0. " "Bit-3 and bit-14 MUST be 1\n"); tp->cp_cmd |= (1 << 14); @@ -3532,10 +3751,10 @@ static void rtl_hw_start_8169(struct net_device *dev) rtl_set_rx_tx_desc_registers(tp, ioaddr); - if ((tp->mac_version != RTL_GIGA_MAC_VER_01) && - (tp->mac_version != RTL_GIGA_MAC_VER_02) && - (tp->mac_version != RTL_GIGA_MAC_VER_03) && - (tp->mac_version != RTL_GIGA_MAC_VER_04)) { + if (tp->mac_version != RTL_GIGA_MAC_VER_01 && + tp->mac_version != RTL_GIGA_MAC_VER_02 && + tp->mac_version != RTL_GIGA_MAC_VER_03 && + tp->mac_version != RTL_GIGA_MAC_VER_04) { RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); rtl_set_rx_tx_config_registers(tp); } @@ -3779,6 +3998,17 @@ 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) +{ + rtl_csi_access_enable_1(ioaddr); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(MaxTxPacketSize, TxPacketMax); + + rtl_disable_clock_request(pdev); +} + static void rtl_hw_start_8168d_4(void __iomem *ioaddr, struct pci_dev *pdev) { static const struct ephy_info e_info_8168d_4[] = { @@ -3805,6 +4035,41 @@ 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(void __iomem *ioaddr, struct pci_dev *pdev) +{ + static const struct ephy_info e_info_8168e[] = { + { 0x00, 0x0200, 0x0100 }, + { 0x00, 0x0000, 0x0004 }, + { 0x06, 0x0002, 0x0001 }, + { 0x06, 0x0000, 0x0030 }, + { 0x07, 0x0000, 0x2000 }, + { 0x00, 0x0000, 0x0020 }, + { 0x03, 0x5800, 0x2000 }, + { 0x03, 0x0000, 0x0001 }, + { 0x01, 0x0800, 0x1000 }, + { 0x07, 0x0000, 0x4000 }, + { 0x1e, 0x0000, 0x2000 }, + { 0x19, 0xffff, 0xfe6c }, + { 0x0a, 0x0000, 0x0040 } + }; + + rtl_csi_access_enable_2(ioaddr); + + rtl_ephy_init(ioaddr, e_info_8168e, ARRAY_SIZE(e_info_8168e)); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(MaxTxPacketSize, TxPacketMax); + + rtl_disable_clock_request(pdev); + + /* Reset tx FIFO pointer */ + RTL_W32(MISC, RTL_R32(MISC) | TXPLA_RST); + RTL_W32(MISC, RTL_R32(MISC) & ~TXPLA_RST); + + RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en); +} + static void rtl_hw_start_8168(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -3842,55 +4107,64 @@ 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); - break; + break; case RTL_GIGA_MAC_VER_12: case RTL_GIGA_MAC_VER_17: rtl_hw_start_8168bef(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_18: rtl_hw_start_8168cp_1(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_19: rtl_hw_start_8168c_1(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_20: rtl_hw_start_8168c_2(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_21: rtl_hw_start_8168c_3(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_22: rtl_hw_start_8168c_4(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_23: rtl_hw_start_8168cp_2(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_24: rtl_hw_start_8168cp_3(ioaddr, pdev); - break; + 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); - break; + break; case RTL_GIGA_MAC_VER_28: rtl_hw_start_8168d_4(ioaddr, pdev); - break; + break; + + case RTL_GIGA_MAC_VER_31: + rtl_hw_start_8168dp(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: + rtl_hw_start_8168e(ioaddr, pdev); + break; default: printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n", dev->name, tp->mac_version); - break; + break; } RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); @@ -3974,10 +4248,10 @@ static void rtl_hw_start_8105e_1(void __iomem *ioaddr, struct pci_dev *pdev) { 0x0a, 0, 0x0020 } }; - /* Force LAN exit from ASPM if Rx/Tx are not idel */ + /* Force LAN exit from ASPM if Rx/Tx are not idle */ RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800); - /* disable Early Tally Counter */ + /* Disable Early Tally Counter */ RTL_W32(FuncEvent, RTL_R32(FuncEvent) & ~0x010000); RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET); @@ -3998,8 +4272,8 @@ static void rtl_hw_start_8101(struct net_device *dev) void __iomem *ioaddr = tp->mmio_addr; struct pci_dev *pdev = tp->pci_dev; - if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || - (tp->mac_version == RTL_GIGA_MAC_VER_16)) { + if (tp->mac_version == RTL_GIGA_MAC_VER_13 || + tp->mac_version == RTL_GIGA_MAC_VER_16) { int cap = tp->pcie_cap; if (cap) { @@ -4062,6 +4336,8 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; dev->mtu = new_mtu; + netdev_update_features(dev); + return 0; } @@ -4299,6 +4575,7 @@ static void rtl8169_reset_task(struct work_struct *work) struct rtl8169_private *tp = container_of(work, struct rtl8169_private, task.work); struct net_device *dev = tp->dev; + int i; rtnl_lock(); @@ -4307,19 +4584,15 @@ static void rtl8169_reset_task(struct work_struct *work) rtl8169_wait_for_quiescence(dev); - rtl8169_rx_interrupt(dev, tp, tp->mmio_addr, ~(u32)0); + for (i = 0; i < NUM_RX_DESC; i++) + rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz); + rtl8169_tx_clear(tp); - if (tp->dirty_rx == tp->cur_rx) { - rtl8169_init_ring_indexes(tp); - rtl_hw_start(dev); - netif_wake_queue(dev); - rtl8169_check_link_status(dev, tp, tp->mmio_addr); - } else { - if (net_ratelimit()) - netif_emerg(tp, intr, dev, "Rx buffers shortage\n"); - rtl8169_schedule_work(dev, rtl8169_reset_task); - } + rtl8169_init_ring_indexes(tp); + rtl_hw_start(dev); + netif_wake_queue(dev); + rtl8169_check_link_status(dev, tp, tp->mmio_addr); out_unlock: rtnl_unlock(); @@ -4336,7 +4609,7 @@ static void rtl8169_tx_timeout(struct net_device *dev) } static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, - u32 opts1) + u32 *opts) { struct skb_shared_info *info = skb_shinfo(skb); unsigned int cur_frag, entry; @@ -4363,10 +4636,12 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, goto err_out; } - /* anti gcc 2.95.3 bugware (sic) */ - status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); + /* Anti gcc 2.95.3 bugware (sic) */ + status = opts[0] | len | + (RingEnd * !((entry + 1) % NUM_TX_DESC)); txd->opts1 = cpu_to_le32(status); + txd->opts2 = cpu_to_le32(opts[1]); txd->addr = cpu_to_le64(mapping); tp->tx_skb[entry].len = len; @@ -4384,24 +4659,26 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, return -EIO; } -static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev) +static inline void rtl8169_tso_csum(struct rtl8169_private *tp, + struct sk_buff *skb, u32 *opts) { - if (dev->features & NETIF_F_TSO) { - u32 mss = skb_shinfo(skb)->gso_size; + const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version; + u32 mss = skb_shinfo(skb)->gso_size; + int offset = info->opts_offset; - if (mss) - return LargeSend | ((mss & MSSMask) << MSSShift); - } - if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (mss) { + opts[0] |= TD_LSO; + opts[offset] |= min(mss, TD_MSS_MAX) << info->mss_shift; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { const struct iphdr *ip = ip_hdr(skb); if (ip->protocol == IPPROTO_TCP) - return IPCS | TCPCS; + opts[offset] |= info->checksum.tcp; else if (ip->protocol == IPPROTO_UDP) - return IPCS | UDPCS; - WARN_ON(1); /* we need a WARN() */ + opts[offset] |= info->checksum.udp; + else + WARN_ON_ONCE(1); } - return 0; } static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, @@ -4414,7 +4691,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, struct device *d = &tp->pci_dev->dev; dma_addr_t mapping; u32 status, len; - u32 opts1; + u32 opts[2]; int frags; if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) { @@ -4435,31 +4712,35 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, tp->tx_skb[entry].len = len; txd->addr = cpu_to_le64(mapping); - txd->opts2 = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb)); - opts1 = DescOwn | rtl8169_tso_csum(skb, dev); + opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb)); + opts[0] = DescOwn; - frags = rtl8169_xmit_frags(tp, skb, opts1); + rtl8169_tso_csum(tp, skb, opts); + + frags = rtl8169_xmit_frags(tp, skb, opts); if (frags < 0) goto err_dma_1; else if (frags) - opts1 |= FirstFrag; + opts[0] |= FirstFrag; else { - opts1 |= FirstFrag | LastFrag; + opts[0] |= FirstFrag | LastFrag; tp->tx_skb[entry].skb = skb; } + txd->opts2 = cpu_to_le32(opts[1]); + wmb(); - /* anti gcc 2.95.3 bugware (sic) */ - status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); + /* Anti gcc 2.95.3 bugware (sic) */ + status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); txd->opts1 = cpu_to_le32(status); tp->cur_tx += frags + 1; wmb(); - RTL_W8(TxPoll, NPQ); /* set polling bit */ + RTL_W8(TxPoll, NPQ); if (TX_BUFFS_AVAIL(tp) < MAX_SKB_FRAGS) { netif_stop_queue(dev); @@ -4616,20 +4897,12 @@ static struct sk_buff *rtl8169_try_rx_copy(void *data, return skb; } -/* - * Warning : rtl8169_rx_interrupt() might be called : - * 1) from NAPI (softirq) context - * (polling = 1 : we should call netif_receive_skb()) - * 2) from process context (rtl8169_reset_task()) - * (polling = 0 : we must call netif_rx() instead) - */ static int rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void __iomem *ioaddr, u32 budget) { unsigned int cur_rx, rx_left; unsigned int count; - int polling = (budget != ~(u32)0) ? 1 : 0; cur_rx = tp->cur_rx; rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; @@ -4689,10 +4962,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev, rtl8169_rx_vlan_tag(desc, skb); - if (likely(polling)) - napi_gro_receive(&tp->napi, skb); - else - netif_rx(skb); + napi_gro_receive(&tp->napi, skb); dev->stats.rx_bytes += pkt_size; dev->stats.rx_packets++; @@ -4755,6 +5025,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) case RTL_GIGA_MAC_VER_24: case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: /* Experimental science. Pktgen proof. */ case RTL_GIGA_MAC_VER_12: case RTL_GIGA_MAC_VER_25: @@ -4847,7 +5118,7 @@ static void rtl8169_down(struct net_device *dev) struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; - rtl8169_delete_timer(dev); + del_timer_sync(&tp->timer); netif_stop_queue(dev); @@ -4884,7 +5155,7 @@ static int rtl8169_close(struct net_device *dev) pm_runtime_get_sync(&pdev->dev); - /* update counters before going down */ + /* Update counters before going down */ rtl8169_update_counters(dev); rtl8169_down(dev); @@ -4939,7 +5210,7 @@ static void rtl_set_rx_mode(struct net_device *dev) spin_lock_irqsave(&tp->lock, flags); tmp = rtl8169_rx_config | rx_mode | - (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); + (RTL_R32(RxConfig) & RTL_RX_CONFIG_MASK); if (tp->mac_version > RTL_GIGA_MAC_VER_06) { u32 data = mc_filter[0]; @@ -5077,15 +5348,15 @@ static int rtl8169_runtime_idle(struct device *device) } static const struct dev_pm_ops rtl8169_pm_ops = { - .suspend = rtl8169_suspend, - .resume = rtl8169_resume, - .freeze = rtl8169_suspend, - .thaw = rtl8169_resume, - .poweroff = rtl8169_suspend, - .restore = rtl8169_resume, - .runtime_suspend = rtl8169_runtime_suspend, - .runtime_resume = rtl8169_runtime_resume, - .runtime_idle = rtl8169_runtime_idle, + .suspend = rtl8169_suspend, + .resume = rtl8169_resume, + .freeze = rtl8169_suspend, + .thaw = rtl8169_resume, + .poweroff = rtl8169_suspend, + .restore = rtl8169_resume, + .runtime_suspend = rtl8169_runtime_suspend, + .runtime_resume = rtl8169_runtime_resume, + .runtime_idle = rtl8169_runtime_idle, }; #define RTL8169_PM_OPS (&rtl8169_pm_ops) @@ -5104,7 +5375,7 @@ static void rtl_shutdown(struct pci_dev *pdev) rtl8169_net_suspend(dev); - /* restore original MAC address */ + /* Restore original MAC address */ rtl_rar_set(tp, dev->perm_addr); spin_lock_irq(&tp->lock); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 337bdcd5abc9..89cfee7e8643 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -2244,13 +2244,12 @@ static int verify_xena_quiescence(struct s2io_nic *sp) static void fix_mac_address(struct s2io_nic *sp) { struct XENA_dev_config __iomem *bar0 = sp->bar0; - u64 val64; int i = 0; while (fix_mac[i] != END_SIGN) { writeq(fix_mac[i++], &bar0->gpio_control); udelay(10); - val64 = readq(&bar0->gpio_control); + (void) readq(&bar0->gpio_control); } } @@ -2727,7 +2726,6 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) int j; struct sk_buff *skb; struct RxD_t *rxdp; - struct buffAdd *ba; struct RxD1 *rxdp1; struct RxD3 *rxdp3; struct mac_info *mac_control = &sp->mac_control; @@ -2751,7 +2749,6 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) memset(rxdp, 0, sizeof(struct RxD1)); } else if (sp->rxd_mode == RXD_MODE_3B) { rxdp3 = (struct RxD3 *)rxdp; - ba = &mac_control->rings[ring_no].ba[blk][j]; pci_unmap_single(sp->pdev, (dma_addr_t)rxdp3->Buffer0_ptr, BUF0_LEN, @@ -5383,7 +5380,7 @@ static int s2io_ethtool_sset(struct net_device *dev, { struct s2io_nic *sp = netdev_priv(dev); if ((info->autoneg == AUTONEG_ENABLE) || - (info->speed != SPEED_10000) || + (ethtool_cmd_speed(info) != SPEED_10000) || (info->duplex != DUPLEX_FULL)) return -EINVAL; else { @@ -5417,10 +5414,10 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) info->transceiver = XCVR_EXTERNAL; if (netif_carrier_ok(sp->dev)) { - info->speed = 10000; + ethtool_cmd_speed_set(info, SPEED_10000); info->duplex = DUPLEX_FULL; } else { - info->speed = -1; + ethtool_cmd_speed_set(info, -1); info->duplex = -1; } @@ -5484,83 +5481,79 @@ static void s2io_ethtool_gregs(struct net_device *dev, } } -/** - * s2io_phy_id - timer function that alternates adapter LED. - * @data : address of the private member of the device structure, which - * is a pointer to the s2io_nic structure, provided as an u32. - * Description: This is actually the timer function that alternates the - * adapter LED bit of the adapter control bit to set/reset every time on - * invocation. The timer is set for 1/2 a second, hence tha NIC blinks - * once every second. +/* + * s2io_set_led - control NIC led */ -static void s2io_phy_id(unsigned long data) +static void s2io_set_led(struct s2io_nic *sp, bool on) { - struct s2io_nic *sp = (struct s2io_nic *)data; struct XENA_dev_config __iomem *bar0 = sp->bar0; - u64 val64 = 0; - u16 subid; + u16 subid = sp->pdev->subsystem_device; + u64 val64; - subid = sp->pdev->subsystem_device; if ((sp->device_type == XFRAME_II_DEVICE) || ((subid & 0xFF) >= 0x07)) { val64 = readq(&bar0->gpio_control); - val64 ^= GPIO_CTRL_GPIO_0; + if (on) + val64 |= GPIO_CTRL_GPIO_0; + else + val64 &= ~GPIO_CTRL_GPIO_0; + writeq(val64, &bar0->gpio_control); } else { val64 = readq(&bar0->adapter_control); - val64 ^= ADAPTER_LED_ON; + if (on) + val64 |= ADAPTER_LED_ON; + else + val64 &= ~ADAPTER_LED_ON; + writeq(val64, &bar0->adapter_control); } - mod_timer(&sp->id_timer, jiffies + HZ / 2); } /** - * s2io_ethtool_idnic - To physically identify the nic on the system. - * @sp : private member of the device structure, which is a pointer to the - * s2io_nic structure. - * @id : pointer to the structure with identification parameters given by - * ethtool. + * s2io_ethtool_set_led - To physically identify the nic on the system. + * @dev : network device + * @state: led setting + * * Description: Used to physically identify the NIC on the system. * The Link LED will blink for a time specified by the user for * identification. * NOTE: The Link has to be Up to be able to blink the LED. Hence * identification is possible only if it's link is up. - * Return value: - * int , returns 0 on success */ -static int s2io_ethtool_idnic(struct net_device *dev, u32 data) +static int s2io_ethtool_set_led(struct net_device *dev, + enum ethtool_phys_id_state state) { - u64 val64 = 0, last_gpio_ctrl_val; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; - u16 subid; + u16 subid = sp->pdev->subsystem_device; - subid = sp->pdev->subsystem_device; - last_gpio_ctrl_val = readq(&bar0->gpio_control); if ((sp->device_type == XFRAME_I_DEVICE) && ((subid & 0xFF) < 0x07)) { - val64 = readq(&bar0->adapter_control); + u64 val64 = readq(&bar0->adapter_control); if (!(val64 & ADAPTER_CNTL_EN)) { pr_err("Adapter Link down, cannot blink LED\n"); - return -EFAULT; + return -EAGAIN; } } - if (sp->id_timer.function == NULL) { - init_timer(&sp->id_timer); - sp->id_timer.function = s2io_phy_id; - sp->id_timer.data = (unsigned long)sp; - } - mod_timer(&sp->id_timer, jiffies); - if (data) - msleep_interruptible(data * HZ); - else - msleep_interruptible(MAX_FLICKER_TIME); - del_timer_sync(&sp->id_timer); - if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) { - writeq(last_gpio_ctrl_val, &bar0->gpio_control); - last_gpio_ctrl_val = readq(&bar0->gpio_control); + switch (state) { + case ETHTOOL_ID_ACTIVE: + sp->adapt_ctrl_org = readq(&bar0->gpio_control); + return 1; /* cycle on/off once per second */ + + case ETHTOOL_ID_ON: + s2io_set_led(sp, true); + break; + + case ETHTOOL_ID_OFF: + s2io_set_led(sp, false); + break; + + case ETHTOOL_ID_INACTIVE: + if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) + writeq(sp->adapt_ctrl_org, &bar0->gpio_control); } return 0; @@ -6625,25 +6618,6 @@ static int s2io_ethtool_get_regs_len(struct net_device *dev) } -static u32 s2io_ethtool_get_rx_csum(struct net_device *dev) -{ - struct s2io_nic *sp = netdev_priv(dev); - - return sp->rx_csum; -} - -static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) -{ - struct s2io_nic *sp = netdev_priv(dev); - - if (data) - sp->rx_csum = 1; - else - sp->rx_csum = 0; - - return 0; -} - static int s2io_get_eeprom_len(struct net_device *dev) { return XENA_EEPROM_SPACE; @@ -6695,61 +6669,27 @@ static void s2io_ethtool_get_strings(struct net_device *dev, } } -static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_IP_CSUM; - else - dev->features &= ~NETIF_F_IP_CSUM; - - return 0; -} - -static u32 s2io_ethtool_op_get_tso(struct net_device *dev) -{ - return (dev->features & NETIF_F_TSO) != 0; -} - -static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - -static int s2io_ethtool_set_flags(struct net_device *dev, u32 data) +static int s2io_set_features(struct net_device *dev, u32 features) { struct s2io_nic *sp = netdev_priv(dev); - int rc = 0; - int changed = 0; - - if (ethtool_invalid_flags(dev, data, ETH_FLAG_LRO)) - return -EINVAL; - - if (data & ETH_FLAG_LRO) { - if (!(dev->features & NETIF_F_LRO)) { - dev->features |= NETIF_F_LRO; - changed = 1; - } - } else if (dev->features & NETIF_F_LRO) { - dev->features &= ~NETIF_F_LRO; - changed = 1; - } + u32 changed = (features ^ dev->features) & NETIF_F_LRO; if (changed && netif_running(dev)) { + int rc; + s2io_stop_all_tx_queue(sp); s2io_card_down(sp); + dev->features = features; rc = s2io_card_up(sp); if (rc) s2io_reset(sp); else s2io_start_all_tx_queue(sp); + + return rc ? rc : 1; } - return rc; + return 0; } static const struct ethtool_ops netdev_ethtool_ops = { @@ -6765,18 +6705,9 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_ringparam = s2io_ethtool_gringparam, .get_pauseparam = s2io_ethtool_getpause_data, .set_pauseparam = s2io_ethtool_setpause_data, - .get_rx_csum = s2io_ethtool_get_rx_csum, - .set_rx_csum = s2io_ethtool_set_rx_csum, - .set_tx_csum = s2io_ethtool_op_set_tx_csum, - .set_flags = s2io_ethtool_set_flags, - .get_flags = ethtool_op_get_flags, - .set_sg = ethtool_op_set_sg, - .get_tso = s2io_ethtool_op_get_tso, - .set_tso = s2io_ethtool_op_set_tso, - .set_ufo = ethtool_op_set_ufo, .self_test = s2io_ethtool_test, .get_strings = s2io_ethtool_get_strings, - .phys_id = s2io_ethtool_idnic, + .set_phys_id = s2io_ethtool_set_led, .get_ethtool_stats = s2io_get_ethtool_stats, .get_sset_count = s2io_get_sset_count, }; @@ -7545,7 +7476,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!ring_data->lro) || (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) && - (sp->rx_csum)) { + (dev->features & NETIF_F_RXCSUM)) { l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) { @@ -7806,6 +7737,7 @@ static const struct net_device_ops s2io_netdev_ops = { .ndo_do_ioctl = s2io_ioctl, .ndo_set_mac_address = s2io_set_mac_addr, .ndo_change_mtu = s2io_change_mtu, + .ndo_set_features = s2io_set_features, .ndo_vlan_rx_register = s2io_vlan_rx_register, .ndo_vlan_rx_kill_vid = s2io_vlan_rx_kill_vid, .ndo_tx_timeout = s2io_tx_watchdog, @@ -8047,17 +7979,18 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Driver entry points */ dev->netdev_ops = &s2io_netdev_ops; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->features |= NETIF_F_LRO; - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_RXCSUM | NETIF_F_LRO; + dev->features |= dev->hw_features | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + if (sp->device_type & XFRAME_II_DEVICE) { + dev->hw_features |= NETIF_F_UFO; + if (ufo) + dev->features |= NETIF_F_UFO; + } if (sp->high_dma_flag == true) dev->features |= NETIF_F_HIGHDMA; - dev->features |= NETIF_F_TSO; - dev->features |= NETIF_F_TSO6; - if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) { - dev->features |= NETIF_F_UFO; - dev->features |= NETIF_F_HW_CSUM; - } dev->watchdog_timeo = WATCH_DOG_TIMEOUT; INIT_WORK(&sp->rst_timer_task, s2io_restart_nic); INIT_WORK(&sp->set_link_task, s2io_set_link); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 2d144979f6f8..800b3a44e653 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -893,9 +893,6 @@ struct s2io_nic { u16 all_multi_pos; u16 promisc_flg; - /* Id timer, used to blink NIC to physically identify NIC. */ - struct timer_list id_timer; - /* Restart timer, used to restart NIC if the device is stuck and * a schedule task that will set the correct Link state once the * NIC's PHY has stabilized after a state change. @@ -1005,18 +1002,16 @@ static inline void writeq(u64 val, void __iomem *addr) #define LF 2 static inline void SPECIAL_REG_WRITE(u64 val, void __iomem *addr, int order) { - u32 ret; - if (order == LF) { writel((u32) (val), addr); - ret = readl(addr); + (void) readl(addr); writel((u32) (val >> 32), (addr + 4)); - ret = readl(addr + 4); + (void) readl(addr + 4); } else { writel((u32) (val >> 32), (addr + 4)); - ret = readl(addr + 4); + (void) readl(addr + 4); writel((u32) (val), addr); - ret = readl(addr); + (void) readl(addr); } } diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index 76290a8c3c14..fa74314ef789 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -1173,7 +1173,8 @@ static int sc92031_ethtool_get_settings(struct net_device *dev, if (phy_ctrl & PhyCtrlAne) cmd->advertising |= ADVERTISED_Autoneg; - cmd->speed = (output_status & 0x2) ? SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(cmd, + (output_status & 0x2) ? SPEED_100 : SPEED_10); cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF; cmd->port = PORT_MII; cmd->phy_address = phy_address; @@ -1188,10 +1189,11 @@ static int sc92031_ethtool_set_settings(struct net_device *dev, { struct sc92031_priv *priv = netdev_priv(dev); void __iomem *port_base = priv->port_base; + u32 speed = ethtool_cmd_speed(cmd); u32 phy_ctrl; u32 old_phy_ctrl; - if (!(cmd->speed == SPEED_10 || cmd->speed == SPEED_100)) + if (!(speed == SPEED_10 || speed == SPEED_100)) return -EINVAL; if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL)) return -EINVAL; @@ -1229,7 +1231,7 @@ static int sc92031_ethtool_set_settings(struct net_device *dev, // FIXME: Whole branch guessed phy_ctrl = 0; - if (cmd->speed == SPEED_10) + if (speed == SPEED_10) phy_ctrl |= PhyCtrlSpd10; else /* cmd->speed == SPEED_100 */ phy_ctrl |= PhyCtrlSpd100; diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index d890679e4c4d..c914729f9554 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -328,7 +328,8 @@ static int efx_poll(struct napi_struct *napi, int budget) * processing to finish, then directly poll (and ack ) the eventq. * Finally reenable NAPI and interrupts. * - * Since we are touching interrupts the caller should hold the suspend lock + * This is for use only during a loopback self-test. It must not + * deliver any packets up the stack as this can result in deadlock. */ void efx_process_channel_now(struct efx_channel *channel) { @@ -336,6 +337,7 @@ void efx_process_channel_now(struct efx_channel *channel) BUG_ON(channel->channel >= efx->n_channels); BUG_ON(!channel->enabled); + BUG_ON(!efx->loopback_selftest); /* Disable interrupts and wait for ISRs to complete */ efx_nic_disable_interrupts(efx); @@ -796,11 +798,6 @@ void efx_link_status_changed(struct efx_nic *efx) if (!netif_running(efx->net_dev)) return; - if (efx->port_inhibited) { - netif_carrier_off(efx->net_dev); - return; - } - if (link_state->up != netif_carrier_ok(efx->net_dev)) { efx->n_link_state_changes++; @@ -836,7 +833,7 @@ void efx_link_set_advertising(struct efx_nic *efx, u32 advertising) } } -void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type wanted_fc) +void efx_link_set_wanted_fc(struct efx_nic *efx, u8 wanted_fc) { efx->wanted_fc = wanted_fc; if (efx->link_advertising) { @@ -1317,8 +1314,20 @@ static void efx_remove_interrupts(struct efx_nic *efx) static void efx_set_channels(struct efx_nic *efx) { + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + efx->tx_channel_offset = separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0; + + /* We need to adjust the TX queue numbers if we have separate + * RX-only and TX-only channels. + */ + efx_for_each_channel(channel, efx) { + efx_for_each_channel_tx_queue(tx_queue, channel) + tx_queue->queue -= (efx->tx_channel_offset * + EFX_TXQ_TYPES); + } } static int efx_probe_nic(struct efx_nic *efx) @@ -1436,7 +1445,7 @@ static void efx_start_all(struct efx_nic *efx) * restart the transmit interface early so the watchdog timer stops */ efx_start_port(efx); - if (efx_dev_registered(efx)) + if (efx_dev_registered(efx) && netif_device_present(efx->net_dev)) netif_tx_wake_all_queues(efx->net_dev); efx_for_each_channel(channel, efx) @@ -1874,6 +1883,17 @@ static void efx_set_multicast_list(struct net_device *net_dev) /* Otherwise efx_start_port() will do this */ } +static int efx_set_features(struct net_device *net_dev, u32 data) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + /* If disabling RX n-tuple filtering, clear existing filters */ + if (net_dev->features & ~data & NETIF_F_NTUPLE) + efx_filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL); + + return 0; +} + static const struct net_device_ops efx_netdev_ops = { .ndo_open = efx_net_open, .ndo_stop = efx_net_stop, @@ -1885,6 +1905,7 @@ static const struct net_device_ops efx_netdev_ops = { .ndo_change_mtu = efx_change_mtu, .ndo_set_mac_address = efx_set_mac_address, .ndo_set_multicast_list = efx_set_multicast_list, + .ndo_set_features = efx_set_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = efx_netpoll, #endif @@ -2088,6 +2109,7 @@ int efx_reset(struct efx_nic *efx, enum reset_type method) netif_info(efx, drv, efx->net_dev, "resetting (%s)\n", RESET_TYPE(method)); + netif_device_detach(efx->net_dev); efx_reset_down(efx, method); rc = efx->type->reset(efx, method); @@ -2121,6 +2143,7 @@ int efx_reset(struct efx_nic *efx, enum reset_type method) efx->state = STATE_DISABLED; } else { netif_dbg(efx, drv, efx->net_dev, "reset complete\n"); + netif_device_attach(efx->net_dev); } return rc; } @@ -2233,7 +2256,7 @@ static bool efx_port_dummy_op_poll(struct efx_nic *efx) return false; } -static struct efx_phy_operations efx_dummy_phy_operations = { +static const struct efx_phy_operations efx_dummy_phy_operations = { .init = efx_port_dummy_op_int, .reconfigure = efx_port_dummy_op_int, .poll = efx_port_dummy_op_poll, @@ -2249,7 +2272,7 @@ static struct efx_phy_operations efx_dummy_phy_operations = { /* This zeroes out and then fills in the invariants in a struct * efx_nic (including all sub-structures). */ -static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, +static int efx_init_struct(struct efx_nic *efx, const struct efx_nic_type *type, struct pci_dev *pci_dev, struct net_device *net_dev) { int i; @@ -2269,7 +2292,6 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name)); efx->net_dev = net_dev; - efx->rx_checksum_enabled = true; spin_lock_init(&efx->stats_lock); mutex_init(&efx->mac_lock); efx->mac_op = type->default_mac_ops; @@ -2440,7 +2462,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) static int __devinit efx_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *entry) { - struct efx_nic_type *type = (struct efx_nic_type *) entry->driver_data; + const struct efx_nic_type *type = (const struct efx_nic_type *) entry->driver_data; struct net_device *net_dev; struct efx_nic *efx; int i, rc; @@ -2452,12 +2474,15 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, return -ENOMEM; net_dev->features |= (type->offload_features | NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_TSO | - NETIF_F_GRO); + NETIF_F_RXCSUM); if (type->offload_features & NETIF_F_V6_CSUM) net_dev->features |= NETIF_F_TSO6; /* Mask for features that also apply to VLAN devices */ net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG | - NETIF_F_HIGHDMA | NETIF_F_TSO); + NETIF_F_HIGHDMA | NETIF_F_ALL_TSO | + NETIF_F_RXCSUM); + /* All offloads can be toggled */ + net_dev->hw_features = net_dev->features & ~NETIF_F_HIGHDMA; efx = netdev_priv(net_dev); pci_set_drvdata(pci_dev, efx); SET_NETDEV_DEV(net_dev, &pci_dev->dev); diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 3d83a1f74fef..b0d1209ea18d 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -142,6 +142,6 @@ static inline void efx_schedule_channel(struct efx_channel *channel) extern void efx_link_status_changed(struct efx_nic *efx); extern void efx_link_set_advertising(struct efx_nic *efx, u32); -extern void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type); +extern void efx_link_set_wanted_fc(struct efx_nic *efx, u8); #endif /* EFX_EFX_H */ diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 807178ef65ad..d229027dc363 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -178,19 +178,27 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { */ /* Identify device by flashing LEDs */ -static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count) +static int efx_ethtool_phys_id(struct net_device *net_dev, + enum ethtool_phys_id_state state) { struct efx_nic *efx = netdev_priv(net_dev); + enum efx_led_mode mode = EFX_LED_DEFAULT; - do { - efx->type->set_id_led(efx, EFX_LED_ON); - schedule_timeout_interruptible(HZ / 2); + switch (state) { + case ETHTOOL_ID_ON: + mode = EFX_LED_ON; + break; + case ETHTOOL_ID_OFF: + mode = EFX_LED_OFF; + break; + case ETHTOOL_ID_INACTIVE: + mode = EFX_LED_DEFAULT; + break; + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ + } - efx->type->set_id_led(efx, EFX_LED_OFF); - schedule_timeout_interruptible(HZ / 2); - } while (!signal_pending(current) && --count != 0); - - efx->type->set_id_led(efx, EFX_LED_DEFAULT); + efx->type->set_id_led(efx, mode); return 0; } @@ -211,7 +219,7 @@ static int efx_ethtool_get_settings(struct net_device *net_dev, ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; if (LOOPBACK_INTERNAL(efx)) { - ecmd->speed = link_state->speed; + ethtool_cmd_speed_set(ecmd, link_state->speed); ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; } @@ -226,7 +234,8 @@ static int efx_ethtool_set_settings(struct net_device *net_dev, int rc; /* GMAC does not support 1000Mbps HD */ - if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) { + if ((ethtool_cmd_speed(ecmd) == SPEED_1000) && + (ecmd->duplex != DUPLEX_FULL)) { netif_dbg(efx, drv, efx->net_dev, "rejecting unsupported 1000Mbps HD setting\n"); return -EINVAL; @@ -518,72 +527,6 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, } } -static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable) -{ - struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev); - u32 features; - - features = NETIF_F_TSO; - if (efx->type->offload_features & NETIF_F_V6_CSUM) - features |= NETIF_F_TSO6; - - if (enable) - net_dev->features |= features; - else - net_dev->features &= ~features; - - return 0; -} - -static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable) -{ - struct efx_nic *efx = netdev_priv(net_dev); - u32 features = efx->type->offload_features & NETIF_F_ALL_CSUM; - - if (enable) - net_dev->features |= features; - else - net_dev->features &= ~features; - - return 0; -} - -static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable) -{ - struct efx_nic *efx = netdev_priv(net_dev); - - /* No way to stop the hardware doing the checks; we just - * ignore the result. - */ - efx->rx_checksum_enabled = !!enable; - - return 0; -} - -static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev) -{ - struct efx_nic *efx = netdev_priv(net_dev); - - return efx->rx_checksum_enabled; -} - -static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data) -{ - struct efx_nic *efx = netdev_priv(net_dev); - u32 supported = (efx->type->offload_features & - (ETH_FLAG_RXHASH | ETH_FLAG_NTUPLE)); - int rc; - - rc = ethtool_op_set_flags(net_dev, data, supported); - if (rc) - return rc; - - if (!(data & ETH_FLAG_NTUPLE)) - efx_filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL); - - return 0; -} - static void efx_ethtool_self_test(struct net_device *net_dev, struct ethtool_test *test, u64 *data) { @@ -755,7 +698,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *pause) { struct efx_nic *efx = netdev_priv(net_dev); - enum efx_fc_type wanted_fc, old_fc; + u8 wanted_fc, old_fc; u32 old_adv; bool reset; int rc = 0; @@ -1012,8 +955,9 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev, if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_CLEAR) return efx_filter_remove_filter(efx, &filter); - else - return efx_filter_insert_filter(efx, &filter, true); + + rc = efx_filter_insert_filter(efx, &filter, true); + return rc < 0 ? rc : 0; } static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, @@ -1070,22 +1014,10 @@ const struct ethtool_ops efx_ethtool_ops = { .set_ringparam = efx_ethtool_set_ringparam, .get_pauseparam = efx_ethtool_get_pauseparam, .set_pauseparam = efx_ethtool_set_pauseparam, - .get_rx_csum = efx_ethtool_get_rx_csum, - .set_rx_csum = efx_ethtool_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - /* Need to enable/disable IPv6 too */ - .set_tx_csum = efx_ethtool_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - /* Need to enable/disable TSO-IPv6 too */ - .set_tso = efx_ethtool_set_tso, - .get_flags = ethtool_op_get_flags, - .set_flags = efx_ethtool_set_flags, .get_sset_count = efx_ethtool_get_sset_count, .self_test = efx_ethtool_self_test, .get_strings = efx_ethtool_get_strings, - .phys_id = efx_ethtool_phys_id, + .set_phys_id = efx_ethtool_phys_id, .get_ethtool_stats = efx_ethtool_get_stats, .get_wol = efx_ethtool_get_wol, .set_wol = efx_ethtool_set_wol, diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index d96b23769bd1..60176e873d62 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1703,7 +1703,7 @@ static int falcon_set_wol(struct efx_nic *efx, u32 type) ************************************************************************** */ -struct efx_nic_type falcon_a1_nic_type = { +const struct efx_nic_type falcon_a1_nic_type = { .probe = falcon_probe_nic, .remove = falcon_remove_nic, .init = falcon_init_nic, @@ -1744,7 +1744,7 @@ struct efx_nic_type falcon_a1_nic_type = { .reset_world_flags = ETH_RESET_IRQ, }; -struct efx_nic_type falcon_b0_nic_type = { +const struct efx_nic_type falcon_b0_nic_type = { .probe = falcon_probe_nic, .remove = falcon_remove_nic, .init = falcon_init_nic, diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 2c9ee5db3bf7..9516452c079c 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -362,7 +362,7 @@ void falcon_poll_xmac(struct efx_nic *efx) falcon_ack_status_intr(efx); } -struct efx_mac_operations falcon_xmac_operations = { +const struct efx_mac_operations falcon_xmac_operations = { .reconfigure = falcon_reconfigure_xmac, .update_stats = falcon_update_stats_xmac, .check_fault = falcon_xmac_check_fault, diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h index d9d8c2ef1074..cc978803d484 100644 --- a/drivers/net/sfc/io.h +++ b/drivers/net/sfc/io.h @@ -152,6 +152,7 @@ static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value, spin_lock_irqsave(&efx->biu_lock, flags); value->u32[0] = _efx_readd(efx, reg + 0); + rmb(); value->u32[1] = _efx_readd(efx, reg + 4); value->u32[2] = _efx_readd(efx, reg + 8); value->u32[3] = _efx_readd(efx, reg + 12); @@ -174,6 +175,7 @@ static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase, value->u64[0] = (__force __le64)__raw_readq(membase + addr); #else value->u32[0] = (__force __le32)__raw_readl(membase + addr); + rmb(); value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4); #endif spin_unlock_irqrestore(&efx->biu_lock, flags); diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h index 6886cdf87c12..d6a255d0856b 100644 --- a/drivers/net/sfc/mac.h +++ b/drivers/net/sfc/mac.h @@ -13,8 +13,8 @@ #include "net_driver.h" -extern struct efx_mac_operations falcon_xmac_operations; -extern struct efx_mac_operations efx_mcdi_mac_operations; +extern const struct efx_mac_operations falcon_xmac_operations; +extern const struct efx_mac_operations efx_mcdi_mac_operations; extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, u32 dma_len, int enable, int clear); diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index d98479030ef2..3dd45ed61f0a 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -50,6 +50,20 @@ static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) return &nic_data->mcdi; } +static inline void +efx_mcdi_readd(struct efx_nic *efx, efx_dword_t *value, unsigned reg) +{ + struct siena_nic_data *nic_data = efx->nic_data; + value->u32[0] = (__force __le32)__raw_readl(nic_data->mcdi_smem + reg); +} + +static inline void +efx_mcdi_writed(struct efx_nic *efx, const efx_dword_t *value, unsigned reg) +{ + struct siena_nic_data *nic_data = efx->nic_data; + __raw_writel((__force u32)value->u32[0], nic_data->mcdi_smem + reg); +} + void efx_mcdi_init(struct efx_nic *efx) { struct efx_mcdi_iface *mcdi; @@ -70,8 +84,8 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, const u8 *inbuf, size_t inlen) { struct efx_mcdi_iface *mcdi = efx_mcdi(efx); - unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); - unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); + unsigned pdu = MCDI_PDU(efx); + unsigned doorbell = MCDI_DOORBELL(efx); unsigned int i; efx_dword_t hdr; u32 xflags, seqno; @@ -92,30 +106,28 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, MCDI_HEADER_SEQ, seqno, MCDI_HEADER_XFLAGS, xflags); - efx_writed(efx, &hdr, pdu); + efx_mcdi_writed(efx, &hdr, pdu); - for (i = 0; i < inlen; i += 4) { - _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i); - /* use wmb() within loop to inhibit write combining */ - wmb(); - } + for (i = 0; i < inlen; i += 4) + efx_mcdi_writed(efx, (const efx_dword_t *)(inbuf + i), + pdu + 4 + i); /* ring the doorbell with a distinctive value */ - _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); - wmb(); + EFX_POPULATE_DWORD_1(hdr, EFX_DWORD_0, 0x45789abc); + efx_mcdi_writed(efx, &hdr, doorbell); } static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen) { struct efx_mcdi_iface *mcdi = efx_mcdi(efx); - unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + unsigned int pdu = MCDI_PDU(efx); int i; BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); BUG_ON(outlen & 3 || outlen >= 0x100); for (i = 0; i < outlen; i += 4) - *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i); + efx_mcdi_readd(efx, (efx_dword_t *)(outbuf + i), pdu + 4 + i); } static int efx_mcdi_poll(struct efx_nic *efx) @@ -123,7 +135,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) struct efx_mcdi_iface *mcdi = efx_mcdi(efx); unsigned int time, finish; unsigned int respseq, respcmd, error; - unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + unsigned int pdu = MCDI_PDU(efx); unsigned int rc, spins; efx_dword_t reg; @@ -149,8 +161,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) time = get_seconds(); - rmb(); - efx_readd(efx, ®, pdu); + efx_mcdi_readd(efx, ®, pdu); /* All 1's indicates that shared memory is in reset (and is * not a valid header). Wait for it to come out reset before @@ -177,7 +188,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) respseq, mcdi->seqno); rc = EIO; } else if (error) { - efx_readd(efx, ®, pdu + 4); + efx_mcdi_readd(efx, ®, pdu + 4); switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) { #define TRANSLATE_ERROR(name) \ case MC_CMD_ERR_ ## name: \ @@ -211,21 +222,21 @@ static int efx_mcdi_poll(struct efx_nic *efx) /* Test and clear MC-rebooted flag for this port/function */ int efx_mcdi_poll_reboot(struct efx_nic *efx) { - unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx); + unsigned int addr = MCDI_REBOOT_FLAG(efx); efx_dword_t reg; uint32_t value; if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) return false; - efx_readd(efx, ®, addr); + efx_mcdi_readd(efx, ®, addr); value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); if (value == 0) return 0; EFX_ZERO_DWORD(reg); - efx_writed(efx, ®, addr); + efx_mcdi_writed(efx, ®, addr); if (value == MC_STATUS_DWORD_ASSERT) return -EINTR; diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c index 33f7294edb47..50c20777a564 100644 --- a/drivers/net/sfc/mcdi_mac.c +++ b/drivers/net/sfc/mcdi_mac.c @@ -138,7 +138,7 @@ static bool efx_mcdi_mac_check_fault(struct efx_nic *efx) } -struct efx_mac_operations efx_mcdi_mac_operations = { +const struct efx_mac_operations efx_mcdi_mac_operations = { .reconfigure = efx_mcdi_mac_reconfigure, .update_stats = efx_port_dummy_op_void, .check_fault = efx_mcdi_mac_check_fault, diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index 7e3c65b0c99f..6c63ab0710af 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -513,7 +513,7 @@ static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *e ecmd->supported = mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap); ecmd->advertising = efx->link_advertising; - ecmd->speed = efx->link_state.speed; + ethtool_cmd_speed_set(ecmd, efx->link_state.speed); ecmd->duplex = efx->link_state.fd; ecmd->port = mcdi_to_ethtool_media(phy_cfg->media); ecmd->phy_address = phy_cfg->port; @@ -545,7 +545,7 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec caps = (ethtool_to_mcdi_cap(ecmd->advertising) | 1 << MC_CMD_PHY_CAP_AN_LBN); } else if (ecmd->duplex) { - switch (ecmd->speed) { + switch (ethtool_cmd_speed(ecmd)) { case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break; case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break; case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break; @@ -553,7 +553,7 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec default: return -EINVAL; } } else { - switch (ecmd->speed) { + switch (ethtool_cmd_speed(ecmd)) { case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break; case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break; case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break; @@ -739,7 +739,7 @@ static const char *efx_mcdi_phy_test_name(struct efx_nic *efx, return NULL; } -struct efx_phy_operations efx_mcdi_phy_ops = { +const struct efx_phy_operations efx_mcdi_phy_ops = { .probe = efx_mcdi_phy_probe, .init = efx_port_dummy_op_int, .reconfigure = efx_mcdi_phy_reconfigure, diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 19e68c26d103..7ab385c8136d 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -232,12 +232,12 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx, */ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - struct ethtool_cmd prev; + struct ethtool_cmd prev = { .cmd = ETHTOOL_GSET }; efx->phy_op->get_settings(efx, &prev); if (ecmd->advertising == prev.advertising && - ecmd->speed == prev.speed && + ethtool_cmd_speed(ecmd) == ethtool_cmd_speed(&prev) && ecmd->duplex == prev.duplex && ecmd->port == prev.port && ecmd->autoneg == prev.autoneg) @@ -284,7 +284,7 @@ void efx_mdio_an_reconfigure(struct efx_nic *efx) efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); } -enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) +u8 efx_mdio_get_pause(struct efx_nic *efx) { BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX)); diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index df0703940c83..a97dbbd2de99 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -92,7 +92,7 @@ extern void efx_mdio_an_reconfigure(struct efx_nic *efx); /* Get pause parameters from AN if available (otherwise return * requested pause parameters) */ -enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx); +u8 efx_mdio_get_pause(struct efx_nic *efx); /* Wait for specified MMDs to exit reset within a timeout */ extern int efx_mdio_wait_reset_mmds(struct efx_nic *efx, diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 9ffa9a6b55a0..e8d5f03a89fe 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -330,7 +330,6 @@ enum efx_rx_alloc_method { * @eventq_mask: Event queue pointer mask * @eventq_read_ptr: Event queue read pointer * @last_eventq_read_ptr: Last event queue read pointer value. - * @magic_count: Event queue test event count * @irq_count: Number of IRQs since last adaptive moderation decision * @irq_mod_score: IRQ moderation score * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors @@ -360,7 +359,6 @@ struct efx_channel { unsigned int eventq_mask; unsigned int eventq_read_ptr; unsigned int last_eventq_read_ptr; - unsigned int magic_count; unsigned int irq_count; unsigned int irq_mod_score; @@ -451,11 +449,9 @@ enum nic_state { struct efx_nic; /* Pseudo bit-mask flow control field */ -enum efx_fc_type { - EFX_FC_RX = FLOW_CTRL_RX, - EFX_FC_TX = FLOW_CTRL_TX, - EFX_FC_AUTO = 4, -}; +#define EFX_FC_RX FLOW_CTRL_RX +#define EFX_FC_TX FLOW_CTRL_TX +#define EFX_FC_AUTO 4 /** * struct efx_link_state - Current state of the link @@ -467,7 +463,7 @@ enum efx_fc_type { struct efx_link_state { bool up; bool fd; - enum efx_fc_type fc; + u8 fc; unsigned int speed; }; @@ -672,16 +668,14 @@ struct efx_filter_state; * @mtd_list: List of MTDs attached to the NIC * @nic_data: Hardware dependent state * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, - * @port_inhibited, efx_monitor() and efx_reconfigure_port() + * efx_monitor() and efx_reconfigure_port() * @port_enabled: Port enabled indicator. * Serialises efx_stop_all(), efx_start_all(), efx_monitor() and * efx_mac_work() with kernel interfaces. Safe to read under any * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must * be held to modify it. - * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock * @port_initialized: Port initialized? * @net_dev: Operating system network device. Consider holding the rtnl lock - * @rx_checksum_enabled: RX checksumming enabled * @stats_buffer: DMA buffer for statistics * @mac_op: MAC interface * @phy_type: PHY type @@ -767,18 +761,16 @@ struct efx_nic { struct mutex mac_lock; struct work_struct mac_work; bool port_enabled; - bool port_inhibited; bool port_initialized; struct net_device *net_dev; - bool rx_checksum_enabled; struct efx_buffer stats_buffer; - struct efx_mac_operations *mac_op; + const struct efx_mac_operations *mac_op; unsigned int phy_type; - struct efx_phy_operations *phy_op; + const struct efx_phy_operations *phy_op; void *phy_data; struct mdio_if_info mdio; unsigned int mdio_bus; @@ -790,7 +782,7 @@ struct efx_nic { bool promiscuous; union efx_multicast_hash multicast_hash; - enum efx_fc_type wanted_fc; + u8 wanted_fc; atomic_t rx_reset; enum efx_loopback_mode loopback_mode; @@ -899,7 +891,7 @@ struct efx_nic_type { void (*resume_wol)(struct efx_nic *efx); int (*test_registers)(struct efx_nic *efx); int (*test_nvram)(struct efx_nic *efx); - struct efx_mac_operations *default_mac_ops; + const struct efx_mac_operations *default_mac_ops; int revision; unsigned int mem_map_size; diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index e8396614daf3..f2a2b947f860 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -84,7 +84,8 @@ static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value, static inline efx_qword_t *efx_event(struct efx_channel *channel, unsigned int index) { - return ((efx_qword_t *) (channel->eventq.addr)) + index; + return ((efx_qword_t *) (channel->eventq.addr)) + + (index & channel->eventq_mask); } /* See if an event is present @@ -673,7 +674,8 @@ void efx_nic_eventq_read_ack(struct efx_channel *channel) efx_dword_t reg; struct efx_nic *efx = channel->efx; - EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr); + EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, + channel->eventq_read_ptr & channel->eventq_mask); efx_writed_table(efx, ®, efx->type->evq_rptr_tbl_base, channel->channel); } @@ -850,7 +852,6 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) unsigned expected_ptr; bool rx_ev_pkt_ok, discard = false, checksummed; struct efx_rx_queue *rx_queue; - struct efx_nic *efx = channel->efx; /* Basic packet information */ rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT); @@ -873,9 +874,8 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) * UDP/IP, then we can rely on the hardware checksum. */ checksummed = - likely(efx->rx_checksum_enabled) && - (rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP || - rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP); + rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP || + rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP; } else { efx_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, &discard); checksummed = false; @@ -908,7 +908,7 @@ efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event) code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC); if (code == EFX_CHANNEL_MAGIC_TEST(channel)) - ++channel->magic_count; + ; /* ignore */ else if (code == EFX_CHANNEL_MAGIC_FILL(channel)) /* The queue must be empty, so we won't receive any rx * events, so efx_process_channel() won't refill the @@ -1015,8 +1015,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget) /* Clear this event by marking it all ones */ EFX_SET_QWORD(*p_event); - /* Increment read pointer */ - read_ptr = (read_ptr + 1) & channel->eventq_mask; + ++read_ptr; ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE); @@ -1060,6 +1059,13 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget) return spent; } +/* Check whether an event is present in the eventq at the current + * read pointer. Only useful for self-test. + */ +bool efx_nic_event_present(struct efx_channel *channel) +{ + return efx_event_present(efx_event(channel, channel->eventq_read_ptr)); +} /* Allocate buffer table entries for event queue */ int efx_nic_probe_eventq(struct efx_channel *channel) @@ -1165,7 +1171,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; unsigned int read_ptr = channel->eventq_read_ptr; - unsigned int end_ptr = (read_ptr - 1) & channel->eventq_mask; + unsigned int end_ptr = read_ptr + channel->eventq_mask - 1; do { efx_qword_t *event = efx_event(channel, read_ptr); @@ -1205,7 +1211,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) * it's ok to throw away every non-flush event */ EFX_SET_QWORD(*event); - read_ptr = (read_ptr + 1) & channel->eventq_mask; + ++read_ptr; } while (read_ptr != end_ptr); channel->eventq_read_ptr = read_ptr; @@ -1929,6 +1935,13 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf) size = min_t(size_t, table->step, 16); + if (table->offset >= efx->type->mem_map_size) { + /* No longer mapped; return dummy data */ + memcpy(buf, "\xde\xc0\xad\xde", 4); + buf += table->rows * size; + continue; + } + for (i = 0; i < table->rows; i++) { switch (table->step) { case 4: /* 32-bit register or SRAM */ diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index d9de1b647d41..4bd1f2839dfe 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -143,16 +143,18 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx) /** * struct siena_nic_data - Siena NIC state * @mcdi: Management-Controller-to-Driver Interface + * @mcdi_smem: MCDI shared memory mapping. The mapping is always uncacheable. * @wol_filter_id: Wake-on-LAN packet filter id */ struct siena_nic_data { struct efx_mcdi_iface mcdi; + void __iomem *mcdi_smem; int wol_filter_id; }; -extern struct efx_nic_type falcon_a1_nic_type; -extern struct efx_nic_type falcon_b0_nic_type; -extern struct efx_nic_type siena_a0_nic_type; +extern const struct efx_nic_type falcon_a1_nic_type; +extern const struct efx_nic_type falcon_b0_nic_type; +extern const struct efx_nic_type siena_a0_nic_type; /************************************************************************** * @@ -184,6 +186,7 @@ extern void efx_nic_fini_eventq(struct efx_channel *channel); extern void efx_nic_remove_eventq(struct efx_channel *channel); extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota); extern void efx_nic_eventq_read_ack(struct efx_channel *channel); +extern bool efx_nic_event_present(struct efx_channel *channel); /* MAC/PHY */ extern void falcon_drain_tx_fifo(struct efx_nic *efx); diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index b3b79472421e..11d148cd8441 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -13,14 +13,14 @@ /**************************************************************************** * 10Xpress (SFX7101) PHY */ -extern struct efx_phy_operations falcon_sfx7101_phy_ops; +extern const struct efx_phy_operations falcon_sfx7101_phy_ops; extern void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); /**************************************************************************** * AMCC/Quake QT202x PHYs */ -extern struct efx_phy_operations falcon_qt202x_phy_ops; +extern const struct efx_phy_operations falcon_qt202x_phy_ops; /* These PHYs provide various H/W control states for LEDs */ #define QUAKE_LED_LINK_INVAL (0) @@ -39,7 +39,7 @@ extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state); /**************************************************************************** * Transwitch CX4 retimer */ -extern struct efx_phy_operations falcon_txc_phy_ops; +extern const struct efx_phy_operations falcon_txc_phy_ops; #define TXC_GPIO_DIR_INPUT 0 #define TXC_GPIO_DIR_OUTPUT 1 @@ -50,7 +50,7 @@ extern void falcon_txc_set_gpio_val(struct efx_nic *efx, int pin, int val); /**************************************************************************** * Siena managed PHYs */ -extern struct efx_phy_operations efx_mcdi_phy_ops; +extern const struct efx_phy_operations efx_mcdi_phy_ops; extern int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, unsigned int prtad, unsigned int devad, diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 55f90924247e..7ad97e397406 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -449,7 +449,7 @@ static void qt202x_phy_remove(struct efx_nic *efx) efx->phy_data = NULL; } -struct efx_phy_operations falcon_qt202x_phy_ops = { +const struct efx_phy_operations falcon_qt202x_phy_ops = { .probe = qt202x_phy_probe, .init = qt202x_phy_init, .reconfigure = qt202x_phy_reconfigure, diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index c0fdb59030fb..b7dc891b4461 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -605,6 +605,9 @@ void __efx_rx_packet(struct efx_channel *channel, skb_record_rx_queue(skb, channel->channel); } + if (unlikely(!(efx->net_dev->features & NETIF_F_RXCSUM))) + checksummed = false; + if (likely(checksummed || rx_buf->is_page)) { efx_rx_packet_gro(channel, rx_buf, eh, checksummed); return; diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index a0f49b348d62..822f6c2a6a7c 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -131,8 +131,6 @@ static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) static int efx_test_interrupts(struct efx_nic *efx, struct efx_self_tests *tests) { - struct efx_channel *channel; - netif_dbg(efx, drv, efx->net_dev, "testing interrupts\n"); tests->interrupt = -1; @@ -140,15 +138,6 @@ static int efx_test_interrupts(struct efx_nic *efx, efx->last_irq_cpu = -1; smp_wmb(); - /* ACK each interrupting event queue. Receiving an interrupt due to - * traffic before a test event is raised is considered a pass */ - efx_for_each_channel(channel, efx) { - if (channel->work_pending) - efx_process_channel_now(channel); - if (efx->last_irq_cpu >= 0) - goto success; - } - efx_nic_generate_interrupt(efx); /* Wait for arrival of test interrupt. */ @@ -173,13 +162,13 @@ static int efx_test_eventq_irq(struct efx_channel *channel, struct efx_self_tests *tests) { struct efx_nic *efx = channel->efx; - unsigned int magic_count, count; + unsigned int read_ptr, count; tests->eventq_dma[channel->channel] = -1; tests->eventq_int[channel->channel] = -1; tests->eventq_poll[channel->channel] = -1; - magic_count = channel->magic_count; + read_ptr = channel->eventq_read_ptr; channel->efx->last_irq_cpu = -1; smp_wmb(); @@ -190,10 +179,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, do { schedule_timeout_uninterruptible(HZ / 100); - if (channel->work_pending) - efx_process_channel_now(channel); - - if (channel->magic_count != magic_count) + if (ACCESS_ONCE(channel->eventq_read_ptr) != read_ptr) goto eventq_ok; } while (++count < 2); @@ -211,8 +197,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, } /* Check to see if event was received even if interrupt wasn't */ - efx_process_channel_now(channel); - if (channel->magic_count != magic_count) { + if (efx_nic_event_present(channel)) { netif_err(efx, drv, efx->net_dev, "channel %d event was generated, but " "failed to trigger an interrupt\n", channel->channel); @@ -710,12 +695,12 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, /* Offline (i.e. disruptive) testing * This checks MAC and PHY loopback on the specified port. */ - /* force the carrier state off so the kernel doesn't transmit during - * the loopback test, and the watchdog timeout doesn't fire. Also put - * falcon into loopback for the register test. + /* Detach the device so the kernel doesn't transmit during the + * loopback test and the watchdog timeout doesn't fire. */ + netif_device_detach(efx->net_dev); + mutex_lock(&efx->mac_lock); - efx->port_inhibited = true; if (efx->loopback_modes) { /* We need the 312 clock from the PHY to test the XMAC * registers, so move into XGMII loopback if available */ @@ -765,11 +750,12 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, /* restore the PHY to the previous state */ mutex_lock(&efx->mac_lock); efx->phy_mode = phy_mode; - efx->port_inhibited = false; efx->loopback_mode = loopback_mode; __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); + netif_device_attach(efx->net_dev); + return rc_test; } diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index e4dd8986b1fe..fb4721f780ff 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -220,12 +220,26 @@ static int siena_probe_nic(struct efx_nic *efx) efx_reado(efx, ®, FR_AZ_CS_DEBUG); efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1; + /* Initialise MCDI */ + nic_data->mcdi_smem = ioremap_nocache(efx->membase_phys + + FR_CZ_MC_TREG_SMEM, + FR_CZ_MC_TREG_SMEM_STEP * + FR_CZ_MC_TREG_SMEM_ROWS); + if (!nic_data->mcdi_smem) { + netif_err(efx, probe, efx->net_dev, + "could not map MCDI at %llx+%x\n", + (unsigned long long)efx->membase_phys + + FR_CZ_MC_TREG_SMEM, + FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS); + rc = -ENOMEM; + goto fail1; + } efx_mcdi_init(efx); /* Recover from a failed assertion before probing */ rc = efx_mcdi_handle_assertion(efx); if (rc) - goto fail1; + goto fail2; /* Let the BMC know that the driver is now in charge of link and * filter settings. We must do this before we reset the NIC */ @@ -280,6 +294,7 @@ static int siena_probe_nic(struct efx_nic *efx) fail3: efx_mcdi_drv_attach(efx, false, NULL); fail2: + iounmap(nic_data->mcdi_smem); fail1: kfree(efx->nic_data); return rc; @@ -359,6 +374,8 @@ static int siena_init_nic(struct efx_nic *efx) static void siena_remove_nic(struct efx_nic *efx) { + struct siena_nic_data *nic_data = efx->nic_data; + efx_nic_free_buffer(efx, &efx->irq_status); siena_reset_hw(efx, RESET_TYPE_ALL); @@ -368,7 +385,8 @@ static void siena_remove_nic(struct efx_nic *efx) efx_mcdi_drv_attach(efx, false, NULL); /* Tear down the private nic state */ - kfree(efx->nic_data); + iounmap(nic_data->mcdi_smem); + kfree(nic_data); efx->nic_data = NULL; } @@ -581,7 +599,7 @@ static void siena_init_wol(struct efx_nic *efx) ************************************************************************** */ -struct efx_nic_type siena_a0_nic_type = { +const struct efx_nic_type siena_a0_nic_type = { .probe = siena_probe_nic, .remove = siena_remove_nic, .init = siena_init_nic, @@ -606,8 +624,7 @@ struct efx_nic_type siena_a0_nic_type = { .default_mac_ops = &efx_mcdi_mac_operations, .revision = EFX_REV_SIENA_A0, - .mem_map_size = (FR_CZ_MC_TREG_SMEM + - FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS), + .mem_map_size = FR_CZ_MC_TREG_SMEM, /* MC_TREG_SMEM mapped separately */ .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, .buf_tbl_base = FR_BZ_BUF_FULL_TBL, diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index efdceb35aaae..7b0fd89e7b85 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -460,7 +460,7 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) /* In loopback, the PHY automatically brings up the correct interface, * but doesn't advertise the correct speed. So override it */ if (LOOPBACK_EXTERNAL(efx)) - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); } static int tenxpress_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) @@ -478,7 +478,7 @@ static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising) advertising & ADVERTISED_10000baseT_Full); } -struct efx_phy_operations falcon_sfx7101_phy_ops = { +const struct efx_phy_operations falcon_sfx7101_phy_ops = { .probe = tenxpress_phy_probe, .init = tenxpress_phy_init, .reconfigure = tenxpress_phy_reconfigure, diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 139801908217..84eb99e0f8d2 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -205,7 +205,9 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) goto unwind; } smp_mb(); - netif_tx_start_queue(tx_queue->core_txq); + if (likely(!efx->loopback_selftest)) + netif_tx_start_queue( + tx_queue->core_txq); } insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask; @@ -338,8 +340,7 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, struct efx_tx_queue *tx_queue; unsigned index, type; - if (unlikely(efx->port_inhibited)) - return NETDEV_TX_BUSY; + EFX_WARN_ON_PARANOID(!netif_device_present(net_dev)); index = skb_get_queue_mapping(skb); type = skb->ip_summed == CHECKSUM_PARTIAL ? EFX_TXQ_TYPE_OFFLOAD : 0; @@ -435,7 +436,8 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) * queue state. */ smp_mb(); if (unlikely(netif_tx_queue_stopped(tx_queue->core_txq)) && - likely(efx->port_enabled)) { + likely(efx->port_enabled) && + likely(netif_device_present(efx->net_dev))) { fill_level = tx_queue->insert_count - tx_queue->read_count; if (fill_level < EFX_TXQ_THRESHOLD(efx)) { EFX_BUG_ON_PARANOID(!efx_dev_registered(efx)); diff --git a/drivers/net/sfc/txc43128_phy.c b/drivers/net/sfc/txc43128_phy.c index d9886addcc99..7c21b334a75b 100644 --- a/drivers/net/sfc/txc43128_phy.c +++ b/drivers/net/sfc/txc43128_phy.c @@ -545,7 +545,7 @@ static void txc43128_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) mdio45_ethtool_gset(&efx->mdio, ecmd); } -struct efx_phy_operations falcon_txc_phy_ops = { +const struct efx_phy_operations falcon_txc_phy_ops = { .probe = txc43128_phy_probe, .init = txc43128_phy_init, .reconfigure = txc43128_phy_reconfigure, diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index cb317cd069ff..484f795a779d 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -240,7 +240,8 @@ static const struct ethtool_ops sis900_ethtool_ops; * @net_dev: the net device to get address for * * Older SiS900 and friends, use EEPROM to store MAC address. - * MAC address is read from read_eeprom() into @net_dev->dev_addr. + * MAC address is read from read_eeprom() into @net_dev->dev_addr and + * @net_dev->perm_addr. */ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) @@ -261,6 +262,9 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de for (i = 0; i < 3; i++) ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); + /* Store MAC Address in perm_addr */ + memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN); + return 1; } @@ -271,7 +275,8 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de * * SiS630E model, use APC CMOS RAM to store MAC address. * APC CMOS RAM is accessed through ISA bridge. - * MAC address is read into @net_dev->dev_addr. + * MAC address is read into @net_dev->dev_addr and + * @net_dev->perm_addr. */ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, @@ -296,6 +301,10 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, outb(0x09 + i, 0x70); ((u8 *)(net_dev->dev_addr))[i] = inb(0x71); } + + /* Store MAC Address in perm_addr */ + memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN); + pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40); pci_dev_put(isa_bridge); @@ -310,7 +319,7 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, * * SiS635 model, set MAC Reload Bit to load Mac address from APC * to rfdr. rfdr is accessed through rfcr. MAC address is read into - * @net_dev->dev_addr. + * @net_dev->dev_addr and @net_dev->perm_addr. */ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, @@ -334,6 +343,9 @@ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, *( ((u16 *)net_dev->dev_addr) + i) = inw(ioaddr + 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); @@ -353,7 +365,7 @@ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, * EEDONE signal to refuse EEPROM access by LAN. * The EEPROM map of SiS962 or SiS963 is different to SiS900. * The signature field in SiS962 or SiS963 spec is meaningless. - * MAC address is read into @net_dev->dev_addr. + * MAC address is read into @net_dev->dev_addr and @net_dev->perm_addr. */ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, @@ -372,6 +384,9 @@ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, for (i = 0; i < 3; i++) ((u16 *)(net_dev->dev_addr))[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 { diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 35b28f42d208..52a48cb75440 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -303,7 +303,7 @@ static int skge_get_settings(struct net_device *dev, ecmd->advertising = skge->advertising; ecmd->autoneg = skge->autoneg; - ecmd->speed = skge->speed; + ethtool_cmd_speed_set(ecmd, skge->speed); ecmd->duplex = skge->duplex; return 0; } @@ -321,8 +321,9 @@ static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) skge->speed = -1; } else { u32 setting; + u32 speed = ethtool_cmd_speed(ecmd); - switch (ecmd->speed) { + switch (speed) { case SPEED_1000: if (ecmd->duplex == DUPLEX_FULL) setting = SUPPORTED_1000baseT_Full; @@ -355,7 +356,7 @@ static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if ((setting & supported) == 0) return -EINVAL; - skge->speed = ecmd->speed; + skge->speed = speed; skge->duplex = ecmd->duplex; } @@ -537,46 +538,6 @@ static int skge_nway_reset(struct net_device *dev) return 0; } -static int skge_set_sg(struct net_device *dev, u32 data) -{ - struct skge_port *skge = netdev_priv(dev); - struct skge_hw *hw = skge->hw; - - if (hw->chip_id == CHIP_ID_GENESIS && data) - return -EOPNOTSUPP; - return ethtool_op_set_sg(dev, data); -} - -static int skge_set_tx_csum(struct net_device *dev, u32 data) -{ - struct skge_port *skge = netdev_priv(dev); - struct skge_hw *hw = skge->hw; - - if (hw->chip_id == CHIP_ID_GENESIS && data) - return -EOPNOTSUPP; - - return ethtool_op_set_tx_csum(dev, data); -} - -static u32 skge_get_rx_csum(struct net_device *dev) -{ - struct skge_port *skge = netdev_priv(dev); - - return skge->rx_csum; -} - -/* Only Yukon supports checksum offload. */ -static int skge_set_rx_csum(struct net_device *dev, u32 data) -{ - struct skge_port *skge = netdev_priv(dev); - - if (skge->hw->chip_id == CHIP_ID_GENESIS && data) - return -EOPNOTSUPP; - - skge->rx_csum = data; - return 0; -} - static void skge_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *ecmd) { @@ -786,29 +747,28 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) } /* blink LED's for finding board */ -static int skge_phys_id(struct net_device *dev, u32 data) +static int skge_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct skge_port *skge = netdev_priv(dev); - unsigned long ms; - enum led_mode mode = LED_MODE_TST; - if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) - ms = jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT / HZ) * 1000; - else - ms = data * 1000; + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 2; /* cycle on/off twice per second */ - while (ms > 0) { - skge_led(skge, mode); - mode ^= LED_MODE_TST; + case ETHTOOL_ID_ON: + skge_led(skge, LED_MODE_TST); + break; - if (msleep_interruptible(BLINK_MS)) - break; - ms -= BLINK_MS; + case ETHTOOL_ID_OFF: + skge_led(skge, LED_MODE_OFF); + break; + + case ETHTOOL_ID_INACTIVE: + /* back to regular LED state */ + skge_led(skge, netif_running(dev) ? LED_MODE_ON : LED_MODE_OFF); } - /* back to regular LED state */ - skge_led(skge, netif_running(dev) ? LED_MODE_ON : LED_MODE_OFF); - return 0; } @@ -925,12 +885,8 @@ static const struct ethtool_ops skge_ethtool_ops = { .set_pauseparam = skge_set_pauseparam, .get_coalesce = skge_get_coalesce, .set_coalesce = skge_set_coalesce, - .set_sg = skge_set_sg, - .set_tx_csum = skge_set_tx_csum, - .get_rx_csum = skge_get_rx_csum, - .set_rx_csum = skge_set_rx_csum, .get_strings = skge_get_strings, - .phys_id = skge_phys_id, + .set_phys_id = skge_set_phys_id, .get_sset_count = skge_get_sset_count, .get_ethtool_stats = skge_get_ethtool_stats, }; @@ -3085,7 +3041,8 @@ static struct sk_buff *skge_rx_get(struct net_device *dev, } skb_put(skb, len); - if (skge->rx_csum) { + + if (dev->features & NETIF_F_RXCSUM) { skb->csum = csum; skb->ip_summed = CHECKSUM_COMPLETE; } @@ -3847,10 +3804,10 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, setup_timer(&skge->link_timer, xm_link_timer, (unsigned long) skge); if (hw->chip_id != CHIP_ID_GENESIS) { - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - skge->rx_csum = 1; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM; + dev->features |= dev->hw_features; } - dev->features |= NETIF_F_GRO; /* read the mac address */ memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 51c0214ac25c..598bf7a1a55e 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2460,7 +2460,6 @@ struct skge_port { struct timer_list link_timer; enum pause_control flow_control; enum pause_status flow_status; - u8 rx_csum; u8 blink_on; u8 wol; u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ff8d262dc276..3ee41da130c2 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1198,12 +1198,12 @@ static void rx_set_checksum(struct sky2_port *sky2) sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), - (sky2->flags & SKY2_FLAG_RX_CHECKSUM) + (sky2->netdev->features & NETIF_F_RXCSUM) ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } /* Enable/disable receive hash calculation (RSS) */ -static void rx_set_rss(struct net_device *dev) +static void rx_set_rss(struct net_device *dev, u32 features) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; @@ -1216,7 +1216,7 @@ static void rx_set_rss(struct net_device *dev) } /* Program RSS initial values */ - if (dev->features & NETIF_F_RXHASH) { + if (features & NETIF_F_RXHASH) { u32 key[nkeys]; get_random_bytes(key, nkeys * sizeof(u32)); @@ -1322,32 +1322,32 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return err; } -#define NETIF_F_ALL_VLAN (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX) +#define SKY2_VLAN_OFFLOADS (NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO) -static void sky2_vlan_mode(struct net_device *dev) +static void sky2_vlan_mode(struct net_device *dev, u32 features) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; u16 port = sky2->port; - if (dev->features & NETIF_F_HW_VLAN_RX) + if (features & NETIF_F_HW_VLAN_RX) sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_ON); else sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF); - dev->vlan_features = dev->features &~ NETIF_F_ALL_VLAN; - if (dev->features & NETIF_F_HW_VLAN_TX) + if (features & NETIF_F_HW_VLAN_TX) { sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_ON); - else { + + dev->vlan_features |= SKY2_VLAN_OFFLOADS; + } else { sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF); /* Can't do transmit offload of vlan without hw vlan */ - dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_SG - | NETIF_F_ALL_CSUM); + dev->vlan_features &= ~SKY2_VLAN_OFFLOADS; } } @@ -1463,7 +1463,7 @@ static void sky2_rx_start(struct sky2_port *sky2) rx_set_checksum(sky2); if (!(hw->flags & SKY2_HW_RSS_BROKEN)) - rx_set_rss(sky2->netdev); + rx_set_rss(sky2->netdev, sky2->netdev->features); /* submit Rx ring */ for (i = 0; i < sky2->rx_pending; i++) { @@ -1626,7 +1626,8 @@ static void sky2_hw_up(struct sky2_port *sky2) sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, sky2->tx_ring_size - 1); - sky2_vlan_mode(sky2->netdev); + sky2_vlan_mode(sky2->netdev, sky2->netdev->features); + netdev_update_features(sky2->netdev); sky2_rx_start(sky2); } @@ -2261,12 +2262,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) hw->chip_id == CHIP_ID_YUKON_FE_P)) return -EINVAL; - /* TSO, etc on Yukon Ultra and MTU > 1500 not supported */ - if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U) - dev->features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM); - if (!netif_running(dev)) { dev->mtu = new_mtu; + netdev_update_features(dev); return 0; } @@ -2288,6 +2286,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) sky2_rx_clean(sky2); dev->mtu = new_mtu; + netdev_update_features(dev); mode = DATA_BLIND_VAL(DATA_BLIND_DEF) | GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF); @@ -2535,8 +2534,11 @@ static void sky2_rx_checksum(struct sky2_port *sky2, u32 status) "%s: receive checksum problem (status = %#x)\n", sky2->netdev->name, status); - /* Disable checksum offload */ - sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; + /* Disable checksum offload + * It will be reenabled on next ndo_set_features, but if it's + * really broken, will get disabled again + */ + sky2->netdev->features &= ~NETIF_F_RXCSUM; sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), BMU_DIS_RX_CHKSUM); } @@ -2591,7 +2593,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) /* This chip reports checksum status differently */ if (hw->flags & SKY2_HW_NEW_LE) { - if ((sky2->flags & SKY2_FLAG_RX_CHECKSUM) && + if ((dev->features & NETIF_F_RXCSUM) && (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) && (le->css & CSS_TCPUDPCSOK)) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2616,7 +2618,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) sky2->rx_tag = length; /* fall through */ case OP_RXCHKS: - if (likely(sky2->flags & SKY2_FLAG_RX_CHECKSUM)) + if (likely(dev->features & NETIF_F_RXCSUM)) sky2_rx_checksum(sky2, status); break; @@ -3411,10 +3413,10 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->phy_address = PHY_ADDR_MARV; if (sky2_is_copper(hw)) { ecmd->port = PORT_TP; - ecmd->speed = sky2->speed; + ethtool_cmd_speed_set(ecmd, sky2->speed); ecmd->supported |= SUPPORTED_Autoneg | SUPPORTED_TP; } else { - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); ecmd->port = PORT_FIBRE; ecmd->supported |= SUPPORTED_Autoneg | SUPPORTED_FIBRE; } @@ -3450,8 +3452,9 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) sky2->speed = -1; } else { u32 setting; + u32 speed = ethtool_cmd_speed(ecmd); - switch (ecmd->speed) { + switch (speed) { case SPEED_1000: if (ecmd->duplex == DUPLEX_FULL) setting = SUPPORTED_1000baseT_Full; @@ -3484,7 +3487,7 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if ((setting & supported) == 0) return -EINVAL; - sky2->speed = ecmd->speed; + sky2->speed = speed; sky2->duplex = ecmd->duplex; sky2->flags &= ~SKY2_FLAG_AUTO_SPEED; } @@ -3552,28 +3555,6 @@ static const struct sky2_stat { { "tx_fifo_underrun", GM_TXE_FIFO_UR }, }; -static u32 sky2_get_rx_csum(struct net_device *dev) -{ - struct sky2_port *sky2 = netdev_priv(dev); - - return !!(sky2->flags & SKY2_FLAG_RX_CHECKSUM); -} - -static int sky2_set_rx_csum(struct net_device *dev, u32 data) -{ - struct sky2_port *sky2 = netdev_priv(dev); - - if (data) - sky2->flags |= SKY2_FLAG_RX_CHECKSUM; - else - sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; - - sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), - data ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); - - return 0; -} - static u32 sky2_get_msglevel(struct net_device *netdev) { struct sky2_port *sky2 = netdev_priv(netdev); @@ -3826,23 +3807,24 @@ static void sky2_led(struct sky2_port *sky2, enum led_mode mode) } /* blink LED's for finding board */ -static int sky2_phys_id(struct net_device *dev, u32 data) +static int sky2_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct sky2_port *sky2 = netdev_priv(dev); - unsigned int i; - if (data == 0) - data = UINT_MAX; - - for (i = 0; i < data; i++) { + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ + case ETHTOOL_ID_INACTIVE: + sky2_led(sky2, MO_LED_NORM); + break; + case ETHTOOL_ID_ON: sky2_led(sky2, MO_LED_ON); - if (msleep_interruptible(500)) - break; + break; + case ETHTOOL_ID_OFF: sky2_led(sky2, MO_LED_OFF); - if (msleep_interruptible(500)) - break; + break; } - sky2_led(sky2, MO_LED_NORM); return 0; } @@ -4083,34 +4065,6 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs, } } -/* In order to do Jumbo packets on these chips, need to turn off the - * transmit store/forward. Therefore checksum offload won't work. - */ -static int no_tx_offload(struct net_device *dev) -{ - const struct sky2_port *sky2 = netdev_priv(dev); - const struct sky2_hw *hw = sky2->hw; - - return dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U; -} - -static int sky2_set_tx_csum(struct net_device *dev, u32 data) -{ - if (data && no_tx_offload(dev)) - return -EINVAL; - - return ethtool_op_set_tx_csum(dev, data); -} - - -static int sky2_set_tso(struct net_device *dev, u32 data) -{ - if (data && no_tx_offload(dev)) - return -EINVAL; - - return ethtool_op_set_tso(dev, data); -} - static int sky2_get_eeprom_len(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); @@ -4213,31 +4167,36 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len); } -static int sky2_set_flags(struct net_device *dev, u32 data) +static u32 sky2_fix_features(struct net_device *dev, u32 features) +{ + const struct sky2_port *sky2 = netdev_priv(dev); + const struct sky2_hw *hw = sky2->hw; + + /* In order to do Jumbo packets on these chips, need to turn off the + * transmit store/forward. Therefore checksum offload won't work. + */ + if (dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U) + features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM); + + return features; +} + +static int sky2_set_features(struct net_device *dev, u32 features) { struct sky2_port *sky2 = netdev_priv(dev); - unsigned long old_feat = dev->features; - u32 supported = 0; - int rc; + u32 changed = dev->features ^ features; - if (!(sky2->hw->flags & SKY2_HW_RSS_BROKEN)) - supported |= ETH_FLAG_RXHASH; + if (changed & NETIF_F_RXCSUM) { + u32 on = features & NETIF_F_RXCSUM; + sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), + on ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); + } - if (!(sky2->hw->flags & SKY2_HW_VLAN_BROKEN)) - supported |= ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN; + if (changed & NETIF_F_RXHASH) + rx_set_rss(dev, features); - printk(KERN_DEBUG "sky2 set_flags: supported %x data %x\n", - supported, data); - - rc = ethtool_op_set_flags(dev, data, supported); - if (rc) - return rc; - - if ((old_feat ^ dev->features) & NETIF_F_RXHASH) - rx_set_rss(dev); - - if ((old_feat ^ dev->features) & NETIF_F_ALL_VLAN) - sky2_vlan_mode(dev); + if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)) + sky2_vlan_mode(dev, features); return 0; } @@ -4257,11 +4216,6 @@ static const struct ethtool_ops sky2_ethtool_ops = { .get_eeprom_len = sky2_get_eeprom_len, .get_eeprom = sky2_get_eeprom, .set_eeprom = sky2_set_eeprom, - .set_sg = ethtool_op_set_sg, - .set_tx_csum = sky2_set_tx_csum, - .set_tso = sky2_set_tso, - .get_rx_csum = sky2_get_rx_csum, - .set_rx_csum = sky2_set_rx_csum, .get_strings = sky2_get_strings, .get_coalesce = sky2_get_coalesce, .set_coalesce = sky2_set_coalesce, @@ -4269,11 +4223,9 @@ static const struct ethtool_ops sky2_ethtool_ops = { .set_ringparam = sky2_set_ringparam, .get_pauseparam = sky2_get_pauseparam, .set_pauseparam = sky2_set_pauseparam, - .phys_id = sky2_phys_id, + .set_phys_id = sky2_set_phys_id, .get_sset_count = sky2_get_sset_count, .get_ethtool_stats = sky2_get_ethtool_stats, - .set_flags = sky2_set_flags, - .get_flags = ethtool_op_get_flags, }; #ifdef CONFIG_SKY2_DEBUG @@ -4553,6 +4505,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = { .ndo_set_mac_address = sky2_set_mac_address, .ndo_set_multicast_list = sky2_set_multicast, .ndo_change_mtu = sky2_change_mtu, + .ndo_fix_features = sky2_fix_features, + .ndo_set_features = sky2_set_features, .ndo_tx_timeout = sky2_tx_timeout, .ndo_get_stats64 = sky2_get_stats, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -4568,6 +4522,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = { .ndo_set_mac_address = sky2_set_mac_address, .ndo_set_multicast_list = sky2_set_multicast, .ndo_change_mtu = sky2_change_mtu, + .ndo_fix_features = sky2_fix_features, + .ndo_set_features = sky2_set_features, .ndo_tx_timeout = sky2_tx_timeout, .ndo_get_stats64 = sky2_get_stats, }, @@ -4600,7 +4556,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, /* Auto speed and flow control */ sky2->flags = SKY2_FLAG_AUTO_SPEED | SKY2_FLAG_AUTO_PAUSE; if (hw->chip_id != CHIP_ID_YUKON_XL) - sky2->flags |= SKY2_FLAG_RX_CHECKSUM; + dev->hw_features |= NETIF_F_RXCSUM; sky2->flow_mode = FC_BOTH; @@ -4619,18 +4575,21 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->port = port; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG - | NETIF_F_TSO | NETIF_F_GRO; + dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO; if (highmem) dev->features |= NETIF_F_HIGHDMA; /* Enable receive hashing unless hardware is known broken */ if (!(hw->flags & SKY2_HW_RSS_BROKEN)) - dev->features |= NETIF_F_RXHASH; + dev->hw_features |= NETIF_F_RXHASH; - if (!(hw->flags & SKY2_HW_VLAN_BROKEN)) - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + if (!(hw->flags & SKY2_HW_VLAN_BROKEN)) { + dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_features |= SKY2_VLAN_OFFLOADS; + } + + dev->features |= dev->hw_features; /* read the mac address */ memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 0c6d10c5f053..318c9ae7bf91 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2254,7 +2254,6 @@ struct sky2_port { u8 wol; /* WAKE_ bits */ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ u16 flags; -#define SKY2_FLAG_RX_CHECKSUM 0x0001 #define SKY2_FLAG_AUTO_SPEED 0x0002 #define SKY2_FLAG_AUTO_PAUSE 0x0004 diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 86cbb9ea2f26..8ec1a9a0bb9a 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -853,7 +853,9 @@ static int slip_open(struct tty_struct *tty) /* Done. We have linked the TTY line to a channel. */ rtnl_unlock(); tty->receive_room = 65536; /* We don't flow control */ - return sl->dev->base_addr; + + /* TTY layer expects 0 on success */ + return 0; err_free_bufs: sl_free_bufs(sl); diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index d07c39cb4daf..0f29f261fcfe 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -156,7 +156,7 @@ static const struct { { 14, 15 } }; -static short smc_mca_adapter_ids[] __initdata = { +static const short smc_mca_adapter_ids[] __devinitconst = { 0x61c8, 0x61c9, 0x6fc0, @@ -168,7 +168,7 @@ static short smc_mca_adapter_ids[] __initdata = { 0x0000 }; -static char *smc_mca_adapter_names[] __initdata = { +static const char *const smc_mca_adapter_names[] __devinitconst = { "SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)", "SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)", "WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)", @@ -199,7 +199,7 @@ static const struct net_device_ops ultramca_netdev_ops = { #endif }; -static int __init ultramca_probe(struct device *gen_dev) +static int __devinit ultramca_probe(struct device *gen_dev) { unsigned short ioaddr; struct net_device *dev; diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 66831f378396..053863aefb12 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1488,9 +1488,9 @@ smc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) SUPPORTED_TP | SUPPORTED_AUI; if (lp->ctl_rspeed == 10) - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); else if (lp->ctl_rspeed == 100) - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); cmd->autoneg = AUTONEG_DISABLE; if (lp->mii.phy_id==1) diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 43654a3bb0ec..dc4805f473e3 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1565,9 +1565,9 @@ smc_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) SUPPORTED_TP | SUPPORTED_AUI; if (lp->ctl_rspeed == 10) - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); else if (lp->ctl_rspeed == 100) - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); cmd->autoneg = AUTONEG_DISABLE; cmd->transceiver = XCVR_INTERNAL; diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 4b42ecc63dcf..c6d47d10590c 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -29,6 +29,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -69,6 +71,17 @@ static int debug = 3; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +struct smsc911x_data; + +struct smsc911x_ops { + u32 (*reg_read)(struct smsc911x_data *pdata, u32 reg); + void (*reg_write)(struct smsc911x_data *pdata, u32 reg, u32 val); + void (*rx_readfifo)(struct smsc911x_data *pdata, + unsigned int *buf, unsigned int wordcount); + void (*tx_writefifo)(struct smsc911x_data *pdata, + unsigned int *buf, unsigned int wordcount); +}; + struct smsc911x_data { void __iomem *ioaddr; @@ -116,8 +129,14 @@ struct smsc911x_data { unsigned int clear_bits_mask; unsigned int hashhi; unsigned int hashlo; + + /* register access functions */ + const struct smsc911x_ops *ops; }; +/* Easy access to information */ +#define __smsc_shift(pdata, reg) ((reg) << ((pdata)->config.shift)) + static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) { if (pdata->config.flags & SMSC911X_USE_32BIT) @@ -131,13 +150,29 @@ static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) return 0; } +static inline u32 +__smsc911x_reg_read_shift(struct smsc911x_data *pdata, u32 reg) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) + return readl(pdata->ioaddr + __smsc_shift(pdata, reg)); + + if (pdata->config.flags & SMSC911X_USE_16BIT) + return (readw(pdata->ioaddr + + __smsc_shift(pdata, reg)) & 0xFFFF) | + ((readw(pdata->ioaddr + + __smsc_shift(pdata, reg + 2)) & 0xFFFF) << 16); + + BUG(); + return 0; +} + static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) { u32 data; unsigned long flags; spin_lock_irqsave(&pdata->dev_lock, flags); - data = __smsc911x_reg_read(pdata, reg); + data = pdata->ops->reg_read(pdata, reg); spin_unlock_irqrestore(&pdata->dev_lock, flags); return data; @@ -160,13 +195,32 @@ static inline void __smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, BUG(); } +static inline void +__smsc911x_reg_write_shift(struct smsc911x_data *pdata, u32 reg, u32 val) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) { + writel(val, pdata->ioaddr + __smsc_shift(pdata, reg)); + return; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + writew(val & 0xFFFF, + pdata->ioaddr + __smsc_shift(pdata, reg)); + writew((val >> 16) & 0xFFFF, + pdata->ioaddr + __smsc_shift(pdata, reg + 2)); + return; + } + + BUG(); +} + static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, u32 val) { unsigned long flags; spin_lock_irqsave(&pdata->dev_lock, flags); - __smsc911x_reg_write(pdata, reg, val); + pdata->ops->reg_write(pdata, reg, val); spin_unlock_irqrestore(&pdata->dev_lock, flags); } @@ -202,6 +256,40 @@ smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, spin_unlock_irqrestore(&pdata->dev_lock, flags); } +/* Writes a packet to the TX_DATA_FIFO - shifted version */ +static inline void +smsc911x_tx_writefifo_shift(struct smsc911x_data *pdata, unsigned int *buf, + unsigned int wordcount) +{ + unsigned long flags; + + spin_lock_irqsave(&pdata->dev_lock, flags); + + if (pdata->config.flags & SMSC911X_SWAP_FIFO) { + while (wordcount--) + __smsc911x_reg_write_shift(pdata, TX_DATA_FIFO, + swab32(*buf++)); + goto out; + } + + if (pdata->config.flags & SMSC911X_USE_32BIT) { + writesl(pdata->ioaddr + __smsc_shift(pdata, + TX_DATA_FIFO), buf, wordcount); + goto out; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + while (wordcount--) + __smsc911x_reg_write_shift(pdata, + TX_DATA_FIFO, *buf++); + goto out; + } + + BUG(); +out: + spin_unlock_irqrestore(&pdata->dev_lock, flags); +} + /* Reads a packet out of the RX_DATA_FIFO */ static inline void smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, @@ -234,6 +322,40 @@ smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, spin_unlock_irqrestore(&pdata->dev_lock, flags); } +/* Reads a packet out of the RX_DATA_FIFO - shifted version */ +static inline void +smsc911x_rx_readfifo_shift(struct smsc911x_data *pdata, unsigned int *buf, + unsigned int wordcount) +{ + unsigned long flags; + + spin_lock_irqsave(&pdata->dev_lock, flags); + + if (pdata->config.flags & SMSC911X_SWAP_FIFO) { + while (wordcount--) + *buf++ = swab32(__smsc911x_reg_read_shift(pdata, + RX_DATA_FIFO)); + goto out; + } + + if (pdata->config.flags & SMSC911X_USE_32BIT) { + readsl(pdata->ioaddr + __smsc_shift(pdata, + RX_DATA_FIFO), buf, wordcount); + goto out; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + while (wordcount--) + *buf++ = __smsc911x_reg_read_shift(pdata, + RX_DATA_FIFO); + goto out; + } + + BUG(); +out: + spin_unlock_irqrestore(&pdata->dev_lock, flags); +} + /* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read * and smsc911x_mac_write, so assumes mac_lock is held */ static int smsc911x_mac_complete(struct smsc911x_data *pdata) @@ -248,8 +370,8 @@ static int smsc911x_mac_complete(struct smsc911x_data *pdata) if (!(val & MAC_CSR_CMD_CSR_BUSY_)) return 0; } - SMSC_WARNING(HW, "Timed out waiting for MAC not BUSY. " - "MAC_CSR_CMD: 0x%08X", val); + SMSC_WARN(pdata, hw, "Timed out waiting for MAC not BUSY. " + "MAC_CSR_CMD: 0x%08X", val); return -EIO; } @@ -262,7 +384,7 @@ static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset) temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { - SMSC_WARNING(HW, "MAC busy at entry"); + SMSC_WARN(pdata, hw, "MAC busy at entry"); return 0xFFFFFFFF; } @@ -277,7 +399,7 @@ static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset) if (likely(smsc911x_mac_complete(pdata) == 0)) return smsc911x_reg_read(pdata, MAC_CSR_DATA); - SMSC_WARNING(HW, "MAC busy after read"); + SMSC_WARN(pdata, hw, "MAC busy after read"); return 0xFFFFFFFF; } @@ -291,8 +413,8 @@ static void smsc911x_mac_write(struct smsc911x_data *pdata, temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { - SMSC_WARNING(HW, - "smsc911x_mac_write failed, MAC busy at entry"); + SMSC_WARN(pdata, hw, + "smsc911x_mac_write failed, MAC busy at entry"); return; } @@ -310,8 +432,7 @@ static void smsc911x_mac_write(struct smsc911x_data *pdata, if (likely(smsc911x_mac_complete(pdata) == 0)) return; - SMSC_WARNING(HW, - "smsc911x_mac_write failed, MAC busy after write"); + SMSC_WARN(pdata, hw, "smsc911x_mac_write failed, MAC busy after write"); } /* Get a phy register */ @@ -326,8 +447,7 @@ static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx) /* Confirm MII not busy */ if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - SMSC_WARNING(HW, - "MII is busy in smsc911x_mii_read???"); + SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_read???"); reg = -EIO; goto out; } @@ -343,7 +463,7 @@ static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx) goto out; } - SMSC_WARNING(HW, "Timed out waiting for MII read to finish"); + SMSC_WARN(pdata, hw, "Timed out waiting for MII read to finish"); reg = -EIO; out: @@ -364,8 +484,7 @@ static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx, /* Confirm MII not busy */ if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - SMSC_WARNING(HW, - "MII is busy in smsc911x_mii_write???"); + SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_write???"); reg = -EIO; goto out; } @@ -385,7 +504,7 @@ static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx, goto out; } - SMSC_WARNING(HW, "Timed out waiting for MII write to finish"); + SMSC_WARN(pdata, hw, "Timed out waiting for MII write to finish"); reg = -EIO; out: @@ -426,18 +545,20 @@ static void smsc911x_phy_initialise_external(struct smsc911x_data *pdata) unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG); if (pdata->config.flags & SMSC911X_FORCE_INTERNAL_PHY) { - SMSC_TRACE(HW, "Forcing internal PHY"); + SMSC_TRACE(pdata, hw, "Forcing internal PHY"); pdata->using_extphy = 0; } else if (pdata->config.flags & SMSC911X_FORCE_EXTERNAL_PHY) { - SMSC_TRACE(HW, "Forcing external PHY"); + SMSC_TRACE(pdata, hw, "Forcing external PHY"); smsc911x_phy_enable_external(pdata); pdata->using_extphy = 1; } else if (hwcfg & HW_CFG_EXT_PHY_DET_) { - SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET set, using external PHY"); + SMSC_TRACE(pdata, hw, + "HW_CFG EXT_PHY_DET set, using external PHY"); smsc911x_phy_enable_external(pdata); pdata->using_extphy = 1; } else { - SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET clear, using internal PHY"); + SMSC_TRACE(pdata, hw, + "HW_CFG EXT_PHY_DET clear, using internal PHY"); pdata->using_extphy = 0; } } @@ -499,7 +620,7 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3); wrsz >>= 2; - smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); + pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); /* Wait till transmit is done */ i = 60; @@ -509,13 +630,13 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) } while ((i--) && (!status)); if (!status) { - SMSC_WARNING(HW, "Failed to transmit " - "during loopback test"); + SMSC_WARN(pdata, hw, + "Failed to transmit during loopback test"); continue; } if (status & TX_STS_ES_) { - SMSC_WARNING(HW, "Transmit encountered " - "errors during loopback test"); + SMSC_WARN(pdata, hw, + "Transmit encountered errors during loopback test"); continue; } @@ -527,13 +648,13 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) } while ((i--) && (!status)); if (!status) { - SMSC_WARNING(HW, - "Failed to receive during loopback test"); + SMSC_WARN(pdata, hw, + "Failed to receive during loopback test"); continue; } if (status & RX_STS_ES_) { - SMSC_WARNING(HW, "Receive encountered " - "errors during loopback test"); + SMSC_WARN(pdata, hw, + "Receive encountered errors during loopback test"); continue; } @@ -543,12 +664,12 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3); rdsz >>= 2; - smsc911x_rx_readfifo(pdata, (unsigned int *)bufp, rdsz); + pdata->ops->rx_readfifo(pdata, (unsigned int *)bufp, rdsz); if (pktlength != (MIN_PACKET_SIZE + 4)) { - SMSC_WARNING(HW, "Unexpected packet size " - "during loop back test, size=%d, will retry", - pktlength); + SMSC_WARN(pdata, hw, "Unexpected packet size " + "during loop back test, size=%d, will retry", + pktlength); } else { unsigned int j; int mismatch = 0; @@ -560,12 +681,12 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) } } if (!mismatch) { - SMSC_TRACE(HW, "Successfully verified " + SMSC_TRACE(pdata, hw, "Successfully verified " "loopback packet"); return 0; } else { - SMSC_WARNING(HW, "Data mismatch " - "during loop back test, will retry"); + SMSC_WARN(pdata, hw, "Data mismatch " + "during loop back test, will retry"); } } } @@ -582,7 +703,7 @@ static int smsc911x_phy_reset(struct smsc911x_data *pdata) BUG_ON(!phy_dev); BUG_ON(!phy_dev->bus); - SMSC_TRACE(HW, "Performing PHY BCR Reset"); + SMSC_TRACE(pdata, hw, "Performing PHY BCR Reset"); smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET); do { msleep(1); @@ -591,7 +712,7 @@ static int smsc911x_phy_reset(struct smsc911x_data *pdata) } while ((i--) && (temp & BMCR_RESET)); if (temp & BMCR_RESET) { - SMSC_WARNING(HW, "PHY reset failed to complete."); + SMSC_WARN(pdata, hw, "PHY reset failed to complete"); return -EIO; } /* Extra delay required because the phy may not be completed with @@ -695,11 +816,11 @@ static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) else afc &= ~0xF; - SMSC_TRACE(HW, "rx pause %s, tx pause %s", - (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), - (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); + SMSC_TRACE(pdata, hw, "rx pause %s, tx pause %s", + (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), + (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); } else { - SMSC_TRACE(HW, "half duplex"); + SMSC_TRACE(pdata, hw, "half duplex"); flow = 0; afc |= 0xF; } @@ -722,17 +843,17 @@ static void smsc911x_phy_adjust_link(struct net_device *dev) if (phy_dev->duplex != pdata->last_duplex) { unsigned int mac_cr; - SMSC_TRACE(HW, "duplex state has changed"); + SMSC_TRACE(pdata, hw, "duplex state has changed"); spin_lock_irqsave(&pdata->mac_lock, flags); mac_cr = smsc911x_mac_read(pdata, MAC_CR); if (phy_dev->duplex) { - SMSC_TRACE(HW, - "configuring for full duplex mode"); + SMSC_TRACE(pdata, hw, + "configuring for full duplex mode"); mac_cr |= MAC_CR_FDPX_; } else { - SMSC_TRACE(HW, - "configuring for half duplex mode"); + SMSC_TRACE(pdata, hw, + "configuring for half duplex mode"); mac_cr &= ~MAC_CR_FDPX_; } smsc911x_mac_write(pdata, MAC_CR, mac_cr); @@ -744,9 +865,9 @@ static void smsc911x_phy_adjust_link(struct net_device *dev) carrier = netif_carrier_ok(dev); if (carrier != pdata->last_carrier) { - SMSC_TRACE(HW, "carrier state has changed"); + SMSC_TRACE(pdata, hw, "carrier state has changed"); if (carrier) { - SMSC_TRACE(HW, "configuring for carrier OK"); + SMSC_TRACE(pdata, hw, "configuring for carrier OK"); if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) && (!pdata->using_extphy)) { /* Restore original GPIO configuration */ @@ -755,7 +876,7 @@ static void smsc911x_phy_adjust_link(struct net_device *dev) pdata->gpio_setting); } } else { - SMSC_TRACE(HW, "configuring for no carrier"); + SMSC_TRACE(pdata, hw, "configuring for no carrier"); /* Check global setting that LED1 * usage is 10/100 indicator */ pdata->gpio_setting = smsc911x_reg_read(pdata, @@ -787,25 +908,25 @@ static int smsc911x_mii_probe(struct net_device *dev) /* find the first phy */ phydev = phy_find_first(pdata->mii_bus); if (!phydev) { - pr_err("%s: no PHY found\n", dev->name); + netdev_err(dev, "no PHY found\n"); return -ENODEV; } - SMSC_TRACE(PROBE, "PHY: addr %d, phy_id 0x%08X", - phydev->addr, phydev->phy_id); + SMSC_TRACE(pdata, probe, "PHY: addr %d, phy_id 0x%08X", + phydev->addr, phydev->phy_id); ret = phy_connect_direct(dev, phydev, &smsc911x_phy_adjust_link, 0, pdata->config.phy_interface); if (ret) { - pr_err("%s: Could not attach to PHY\n", dev->name); + netdev_err(dev, "Could not attach to PHY\n"); return ret; } - pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", - dev->name, phydev->drv->name, - dev_name(&phydev->dev), phydev->irq); + netdev_info(dev, + "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", + phydev->drv->name, dev_name(&phydev->dev), phydev->irq); /* mask with MAC supported features */ phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | @@ -818,13 +939,13 @@ static int smsc911x_mii_probe(struct net_device *dev) #ifdef USE_PHY_WORK_AROUND if (smsc911x_phy_loopbacktest(dev) < 0) { - SMSC_WARNING(HW, "Failed Loop Back Test"); + SMSC_WARN(pdata, hw, "Failed Loop Back Test"); return -ENODEV; } - SMSC_TRACE(HW, "Passed Loop Back Test"); + SMSC_TRACE(pdata, hw, "Passed Loop Back Test"); #endif /* USE_PHY_WORK_AROUND */ - SMSC_TRACE(HW, "phy initialised successfully"); + SMSC_TRACE(pdata, hw, "phy initialised successfully"); return 0; } @@ -860,8 +981,8 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev, smsc911x_phy_initialise_external(pdata); break; default: - SMSC_TRACE(HW, "External PHY is not supported, " - "using internal PHY"); + SMSC_TRACE(pdata, hw, "External PHY is not supported, " + "using internal PHY"); pdata->using_extphy = 0; break; } @@ -872,12 +993,12 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev, } if (mdiobus_register(pdata->mii_bus)) { - SMSC_WARNING(PROBE, "Error registering mii bus"); + SMSC_WARN(pdata, probe, "Error registering mii bus"); goto err_out_free_bus_2; } if (smsc911x_mii_probe(dev) < 0) { - SMSC_WARNING(PROBE, "Error registering mii bus"); + SMSC_WARN(pdata, probe, "Error registering mii bus"); goto err_out_unregister_bus_3; } @@ -913,8 +1034,7 @@ static void smsc911x_tx_update_txcounters(struct net_device *dev) * does not reference a hardware defined reserved bit * but rather a driver defined one. */ - SMSC_WARNING(HW, - "Packet tag reserved bit is high"); + SMSC_WARN(pdata, hw, "Packet tag reserved bit is high"); } else { if (unlikely(tx_stat & TX_STS_ES_)) { dev->stats.tx_errors++; @@ -977,8 +1097,8 @@ smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes) } while ((val & RX_DP_CTRL_RX_FFWD_) && --timeout); if (unlikely(timeout == 0)) - SMSC_WARNING(HW, "Timed out waiting for " - "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val); + SMSC_WARN(pdata, hw, "Timed out waiting for " + "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val); } else { unsigned int temp; while (pktwords--) @@ -1021,8 +1141,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) smsc911x_rx_counterrors(dev, rxstat); if (unlikely(rxstat & RX_STS_ES_)) { - SMSC_WARNING(RX_ERR, - "Discarding packet with error bit set"); + SMSC_WARN(pdata, rx_err, + "Discarding packet with error bit set"); /* Packet has an error, discard it and continue with * the next */ smsc911x_rx_fastforward(pdata, pktwords); @@ -1032,8 +1152,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) skb = netdev_alloc_skb(dev, pktlength + NET_IP_ALIGN); if (unlikely(!skb)) { - SMSC_WARNING(RX_ERR, - "Unable to allocate skb for rx packet"); + SMSC_WARN(pdata, rx_err, + "Unable to allocate skb for rx packet"); /* Drop the packet and stop this polling iteration */ smsc911x_rx_fastforward(pdata, pktwords); dev->stats.rx_dropped++; @@ -1046,8 +1166,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) /* Align IP on 16B boundary */ skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, pktlength - 4); - smsc911x_rx_readfifo(pdata, (unsigned int *)skb->head, - pktwords); + pdata->ops->rx_readfifo(pdata, + (unsigned int *)skb->head, pktwords); skb->protocol = eth_type_trans(skb, dev); skb_checksum_none_assert(skb); netif_receive_skb(skb); @@ -1083,8 +1203,8 @@ static void smsc911x_rx_multicast_update(struct smsc911x_data *pdata) smsc911x_mac_write(pdata, MAC_CR, mac_cr); smsc911x_mac_write(pdata, HASHH, pdata->hashhi); smsc911x_mac_write(pdata, HASHL, pdata->hashlo); - SMSC_TRACE(HW, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X", - mac_cr, pdata->hashhi, pdata->hashlo); + SMSC_TRACE(pdata, hw, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X", + mac_cr, pdata->hashhi, pdata->hashlo); } static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata) @@ -1102,7 +1222,7 @@ static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata) /* Check Rx has stopped */ if (smsc911x_mac_read(pdata, MAC_CR) & MAC_CR_RXEN_) - SMSC_WARNING(DRV, "Rx not stopped"); + SMSC_WARN(pdata, drv, "Rx not stopped"); /* Perform the update - safe to do now Rx has stopped */ smsc911x_rx_multicast_update(pdata); @@ -1131,7 +1251,7 @@ static int smsc911x_soft_reset(struct smsc911x_data *pdata) } while ((--timeout) && (temp & HW_CFG_SRST_)); if (unlikely(temp & HW_CFG_SRST_)) { - SMSC_WARNING(DRV, "Failed to complete reset"); + SMSC_WARN(pdata, drv, "Failed to complete reset"); return -EIO; } return 0; @@ -1160,18 +1280,18 @@ static int smsc911x_open(struct net_device *dev) /* if the phy is not yet registered, retry later*/ if (!pdata->phy_dev) { - SMSC_WARNING(HW, "phy_dev is NULL"); + SMSC_WARN(pdata, hw, "phy_dev is NULL"); return -EAGAIN; } if (!is_valid_ether_addr(dev->dev_addr)) { - SMSC_WARNING(HW, "dev_addr is not a valid MAC address"); + SMSC_WARN(pdata, hw, "dev_addr is not a valid MAC address"); return -EADDRNOTAVAIL; } /* Reset the LAN911x */ if (smsc911x_soft_reset(pdata)) { - SMSC_WARNING(HW, "soft reset failed"); + SMSC_WARN(pdata, hw, "soft reset failed"); return -EIO; } @@ -1191,8 +1311,8 @@ static int smsc911x_open(struct net_device *dev) } if (unlikely(timeout == 0)) - SMSC_WARNING(IFUP, - "Timed out waiting for EEPROM busy bit to clear"); + SMSC_WARN(pdata, ifup, + "Timed out waiting for EEPROM busy bit to clear"); smsc911x_reg_write(pdata, GPIO_CFG, 0x70070000); @@ -1210,22 +1330,22 @@ static int smsc911x_open(struct net_device *dev) intcfg = ((10 << 24) | INT_CFG_IRQ_EN_); if (pdata->config.irq_polarity) { - SMSC_TRACE(IFUP, "irq polarity: active high"); + SMSC_TRACE(pdata, ifup, "irq polarity: active high"); intcfg |= INT_CFG_IRQ_POL_; } else { - SMSC_TRACE(IFUP, "irq polarity: active low"); + SMSC_TRACE(pdata, ifup, "irq polarity: active low"); } if (pdata->config.irq_type) { - SMSC_TRACE(IFUP, "irq type: push-pull"); + SMSC_TRACE(pdata, ifup, "irq type: push-pull"); intcfg |= INT_CFG_IRQ_TYPE_; } else { - SMSC_TRACE(IFUP, "irq type: open drain"); + SMSC_TRACE(pdata, ifup, "irq type: open drain"); } smsc911x_reg_write(pdata, INT_CFG, intcfg); - SMSC_TRACE(IFUP, "Testing irq handler using IRQ %d", dev->irq); + SMSC_TRACE(pdata, ifup, "Testing irq handler using IRQ %d", dev->irq); pdata->software_irq_signal = 0; smp_wmb(); @@ -1241,14 +1361,15 @@ static int smsc911x_open(struct net_device *dev) } if (!pdata->software_irq_signal) { - dev_warn(&dev->dev, "ISR failed signaling test (IRQ %d)\n", - dev->irq); + netdev_warn(dev, "ISR failed signaling test (IRQ %d)\n", + dev->irq); return -ENODEV; } - SMSC_TRACE(IFUP, "IRQ handler passed test using IRQ %d", dev->irq); + SMSC_TRACE(pdata, ifup, "IRQ handler passed test using IRQ %d", + dev->irq); - dev_info(&dev->dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n", - (unsigned long)pdata->ioaddr, dev->irq); + netdev_info(dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n", + (unsigned long)pdata->ioaddr, dev->irq); /* Reset the last known duplex and carrier */ pdata->last_duplex = -1; @@ -1313,7 +1434,7 @@ static int smsc911x_stop(struct net_device *dev) if (pdata->phy_dev) phy_stop(pdata->phy_dev); - SMSC_TRACE(IFDOWN, "Interface stopped"); + SMSC_TRACE(pdata, ifdown, "Interface stopped"); return 0; } @@ -1331,8 +1452,8 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) freespace = smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TDFREE_; if (unlikely(freespace < TX_FIFO_LOW_THRESHOLD)) - SMSC_WARNING(TX_ERR, - "Tx data fifo low, space available: %d", freespace); + SMSC_WARN(pdata, tx_err, + "Tx data fifo low, space available: %d", freespace); /* Word alignment adjustment */ tx_cmd_a = (u32)((ulong)skb->data & 0x03) << 16; @@ -1350,7 +1471,7 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) wrsz += (u32)((ulong)skb->data & 0x3); wrsz >>= 2; - smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); + pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); freespace -= (skb->len + 32); dev_kfree_skb(skb); @@ -1432,7 +1553,7 @@ static void smsc911x_set_multicast_list(struct net_device *dev) * receiving data */ if (!pdata->multicast_update_pending) { unsigned int temp; - SMSC_TRACE(HW, "scheduling mcast update"); + SMSC_TRACE(pdata, hw, "scheduling mcast update"); pdata->multicast_update_pending = 1; /* Request the hardware to stop, then perform the @@ -1474,7 +1595,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) if (unlikely(intsts & inten & INT_STS_RXSTOP_INT_)) { /* Called when there is a multicast update scheduled and * it is now safe to complete the update */ - SMSC_TRACE(INTR, "RX Stop interrupt"); + SMSC_TRACE(pdata, intr, "RX Stop interrupt"); smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_); if (pdata->multicast_update_pending) smsc911x_rx_multicast_update_workaround(pdata); @@ -1491,7 +1612,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) } if (unlikely(intsts & inten & INT_STS_RXE_)) { - SMSC_TRACE(INTR, "RX Error interrupt"); + SMSC_TRACE(pdata, intr, "RX Error interrupt"); smsc911x_reg_write(pdata, INT_STS, INT_STS_RXE_); serviced = IRQ_HANDLED; } @@ -1505,8 +1626,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) /* Schedule a NAPI poll */ __napi_schedule(&pdata->napi); } else { - SMSC_WARNING(RX_ERR, - "napi_schedule_prep failed"); + SMSC_WARN(pdata, rx_err, "napi_schedule_prep failed"); } serviced = IRQ_HANDLED; } @@ -1543,7 +1663,7 @@ static int smsc911x_set_mac_address(struct net_device *dev, void *p) smsc911x_set_hw_mac_address(pdata, dev->dev_addr); spin_unlock_irq(&pdata->mac_lock); - dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr); + netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr); return 0; } @@ -1649,9 +1769,9 @@ static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op) int timeout = 100; u32 e2cmd; - SMSC_TRACE(DRV, "op 0x%08x", op); + SMSC_TRACE(pdata, drv, "op 0x%08x", op); if (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) { - SMSC_WARNING(DRV, "Busy at start"); + SMSC_WARN(pdata, drv, "Busy at start"); return -EBUSY; } @@ -1664,12 +1784,12 @@ static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op) } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout)); if (!timeout) { - SMSC_TRACE(DRV, "TIMED OUT"); + SMSC_TRACE(pdata, drv, "TIMED OUT"); return -EAGAIN; } if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { - SMSC_TRACE(DRV, "Error occurred during eeprom operation"); + SMSC_TRACE(pdata, drv, "Error occurred during eeprom operation"); return -EINVAL; } @@ -1682,7 +1802,7 @@ static int smsc911x_eeprom_read_location(struct smsc911x_data *pdata, u32 op = E2P_CMD_EPC_CMD_READ_ | address; int ret; - SMSC_TRACE(DRV, "address 0x%x", address); + SMSC_TRACE(pdata, drv, "address 0x%x", address); ret = smsc911x_eeprom_send_cmd(pdata, op); if (!ret) @@ -1698,7 +1818,7 @@ static int smsc911x_eeprom_write_location(struct smsc911x_data *pdata, u32 temp; int ret; - SMSC_TRACE(DRV, "address 0x%x, data 0x%x", address, data); + SMSC_TRACE(pdata, drv, "address 0x%x, data 0x%x", address, data); ret = smsc911x_eeprom_send_cmd(pdata, op); if (!ret) { @@ -1811,26 +1931,26 @@ static int __devinit smsc911x_init(struct net_device *dev) struct smsc911x_data *pdata = netdev_priv(dev); unsigned int byte_test; - SMSC_TRACE(PROBE, "Driver Parameters:"); - SMSC_TRACE(PROBE, "LAN base: 0x%08lX", - (unsigned long)pdata->ioaddr); - SMSC_TRACE(PROBE, "IRQ: %d", dev->irq); - SMSC_TRACE(PROBE, "PHY will be autodetected."); + SMSC_TRACE(pdata, probe, "Driver Parameters:"); + SMSC_TRACE(pdata, probe, "LAN base: 0x%08lX", + (unsigned long)pdata->ioaddr); + SMSC_TRACE(pdata, probe, "IRQ: %d", dev->irq); + SMSC_TRACE(pdata, probe, "PHY will be autodetected."); spin_lock_init(&pdata->dev_lock); spin_lock_init(&pdata->mac_lock); if (pdata->ioaddr == 0) { - SMSC_WARNING(PROBE, "pdata->ioaddr: 0x00000000"); + SMSC_WARN(pdata, probe, "pdata->ioaddr: 0x00000000"); return -ENODEV; } /* Check byte ordering */ byte_test = smsc911x_reg_read(pdata, BYTE_TEST); - SMSC_TRACE(PROBE, "BYTE_TEST: 0x%08X", byte_test); + SMSC_TRACE(pdata, probe, "BYTE_TEST: 0x%08X", byte_test); if (byte_test == 0x43218765) { - SMSC_TRACE(PROBE, "BYTE_TEST looks swapped, " - "applying WORD_SWAP"); + SMSC_TRACE(pdata, probe, "BYTE_TEST looks swapped, " + "applying WORD_SWAP"); smsc911x_reg_write(pdata, WORD_SWAP, 0xffffffff); /* 1 dummy read of BYTE_TEST is needed after a write to @@ -1841,12 +1961,13 @@ static int __devinit smsc911x_init(struct net_device *dev) } if (byte_test != 0x87654321) { - SMSC_WARNING(DRV, "BYTE_TEST: 0x%08X", byte_test); + SMSC_WARN(pdata, drv, "BYTE_TEST: 0x%08X", byte_test); if (((byte_test >> 16) & 0xFFFF) == (byte_test & 0xFFFF)) { - SMSC_WARNING(PROBE, - "top 16 bits equal to bottom 16 bits"); - SMSC_TRACE(PROBE, "This may mean the chip is set " - "for 32 bit while the bus is reading 16 bit"); + SMSC_WARN(pdata, probe, + "top 16 bits equal to bottom 16 bits"); + SMSC_TRACE(pdata, probe, + "This may mean the chip is set " + "for 32 bit while the bus is reading 16 bit"); } return -ENODEV; } @@ -1881,17 +2002,18 @@ static int __devinit smsc911x_init(struct net_device *dev) break; default: - SMSC_WARNING(PROBE, "LAN911x not identified, idrev: 0x%08X", - pdata->idrev); + SMSC_WARN(pdata, probe, "LAN911x not identified, idrev: 0x%08X", + pdata->idrev); return -ENODEV; } - SMSC_TRACE(PROBE, "LAN911x identified, idrev: 0x%08X, generation: %d", - pdata->idrev, pdata->generation); + SMSC_TRACE(pdata, probe, + "LAN911x identified, idrev: 0x%08X, generation: %d", + pdata->idrev, pdata->generation); if (pdata->generation == 0) - SMSC_WARNING(PROBE, - "This driver is not intended for this chip revision"); + SMSC_WARN(pdata, probe, + "This driver is not intended for this chip revision"); /* workaround for platforms without an eeprom, where the mac address * is stored elsewhere and set by the bootloader. This saves the @@ -1931,7 +2053,7 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev) BUG_ON(!pdata->ioaddr); BUG_ON(!pdata->phy_dev); - SMSC_TRACE(IFDOWN, "Stopping driver."); + SMSC_TRACE(pdata, ifdown, "Stopping driver"); phy_disconnect(pdata->phy_dev); pdata->phy_dev = NULL; @@ -1955,6 +2077,22 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev) return 0; } +/* standard register acces */ +static const struct smsc911x_ops standard_smsc911x_ops = { + .reg_read = __smsc911x_reg_read, + .reg_write = __smsc911x_reg_write, + .rx_readfifo = smsc911x_rx_readfifo, + .tx_writefifo = smsc911x_tx_writefifo, +}; + +/* shifted register access */ +static const struct smsc911x_ops shifted_smsc911x_ops = { + .reg_read = __smsc911x_reg_read_shift, + .reg_write = __smsc911x_reg_write_shift, + .rx_readfifo = smsc911x_rx_readfifo_shift, + .tx_writefifo = smsc911x_tx_writefifo_shift, +}; + static int __devinit smsc911x_drv_probe(struct platform_device *pdev) { struct net_device *dev; @@ -1965,11 +2103,11 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) int res_size, irq_flags; int retval; - pr_info("%s: Driver version %s.\n", SMSC_CHIPNAME, SMSC_DRV_VERSION); + pr_info("Driver version %s\n", SMSC_DRV_VERSION); /* platform data specifies irq & dynamic bus configuration */ if (!pdev->dev.platform_data) { - pr_warning("%s: platform_data not provided\n", SMSC_CHIPNAME); + pr_warn("platform_data not provided\n"); retval = -ENODEV; goto out_0; } @@ -1979,8 +2117,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) if (!res) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { - pr_warning("%s: Could not allocate resource.\n", - SMSC_CHIPNAME); + pr_warn("Could not allocate resource\n"); retval = -ENODEV; goto out_0; } @@ -1988,8 +2125,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq_res) { - pr_warning("%s: Could not allocate irq resource.\n", - SMSC_CHIPNAME); + pr_warn("Could not allocate irq resource\n"); retval = -ENODEV; goto out_0; } @@ -2001,7 +2137,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) dev = alloc_etherdev(sizeof(struct smsc911x_data)); if (!dev) { - pr_warning("%s: Could not allocate device.\n", SMSC_CHIPNAME); + pr_warn("Could not allocate device\n"); retval = -ENOMEM; goto out_release_io_1; } @@ -2021,12 +2157,17 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) pdata->msg_enable = ((1 << debug) - 1); if (pdata->ioaddr == NULL) { - SMSC_WARNING(PROBE, - "Error smsc911x base address invalid"); + SMSC_WARN(pdata, probe, "Error smsc911x base address invalid"); retval = -ENOMEM; goto out_free_netdev_2; } + /* assume standard, non-shifted, access to HW registers */ + pdata->ops = &standard_smsc911x_ops; + /* apply the right access if shifting is needed */ + if (config->shift) + pdata->ops = &shifted_smsc911x_ops; + retval = smsc911x_init(dev); if (retval < 0) goto out_unmap_io_3; @@ -2047,8 +2188,8 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) retval = request_irq(dev->irq, smsc911x_irqhandler, irq_flags | IRQF_SHARED, dev->name, dev); if (retval) { - SMSC_WARNING(PROBE, - "Unable to claim requested irq: %d", dev->irq); + SMSC_WARN(pdata, probe, + "Unable to claim requested irq: %d", dev->irq); goto out_unmap_io_3; } @@ -2056,17 +2197,16 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) retval = register_netdev(dev); if (retval) { - SMSC_WARNING(PROBE, - "Error %i registering device", retval); + SMSC_WARN(pdata, probe, "Error %i registering device", retval); goto out_unset_drvdata_4; } else { - SMSC_TRACE(PROBE, "Network interface: \"%s\"", dev->name); + SMSC_TRACE(pdata, probe, + "Network interface: \"%s\"", dev->name); } retval = smsc911x_mii_init(pdev, dev); if (retval) { - SMSC_WARNING(PROBE, - "Error %i initialising mii", retval); + SMSC_WARN(pdata, probe, "Error %i initialising mii", retval); goto out_unregister_netdev_5; } @@ -2075,10 +2215,12 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) /* Check if mac address has been specified when bringing interface up */ if (is_valid_ether_addr(dev->dev_addr)) { smsc911x_set_hw_mac_address(pdata, dev->dev_addr); - SMSC_TRACE(PROBE, "MAC Address is specified by configuration"); + SMSC_TRACE(pdata, probe, + "MAC Address is specified by configuration"); } else if (is_valid_ether_addr(pdata->config.mac)) { memcpy(dev->dev_addr, pdata->config.mac, 6); - SMSC_TRACE(PROBE, "MAC Address specified by platform data"); + SMSC_TRACE(pdata, probe, + "MAC Address specified by platform data"); } else { /* Try reading mac address from device. if EEPROM is present * it will already have been set */ @@ -2086,20 +2228,20 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) if (is_valid_ether_addr(dev->dev_addr)) { /* eeprom values are valid so use them */ - SMSC_TRACE(PROBE, - "Mac Address is read from LAN911x EEPROM"); + SMSC_TRACE(pdata, probe, + "Mac Address is read from LAN911x EEPROM"); } else { /* eeprom values are invalid, generate random MAC */ random_ether_addr(dev->dev_addr); smsc911x_set_hw_mac_address(pdata, dev->dev_addr); - SMSC_TRACE(PROBE, - "MAC Address is set to random_ether_addr"); + SMSC_TRACE(pdata, probe, + "MAC Address is set to random_ether_addr"); } } spin_unlock_irq(&pdata->mac_lock); - dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr); + netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr); return 0; diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h index 50f712e99e96..8d67aacf8867 100644 --- a/drivers/net/smsc911x.h +++ b/drivers/net/smsc911x.h @@ -33,25 +33,21 @@ * can be successfully looped back */ #define USE_PHY_WORK_AROUND -#define DPRINTK(nlevel, klevel, fmt, args...) \ - ((void)((NETIF_MSG_##nlevel & pdata->msg_enable) && \ - printk(KERN_##klevel "%s: %s: " fmt "\n", \ - pdata->dev->name, __func__, ## args))) - #if USE_DEBUG >= 1 -#define SMSC_WARNING(nlevel, fmt, args...) \ - DPRINTK(nlevel, WARNING, fmt, ## args) +#define SMSC_WARN(pdata, nlevel, fmt, args...) \ + netif_warn(pdata, nlevel, (pdata)->dev, \ + "%s: " fmt "\n", __func__, ##args) #else -#define SMSC_WARNING(nlevel, fmt, args...) \ - ({ do {} while (0); 0; }) +#define SMSC_WARN(pdata, nlevel, fmt, args...) \ + no_printk(fmt "\n", ##args) #endif #if USE_DEBUG >= 2 -#define SMSC_TRACE(nlevel, fmt, args...) \ - DPRINTK(nlevel, INFO, fmt, ## args) +#define SMSC_TRACE(pdata, nlevel, fmt, args...) \ + netif_info(pdata, nlevel, pdata->dev, fmt "\n", ##args) #else -#define SMSC_TRACE(nlevel, fmt, args...) \ - ({ do {} while (0); 0; }) +#define SMSC_TRACE(pdata, nlevel, fmt, args...) \ + no_printk(fmt "\n", ##args) #endif #ifdef CONFIG_DEBUG_SPINLOCK diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index cb6bcca9d541..949f124e1278 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -994,15 +994,13 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, skb->protocol = eth_type_trans(skb, netdev); /* checksum offload */ - if (card->options.rx_csum) { + skb_checksum_none_assert(skb); + if (netdev->features & NETIF_F_RXCSUM) { if ( ( (data_status & SPIDER_NET_DATA_STATUS_CKSUM_MASK) == SPIDER_NET_DATA_STATUS_CKSUM_MASK) && !(data_error & SPIDER_NET_DATA_ERR_CKSUM_MASK)) skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb_checksum_none_assert(skb); - } else - skb_checksum_none_assert(skb); + } if (data_status & SPIDER_NET_VLAN_PACKET) { /* further enhancements: HW-accel VLAN @@ -2322,14 +2320,15 @@ spider_net_setup_netdev(struct spider_net_card *card) card->aneg_timer.function = spider_net_link_phy; card->aneg_timer.data = (unsigned long) card; - card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; - netif_napi_add(netdev, &card->napi, spider_net_poll, SPIDER_NET_NAPI_WEIGHT); spider_net_setup_netdev_ops(netdev); - netdev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX; + netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM; + if (SPIDER_NET_RX_CSUM_DEFAULT) + netdev->features |= NETIF_F_RXCSUM; + netdev->features |= NETIF_F_IP_CSUM | NETIF_F_LLTX; /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | * NETIF_F_HW_VLAN_FILTER */ diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 05f74cbdd617..020f64a8fcf7 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -429,12 +429,6 @@ struct spider_net_descr_chain { * 701b8000 would be correct, but every packets gets that flag */ #define SPIDER_NET_DESTROY_RX_FLAGS 0x700b8000 -/* this will be bigger some time */ -struct spider_net_options { - int rx_csum; /* for rx: if 0 ip_summed=NONE, - if 1 and hw has verified, ip_summed=UNNECESSARY */ -}; - #define SPIDER_NET_DEFAULT_MSG ( NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ NETIF_MSG_LINK | \ @@ -487,7 +481,6 @@ struct spider_net_card { /* for ethtool */ int msg_enable; struct spider_net_extra_stats spider_stats; - struct spider_net_options options; /* Must be last item in struct */ struct spider_net_descr darray[0]; diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 5bae728c3820..9c288cd7d171 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -58,7 +58,7 @@ spider_net_ethtool_get_settings(struct net_device *netdev, cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE); cmd->port = PORT_FIBRE; - cmd->speed = card->phy.speed; + ethtool_cmd_speed_set(cmd, card->phy.speed); cmd->duplex = DUPLEX_FULL; return 0; @@ -115,24 +115,6 @@ spider_net_ethtool_nway_reset(struct net_device *netdev) return 0; } -static u32 -spider_net_ethtool_get_rx_csum(struct net_device *netdev) -{ - struct spider_net_card *card = netdev_priv(netdev); - - return card->options.rx_csum; -} - -static int -spider_net_ethtool_set_rx_csum(struct net_device *netdev, u32 n) -{ - struct spider_net_card *card = netdev_priv(netdev); - - card->options.rx_csum = n; - return 0; -} - - static void spider_net_ethtool_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ering) @@ -189,9 +171,6 @@ const struct ethtool_ops spider_net_ethtool_ops = { .set_msglevel = spider_net_ethtool_set_msglevel, .get_link = ethtool_op_get_link, .nway_reset = spider_net_ethtool_nway_reset, - .get_rx_csum = spider_net_ethtool_get_rx_csum, - .set_rx_csum = spider_net_ethtool_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, .get_ringparam = spider_net_ethtool_get_ringparam, .get_strings = spider_net_get_strings, .get_sset_count = spider_net_get_sset_count, diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c index 6ae4c3f4c63c..f20455cbfbbc 100644 --- a/drivers/net/stmmac/dwmac1000_core.c +++ b/drivers/net/stmmac/dwmac1000_core.c @@ -178,10 +178,11 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode) { unsigned int pmt = 0; - if (mode == WAKE_MAGIC) { + if (mode & WAKE_MAGIC) { CHIP_DBG(KERN_DEBUG "GMAC: WOL Magic frame\n"); pmt |= power_down | magic_pkt_en; - } else if (mode == WAKE_UCAST) { + } + if (mode & WAKE_UCAST) { CHIP_DBG(KERN_DEBUG "GMAC: WOL on global unicast\n"); pmt |= global_unicast; } diff --git a/drivers/net/stmmac/dwmac_lib.c b/drivers/net/stmmac/dwmac_lib.c index d65fab1ba790..e25093510b0c 100644 --- a/drivers/net/stmmac/dwmac_lib.c +++ b/drivers/net/stmmac/dwmac_lib.c @@ -26,9 +26,9 @@ #undef DWMAC_DMA_DEBUG #ifdef DWMAC_DMA_DEBUG -#define DBG(fmt, args...) printk(fmt, ## args) +#define DWMAC_LIB_DBG(fmt, args...) printk(fmt, ## args) #else -#define DBG(fmt, args...) do { } while (0) +#define DWMAC_LIB_DBG(fmt, args...) do { } while (0) #endif /* CSR1 enables the transmit DMA to check for new descriptor */ @@ -152,7 +152,7 @@ int dwmac_dma_interrupt(void __iomem *ioaddr, /* read the status register (CSR5) */ u32 intr_status = readl(ioaddr + DMA_STATUS); - DBG(INFO, "%s: [CSR5: 0x%08x]\n", __func__, intr_status); + DWMAC_LIB_DBG(KERN_INFO "%s: [CSR5: 0x%08x]\n", __func__, intr_status); #ifdef DWMAC_DMA_DEBUG /* It displays the DMA process states (CSR5 register) */ show_tx_process_state(intr_status); @@ -160,43 +160,43 @@ int dwmac_dma_interrupt(void __iomem *ioaddr, #endif /* ABNORMAL interrupts */ if (unlikely(intr_status & DMA_STATUS_AIS)) { - DBG(INFO, "CSR5[15] DMA ABNORMAL IRQ: "); + DWMAC_LIB_DBG(KERN_INFO "CSR5[15] DMA ABNORMAL IRQ: "); if (unlikely(intr_status & DMA_STATUS_UNF)) { - DBG(INFO, "transmit underflow\n"); + DWMAC_LIB_DBG(KERN_INFO "transmit underflow\n"); ret = tx_hard_error_bump_tc; x->tx_undeflow_irq++; } if (unlikely(intr_status & DMA_STATUS_TJT)) { - DBG(INFO, "transmit jabber\n"); + DWMAC_LIB_DBG(KERN_INFO "transmit jabber\n"); x->tx_jabber_irq++; } if (unlikely(intr_status & DMA_STATUS_OVF)) { - DBG(INFO, "recv overflow\n"); + DWMAC_LIB_DBG(KERN_INFO "recv overflow\n"); x->rx_overflow_irq++; } if (unlikely(intr_status & DMA_STATUS_RU)) { - DBG(INFO, "receive buffer unavailable\n"); + DWMAC_LIB_DBG(KERN_INFO "receive buffer unavailable\n"); x->rx_buf_unav_irq++; } if (unlikely(intr_status & DMA_STATUS_RPS)) { - DBG(INFO, "receive process stopped\n"); + DWMAC_LIB_DBG(KERN_INFO "receive process stopped\n"); x->rx_process_stopped_irq++; } if (unlikely(intr_status & DMA_STATUS_RWT)) { - DBG(INFO, "receive watchdog\n"); + DWMAC_LIB_DBG(KERN_INFO "receive watchdog\n"); x->rx_watchdog_irq++; } if (unlikely(intr_status & DMA_STATUS_ETI)) { - DBG(INFO, "transmit early interrupt\n"); + DWMAC_LIB_DBG(KERN_INFO "transmit early interrupt\n"); x->tx_early_irq++; } if (unlikely(intr_status & DMA_STATUS_TPS)) { - DBG(INFO, "transmit process stopped\n"); + DWMAC_LIB_DBG(KERN_INFO "transmit process stopped\n"); x->tx_process_stopped_irq++; ret = tx_hard_error; } if (unlikely(intr_status & DMA_STATUS_FBI)) { - DBG(INFO, "fatal bus error\n"); + DWMAC_LIB_DBG(KERN_INFO "fatal bus error\n"); x->fatal_bus_error_irq++; ret = tx_hard_error; } @@ -215,7 +215,7 @@ int dwmac_dma_interrupt(void __iomem *ioaddr, /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */ writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS); - DBG(INFO, "\n\n"); + DWMAC_LIB_DBG(KERN_INFO "\n\n"); return ret; } diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/stmmac/stmmac.h index 5f06c4706abe..2b076b313622 100644 --- a/drivers/net/stmmac/stmmac.h +++ b/drivers/net/stmmac/stmmac.h @@ -21,7 +21,6 @@ *******************************************************************************/ #define DRV_MODULE_VERSION "Nov_2010" -#include #include #include "common.h" diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c index fd719edc7f7c..ae5213a8c4cd 100644 --- a/drivers/net/stmmac/stmmac_ethtool.c +++ b/drivers/net/stmmac/stmmac_ethtool.c @@ -197,13 +197,6 @@ static void stmmac_ethtool_gregs(struct net_device *dev, } } -static u32 stmmac_ethtool_get_rx_csum(struct net_device *dev) -{ - struct stmmac_priv *priv = netdev_priv(dev); - - return priv->rx_coe; -} - static void stmmac_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) @@ -241,20 +234,11 @@ stmmac_set_pauseparam(struct net_device *netdev, new_pause |= FLOW_TX; priv->flow_ctrl = new_pause; + phy->autoneg = pause->autoneg; if (phy->autoneg) { - if (netif_running(netdev)) { - struct ethtool_cmd cmd; - /* auto-negotiation automatically restarted */ - cmd.cmd = ETHTOOL_NWAY_RST; - cmd.supported = phy->supported; - cmd.advertising = phy->advertising; - cmd.autoneg = phy->autoneg; - cmd.speed = phy->speed; - cmd.duplex = phy->duplex; - cmd.phy_address = phy->addr; - ret = phy_ethtool_sset(phy, &cmd); - } + if (netif_running(netdev)) + ret = phy_start_aneg(phy); } else priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex, priv->flow_ctrl, priv->pause); @@ -315,7 +299,7 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) spin_lock_irq(&priv->lock); if (device_can_wakeup(priv->device)) { - wol->supported = WAKE_MAGIC; + wol->supported = WAKE_MAGIC | WAKE_UCAST; wol->wolopts = priv->wolopts; } spin_unlock_irq(&priv->lock); @@ -324,7 +308,7 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct stmmac_priv *priv = netdev_priv(dev); - u32 support = WAKE_MAGIC; + u32 support = WAKE_MAGIC | WAKE_UCAST; if (!device_can_wakeup(priv->device)) return -EINVAL; @@ -358,11 +342,6 @@ static struct ethtool_ops stmmac_ethtool_ops = { .get_regs = stmmac_ethtool_gregs, .get_regs_len = stmmac_ethtool_get_regs_len, .get_link = ethtool_op_get_link, - .get_rx_csum = stmmac_ethtool_get_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, .get_pauseparam = stmmac_get_pauseparam, .set_pauseparam = stmmac_set_pauseparam, .get_ethtool_stats = stmmac_get_ethtool_stats, @@ -370,8 +349,6 @@ static struct ethtool_ops stmmac_ethtool_ops = { .get_wol = stmmac_get_wol, .set_wol = stmmac_set_wol, .get_sset_count = stmmac_get_sset_count, - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, }; void stmmac_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 0e5f03135b50..e15c4a0bb96d 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -116,9 +116,6 @@ static int tc = TC_DEFAULT; module_param(tc, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(tc, "DMA threshold control value"); -#define RX_NO_COALESCE 1 /* Always interrupt on completion */ -#define TX_NO_COALESCE -1 /* No moderation by default */ - /* Pay attention to tune this parameter; take care of both * hardware capability and network stabitily/performance impact. * Many tests showed that ~4ms latency seems to be good enough. */ @@ -139,7 +136,6 @@ static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFDOWN | NETIF_MSG_TIMER); static irqreturn_t stmmac_interrupt(int irq, void *dev_id); -static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev); /** * stmmac_verify_args - verify the driver parameters. @@ -750,7 +746,6 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv) priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); priv->xstats.threshold = tc; } - stmmac_tx_err(priv); } else if (unlikely(status == tx_hard_error)) stmmac_tx_err(priv); } @@ -781,21 +776,6 @@ static int stmmac_open(struct net_device *dev) stmmac_verify_args(); - ret = stmmac_init_phy(dev); - if (unlikely(ret)) { - pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret); - return ret; - } - - /* Request the IRQ lines */ - ret = request_irq(dev->irq, stmmac_interrupt, - IRQF_SHARED, dev->name, dev); - if (unlikely(ret < 0)) { - pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n", - __func__, dev->irq, ret); - return ret; - } - #ifdef CONFIG_STMMAC_TIMER priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL); if (unlikely(priv->tm == NULL)) { @@ -814,6 +794,11 @@ static int stmmac_open(struct net_device *dev) } else priv->tm->enable = 1; #endif + ret = stmmac_init_phy(dev); + if (unlikely(ret)) { + pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret); + goto open_error; + } /* Create and initialize the TX/RX descriptors chains. */ priv->dma_tx_size = STMMAC_ALIGN(dma_txsize); @@ -822,12 +807,11 @@ static int stmmac_open(struct net_device *dev) init_dma_desc_rings(dev); /* DMA initialization and SW reset */ - if (unlikely(priv->hw->dma->init(priv->ioaddr, priv->plat->pbl, - priv->dma_tx_phy, - priv->dma_rx_phy) < 0)) { - + ret = priv->hw->dma->init(priv->ioaddr, priv->plat->pbl, + priv->dma_tx_phy, priv->dma_rx_phy); + if (ret < 0) { pr_err("%s: DMA initialization failed\n", __func__); - return -1; + goto open_error; } /* Copy the MAC addr into the HW */ @@ -843,11 +827,21 @@ static int stmmac_open(struct net_device *dev) pr_info("stmmac: Rx Checksum Offload Engine supported\n"); if (priv->plat->tx_coe) pr_info("\tTX Checksum insertion supported\n"); + netdev_update_features(dev); /* Initialise the MMC (if present) to disable all interrupts. */ writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK); writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK); + /* Request the IRQ lines */ + ret = request_irq(dev->irq, stmmac_interrupt, + IRQF_SHARED, dev->name, dev); + if (unlikely(ret < 0)) { + pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n", + __func__, dev->irq, ret); + goto open_error; + } + /* Enable the MAC Rx/Tx */ stmmac_enable_mac(priv->ioaddr); @@ -878,7 +872,17 @@ static int stmmac_open(struct net_device *dev) napi_enable(&priv->napi); skb_queue_head_init(&priv->rx_recycle); netif_start_queue(dev); + return 0; + +open_error: +#ifdef CONFIG_STMMAC_TIMER + kfree(priv->tm); +#endif + if (priv->phydev) + phy_disconnect(priv->phydev); + + return ret; } /** @@ -927,46 +931,6 @@ static int stmmac_release(struct net_device *dev) return 0; } -/* - * To perform emulated hardware segmentation on skb. - */ -static int stmmac_sw_tso(struct stmmac_priv *priv, struct sk_buff *skb) -{ - struct sk_buff *segs, *curr_skb; - int gso_segs = skb_shinfo(skb)->gso_segs; - - /* Estimate the number of fragments in the worst case */ - if (unlikely(stmmac_tx_avail(priv) < gso_segs)) { - netif_stop_queue(priv->dev); - TX_DBG(KERN_ERR "%s: TSO BUG! Tx Ring full when queue awake\n", - __func__); - if (stmmac_tx_avail(priv) < gso_segs) - return NETDEV_TX_BUSY; - - netif_wake_queue(priv->dev); - } - TX_DBG("\tstmmac_sw_tso: segmenting: skb %p (len %d)\n", - skb, skb->len); - - segs = skb_gso_segment(skb, priv->dev->features & ~NETIF_F_TSO); - if (IS_ERR(segs)) - goto sw_tso_end; - - do { - curr_skb = segs; - segs = segs->next; - TX_DBG("\t\tcurrent skb->len: %d, *curr %p," - "*next %p\n", curr_skb->len, curr_skb, segs); - curr_skb->next = NULL; - stmmac_xmit(curr_skb, priv->dev); - } while (segs); - -sw_tso_end: - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb, struct net_device *dev, int csum_insertion) @@ -1044,16 +1008,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) !skb_is_gso(skb) ? "isn't" : "is"); #endif - if (unlikely(skb_is_gso(skb))) - return stmmac_sw_tso(priv, skb); - - if (likely((skb->ip_summed == CHECKSUM_PARTIAL))) { - if (unlikely((!priv->plat->tx_coe) || - (priv->no_csum_insertion))) - skb_checksum_help(skb); - else - csum_insertion = 1; - } + csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL); desc = priv->dma_tx + entry; first = desc; @@ -1373,18 +1328,29 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } + dev->mtu = new_mtu; + netdev_update_features(dev); + + return 0; +} + +static u32 stmmac_fix_features(struct net_device *dev, u32 features) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + if (!priv->rx_coe) + features &= ~NETIF_F_RXCSUM; + if (!priv->plat->tx_coe) + features &= ~NETIF_F_ALL_CSUM; + /* Some GMAC devices have a bugged Jumbo frame support that * needs to have the Tx COE disabled for oversized frames * (due to limited buffer sizes). In this case we disable * the TX csum insertionin the TDES and not use SF. */ - if ((priv->plat->bugged_jumbo) && (priv->dev->mtu > ETH_DATA_LEN)) - priv->no_csum_insertion = 1; - else - priv->no_csum_insertion = 0; + if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN)) + features &= ~NETIF_F_ALL_CSUM; - dev->mtu = new_mtu; - - return 0; + return features; } static irqreturn_t stmmac_interrupt(int irq, void *dev_id) @@ -1464,6 +1430,7 @@ static const struct net_device_ops stmmac_netdev_ops = { .ndo_start_xmit = stmmac_xmit, .ndo_stop = stmmac_release, .ndo_change_mtu = stmmac_change_mtu, + .ndo_fix_features = stmmac_fix_features, .ndo_set_multicast_list = stmmac_multicast_list, .ndo_tx_timeout = stmmac_tx_timeout, .ndo_do_ioctl = stmmac_ioctl, @@ -1494,8 +1461,8 @@ static int stmmac_probe(struct net_device *dev) dev->netdev_ops = &stmmac_netdev_ops; stmmac_set_ethtool_ops(dev); - dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->features |= dev->hw_features | NETIF_F_HIGHDMA; dev->watchdog_timeo = msecs_to_jiffies(watchdog); #ifdef STMMAC_VLAN_TAG_USED /* Both mac100 and gmac support receive VLAN tag detection */ diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index d3be735c4719..ab5930099267 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -1294,7 +1294,7 @@ static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) autoneg = 1; } else { autoneg = 0; - speed = ep->speed; + speed = ethtool_cmd_speed(ep); duplex = ep->duplex; } @@ -2642,7 +2642,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) /* Return current PHY settings */ spin_lock_irq(&gp->lock); cmd->autoneg = gp->want_autoneg; - cmd->speed = gp->phy_mii.speed; + ethtool_cmd_speed_set(cmd, gp->phy_mii.speed); cmd->duplex = gp->phy_mii.duplex; cmd->advertising = gp->phy_mii.advertising; @@ -2659,7 +2659,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg); cmd->advertising = cmd->supported; - cmd->speed = 0; + ethtool_cmd_speed_set(cmd, 0); cmd->duplex = cmd->port = cmd->phy_address = cmd->transceiver = cmd->autoneg = 0; @@ -2673,7 +2673,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = cmd->supported; cmd->transceiver = XCVR_INTERNAL; if (gp->lstate == link_up) - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); cmd->duplex = DUPLEX_FULL; cmd->autoneg = 1; } @@ -2686,6 +2686,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct gem *gp = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(cmd); /* Verify the settings we care about. */ if (cmd->autoneg != AUTONEG_ENABLE && @@ -2697,9 +2698,9 @@ static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EINVAL; if (cmd->autoneg == AUTONEG_DISABLE && - ((cmd->speed != SPEED_1000 && - cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || + ((speed != SPEED_1000 && + speed != SPEED_100 && + speed != SPEED_10) || (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL))) return -EINVAL; @@ -3146,7 +3147,8 @@ static int __devinit gem_init_one(struct pci_dev *pdev, gp->phy_mii.def ? gp->phy_mii.def->name : "no"); /* GEM can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_LLTX; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= dev->hw_features | NETIF_F_RXCSUM | NETIF_F_LLTX; if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index eb4f59fb01e9..30aad54b1b3a 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -1383,7 +1383,7 @@ static void happy_meal_begin_auto_negotiation(struct happy_meal *hp, if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { hp->sw_bmcr = BMCR_SPEED100; } else { - if (ep->speed == SPEED_100) + if (ethtool_cmd_speed(ep) == SPEED_100) hp->sw_bmcr = BMCR_SPEED100; else hp->sw_bmcr = 0; @@ -2401,6 +2401,7 @@ static void happy_meal_set_multicast(struct net_device *dev) static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct happy_meal *hp = netdev_priv(dev); + u32 speed; cmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@ -2420,10 +2421,9 @@ static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (hp->sw_bmcr & BMCR_ANENABLE) { cmd->autoneg = AUTONEG_ENABLE; - cmd->speed = - (hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ? - SPEED_100 : SPEED_10; - if (cmd->speed == SPEED_100) + speed = ((hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ? + SPEED_100 : SPEED_10); + if (speed == SPEED_100) cmd->duplex = (hp->sw_lpa & (LPA_100FULL)) ? DUPLEX_FULL : DUPLEX_HALF; @@ -2433,13 +2433,12 @@ static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) DUPLEX_FULL : DUPLEX_HALF; } else { cmd->autoneg = AUTONEG_DISABLE; - cmd->speed = - (hp->sw_bmcr & BMCR_SPEED100) ? - SPEED_100 : SPEED_10; + speed = (hp->sw_bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; cmd->duplex = (hp->sw_bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } + ethtool_cmd_speed_set(cmd, speed); return 0; } @@ -2452,8 +2451,8 @@ static int hme_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->autoneg != AUTONEG_DISABLE) return -EINVAL; if (cmd->autoneg == AUTONEG_DISABLE && - ((cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || + ((ethtool_cmd_speed(cmd) != SPEED_100 && + ethtool_cmd_speed(cmd) != SPEED_10) || (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL))) return -EINVAL; @@ -2788,7 +2787,8 @@ static int __devinit happy_meal_sbus_probe_one(struct platform_device *op, int i dev->ethtool_ops = &hme_ethtool_ops; /* Happy Meal can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= dev->hw_features | NETIF_F_RXCSUM; dev->irq = op->archdata.irqs[0]; @@ -3113,7 +3113,8 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, dev->dma = 0; /* Happy Meal can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= dev->hw_features | NETIF_F_RXCSUM; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) /* Hook up PCI register/descriptor accessors. */ @@ -3237,15 +3238,18 @@ static void happy_meal_pci_exit(void) #endif #ifdef CONFIG_SBUS +static const struct of_device_id hme_sbus_match[]; static int __devinit hme_sbus_probe(struct platform_device *op) { + const struct of_device_id *match; struct device_node *dp = op->dev.of_node; const char *model = of_get_property(dp, "model", NULL); int is_qfe; - if (!op->dev.of_match) + match = of_match_device(hme_sbus_match, &op->dev); + if (!match) return -EINVAL; - is_qfe = (op->dev.of_match->data != NULL); + is_qfe = (match->data != NULL); if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) is_qfe = 1; diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 8564ec5cfb7f..80fbee0d40af 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -2017,9 +2017,11 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 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_HW_VLAN_FILTER | NETIF_F_RXCSUM /*| NETIF_F_FRAGLIST */ ; + ndev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_HW_VLAN_TX; if (pci_using_dac) ndev->features |= NETIF_F_HIGHDMA; @@ -2149,7 +2151,7 @@ static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); ecmd->duplex = DUPLEX_FULL; ecmd->port = PORT_FIBRE; ecmd->transceiver = XCVR_EXTERNAL; /* what does it mean? */ @@ -2187,24 +2189,6 @@ bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) drvinfo->eedump_len = 0; } -/* - * bdx_get_rx_csum - report whether receive checksums are turned on or off - * @netdev - */ -static u32 bdx_get_rx_csum(struct net_device *netdev) -{ - return 1; /* always on */ -} - -/* - * bdx_get_tx_csum - report whether transmit checksums are turned on or off - * @netdev - */ -static u32 bdx_get_tx_csum(struct net_device *netdev) -{ - return (netdev->features & NETIF_F_IP_CSUM) != 0; -} - /* * bdx_get_coalesce - get interrupt coalescing parameters * @netdev @@ -2424,10 +2408,6 @@ static void bdx_set_ethtool_ops(struct net_device *netdev) .set_coalesce = bdx_set_coalesce, .get_ringparam = bdx_get_ringparam, .set_ringparam = bdx_set_ringparam, - .get_rx_csum = bdx_get_rx_csum, - .get_tx_csum = bdx_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .get_tso = ethtool_op_get_tso, .get_strings = bdx_get_strings, .get_sset_count = bdx_get_sset_count, .get_ethtool_stats = bdx_get_ethtool_stats, diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b8c5f35577e4..db19332a7d87 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -62,12 +62,36 @@ #include "tg3.h" +/* Functions & macros to verify TG3_FLAGS types */ + +static inline int _tg3_flag(enum TG3_FLAGS flag, unsigned long *bits) +{ + return test_bit(flag, bits); +} + +static inline void _tg3_flag_set(enum TG3_FLAGS flag, unsigned long *bits) +{ + set_bit(flag, bits); +} + +static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) +{ + clear_bit(flag, bits); +} + +#define tg3_flag(tp, flag) \ + _tg3_flag(TG3_FLAG_##flag, (tp)->tg3_flags) +#define tg3_flag_set(tp, flag) \ + _tg3_flag_set(TG3_FLAG_##flag, (tp)->tg3_flags) +#define tg3_flag_clear(tp, flag) \ + _tg3_flag_clear(TG3_FLAG_##flag, (tp)->tg3_flags) + #define DRV_MODULE_NAME "tg3" #define TG3_MAJ_NUM 3 -#define TG3_MIN_NUM 117 +#define TG3_MIN_NUM 119 #define DRV_MODULE_VERSION \ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) -#define DRV_MODULE_RELDATE "January 25, 2011" +#define DRV_MODULE_RELDATE "May 18, 2011" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -85,26 +109,25 @@ /* length of time before we decide the hardware is borked, * and dev->tx_timeout() should be called to fix the problem */ + #define TG3_TX_TIMEOUT (5 * HZ) /* hardware minimum and maximum for a single frame's data payload */ #define TG3_MIN_MTU 60 #define TG3_MAX_MTU(tp) \ - ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) ? 9000 : 1500) + (tg3_flag(tp, JUMBO_CAPABLE) ? 9000 : 1500) /* These numbers seem to be hard coded in the NIC firmware somehow. * You can't change the ring sizes, but you can change where you place * them in the NIC onboard memory. */ #define TG3_RX_STD_RING_SIZE(tp) \ - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || \ - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ? \ - RX_STD_MAX_SIZE_5717 : 512) + (tg3_flag(tp, LRG_PROD_RING_CAP) ? \ + TG3_RX_STD_MAX_SIZE_5717 : TG3_RX_STD_MAX_SIZE_5700) #define TG3_DEF_RX_RING_PENDING 200 #define TG3_RX_JMB_RING_SIZE(tp) \ - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || \ - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ? \ - 1024 : 256) + (tg3_flag(tp, LRG_PROD_RING_CAP) ? \ + TG3_RX_JMB_MAX_SIZE_5717 : TG3_RX_JMB_MAX_SIZE_5700) #define TG3_DEF_RX_JUMBO_RING_PENDING 100 #define TG3_RSS_INDIR_TBL_SIZE 128 @@ -167,11 +190,6 @@ #define TG3_RAW_IP_ALIGN 2 -/* number of ETHTOOL_GSTATS u64's */ -#define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64)) - -#define TG3_NUM_TEST 6 - #define TG3_FW_UPDATE_TIMEOUT_SEC 5 #define FIRMWARE_TG3 "tigon/tg3.bin" @@ -266,6 +284,7 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5719)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5720)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, @@ -280,7 +299,7 @@ MODULE_DEVICE_TABLE(pci, tg3_pci_tbl); static const struct { const char string[ETH_GSTRING_LEN]; -} ethtool_stats_keys[TG3_NUM_STATS] = { +} ethtool_stats_keys[] = { { "rx_octets" }, { "rx_fragments" }, { "rx_ucast_packets" }, @@ -356,12 +375,17 @@ static const struct { { "ring_status_update" }, { "nic_irqs" }, { "nic_avoided_irqs" }, - { "nic_tx_threshold_hit" } + { "nic_tx_threshold_hit" }, + + { "mbuf_lwm_thresh_hit" }, }; +#define TG3_NUM_STATS ARRAY_SIZE(ethtool_stats_keys) + + static const struct { const char string[ETH_GSTRING_LEN]; -} ethtool_test_keys[TG3_NUM_TEST] = { +} ethtool_test_keys[] = { { "nvram test (online) " }, { "link test (online) " }, { "register test (offline)" }, @@ -370,6 +394,9 @@ static const struct { { "interrupt test (offline)" }, }; +#define TG3_NUM_TEST ARRAY_SIZE(ethtool_test_keys) + + static void tg3_write32(struct tg3 *tp, u32 off, u32 val) { writel(val, tp->regs + off); @@ -467,8 +494,7 @@ static u32 tg3_read_indirect_mbox(struct tg3 *tp, u32 off) */ static void _tw32_flush(struct tg3 *tp, u32 off, u32 val, u32 usec_wait) { - if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) || - (tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND)) + if (tg3_flag(tp, PCIX_TARGET_HWBUG) || tg3_flag(tp, ICH_WORKAROUND)) /* Non-posted methods */ tp->write32(tp, off, val); else { @@ -488,8 +514,7 @@ static void _tw32_flush(struct tg3 *tp, u32 off, u32 val, u32 usec_wait) static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val) { tp->write32_mbox(tp, off, val); - if (!(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) && - !(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND)) + if (!tg3_flag(tp, MBOX_WRITE_REORDER) && !tg3_flag(tp, ICH_WORKAROUND)) tp->read32_mbox(tp, off); } @@ -497,9 +522,9 @@ static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val) { void __iomem *mbox = tp->regs + off; writel(val, mbox); - if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) + if (tg3_flag(tp, TXD_MBOX_HWBUG)) writel(val, mbox); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + if (tg3_flag(tp, MBOX_WRITE_REORDER)) readl(mbox); } @@ -528,12 +553,12 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) { unsigned long flags; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) && + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 && (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) return; spin_lock_irqsave(&tp->indirect_lock, flags); - if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { + if (tg3_flag(tp, SRAM_USE_CONFIG)) { pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); @@ -553,14 +578,14 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) { unsigned long flags; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) && + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 && (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) { *val = 0; return; } spin_lock_irqsave(&tp->indirect_lock, flags); - if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { + if (tg3_flag(tp, SRAM_USE_CONFIG)) { pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); @@ -597,7 +622,7 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum) int ret = 0; u32 status, req, gnt; - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) + if (!tg3_flag(tp, ENABLE_APE)) return 0; switch (locknum) { @@ -643,7 +668,7 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum) { u32 gnt; - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) + if (!tg3_flag(tp, ENABLE_APE)) return; switch (locknum) { @@ -687,14 +712,14 @@ static void tg3_enable_ints(struct tg3 *tp) struct tg3_napi *tnapi = &tp->napi[i]; tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); - if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) + if (tg3_flag(tp, 1SHOT_MSI)) tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); tp->coal_now |= tnapi->coal_now; } /* Force an initial interrupt */ - if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && + if (!tg3_flag(tp, TAGGED_STATUS) && (tp->napi[0].hw_status->status & SD_STATUS_UPDATED)) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); else @@ -710,9 +735,7 @@ static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) unsigned int work_exists = 0; /* check for phy events */ - if (!(tp->tg3_flags & - (TG3_FLAG_USE_LINKCHG_REG | - TG3_FLAG_POLL_SERDES))) { + if (!(tg3_flag(tp, USE_LINKCHG_REG) || tg3_flag(tp, POLL_SERDES))) { if (sblk->status & SD_STATUS_LINK_CHG) work_exists = 1; } @@ -740,8 +763,7 @@ static void tg3_int_reenable(struct tg3_napi *tnapi) * The last_tag we write above tells the chip which piece of * work we've completed. */ - if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && - tg3_has_work(tnapi)) + if (!tg3_flag(tp, TAGGED_STATUS) && tg3_has_work(tnapi)) tw32(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | tnapi->coal_now); } @@ -751,8 +773,7 @@ static void tg3_switch_clocks(struct tg3 *tp) u32 clock_ctrl; u32 orig_clock_ctrl; - if ((tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + if (tg3_flag(tp, CPMU_PRESENT) || tg3_flag(tp, 5780_CLASS)) return; clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); @@ -763,7 +784,7 @@ static void tg3_switch_clocks(struct tg3 *tp) 0x1f); tp->pci_clock_ctrl = clock_ctrl; - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if (tg3_flag(tp, 5705_PLUS)) { if (orig_clock_ctrl & CLOCK_CTRL_625_CORE) { tw32_wait_f(TG3PCI_CLOCK_CTRL, clock_ctrl | CLOCK_CTRL_625_CORE, 40); @@ -880,6 +901,104 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val) return ret; } +static int tg3_phy_cl45_write(struct tg3 *tp, u32 devad, u32 addr, u32 val) +{ + int err; + + err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad); + if (err) + goto done; + + err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr); + if (err) + goto done; + + err = tg3_writephy(tp, MII_TG3_MMD_CTRL, + MII_TG3_MMD_CTRL_DATA_NOINC | devad); + if (err) + goto done; + + err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, val); + +done: + return err; +} + +static int tg3_phy_cl45_read(struct tg3 *tp, u32 devad, u32 addr, u32 *val) +{ + int err; + + err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad); + if (err) + goto done; + + err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr); + if (err) + goto done; + + err = tg3_writephy(tp, MII_TG3_MMD_CTRL, + MII_TG3_MMD_CTRL_DATA_NOINC | devad); + if (err) + goto done; + + err = tg3_readphy(tp, MII_TG3_MMD_ADDRESS, val); + +done: + return err; +} + +static int tg3_phydsp_read(struct tg3 *tp, u32 reg, u32 *val) +{ + int err; + + err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); + if (!err) + err = tg3_readphy(tp, MII_TG3_DSP_RW_PORT, val); + + return err; +} + +static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) +{ + int err; + + err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); + if (!err) + err = tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val); + + return err; +} + +static int tg3_phy_auxctl_read(struct tg3 *tp, int reg, u32 *val) +{ + int err; + + err = tg3_writephy(tp, MII_TG3_AUX_CTRL, + (reg << MII_TG3_AUXCTL_MISC_RDSEL_SHIFT) | + MII_TG3_AUXCTL_SHDWSEL_MISC); + if (!err) + err = tg3_readphy(tp, MII_TG3_AUX_CTRL, val); + + return err; +} + +static int tg3_phy_auxctl_write(struct tg3 *tp, int reg, u32 set) +{ + if (reg == MII_TG3_AUXCTL_SHDWSEL_MISC) + set |= MII_TG3_AUXCTL_MISC_WREN; + + return tg3_writephy(tp, MII_TG3_AUX_CTRL, set | reg); +} + +#define TG3_PHY_AUXCTL_SMDSP_ENABLE(tp) \ + tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \ + MII_TG3_AUXCTL_ACTL_SMDSP_ENA | \ + MII_TG3_AUXCTL_ACTL_TX_6DB) + +#define TG3_PHY_AUXCTL_SMDSP_DISABLE(tp) \ + tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \ + MII_TG3_AUXCTL_ACTL_TX_6DB); + static int tg3_bmcr_reset(struct tg3 *tp) { u32 phy_control; @@ -982,7 +1101,7 @@ static void tg3_mdio_config_5785(struct tg3 *tp) return; } - if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) + if (!tg3_flag(tp, RGMII_INBAND_DISABLE)) val |= MAC_PHYCFG2_EMODE_MASK_MASK | MAC_PHYCFG2_FMODE_MASK_MASK | MAC_PHYCFG2_GMODE_MASK_MASK | @@ -995,10 +1114,10 @@ static void tg3_mdio_config_5785(struct tg3 *tp) val = tr32(MAC_PHYCFG1); val &= ~(MAC_PHYCFG1_RXCLK_TO_MASK | MAC_PHYCFG1_TXCLK_TO_MASK | MAC_PHYCFG1_RGMII_EXT_RX_DEC | MAC_PHYCFG1_RGMII_SND_STAT_EN); - if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) { - if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) + if (!tg3_flag(tp, RGMII_INBAND_DISABLE)) { + if (tg3_flag(tp, RGMII_EXT_IBND_RX_EN)) val |= MAC_PHYCFG1_RGMII_EXT_RX_DEC; - if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) + if (tg3_flag(tp, RGMII_EXT_IBND_TX_EN)) val |= MAC_PHYCFG1_RGMII_SND_STAT_EN; } val |= MAC_PHYCFG1_RXCLK_TIMEOUT | MAC_PHYCFG1_TXCLK_TIMEOUT | @@ -1013,13 +1132,13 @@ static void tg3_mdio_config_5785(struct tg3 *tp) MAC_RGMII_MODE_TX_ENABLE | MAC_RGMII_MODE_TX_LOWPWR | MAC_RGMII_MODE_TX_RESET); - if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) { - if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) + if (!tg3_flag(tp, RGMII_INBAND_DISABLE)) { + if (tg3_flag(tp, RGMII_EXT_IBND_RX_EN)) val |= MAC_RGMII_MODE_RX_INT_B | MAC_RGMII_MODE_RX_QUALITY | MAC_RGMII_MODE_RX_ACTIVITY | MAC_RGMII_MODE_RX_ENG_DET; - if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) + if (tg3_flag(tp, RGMII_EXT_IBND_TX_EN)) val |= MAC_RGMII_MODE_TX_ENABLE | MAC_RGMII_MODE_TX_LOWPWR | MAC_RGMII_MODE_TX_RESET; @@ -1033,7 +1152,7 @@ static void tg3_mdio_start(struct tg3 *tp) tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(80); - if ((tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) && + if (tg3_flag(tp, MDIOBUS_INITED) && GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) tg3_mdio_config_5785(tp); } @@ -1044,8 +1163,7 @@ static int tg3_mdio_init(struct tg3 *tp) u32 reg; struct phy_device *phydev; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + if (tg3_flag(tp, 5717_PLUS)) { u32 is_serdes; tp->phy_addr = PCI_FUNC(tp->pdev->devfn) + 1; @@ -1062,8 +1180,7 @@ static int tg3_mdio_init(struct tg3 *tp) tg3_mdio_start(tp); - if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) || - (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED)) + if (!tg3_flag(tp, USE_PHYLIB) || tg3_flag(tp, MDIOBUS_INITED)) return 0; tp->mdio_bus = mdiobus_alloc(); @@ -1119,11 +1236,11 @@ static int tg3_mdio_init(struct tg3 *tp) PHY_BRCM_RX_REFCLK_UNUSED | PHY_BRCM_DIS_TXCRXC_NOENRGY | PHY_BRCM_AUTO_PWRDWN_ENABLE; - if (tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE) + if (tg3_flag(tp, RGMII_INBAND_DISABLE)) phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE; - if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) + if (tg3_flag(tp, RGMII_EXT_IBND_RX_EN)) phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE; - if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) + if (tg3_flag(tp, RGMII_EXT_IBND_TX_EN)) phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE; /* fallthru */ case PHY_ID_RTL8211C: @@ -1137,7 +1254,7 @@ static int tg3_mdio_init(struct tg3 *tp) break; } - tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; + tg3_flag_set(tp, MDIOBUS_INITED); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) tg3_mdio_config_5785(tp); @@ -1147,59 +1264,13 @@ static int tg3_mdio_init(struct tg3 *tp) static void tg3_mdio_fini(struct tg3 *tp) { - if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { - tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED; + if (tg3_flag(tp, MDIOBUS_INITED)) { + tg3_flag_clear(tp, MDIOBUS_INITED); mdiobus_unregister(tp->mdio_bus); mdiobus_free(tp->mdio_bus); } } -static int tg3_phy_cl45_write(struct tg3 *tp, u32 devad, u32 addr, u32 val) -{ - int err; - - err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad); - if (err) - goto done; - - err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr); - if (err) - goto done; - - err = tg3_writephy(tp, MII_TG3_MMD_CTRL, - MII_TG3_MMD_CTRL_DATA_NOINC | devad); - if (err) - goto done; - - err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, val); - -done: - return err; -} - -static int tg3_phy_cl45_read(struct tg3 *tp, u32 devad, u32 addr, u32 *val) -{ - int err; - - err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad); - if (err) - goto done; - - err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr); - if (err) - goto done; - - err = tg3_writephy(tp, MII_TG3_MMD_CTRL, - MII_TG3_MMD_CTRL_DATA_NOINC | devad); - if (err) - goto done; - - err = tg3_readphy(tp, MII_TG3_MMD_ADDRESS, val); - -done: - return err; -} - /* tp->lock is held. */ static inline void tg3_generate_fw_event(struct tg3 *tp) { @@ -1247,8 +1318,7 @@ static void tg3_ump_link_report(struct tg3 *tp) u32 reg; u32 val; - if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (!tg3_flag(tp, 5780_CLASS) || !tg3_flag(tp, ENABLE_ASF)) return; tg3_wait_for_event_ack(tp); @@ -1308,6 +1378,11 @@ static void tg3_link_report(struct tg3 *tp) "on" : "off", (tp->link_config.active_flowctrl & FLOW_CTRL_RX) ? "on" : "off"); + + if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) + netdev_info(tp->dev, "EEE is %s\n", + tp->setlpicnt ? "enabled" : "disabled"); + tg3_ump_link_report(tp); } } @@ -1373,13 +1448,12 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) u32 old_rx_mode = tp->rx_mode; u32 old_tx_mode = tp->tx_mode; - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) + if (tg3_flag(tp, USE_PHYLIB)) autoneg = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]->autoneg; else autoneg = tp->link_config.autoneg; - if (autoneg == AUTONEG_ENABLE && - (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { + if (autoneg == AUTONEG_ENABLE && tg3_flag(tp, PAUSE_AUTONEG)) { if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES) flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); else @@ -1576,28 +1650,6 @@ static void tg3_phy_fini(struct tg3 *tp) } } -static int tg3_phydsp_read(struct tg3 *tp, u32 reg, u32 *val) -{ - int err; - - err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); - if (!err) - err = tg3_readphy(tp, MII_TG3_DSP_RW_PORT, val); - - return err; -} - -static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) -{ - int err; - - err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); - if (!err) - err = tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val); - - return err; -} - static void tg3_phy_fet_toggle_apd(struct tg3 *tp, bool enable) { u32 phytest; @@ -1622,9 +1674,8 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable) { u32 reg; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) && + if (!tg3_flag(tp, 5705_PLUS) || + (tg3_flag(tp, 5717_PLUS) && (tp->phy_flags & TG3_PHYFLG_MII_SERDES))) return; @@ -1658,7 +1709,7 @@ static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) { u32 phy; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || + if (!tg3_flag(tp, 5705_PLUS) || (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) return; @@ -1680,31 +1731,33 @@ static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) tg3_writephy(tp, MII_TG3_FET_TEST, ephy); } } else { - phy = MII_TG3_AUXCTL_MISC_RDSEL_MISC | - MII_TG3_AUXCTL_SHDWSEL_MISC; - if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, phy) && - !tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy)) { + int ret; + + ret = tg3_phy_auxctl_read(tp, + MII_TG3_AUXCTL_SHDWSEL_MISC, &phy); + if (!ret) { if (enable) phy |= MII_TG3_AUXCTL_MISC_FORCE_AMDIX; else phy &= ~MII_TG3_AUXCTL_MISC_FORCE_AMDIX; - phy |= MII_TG3_AUXCTL_MISC_WREN; - tg3_writephy(tp, MII_TG3_AUX_CTRL, phy); + tg3_phy_auxctl_write(tp, + MII_TG3_AUXCTL_SHDWSEL_MISC, phy); } } } static void tg3_phy_set_wirespeed(struct tg3 *tp) { + int ret; u32 val; if (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED) return; - if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007) && - !tg3_readphy(tp, MII_TG3_AUX_CTRL, &val)) - tg3_writephy(tp, MII_TG3_AUX_CTRL, - (val | (1 << 15) | (1 << 4))); + ret = tg3_phy_auxctl_read(tp, MII_TG3_AUXCTL_SHDWSEL_MISC, &val); + if (!ret) + tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_MISC, + val | MII_TG3_AUXCTL_MISC_WIRESPD_EN); } static void tg3_phy_apply_otp(struct tg3 *tp) @@ -1716,11 +1769,8 @@ static void tg3_phy_apply_otp(struct tg3 *tp) otp = tp->phy_otp; - /* Enable SM_DSP clock and tx 6dB coding. */ - phy = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | - MII_TG3_AUXCTL_ACTL_SMDSP_ENA | - MII_TG3_AUXCTL_ACTL_TX_6DB; - tg3_writephy(tp, MII_TG3_AUX_CTRL, phy); + if (TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) + return; phy = ((otp & TG3_OTP_AGCTGT_MASK) >> TG3_OTP_AGCTGT_SHIFT); phy |= MII_TG3_DSP_TAP1_AGCTGT_DFLT; @@ -1744,10 +1794,7 @@ static void tg3_phy_apply_otp(struct tg3 *tp) ((otp & TG3_OTP_RCOFF_MASK) >> TG3_OTP_RCOFF_SHIFT); tg3_phydsp_write(tp, MII_TG3_DSP_EXP97, phy); - /* Turn off SM_DSP clock. */ - phy = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | - MII_TG3_AUXCTL_ACTL_TX_6DB; - tg3_writephy(tp, MII_TG3_AUX_CTRL, phy); + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); } static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) @@ -1776,29 +1823,9 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) tg3_phy_cl45_read(tp, MDIO_MMD_AN, TG3_CL45_D7_EEERES_STAT, &val); - switch (val) { - case TG3_CL45_D7_EEERES_STAT_LP_1000T: - switch (GET_ASIC_REV(tp->pci_chip_rev_id)) { - case ASIC_REV_5717: - case ASIC_REV_5719: - case ASIC_REV_57765: - /* Enable SM_DSP clock and tx 6dB coding. */ - val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | - MII_TG3_AUXCTL_ACTL_SMDSP_ENA | - MII_TG3_AUXCTL_ACTL_TX_6DB; - tg3_writephy(tp, MII_TG3_AUX_CTRL, val); - - tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0000); - - /* Turn off SM_DSP clock. */ - val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | - MII_TG3_AUXCTL_ACTL_TX_6DB; - tg3_writephy(tp, MII_TG3_AUX_CTRL, val); - } - /* Fallthrough */ - case TG3_CL45_D7_EEERES_STAT_LP_100TX: + if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T || + val == TG3_CL45_D7_EEERES_STAT_LP_100TX) tp->setlpicnt = 2; - } } if (!tp->setlpicnt) { @@ -1807,6 +1834,23 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) } } +static void tg3_phy_eee_enable(struct tg3 *tp) +{ + u32 val; + + if (tp->link_config.active_speed == SPEED_1000 && + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) && + !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { + tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0003); + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + } + + val = tr32(TG3_CPMU_EEE_MODE); + tw32(TG3_CPMU_EEE_MODE, val | TG3_CPMU_EEEMD_LPI_ENABLE); +} + static int tg3_wait_macro_done(struct tg3 *tp) { int limit = 100; @@ -1945,8 +1989,9 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp) (MII_TG3_CTRL_AS_MASTER | MII_TG3_CTRL_ENABLE_AS_MASTER)); - /* Enable SM_DSP_CLOCK and 6dB. */ - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); + err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp); + if (err) + return err; /* Block the PHY control access. */ tg3_phydsp_write(tp, 0x8005, 0x0800); @@ -1965,13 +2010,7 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp) tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200); tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0000); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { - /* Set Extended packet length bit for jumbo frames */ - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4400); - } else { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); - } + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); tg3_writephy(tp, MII_TG3_CTRL, phy9_orig); @@ -2047,8 +2086,7 @@ static int tg3_phy_reset(struct tg3 *tp) } } - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) && + if (tg3_flag(tp, 5717_PLUS) && (tp->phy_flags & TG3_PHYFLG_MII_SERDES)) return 0; @@ -2060,49 +2098,57 @@ static int tg3_phy_reset(struct tg3 *tp) tg3_phy_toggle_apd(tp, false); out: - if (tp->phy_flags & TG3_PHYFLG_ADC_BUG) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); + if ((tp->phy_flags & TG3_PHYFLG_ADC_BUG) && + !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { tg3_phydsp_write(tp, 0x201f, 0x2aaa); tg3_phydsp_write(tp, 0x000a, 0x0323); - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); } + if (tp->phy_flags & TG3_PHYFLG_5704_A0_BUG) { tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68); tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68); } + if (tp->phy_flags & TG3_PHYFLG_BER_BUG) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); - tg3_phydsp_write(tp, 0x000a, 0x310b); - tg3_phydsp_write(tp, 0x201f, 0x9506); - tg3_phydsp_write(tp, 0x401f, 0x14e2); - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); + if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { + tg3_phydsp_write(tp, 0x000a, 0x310b); + tg3_phydsp_write(tp, 0x201f, 0x9506); + tg3_phydsp_write(tp, 0x401f, 0x14e2); + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + } } else if (tp->phy_flags & TG3_PHYFLG_JITTER_BUG) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); - tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a); - if (tp->phy_flags & TG3_PHYFLG_ADJUST_TRIM) { - tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b); - tg3_writephy(tp, MII_TG3_TEST1, - MII_TG3_TEST1_TRIM_EN | 0x4); - } else - tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b); - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); + if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { + tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a); + if (tp->phy_flags & TG3_PHYFLG_ADJUST_TRIM) { + tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b); + tg3_writephy(tp, MII_TG3_TEST1, + MII_TG3_TEST1_TRIM_EN | 0x4); + } else + tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b); + + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + } } + /* Set Extended packet length bit (bit 14) on all chips that */ /* support jumbo frames */ if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) { /* Cannot do read-modify-write on 5401 */ - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20); - } else if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { + tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, 0x4c20); + } else if (tg3_flag(tp, JUMBO_CAPABLE)) { /* Set bit 14 with read-modify-write to preserve other bits */ - if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0007) && - !tg3_readphy(tp, MII_TG3_AUX_CTRL, &val)) - tg3_writephy(tp, MII_TG3_AUX_CTRL, val | 0x4000); + err = tg3_phy_auxctl_read(tp, + MII_TG3_AUXCTL_SHDWSEL_AUXCTL, &val); + if (!err) + tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, + val | MII_TG3_AUXCTL_ACTL_EXTPKTLEN); } /* Set phy register 0x10 bit 0 to high fifo elasticity to support * jumbo frames transmission. */ - if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { + if (tg3_flag(tp, JUMBO_CAPABLE)) { if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &val)) tg3_writephy(tp, MII_TG3_EXT_CTRL, val | MII_TG3_EXT_CTRL_FIFO_ELASTIC); @@ -2123,14 +2169,15 @@ static void tg3_frob_aux_power(struct tg3 *tp) bool need_vaux = false; /* The GPIOs do something completely different on 57765. */ - if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0 || + if (!tg3_flag(tp, IS_NIC) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) return; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) && + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) && tp->pdev_peer != tp->pdev) { struct net_device *dev_peer; @@ -2140,17 +2187,16 @@ static void tg3_frob_aux_power(struct tg3 *tp) if (dev_peer) { struct tg3 *tp_peer = netdev_priv(dev_peer); - if (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) + if (tg3_flag(tp_peer, INIT_COMPLETE)) return; - if ((tp_peer->tg3_flags & TG3_FLAG_WOL_ENABLE) || - (tp_peer->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (tg3_flag(tp_peer, WOL_ENABLE) || + tg3_flag(tp_peer, ENABLE_ASF)) need_vaux = true; } } - if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) || - (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (tg3_flag(tp, WOL_ENABLE) || tg3_flag(tp, ENABLE_ASF)) need_vaux = true; if (need_vaux) { @@ -2304,11 +2350,10 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power) tg3_writephy(tp, MII_TG3_EXT_CTRL, MII_TG3_EXT_CTRL_FORCE_LED_OFF); - tg3_writephy(tp, MII_TG3_AUX_CTRL, - MII_TG3_AUXCTL_SHDWSEL_PWRCTL | - MII_TG3_AUXCTL_PCTL_100TX_LPWR | - MII_TG3_AUXCTL_PCTL_SPR_ISOLATE | - MII_TG3_AUXCTL_PCTL_VREG_11V); + val = MII_TG3_AUXCTL_PCTL_100TX_LPWR | + MII_TG3_AUXCTL_PCTL_SPR_ISOLATE | + MII_TG3_AUXCTL_PCTL_VREG_11V; + tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_PWRCTL, val); } /* The PHY should not be powered down on some chips because @@ -2334,7 +2379,7 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power) /* tp->lock is held. */ static int tg3_nvram_lock(struct tg3 *tp) { - if (tp->tg3_flags & TG3_FLAG_NVRAM) { + if (tg3_flag(tp, NVRAM)) { int i; if (tp->nvram_lock_cnt == 0) { @@ -2357,7 +2402,7 @@ static int tg3_nvram_lock(struct tg3 *tp) /* tp->lock is held. */ static void tg3_nvram_unlock(struct tg3 *tp) { - if (tp->tg3_flags & TG3_FLAG_NVRAM) { + if (tg3_flag(tp, NVRAM)) { if (tp->nvram_lock_cnt > 0) tp->nvram_lock_cnt--; if (tp->nvram_lock_cnt == 0) @@ -2368,8 +2413,7 @@ static void tg3_nvram_unlock(struct tg3 *tp) /* tp->lock is held. */ static void tg3_enable_nvram_access(struct tg3 *tp) { - if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && - !(tp->tg3_flags3 & TG3_FLG3_PROTECTED_NVRAM)) { + if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM)) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); @@ -2379,8 +2423,7 @@ static void tg3_enable_nvram_access(struct tg3 *tp) /* tp->lock is held. */ static void tg3_disable_nvram_access(struct tg3 *tp) { - if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && - !(tp->tg3_flags3 & TG3_FLG3_PROTECTED_NVRAM)) { + if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM)) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); @@ -2450,10 +2493,10 @@ static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd) static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr) { - if ((tp->tg3_flags & TG3_FLAG_NVRAM) && - (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && - (tp->tg3_flags2 & TG3_FLG2_FLASH) && - !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) && + if (tg3_flag(tp, NVRAM) && + tg3_flag(tp, NVRAM_BUFFERED) && + tg3_flag(tp, FLASH) && + !tg3_flag(tp, NO_NVRAM_ADDR_TRANS) && (tp->nvram_jedecnum == JEDEC_ATMEL)) addr = ((addr / tp->nvram_pagesize) << @@ -2465,10 +2508,10 @@ static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr) static u32 tg3_nvram_logical_addr(struct tg3 *tp, u32 addr) { - if ((tp->tg3_flags & TG3_FLAG_NVRAM) && - (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && - (tp->tg3_flags2 & TG3_FLG2_FLASH) && - !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) && + if (tg3_flag(tp, NVRAM) && + tg3_flag(tp, NVRAM_BUFFERED) && + tg3_flag(tp, FLASH) && + !tg3_flag(tp, NO_NVRAM_ADDR_TRANS) && (tp->nvram_jedecnum == JEDEC_ATMEL)) addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) * @@ -2488,7 +2531,7 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) { int ret; - if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) + if (!tg3_flag(tp, NVRAM)) return tg3_nvram_read_using_eeprom(tp, offset, val); offset = tg3_nvram_phys_addr(tp, offset); @@ -2580,7 +2623,7 @@ static int tg3_power_up(struct tg3 *tp) pci_set_power_state(tp->pdev, PCI_D0); /* Switch out of Vaux if it is a NIC */ - if (tp->tg3_flags2 & TG3_FLG2_IS_NIC) + if (tg3_flag(tp, IS_NIC)) tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl, 100); return 0; @@ -2594,7 +2637,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) tg3_enable_register_access(tp); /* Restore the CLKREQ setting. */ - if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) { + if (tg3_flag(tp, CLKREQ_BUG)) { u16 lnkctl; pci_read_config_word(tp->pdev, @@ -2611,9 +2654,9 @@ static int tg3_power_down_prepare(struct tg3 *tp) misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); device_should_wake = device_may_wakeup(&tp->pdev->dev) && - (tp->tg3_flags & TG3_FLAG_WOL_ENABLE); + tg3_flag(tp, WOL_ENABLE); - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { do_low_power = false; if ((tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) && !(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) { @@ -2634,9 +2677,8 @@ static int tg3_power_down_prepare(struct tg3 *tp) ADVERTISED_Autoneg | ADVERTISED_10baseT_Half; - if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || - device_should_wake) { - if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) + if (tg3_flag(tp, ENABLE_ASF) || device_should_wake) { + if (tg3_flag(tp, WOL_SPEED_100MB)) advertising |= ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | @@ -2681,7 +2723,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) val = tr32(GRC_VCPU_EXT_CTRL); tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_DISABLE_WOL); - } else if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { + } else if (!tg3_flag(tp, ENABLE_ASF)) { int i; u32 val; @@ -2692,7 +2734,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) msleep(1); } } - if (tp->tg3_flags & TG3_FLAG_WOL_CAP) + if (tg3_flag(tp, WOL_CAP)) tg3_write_mem(tp, NIC_SRAM_WOL_MBOX, WOL_SIGNATURE | WOL_DRV_STATE_SHUTDOWN | WOL_DRV_WOL | @@ -2702,8 +2744,13 @@ static int tg3_power_down_prepare(struct tg3 *tp) u32 mac_mode; if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) { - if (do_low_power) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); + if (do_low_power && + !(tp->phy_flags & TG3_PHYFLG_IS_FET)) { + tg3_phy_auxctl_write(tp, + MII_TG3_AUXCTL_SHDWSEL_PWRCTL, + MII_TG3_AUXCTL_PCTL_WOL_EN | + MII_TG3_AUXCTL_PCTL_100TX_LPWR | + MII_TG3_AUXCTL_PCTL_CL_AB_TXDAC); udelay(40); } @@ -2715,8 +2762,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) mac_mode |= tp->mac_mode & MAC_MODE_LINK_POLARITY; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) { - u32 speed = (tp->tg3_flags & - TG3_FLAG_WOL_SPEED_100MB) ? + u32 speed = tg3_flag(tp, WOL_SPEED_100MB) ? SPEED_100 : SPEED_10; if (tg3_5700_link_polarity(tp, speed)) mac_mode |= MAC_MODE_LINK_POLARITY; @@ -2727,17 +2773,15 @@ static int tg3_power_down_prepare(struct tg3 *tp) mac_mode = MAC_MODE_PORT_MODE_TBI; } - if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) + if (!tg3_flag(tp, 5750_PLUS)) tw32(MAC_LED_CTRL, tp->led_ctrl); mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE; - if (((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) && - ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || - (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))) + if ((tg3_flag(tp, 5705_PLUS) && !tg3_flag(tp, 5780_CLASS)) && + (tg3_flag(tp, ENABLE_ASF) || tg3_flag(tp, ENABLE_APE))) mac_mode |= MAC_MODE_KEEP_FRAME_IN_WOL; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) mac_mode |= MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN | MAC_MODE_TDE_ENABLE; @@ -2749,7 +2793,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) udelay(10); } - if (!(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) && + if (!tg3_flag(tp, WOL_SPEED_100MB) && (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { u32 base_val; @@ -2760,12 +2804,11 @@ static int tg3_power_down_prepare(struct tg3 *tp) tw32_wait_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK | CLOCK_CTRL_PWRDOWN_PLL133, 40); - } else if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || - (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)) { + } else if (tg3_flag(tp, 5780_CLASS) || + tg3_flag(tp, CPMU_PRESENT) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { /* do nothing */ - } else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && - (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) { + } else if (!(tg3_flag(tp, 5750_PLUS) && tg3_flag(tp, ENABLE_ASF))) { u32 newbits1, newbits2; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || @@ -2774,7 +2817,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) CLOCK_CTRL_TXCLK_DISABLE | CLOCK_CTRL_ALTCLK); newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE; - } else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + } else if (tg3_flag(tp, 5705_PLUS)) { newbits1 = CLOCK_CTRL_625_CORE; newbits2 = newbits1 | CLOCK_CTRL_ALTCLK; } else { @@ -2788,7 +2831,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) tw32_wait_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits2, 40); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { u32 newbits3; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || @@ -2805,8 +2848,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) } } - if (!(device_should_wake) && - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (!(device_should_wake) && !tg3_flag(tp, ENABLE_ASF)) tg3_power_down_phy(tp, do_low_power); tg3_frob_aux_power(tp); @@ -2818,7 +2860,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1); tw32(0x7d00, val); - if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { + if (!tg3_flag(tp, ENABLE_ASF)) { int err; err = tg3_nvram_lock(tp); @@ -2837,7 +2879,7 @@ static void tg3_power_down(struct tg3 *tp) { tg3_power_down_prepare(tp); - pci_wake_from_d3(tp->pdev, tp->tg3_flags & TG3_FLAG_WOL_ENABLE); + pci_wake_from_d3(tp->pdev, tg3_flag(tp, WOL_ENABLE)); pci_set_power_state(tp->pdev, PCI_D3hot); } @@ -2888,106 +2930,54 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 } } -static void tg3_phy_copper_begin(struct tg3 *tp) +static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl) { - u32 new_adv; - int i; + int err = 0; + u32 val, new_adv; - if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) { - /* Entering low power mode. Disable gigabit and - * 100baseT advertisements. - */ - tg3_writephy(tp, MII_TG3_CTRL, 0); + new_adv = ADVERTISE_CSMA; + if (advertise & ADVERTISED_10baseT_Half) + new_adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + new_adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + new_adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + new_adv |= ADVERTISE_100FULL; - new_adv = (ADVERTISE_10HALF | ADVERTISE_10FULL | - ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) - new_adv |= (ADVERTISE_100HALF | ADVERTISE_100FULL); + new_adv |= tg3_advert_flowctrl_1000T(flowctrl); - tg3_writephy(tp, MII_ADVERTISE, new_adv); - } else if (tp->link_config.speed == SPEED_INVALID) { - if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) - tp->link_config.advertising &= - ~(ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full); + err = tg3_writephy(tp, MII_ADVERTISE, new_adv); + if (err) + goto done; - new_adv = ADVERTISE_CSMA; - if (tp->link_config.advertising & ADVERTISED_10baseT_Half) - new_adv |= ADVERTISE_10HALF; - if (tp->link_config.advertising & ADVERTISED_10baseT_Full) - new_adv |= ADVERTISE_10FULL; - if (tp->link_config.advertising & ADVERTISED_100baseT_Half) - new_adv |= ADVERTISE_100HALF; - if (tp->link_config.advertising & ADVERTISED_100baseT_Full) - new_adv |= ADVERTISE_100FULL; + if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) + goto done; - new_adv |= tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); + new_adv = 0; + if (advertise & ADVERTISED_1000baseT_Half) + new_adv |= MII_TG3_CTRL_ADV_1000_HALF; + if (advertise & ADVERTISED_1000baseT_Full) + new_adv |= MII_TG3_CTRL_ADV_1000_FULL; - tg3_writephy(tp, MII_ADVERTISE, new_adv); + if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) + new_adv |= (MII_TG3_CTRL_AS_MASTER | + MII_TG3_CTRL_ENABLE_AS_MASTER); - if (tp->link_config.advertising & - (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) { - new_adv = 0; - if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) - new_adv |= MII_TG3_CTRL_ADV_1000_HALF; - if (tp->link_config.advertising & ADVERTISED_1000baseT_Full) - new_adv |= MII_TG3_CTRL_ADV_1000_FULL; - if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY) && - (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) - new_adv |= (MII_TG3_CTRL_AS_MASTER | - MII_TG3_CTRL_ENABLE_AS_MASTER); - tg3_writephy(tp, MII_TG3_CTRL, new_adv); - } else { - tg3_writephy(tp, MII_TG3_CTRL, 0); - } - } else { - new_adv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); - new_adv |= ADVERTISE_CSMA; + err = tg3_writephy(tp, MII_TG3_CTRL, new_adv); + if (err) + goto done; - /* Asking for a specific link mode. */ - if (tp->link_config.speed == SPEED_1000) { - tg3_writephy(tp, MII_ADVERTISE, new_adv); + if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) + goto done; - if (tp->link_config.duplex == DUPLEX_FULL) - new_adv = MII_TG3_CTRL_ADV_1000_FULL; - else - new_adv = MII_TG3_CTRL_ADV_1000_HALF; - if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) - new_adv |= (MII_TG3_CTRL_AS_MASTER | - MII_TG3_CTRL_ENABLE_AS_MASTER); - } else { - if (tp->link_config.speed == SPEED_100) { - if (tp->link_config.duplex == DUPLEX_FULL) - new_adv |= ADVERTISE_100FULL; - else - new_adv |= ADVERTISE_100HALF; - } else { - if (tp->link_config.duplex == DUPLEX_FULL) - new_adv |= ADVERTISE_10FULL; - else - new_adv |= ADVERTISE_10HALF; - } - tg3_writephy(tp, MII_ADVERTISE, new_adv); + tw32(TG3_CPMU_EEE_MODE, + tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE); - new_adv = 0; - } - - tg3_writephy(tp, MII_TG3_CTRL, new_adv); - } - - if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) { - u32 val; - - tw32(TG3_CPMU_EEE_MODE, - tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE); - - /* Enable SM_DSP clock and tx 6dB coding. */ - val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | - MII_TG3_AUXCTL_ACTL_SMDSP_ENA | - MII_TG3_AUXCTL_ACTL_TX_6DB; - tg3_writephy(tp, MII_TG3_AUX_CTRL, val); + err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp); + if (!err) { + u32 err2; switch (GET_ASIC_REV(tp->pci_chip_rev_id)) { case ASIC_REV_5717: @@ -3004,22 +2994,66 @@ static void tg3_phy_copper_begin(struct tg3 *tp) } val = 0; - if (tp->link_config.autoneg == AUTONEG_ENABLE) { - /* Advertise 100-BaseTX EEE ability */ - if (tp->link_config.advertising & - ADVERTISED_100baseT_Full) - val |= MDIO_AN_EEE_ADV_100TX; - /* Advertise 1000-BaseT EEE ability */ - if (tp->link_config.advertising & - ADVERTISED_1000baseT_Full) - val |= MDIO_AN_EEE_ADV_1000T; - } - tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val); + /* Advertise 100-BaseTX EEE ability */ + if (advertise & ADVERTISED_100baseT_Full) + val |= MDIO_AN_EEE_ADV_100TX; + /* Advertise 1000-BaseT EEE ability */ + if (advertise & ADVERTISED_1000baseT_Full) + val |= MDIO_AN_EEE_ADV_1000T; + err = tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val); - /* Turn off SM_DSP clock. */ - val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | - MII_TG3_AUXCTL_ACTL_TX_6DB; - tg3_writephy(tp, MII_TG3_AUX_CTRL, val); + err2 = TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + if (!err) + err = err2; + } + +done: + return err; +} + +static void tg3_phy_copper_begin(struct tg3 *tp) +{ + u32 new_adv; + int i; + + if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) { + new_adv = ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full; + if (tg3_flag(tp, WOL_SPEED_100MB)) + new_adv |= ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full; + + tg3_phy_autoneg_cfg(tp, new_adv, + FLOW_CTRL_TX | FLOW_CTRL_RX); + } else if (tp->link_config.speed == SPEED_INVALID) { + if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) + tp->link_config.advertising &= + ~(ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full); + + tg3_phy_autoneg_cfg(tp, tp->link_config.advertising, + tp->link_config.flowctrl); + } else { + /* Asking for a specific link mode. */ + if (tp->link_config.speed == SPEED_1000) { + if (tp->link_config.duplex == DUPLEX_FULL) + new_adv = ADVERTISED_1000baseT_Full; + else + new_adv = ADVERTISED_1000baseT_Half; + } else if (tp->link_config.speed == SPEED_100) { + if (tp->link_config.duplex == DUPLEX_FULL) + new_adv = ADVERTISED_100baseT_Full; + else + new_adv = ADVERTISED_100baseT_Half; + } else { + if (tp->link_config.duplex == DUPLEX_FULL) + new_adv = ADVERTISED_10baseT_Full; + else + new_adv = ADVERTISED_10baseT_Half; + } + + tg3_phy_autoneg_cfg(tp, new_adv, + tp->link_config.flowctrl); } if (tp->link_config.autoneg == AUTONEG_DISABLE && @@ -3077,7 +3111,7 @@ static int tg3_init_5401phy_dsp(struct tg3 *tp) /* Turn off tap power management. */ /* Set Extended packet length bit */ - err = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20); + err = tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, 0x4c20); err |= tg3_phydsp_write(tp, 0x0012, 0x1804); err |= tg3_phydsp_write(tp, 0x0013, 0x1204); @@ -3140,7 +3174,7 @@ static int tg3_adv_1000T_flowctrl_ok(struct tg3 *tp, u32 *lcladv, u32 *rmtadv) if (curadv != reqadv) return 0; - if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) + if (tg3_flag(tp, PAUSE_AUTONEG)) tg3_readphy(tp, MII_LPA, rmtadv); } else { /* Reprogram the advertisement register, even if it @@ -3183,7 +3217,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) udelay(80); } - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02); + tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_PWRCTL, 0); /* Some third-party PHYs need to be reset on link going * down. @@ -3203,7 +3237,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) { tg3_readphy(tp, MII_BMSR, &bmsr); if (tg3_readphy(tp, MII_BMSR, &bmsr) || - !(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)) + !tg3_flag(tp, INIT_COMPLETE)) bmsr = 0; if (!(bmsr & BMSR_LSTATUS)) { @@ -3264,11 +3298,13 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) current_duplex = DUPLEX_INVALID; if (tp->phy_flags & TG3_PHYFLG_CAPACITIVE_COUPLING) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4007); - tg3_readphy(tp, MII_TG3_AUX_CTRL, &val); - if (!(val & (1 << 10))) { - val |= (1 << 10); - tg3_writephy(tp, MII_TG3_AUX_CTRL, val); + err = tg3_phy_auxctl_read(tp, + MII_TG3_AUXCTL_SHDWSEL_MISCTEST, + &val); + if (!err && !(val & (1 << 10))) { + tg3_phy_auxctl_write(tp, + MII_TG3_AUXCTL_SHDWSEL_MISCTEST, + val | (1 << 10)); goto relink; } } @@ -3341,8 +3377,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) tg3_phy_copper_begin(tp); tg3_readphy(tp, MII_BMSR, &bmsr); - if (!tg3_readphy(tp, MII_BMSR, &bmsr) && - (bmsr & BMSR_LSTATUS)) + if ((!tg3_readphy(tp, MII_BMSR, &bmsr) && (bmsr & BMSR_LSTATUS)) || + (tp->mac_mode & MAC_MODE_PORT_INT_LPBACK)) current_link_up = 1; } @@ -3385,7 +3421,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) tg3_phy_eee_adjust(tp, current_link_up); - if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) { + if (tg3_flag(tp, USE_LINKCHG_REG)) { /* Polled via timer. */ tw32_f(MAC_EVENT, 0); } else { @@ -3396,8 +3432,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 && current_link_up == 1 && tp->link_config.active_speed == SPEED_1000 && - ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) || - (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED))) { + (tg3_flag(tp, PCIX_MODE) || tg3_flag(tp, PCI_HIGH_SPEED))) { udelay(120); tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | @@ -3409,7 +3444,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) } /* Prevent send BD corruption. */ - if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) { + if (tg3_flag(tp, CLKREQ_BUG)) { u16 oldlnkctl, newlnkctl; pci_read_config_word(tp->pdev, @@ -3804,7 +3839,7 @@ static void tg3_init_bcm8002(struct tg3 *tp) int i; /* Reset when initting first time or we have a link. */ - if ((tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) && + if (tg3_flag(tp, INIT_COMPLETE) && !(mac_status & MAC_STATUS_PCS_SYNCED)) return; @@ -4065,9 +4100,9 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) orig_active_speed = tp->link_config.active_speed; orig_active_duplex = tp->link_config.active_duplex; - if (!(tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) && + if (!tg3_flag(tp, HW_AUTONEG) && netif_carrier_ok(tp->dev) && - (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)) { + tg3_flag(tp, INIT_COMPLETE)) { mac_status = tr32(MAC_STATUS); mac_status &= (MAC_STATUS_PCS_SYNCED | MAC_STATUS_SIGNAL_DET | @@ -4098,7 +4133,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) current_link_up = 0; mac_status = tr32(MAC_STATUS); - if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) + if (tg3_flag(tp, HW_AUTONEG)) current_link_up = tg3_setup_fiber_hw_autoneg(tp, mac_status); else current_link_up = tg3_setup_fiber_by_hand(tp, mac_status); @@ -4297,7 +4332,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) current_duplex = DUPLEX_FULL; else current_duplex = DUPLEX_HALF; - } else if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + } else if (!tg3_flag(tp, 5780_CLASS)) { /* Link is up via parallel detect */ } else { current_link_up = 0; @@ -4394,6 +4429,7 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp) static int tg3_setup_phy(struct tg3 *tp, int force_reset) { + u32 val; int err; if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) @@ -4404,7 +4440,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) err = tg3_setup_copper_phy(tp, force_reset); if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) { - u32 val, scale; + u32 scale; val = tr32(TG3_CPMU_CLCK_STAT) & CPMU_CLCK_STAT_MAC_CLCK_MASK; if (val == CPMU_CLCK_STAT_MAC_CLCK_62_5) @@ -4419,19 +4455,22 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) tw32(GRC_MISC_CFG, val); } + val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + val |= tr32(MAC_TX_LENGTHS) & + (TX_LENGTHS_JMB_FRM_LEN_MSK | + TX_LENGTHS_CNT_DWN_VAL_MSK); + if (tp->link_config.active_speed == SPEED_1000 && tp->link_config.active_duplex == DUPLEX_HALF) - tw32(MAC_TX_LENGTHS, - ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | - (6 << TX_LENGTHS_IPG_SHIFT) | - (0xff << TX_LENGTHS_SLOT_TIME_SHIFT))); + tw32(MAC_TX_LENGTHS, val | + (0xff << TX_LENGTHS_SLOT_TIME_SHIFT)); else - tw32(MAC_TX_LENGTHS, - ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | - (6 << TX_LENGTHS_IPG_SHIFT) | - (32 << TX_LENGTHS_SLOT_TIME_SHIFT))); + tw32(MAC_TX_LENGTHS, val | + (32 << TX_LENGTHS_SLOT_TIME_SHIFT)); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { if (netif_carrier_ok(tp->dev)) { tw32(HOSTCC_STAT_COAL_TICKS, tp->coal.stats_block_coalesce_usecs); @@ -4440,8 +4479,8 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) } } - if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) { - u32 val = tr32(PCIE_PWR_MGMT_THRESH); + if (tg3_flag(tp, ASPM_WORKAROUND)) { + val = tr32(PCIE_PWR_MGMT_THRESH); if (!netif_carrier_ok(tp->dev)) val = (val & ~PCIE_PWR_MGMT_L1_THRESH_MSK) | tp->pwrmgmt_thresh; @@ -4458,6 +4497,123 @@ static inline int tg3_irq_sync(struct tg3 *tp) return tp->irq_sync; } +static inline void tg3_rd32_loop(struct tg3 *tp, u32 *dst, u32 off, u32 len) +{ + int i; + + dst = (u32 *)((u8 *)dst + off); + for (i = 0; i < len; i += sizeof(u32)) + *dst++ = tr32(off + i); +} + +static void tg3_dump_legacy_regs(struct tg3 *tp, u32 *regs) +{ + tg3_rd32_loop(tp, regs, TG3PCI_VENDOR, 0xb0); + tg3_rd32_loop(tp, regs, MAILBOX_INTERRUPT_0, 0x200); + tg3_rd32_loop(tp, regs, MAC_MODE, 0x4f0); + tg3_rd32_loop(tp, regs, SNDDATAI_MODE, 0xe0); + tg3_rd32_loop(tp, regs, SNDDATAC_MODE, 0x04); + tg3_rd32_loop(tp, regs, SNDBDS_MODE, 0x80); + tg3_rd32_loop(tp, regs, SNDBDI_MODE, 0x48); + tg3_rd32_loop(tp, regs, SNDBDC_MODE, 0x04); + tg3_rd32_loop(tp, regs, RCVLPC_MODE, 0x20); + tg3_rd32_loop(tp, regs, RCVLPC_SELLST_BASE, 0x15c); + tg3_rd32_loop(tp, regs, RCVDBDI_MODE, 0x0c); + tg3_rd32_loop(tp, regs, RCVDBDI_JUMBO_BD, 0x3c); + tg3_rd32_loop(tp, regs, RCVDBDI_BD_PROD_IDX_0, 0x44); + tg3_rd32_loop(tp, regs, RCVDCC_MODE, 0x04); + tg3_rd32_loop(tp, regs, RCVBDI_MODE, 0x20); + tg3_rd32_loop(tp, regs, RCVCC_MODE, 0x14); + tg3_rd32_loop(tp, regs, RCVLSC_MODE, 0x08); + tg3_rd32_loop(tp, regs, MBFREE_MODE, 0x08); + tg3_rd32_loop(tp, regs, HOSTCC_MODE, 0x100); + + if (tg3_flag(tp, SUPPORT_MSIX)) + tg3_rd32_loop(tp, regs, HOSTCC_RXCOL_TICKS_VEC1, 0x180); + + tg3_rd32_loop(tp, regs, MEMARB_MODE, 0x10); + tg3_rd32_loop(tp, regs, BUFMGR_MODE, 0x58); + tg3_rd32_loop(tp, regs, RDMAC_MODE, 0x08); + tg3_rd32_loop(tp, regs, WDMAC_MODE, 0x08); + tg3_rd32_loop(tp, regs, RX_CPU_MODE, 0x04); + tg3_rd32_loop(tp, regs, RX_CPU_STATE, 0x04); + tg3_rd32_loop(tp, regs, RX_CPU_PGMCTR, 0x04); + tg3_rd32_loop(tp, regs, RX_CPU_HWBKPT, 0x04); + + if (!tg3_flag(tp, 5705_PLUS)) { + tg3_rd32_loop(tp, regs, TX_CPU_MODE, 0x04); + tg3_rd32_loop(tp, regs, TX_CPU_STATE, 0x04); + tg3_rd32_loop(tp, regs, TX_CPU_PGMCTR, 0x04); + } + + tg3_rd32_loop(tp, regs, GRCMBOX_INTERRUPT_0, 0x110); + tg3_rd32_loop(tp, regs, FTQ_RESET, 0x120); + tg3_rd32_loop(tp, regs, MSGINT_MODE, 0x0c); + tg3_rd32_loop(tp, regs, DMAC_MODE, 0x04); + tg3_rd32_loop(tp, regs, GRC_MODE, 0x4c); + + if (tg3_flag(tp, NVRAM)) + tg3_rd32_loop(tp, regs, NVRAM_CMD, 0x24); +} + +static void tg3_dump_state(struct tg3 *tp) +{ + int i; + u32 *regs; + + regs = kzalloc(TG3_REG_BLK_SIZE, GFP_ATOMIC); + if (!regs) { + netdev_err(tp->dev, "Failed allocating register dump buffer\n"); + return; + } + + if (tg3_flag(tp, PCI_EXPRESS)) { + /* Read up to but not including private PCI registers */ + for (i = 0; i < TG3_PCIE_TLDLPL_PORT; i += sizeof(u32)) + regs[i / sizeof(u32)] = tr32(i); + } else + tg3_dump_legacy_regs(tp, regs); + + for (i = 0; i < TG3_REG_BLK_SIZE / sizeof(u32); i += 4) { + if (!regs[i + 0] && !regs[i + 1] && + !regs[i + 2] && !regs[i + 3]) + continue; + + netdev_err(tp->dev, "0x%08x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + i * 4, + regs[i + 0], regs[i + 1], regs[i + 2], regs[i + 3]); + } + + kfree(regs); + + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + + /* SW status block */ + netdev_err(tp->dev, + "%d: Host status block [%08x:%08x:(%04x:%04x:%04x):(%04x:%04x)]\n", + i, + tnapi->hw_status->status, + tnapi->hw_status->status_tag, + tnapi->hw_status->rx_jumbo_consumer, + tnapi->hw_status->rx_consumer, + tnapi->hw_status->rx_mini_consumer, + tnapi->hw_status->idx[0].rx_producer, + tnapi->hw_status->idx[0].tx_consumer); + + netdev_err(tp->dev, + "%d: NAPI info [%08x:%08x:(%04x:%04x:%04x):%04x:(%04x:%04x:%04x:%04x)]\n", + i, + tnapi->last_tag, tnapi->last_irq_tag, + tnapi->tx_prod, tnapi->tx_cons, tnapi->tx_pending, + tnapi->rx_rcb_ptr, + tnapi->prodring.rx_std_prod_idx, + tnapi->prodring.rx_std_cons_idx, + tnapi->prodring.rx_jmb_prod_idx, + tnapi->prodring.rx_jmb_cons_idx); + } +} + /* This is called whenever we suspect that the system chipset is re- * ordering the sequence of MMIO to the tx send mailbox. The symptom * is bogus tx completions. We try to recover by setting the @@ -4466,7 +4622,7 @@ static inline int tg3_irq_sync(struct tg3 *tp) */ static void tg3_tx_recover(struct tg3 *tp) { - BUG_ON((tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) || + BUG_ON(tg3_flag(tp, MBOX_WRITE_REORDER) || tp->write32_tx_mbox == tg3_write_indirect_mbox); netdev_warn(tp->dev, @@ -4476,7 +4632,7 @@ static void tg3_tx_recover(struct tg3 *tp) "and include system chipset information.\n"); spin_lock(&tp->lock); - tp->tg3_flags |= TG3_FLAG_TX_RECOVERY_PENDING; + tg3_flag_set(tp, TX_RECOVERY_PENDING); spin_unlock(&tp->lock); } @@ -4500,7 +4656,7 @@ static void tg3_tx(struct tg3_napi *tnapi) struct netdev_queue *txq; int index = tnapi - tp->napi; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + if (tg3_flag(tp, ENABLE_TSS)) index--; txq = netdev_get_tx_queue(tp->dev, index); @@ -4815,7 +4971,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) skb = copy_skb; } - if ((tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) && + if ((tp->dev->features & NETIF_F_RXCSUM) && (desc->type_flags & RXD_FLAG_TCPUDP_CSUM) && (((desc->ip_tcp_csum & RXD_TCPCSUM_MASK) >> RXD_TCPCSUM_SHIFT) == 0xffff)) @@ -4868,7 +5024,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) tw32_rx_mbox(tnapi->consmbox, sw_idx); /* Refill RX ring(s). */ - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) { + if (!tg3_flag(tp, ENABLE_RSS)) { if (work_mask & RXD_OPAQUE_RING_STD) { tpr->rx_std_prod_idx = std_prod_idx & tp->rx_std_ring_mask; @@ -4901,16 +5057,14 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) static void tg3_poll_link(struct tg3 *tp) { /* handle link change and other phy events */ - if (!(tp->tg3_flags & - (TG3_FLAG_USE_LINKCHG_REG | - TG3_FLAG_POLL_SERDES))) { + if (!(tg3_flag(tp, USE_LINKCHG_REG) || tg3_flag(tp, POLL_SERDES))) { struct tg3_hw_status *sblk = tp->napi[0].hw_status; if (sblk->status & SD_STATUS_LINK_CHG) { sblk->status = SD_STATUS_UPDATED | (sblk->status & ~SD_STATUS_LINK_CHG); spin_lock(&tp->lock); - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED | @@ -5057,7 +5211,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) /* run TX completion thread */ if (tnapi->hw_status->idx[0].tx_consumer != tnapi->tx_cons) { tg3_tx(tnapi); - if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) + if (unlikely(tg3_flag(tp, TX_RECOVERY_PENDING))) return work_done; } @@ -5068,7 +5222,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) if (*(tnapi->rx_rcb_prod_idx) != tnapi->rx_rcb_ptr) work_done += tg3_rx(tnapi, budget - work_done); - if ((tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) && tnapi == &tp->napi[1]) { + if (tg3_flag(tp, ENABLE_RSS) && tnapi == &tp->napi[1]) { struct tg3_rx_prodring_set *dpr = &tp->napi[0].prodring; int i, err = 0; u32 std_prod_idx = dpr->rx_std_prod_idx; @@ -5107,7 +5261,7 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget) while (1) { work_done = tg3_poll_work(tnapi, work_done, budget); - if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) + if (unlikely(tg3_flag(tp, TX_RECOVERY_PENDING))) goto tx_recovery; if (unlikely(work_done >= budget)) @@ -5141,6 +5295,40 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget) return work_done; } +static void tg3_process_error(struct tg3 *tp) +{ + u32 val; + bool real_error = false; + + if (tg3_flag(tp, ERROR_PROCESSED)) + return; + + /* Check Flow Attention register */ + val = tr32(HOSTCC_FLOW_ATTN); + if (val & ~HOSTCC_FLOW_ATTN_MBUF_LWM) { + netdev_err(tp->dev, "FLOW Attention error. Resetting chip.\n"); + real_error = true; + } + + if (tr32(MSGINT_STATUS) & ~MSGINT_STATUS_MSI_REQ) { + netdev_err(tp->dev, "MSI Status error. Resetting chip.\n"); + real_error = true; + } + + if (tr32(RDMAC_STATUS) || tr32(WDMAC_STATUS)) { + netdev_err(tp->dev, "DMA Status error. Resetting chip.\n"); + real_error = true; + } + + if (!real_error) + return; + + tg3_dump_state(tp); + + tg3_flag_set(tp, ERROR_PROCESSED); + schedule_work(&tp->reset_task); +} + static int tg3_poll(struct napi_struct *napi, int budget) { struct tg3_napi *tnapi = container_of(napi, struct tg3_napi, napi); @@ -5149,17 +5337,20 @@ static int tg3_poll(struct napi_struct *napi, int budget) struct tg3_hw_status *sblk = tnapi->hw_status; while (1) { + if (sblk->status & SD_STATUS_ERROR) + tg3_process_error(tp); + tg3_poll_link(tp); work_done = tg3_poll_work(tnapi, work_done, budget); - if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) + if (unlikely(tg3_flag(tp, TX_RECOVERY_PENDING))) goto tx_recovery; if (unlikely(work_done >= budget)) break; - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { + if (tg3_flag(tp, TAGGED_STATUS)) { /* tp->last_tag is used in tg3_int_reenable() below * to tell the hw how much work has been processed, * so we must read it before checking for more work. @@ -5326,7 +5517,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) * interrupt is ours and will flush the status block. */ if (unlikely(!(sblk->status & SD_STATUS_UPDATED))) { - if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) || + if (tg3_flag(tp, CHIP_RESETTING) || (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { handled = 0; goto out; @@ -5375,7 +5566,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * interrupt is ours and will flush the status block. */ if (unlikely(sblk->status_tag == tnapi->last_irq_tag)) { - if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) || + if (tg3_flag(tp, CHIP_RESETTING) || (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { handled = 0; goto out; @@ -5488,14 +5679,14 @@ static void tg3_reset_task(struct work_struct *work) tg3_full_lock(tp, 1); - restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER; - tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; + restart_timer = tg3_flag(tp, RESTART_TIMER); + tg3_flag_clear(tp, RESTART_TIMER); - if (tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING) { + if (tg3_flag(tp, TX_RECOVERY_PENDING)) { tp->write32_tx_mbox = tg3_write32_tx_mbox; tp->write32_rx_mbox = tg3_write_flush_reg32; - tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER; - tp->tg3_flags &= ~TG3_FLAG_TX_RECOVERY_PENDING; + tg3_flag_set(tp, MBOX_WRITE_REORDER); + tg3_flag_clear(tp, TX_RECOVERY_PENDING); } tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); @@ -5515,21 +5706,13 @@ static void tg3_reset_task(struct work_struct *work) tg3_phy_start(tp); } -static void tg3_dump_short_state(struct tg3 *tp) -{ - netdev_err(tp->dev, "DEBUG: MAC_TX_STATUS[%08x] MAC_RX_STATUS[%08x]\n", - tr32(MAC_TX_STATUS), tr32(MAC_RX_STATUS)); - netdev_err(tp->dev, "DEBUG: RDMAC_STATUS[%08x] WDMAC_STATUS[%08x]\n", - tr32(RDMAC_STATUS), tr32(WDMAC_STATUS)); -} - static void tg3_tx_timeout(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); if (netif_msg_tx_err(tp)) { netdev_err(dev, "transmit timed out, resetting\n"); - tg3_dump_short_state(tp); + tg3_dump_state(tp); } schedule_work(&tp->reset_task); @@ -5548,7 +5731,7 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping, int len) { #if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64) - if (tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG) + if (tg3_flag(tp, 40BIT_DMA_BUG)) return ((u64) mapping + len) > DMA_BIT_MASK(40); return 0; #else @@ -5556,89 +5739,6 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping, #endif } -static void tg3_set_txd(struct tg3_napi *, int, dma_addr_t, int, u32, u32); - -/* Workaround 4GB and 40-bit hardware DMA bugs. */ -static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, - struct sk_buff *skb, u32 last_plus_one, - u32 *start, u32 base_flags, u32 mss) -{ - struct tg3 *tp = tnapi->tp; - struct sk_buff *new_skb; - dma_addr_t new_addr = 0; - u32 entry = *start; - int i, ret = 0; - - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) - new_skb = skb_copy(skb, GFP_ATOMIC); - else { - int more_headroom = 4 - ((unsigned long)skb->data & 3); - - new_skb = skb_copy_expand(skb, - skb_headroom(skb) + more_headroom, - skb_tailroom(skb), GFP_ATOMIC); - } - - if (!new_skb) { - ret = -1; - } else { - /* New SKB is guaranteed to be linear. */ - entry = *start; - new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len, - PCI_DMA_TODEVICE); - /* Make sure the mapping succeeded */ - if (pci_dma_mapping_error(tp->pdev, new_addr)) { - ret = -1; - dev_kfree_skb(new_skb); - new_skb = NULL; - - /* Make sure new skb does not cross any 4G boundaries. - * Drop the packet if it does. - */ - } else if ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) && - tg3_4g_overflow_test(new_addr, new_skb->len)) { - pci_unmap_single(tp->pdev, new_addr, new_skb->len, - PCI_DMA_TODEVICE); - ret = -1; - dev_kfree_skb(new_skb); - new_skb = NULL; - } else { - tg3_set_txd(tnapi, entry, new_addr, new_skb->len, - base_flags, 1 | (mss << 1)); - *start = NEXT_TX(entry); - } - } - - /* Now clean up the sw ring entries. */ - i = 0; - while (entry != last_plus_one) { - int len; - - if (i == 0) - len = skb_headlen(skb); - else - len = skb_shinfo(skb)->frags[i-1].size; - - pci_unmap_single(tp->pdev, - dma_unmap_addr(&tnapi->tx_buffers[entry], - mapping), - len, PCI_DMA_TODEVICE); - if (i == 0) { - tnapi->tx_buffers[entry].skb = new_skb; - dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, - new_addr); - } else { - tnapi->tx_buffers[entry].skb = NULL; - } - entry = NEXT_TX(entry); - i++; - } - - dev_kfree_skb(skb); - - return ret; -} - static void tg3_set_txd(struct tg3_napi *tnapi, int entry, dma_addr_t mapping, int len, u32 flags, u32 mss_and_is_end) @@ -5662,179 +5762,86 @@ static void tg3_set_txd(struct tg3_napi *tnapi, int entry, txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; } -/* hard_start_xmit for devices that don't have any bugs and - * support TG3_FLG2_HW_TSO_2 and TG3_FLG2_HW_TSO_3 only. - */ -static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, - struct net_device *dev) +static void tg3_skb_error_unmap(struct tg3_napi *tnapi, + struct sk_buff *skb, int last) { - struct tg3 *tp = netdev_priv(dev); - u32 len, entry, base_flags, mss; - dma_addr_t mapping; - struct tg3_napi *tnapi; - struct netdev_queue *txq; - unsigned int i, last; + int i; + u32 entry = tnapi->tx_prod; + struct ring_info *txb = &tnapi->tx_buffers[entry]; - txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); - tnapi = &tp->napi[skb_get_queue_mapping(skb)]; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) - tnapi++; - - /* We are running in BH disabled context with netif_tx_lock - * and TX reclaim runs via tp->napi.poll inside of a software - * interrupt. Furthermore, IRQ processing runs lockless so we have - * no IRQ context deadlocks to worry about either. Rejoice! - */ - if (unlikely(tg3_tx_avail(tnapi) <= (skb_shinfo(skb)->nr_frags + 1))) { - if (!netif_tx_queue_stopped(txq)) { - netif_tx_stop_queue(txq); - - /* This is a hard error, log it. */ - netdev_err(dev, - "BUG! Tx Ring full when queue awake!\n"); - } - return NETDEV_TX_BUSY; - } - - entry = tnapi->tx_prod; - base_flags = 0; - mss = skb_shinfo(skb)->gso_size; - if (mss) { - int tcp_opt_len, ip_tcp_len; - u32 hdrlen; - - if (skb_header_cloned(skb) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - goto out_unlock; - } - - if (skb_is_gso_v6(skb)) { - hdrlen = skb_headlen(skb) - ETH_HLEN; - } else { - struct iphdr *iph = ip_hdr(skb); - - tcp_opt_len = tcp_optlen(skb); - ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr); - - iph->check = 0; - iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len); - hdrlen = ip_tcp_len + tcp_opt_len; - } - - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) { - mss |= (hdrlen & 0xc) << 12; - if (hdrlen & 0x10) - base_flags |= 0x00000010; - base_flags |= (hdrlen & 0x3e0) << 5; - } else - mss |= hdrlen << 9; - - base_flags |= (TXD_FLAG_CPU_PRE_DMA | - TXD_FLAG_CPU_POST_DMA); - - tcp_hdr(skb)->check = 0; - - } else if (skb->ip_summed == CHECKSUM_PARTIAL) { - base_flags |= TXD_FLAG_TCPUDP_CSUM; - } - - if (vlan_tx_tag_present(skb)) - base_flags |= (TXD_FLAG_VLAN | - (vlan_tx_tag_get(skb) << 16)); - - len = skb_headlen(skb); - - /* Queue skb data, a.k.a. the main skb fragment. */ - mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(tp->pdev, mapping)) { - dev_kfree_skb(skb); - goto out_unlock; - } - - tnapi->tx_buffers[entry].skb = skb; - dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping); - - if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) && - !mss && skb->len > VLAN_ETH_FRAME_LEN) - base_flags |= TXD_FLAG_JMB_PKT; - - tg3_set_txd(tnapi, entry, mapping, len, base_flags, - (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); - - entry = NEXT_TX(entry); - - /* Now loop through additional data fragments, and queue them. */ - if (skb_shinfo(skb)->nr_frags > 0) { - last = skb_shinfo(skb)->nr_frags - 1; - for (i = 0; i <= last; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - len = frag->size; - mapping = pci_map_page(tp->pdev, - frag->page, - frag->page_offset, - len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(tp->pdev, mapping)) - goto dma_error; - - tnapi->tx_buffers[entry].skb = NULL; - dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, - mapping); - - tg3_set_txd(tnapi, entry, mapping, len, - base_flags, (i == last) | (mss << 1)); - - entry = NEXT_TX(entry); - } - } - - /* Packets are ready, update Tx producer idx local and on card. */ - tw32_tx_mbox(tnapi->prodmbox, entry); - - tnapi->tx_prod = entry; - if (unlikely(tg3_tx_avail(tnapi) <= (MAX_SKB_FRAGS + 1))) { - netif_tx_stop_queue(txq); - - /* netif_tx_stop_queue() must be done before checking - * checking tx index in tg3_tx_avail() below, because in - * tg3_tx(), we update tx index before checking for - * netif_tx_queue_stopped(). - */ - smp_mb(); - if (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)) - netif_tx_wake_queue(txq); - } - -out_unlock: - mmiowb(); - - return NETDEV_TX_OK; - -dma_error: - last = i; - entry = tnapi->tx_prod; - tnapi->tx_buffers[entry].skb = NULL; - pci_unmap_single(tp->pdev, - dma_unmap_addr(&tnapi->tx_buffers[entry], mapping), + pci_unmap_single(tnapi->tp->pdev, + dma_unmap_addr(txb, mapping), skb_headlen(skb), PCI_DMA_TODEVICE); for (i = 0; i <= last; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - entry = NEXT_TX(entry); - pci_unmap_page(tp->pdev, - dma_unmap_addr(&tnapi->tx_buffers[entry], - mapping), + entry = NEXT_TX(entry); + txb = &tnapi->tx_buffers[entry]; + + pci_unmap_page(tnapi->tp->pdev, + dma_unmap_addr(txb, mapping), frag->size, PCI_DMA_TODEVICE); } +} + +/* Workaround 4GB and 40-bit hardware DMA bugs. */ +static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, + struct sk_buff *skb, + u32 base_flags, u32 mss) +{ + struct tg3 *tp = tnapi->tp; + struct sk_buff *new_skb; + dma_addr_t new_addr = 0; + u32 entry = tnapi->tx_prod; + int ret = 0; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) + new_skb = skb_copy(skb, GFP_ATOMIC); + else { + int more_headroom = 4 - ((unsigned long)skb->data & 3); + + new_skb = skb_copy_expand(skb, + skb_headroom(skb) + more_headroom, + skb_tailroom(skb), GFP_ATOMIC); + } + + if (!new_skb) { + ret = -1; + } else { + /* New SKB is guaranteed to be linear. */ + new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len, + PCI_DMA_TODEVICE); + /* Make sure the mapping succeeded */ + if (pci_dma_mapping_error(tp->pdev, new_addr)) { + ret = -1; + dev_kfree_skb(new_skb); + + /* Make sure new skb does not cross any 4G boundaries. + * Drop the packet if it does. + */ + } else if (tg3_flag(tp, 4G_DMA_BNDRY_BUG) && + tg3_4g_overflow_test(new_addr, new_skb->len)) { + pci_unmap_single(tp->pdev, new_addr, new_skb->len, + PCI_DMA_TODEVICE); + ret = -1; + dev_kfree_skb(new_skb); + } else { + tnapi->tx_buffers[entry].skb = new_skb; + dma_unmap_addr_set(&tnapi->tx_buffers[entry], + mapping, new_addr); + + tg3_set_txd(tnapi, entry, new_addr, new_skb->len, + base_flags, 1 | (mss << 1)); + } + } dev_kfree_skb(skb); - return NETDEV_TX_OK; + + return ret; } -static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *, - struct net_device *); +static netdev_tx_t tg3_start_xmit(struct sk_buff *, struct net_device *); /* Use GSO to workaround a rare TSO bug that may be triggered when the * TSO header is greater than 80 bytes. @@ -5868,7 +5875,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) nskb = segs; segs = segs->next; nskb->next = NULL; - tg3_start_xmit_dma_bug(nskb, tp->dev); + tg3_start_xmit(nskb, tp->dev); } while (segs); tg3_tso_bug_end: @@ -5878,22 +5885,21 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) } /* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and - * support TG3_FLG2_HW_TSO_1 or firmware TSO only. + * support TG3_FLAG_HW_TSO_1 or firmware TSO only. */ -static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); u32 len, entry, base_flags, mss; - int would_hit_hwbug; + int i = -1, would_hit_hwbug; dma_addr_t mapping; struct tg3_napi *tnapi; struct netdev_queue *txq; - unsigned int i, last; + unsigned int last; txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); tnapi = &tp->napi[skb_get_queue_mapping(skb)]; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + if (tg3_flag(tp, ENABLE_TSS)) tnapi++; /* We are running in BH disabled context with netif_tx_lock @@ -5944,13 +5950,15 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, } if (unlikely((ETH_HLEN + hdr_len) > 80) && - (tp->tg3_flags2 & TG3_FLG2_TSO_BUG)) + tg3_flag(tp, TSO_BUG)) return tg3_tso_bug(tp, skb); base_flags |= (TXD_FLAG_CPU_PRE_DMA | TXD_FLAG_CPU_POST_DMA); - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) { + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) { tcp_hdr(skb)->check = 0; base_flags &= ~TXD_FLAG_TCPUDP_CSUM; } else @@ -5959,14 +5967,14 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, IPPROTO_TCP, 0); - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) { + if (tg3_flag(tp, HW_TSO_3)) { mss |= (hdr_len & 0xc) << 12; if (hdr_len & 0x10) base_flags |= 0x00000010; base_flags |= (hdr_len & 0x3e0) << 5; - } else if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) + } else if (tg3_flag(tp, HW_TSO_2)) mss |= hdr_len << 9; - else if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1) || + else if (tg3_flag(tp, HW_TSO_1) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) { if (tcp_opt_len || iph->ihl > 5) { int tsflags; @@ -5988,7 +5996,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, base_flags |= (TXD_FLAG_VLAN | (vlan_tx_tag_get(skb) << 16)); - if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) && + if (tg3_flag(tp, USE_JUMBO_BDFLAG) && !mss && skb->len > VLAN_ETH_FRAME_LEN) base_flags |= TXD_FLAG_JMB_PKT; @@ -6005,18 +6013,18 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, would_hit_hwbug = 0; - if ((tp->tg3_flags3 & TG3_FLG3_SHORT_DMA_BUG) && len <= 8) + if (tg3_flag(tp, SHORT_DMA_BUG) && len <= 8) would_hit_hwbug = 1; - if ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) && + if (tg3_flag(tp, 4G_DMA_BNDRY_BUG) && tg3_4g_overflow_test(mapping, len)) would_hit_hwbug = 1; - if ((tp->tg3_flags3 & TG3_FLG3_40BIT_DMA_LIMIT_BUG) && + if (tg3_flag(tp, 40BIT_DMA_LIMIT_BUG) && tg3_40bit_overflow_test(tp, mapping, len)) would_hit_hwbug = 1; - if (tp->tg3_flags3 & TG3_FLG3_5701_DMA_BUG) + if (tg3_flag(tp, 5701_DMA_BUG)) would_hit_hwbug = 1; tg3_set_txd(tnapi, entry, mapping, len, base_flags, @@ -6042,19 +6050,21 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, if (pci_dma_mapping_error(tp->pdev, mapping)) goto dma_error; - if ((tp->tg3_flags3 & TG3_FLG3_SHORT_DMA_BUG) && + if (tg3_flag(tp, SHORT_DMA_BUG) && len <= 8) would_hit_hwbug = 1; - if ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) && + if (tg3_flag(tp, 4G_DMA_BNDRY_BUG) && tg3_4g_overflow_test(mapping, len)) would_hit_hwbug = 1; - if ((tp->tg3_flags3 & TG3_FLG3_40BIT_DMA_LIMIT_BUG) && + if (tg3_flag(tp, 40BIT_DMA_LIMIT_BUG) && tg3_40bit_overflow_test(tp, mapping, len)) would_hit_hwbug = 1; - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) tg3_set_txd(tnapi, entry, mapping, len, base_flags, (i == last)|(mss << 1)); else @@ -6066,20 +6076,15 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, } if (would_hit_hwbug) { - u32 last_plus_one = entry; - u32 start; - - start = entry - 1 - skb_shinfo(skb)->nr_frags; - start &= (TG3_TX_RING_SIZE - 1); + tg3_skb_error_unmap(tnapi, skb, i); /* If the workaround fails due to memory/mapping * failure, silently drop this packet. */ - if (tigon3_dma_hwbug_workaround(tnapi, skb, last_plus_one, - &start, base_flags, mss)) + if (tigon3_dma_hwbug_workaround(tnapi, skb, base_flags, mss)) goto out_unlock; - entry = start; + entry = NEXT_TX(tnapi->tx_prod); } /* Packets are ready, update Tx producer idx local and on card. */ @@ -6105,43 +6110,86 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, return NETDEV_TX_OK; dma_error: - last = i; - entry = tnapi->tx_prod; - tnapi->tx_buffers[entry].skb = NULL; - pci_unmap_single(tp->pdev, - dma_unmap_addr(&tnapi->tx_buffers[entry], mapping), - skb_headlen(skb), - PCI_DMA_TODEVICE); - for (i = 0; i <= last; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - entry = NEXT_TX(entry); - - pci_unmap_page(tp->pdev, - dma_unmap_addr(&tnapi->tx_buffers[entry], - mapping), - frag->size, PCI_DMA_TODEVICE); - } - + tg3_skb_error_unmap(tnapi, skb, i); dev_kfree_skb(skb); + tnapi->tx_buffers[tnapi->tx_prod].skb = NULL; return NETDEV_TX_OK; } +static void tg3_set_loopback(struct net_device *dev, u32 features) +{ + struct tg3 *tp = netdev_priv(dev); + + if (features & NETIF_F_LOOPBACK) { + if (tp->mac_mode & MAC_MODE_PORT_INT_LPBACK) + return; + + /* + * Clear MAC_MODE_HALF_DUPLEX or you won't get packets back in + * loopback mode if Half-Duplex mode was negotiated earlier. + */ + tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX; + + /* Enable internal MAC loopback mode */ + tp->mac_mode |= MAC_MODE_PORT_INT_LPBACK; + spin_lock_bh(&tp->lock); + tw32(MAC_MODE, tp->mac_mode); + netif_carrier_on(tp->dev); + spin_unlock_bh(&tp->lock); + netdev_info(dev, "Internal MAC loopback mode enabled.\n"); + } else { + if (!(tp->mac_mode & MAC_MODE_PORT_INT_LPBACK)) + return; + + /* Disable internal MAC loopback mode */ + tp->mac_mode &= ~MAC_MODE_PORT_INT_LPBACK; + spin_lock_bh(&tp->lock); + tw32(MAC_MODE, tp->mac_mode); + /* Force link status check */ + tg3_setup_phy(tp, 1); + spin_unlock_bh(&tp->lock); + netdev_info(dev, "Internal MAC loopback mode disabled.\n"); + } +} + +static u32 tg3_fix_features(struct net_device *dev, u32 features) +{ + struct tg3 *tp = netdev_priv(dev); + + if (dev->mtu > ETH_DATA_LEN && tg3_flag(tp, 5780_CLASS)) + features &= ~NETIF_F_ALL_TSO; + + return features; +} + +static int tg3_set_features(struct net_device *dev, u32 features) +{ + u32 changed = dev->features ^ features; + + if ((changed & NETIF_F_LOOPBACK) && netif_running(dev)) + tg3_set_loopback(dev, features); + + return 0; +} + static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, int new_mtu) { dev->mtu = new_mtu; if (new_mtu > ETH_DATA_LEN) { - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { - tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; - ethtool_op_set_tso(dev, 0); + if (tg3_flag(tp, 5780_CLASS)) { + netdev_update_features(dev); + tg3_flag_clear(tp, TSO_CAPABLE); } else { - tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; + tg3_flag_set(tp, JUMBO_RING_ENABLE); } } else { - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) - tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; - tp->tg3_flags &= ~TG3_FLAG_JUMBO_RING_ENABLE; + if (tg3_flag(tp, 5780_CLASS)) { + tg3_flag_set(tp, TSO_CAPABLE); + netdev_update_features(dev); + } + tg3_flag_clear(tp, JUMBO_RING_ENABLE); } } @@ -6195,7 +6243,7 @@ static void tg3_rx_prodring_free(struct tg3 *tp, tg3_rx_skb_free(tp, &tpr->rx_std_buffers[i], tp->rx_pkt_map_sz); - if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { + if (tg3_flag(tp, JUMBO_CAPABLE)) { for (i = tpr->rx_jmb_cons_idx; i != tpr->rx_jmb_prod_idx; i = (i + 1) & tp->rx_jmb_ring_mask) { @@ -6211,8 +6259,7 @@ static void tg3_rx_prodring_free(struct tg3 *tp, tg3_rx_skb_free(tp, &tpr->rx_std_buffers[i], tp->rx_pkt_map_sz); - if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + if (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS)) { for (i = 0; i <= tp->rx_jmb_ring_mask; i++) tg3_rx_skb_free(tp, &tpr->rx_jmb_buffers[i], TG3_RX_JMB_MAP_SZ); @@ -6249,7 +6296,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp, memset(tpr->rx_std, 0, TG3_RX_STD_RING_BYTES(tp)); rx_pkt_dma_sz = TG3_RX_STD_DMA_SZ; - if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && + if (tg3_flag(tp, 5780_CLASS) && tp->dev->mtu > ETH_DATA_LEN) rx_pkt_dma_sz = TG3_RX_JMB_DMA_SZ; tp->rx_pkt_map_sz = TG3_RX_DMA_TO_MAP_SZ(rx_pkt_dma_sz); @@ -6282,13 +6329,12 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp, } } - if (!(tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + if (!tg3_flag(tp, JUMBO_CAPABLE) || tg3_flag(tp, 5780_CLASS)) goto done; memset(tpr->rx_jmb, 0, TG3_RX_JMB_RING_BYTES(tp)); - if (!(tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE)) + if (!tg3_flag(tp, JUMBO_RING_ENABLE)) goto done; for (i = 0; i <= tp->rx_jmb_ring_mask; i++) { @@ -6357,8 +6403,7 @@ static int tg3_rx_prodring_init(struct tg3 *tp, if (!tpr->rx_std) goto err_out; - if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + if (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS)) { tpr->rx_jmb_buffers = kzalloc(TG3_RX_JMB_BUFF_RING_SIZE(tp), GFP_KERNEL); if (!tpr->rx_jmb_buffers) @@ -6556,8 +6601,8 @@ static int tg3_alloc_consistent(struct tg3 *tp) /* If multivector TSS is enabled, vector 0 does not handle * tx interrupts. Don't allocate any resources for it. */ - if ((!i && !(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)) || - (i && (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS))) { + if ((!i && !tg3_flag(tp, ENABLE_TSS)) || + (i && tg3_flag(tp, ENABLE_TSS))) { tnapi->tx_buffers = kzalloc(sizeof(struct ring_info) * TG3_TX_RING_SIZE, GFP_KERNEL); @@ -6597,7 +6642,7 @@ static int tg3_alloc_consistent(struct tg3 *tp) * If multivector RSS is enabled, vector 0 does not handle * rx or tx interrupts. Don't allocate any resources for it. */ - if (!i && (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) + if (!i && tg3_flag(tp, ENABLE_RSS)) continue; tnapi->rx_rcb = dma_alloc_coherent(&tp->pdev->dev, @@ -6627,7 +6672,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int unsigned int i; u32 val; - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if (tg3_flag(tp, 5705_PLUS)) { switch (ofs) { case RCVLSC_MODE: case DMAC_MODE: @@ -6737,7 +6782,7 @@ static void tg3_ape_send_event(struct tg3 *tp, u32 event) u32 apedata; /* NCSI does not support APE events */ - if (tp->tg3_flags3 & TG3_FLG3_APE_HAS_NCSI) + if (tg3_flag(tp, APE_HAS_NCSI)) return; apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG); @@ -6776,7 +6821,7 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) u32 event; u32 apedata; - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) + if (!tg3_flag(tp, ENABLE_APE)) return; switch (kind) { @@ -6805,7 +6850,7 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0); if (device_may_wakeup(&tp->pdev->dev) && - (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) { + tg3_flag(tp, WOL_ENABLE)) { tg3_ape_write32(tp, TG3_APE_HOST_WOL_SPEED, TG3_APE_HOST_WOL_SPEED_AUTO); apedata = TG3_APE_HOST_DRVR_STATE_WOL; @@ -6834,7 +6879,7 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind) tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX, NIC_SRAM_FIRMWARE_MBOX_MAGIC1); - if (tp->tg3_flags2 & TG3_FLG2_ASF_NEW_HANDSHAKE) { + if (tg3_flag(tp, ASF_NEW_HANDSHAKE)) { switch (kind) { case RESET_KIND_INIT: tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX, @@ -6864,7 +6909,7 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind) /* tp->lock is held. */ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind) { - if (tp->tg3_flags2 & TG3_FLG2_ASF_NEW_HANDSHAKE) { + if (tg3_flag(tp, ASF_NEW_HANDSHAKE)) { switch (kind) { case RESET_KIND_INIT: tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX, @@ -6888,7 +6933,7 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind) /* tp->lock is held. */ static void tg3_write_sig_legacy(struct tg3 *tp, int kind) { - if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { + if (tg3_flag(tp, ENABLE_ASF)) { switch (kind) { case RESET_KIND_INIT: tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX, @@ -6939,9 +6984,8 @@ static int tg3_poll_fw(struct tg3 *tp) * of the above loop as an error, but do report the lack of * running firmware once. */ - if (i >= 100000 && - !(tp->tg3_flags2 & TG3_FLG2_NO_FWARE_REPORTED)) { - tp->tg3_flags2 |= TG3_FLG2_NO_FWARE_REPORTED; + if (i >= 100000 && !tg3_flag(tp, NO_FWARE_REPORTED)) { + tg3_flag_set(tp, NO_FWARE_REPORTED); netdev_info(tp->dev, "No firmware running\n"); } @@ -6974,10 +7018,10 @@ static void tg3_restore_pci_state(struct tg3 *tp) /* Set MAX PCI retry to zero. */ val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE); if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && - (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) + tg3_flag(tp, PCIX_MODE)) val |= PCISTATE_RETRY_SAME_DMA; /* Allow reads and writes to the APE register and memory space. */ - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) val |= PCISTATE_ALLOW_APE_CTLSPC_WR | PCISTATE_ALLOW_APE_SHMEM_WR | PCISTATE_ALLOW_APE_PSPACE_WR; @@ -6986,7 +7030,7 @@ static void tg3_restore_pci_state(struct tg3 *tp) pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd); if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) { - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) + if (tg3_flag(tp, PCI_EXPRESS)) pcie_set_readrq(tp->pdev, tp->pcie_readrq); else { pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, @@ -6997,7 +7041,7 @@ static void tg3_restore_pci_state(struct tg3 *tp) } /* Make sure PCI-X relaxed ordering bit is clear. */ - if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { + if (tg3_flag(tp, PCIX_MODE)) { u16 pcix_cmd; pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, @@ -7007,12 +7051,12 @@ static void tg3_restore_pci_state(struct tg3 *tp) pcix_cmd); } - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { + if (tg3_flag(tp, 5780_CLASS)) { /* Chip reset on 5780 will reset MSI enable bit, * so need to restore it. */ - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + if (tg3_flag(tp, USING_MSI)) { u16 ctrl; pci_read_config_word(tp->pdev, @@ -7052,7 +7096,7 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_save_pci_state(tp); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || - (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)) + tg3_flag(tp, 5755_PLUS)) tw32(GRC_FASTBOOT_PC, 0); /* @@ -7071,7 +7115,7 @@ static int tg3_chip_reset(struct tg3 *tp) * at this time, but the irq handler may still be called due to irq * sharing or irqpoll. */ - tp->tg3_flags |= TG3_FLAG_CHIP_RESETTING; + tg3_flag_set(tp, CHIP_RESETTING); for (i = 0; i < tp->irq_cnt; i++) { struct tg3_napi *tnapi = &tp->napi[i]; if (tnapi->hw_status) { @@ -7094,10 +7138,10 @@ static int tg3_chip_reset(struct tg3 *tp) /* do the reset */ val = GRC_MISC_CFG_CORECLK_RESET; - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + if (tg3_flag(tp, PCI_EXPRESS)) { /* Force PCIe 1.0a mode */ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + !tg3_flag(tp, 57765_PLUS) && tr32(TG3_PCIE_PHY_TSTCTL) == (TG3_PCIE_PHY_TSTCTL_PCIE10 | TG3_PCIE_PHY_TSTCTL_PSCRAM)) tw32(TG3_PCIE_PHY_TSTCTL, TG3_PCIE_PHY_TSTCTL_PSCRAM); @@ -7115,8 +7159,7 @@ static int tg3_chip_reset(struct tg3 *tp) } /* Manage gphy power for all CPMU absent PCIe devices. */ - if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - !(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) + if (tg3_flag(tp, 5705_PLUS) && !tg3_flag(tp, CPMU_PRESENT)) val |= GRC_MISC_CFG_KEEP_GPHY_POWER; tw32(GRC_MISC_CFG, val); @@ -7149,7 +7192,7 @@ static int tg3_chip_reset(struct tg3 *tp) udelay(120); - if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pcie_cap) { + if (tg3_flag(tp, PCI_EXPRESS) && tp->pcie_cap) { u16 val16; if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) { @@ -7175,7 +7218,7 @@ static int tg3_chip_reset(struct tg3 *tp) * Older PCIe devices only support the 128 byte * MPS setting. Enforce the restriction. */ - if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) + if (!tg3_flag(tp, CPMU_PRESENT)) val16 &= ~PCI_EXP_DEVCTL_PAYLOAD; pci_write_config_word(tp->pdev, tp->pcie_cap + PCI_EXP_DEVCTL, @@ -7194,10 +7237,11 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_restore_pci_state(tp); - tp->tg3_flags &= ~TG3_FLAG_CHIP_RESETTING; + tg3_flag_clear(tp, CHIP_RESETTING); + tg3_flag_clear(tp, ERROR_PROCESSED); val = 0; - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) + if (tg3_flag(tp, 5780_CLASS)) val = tr32(MEMARB_MODE); tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE); @@ -7222,7 +7266,7 @@ static int tg3_chip_reset(struct tg3 *tp) tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); } - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN | MAC_MODE_TDE_ENABLE; @@ -7247,28 +7291,33 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_mdio_start(tp); - if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && + if (tg3_flag(tp, PCI_EXPRESS) && tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { + !tg3_flag(tp, 57765_PLUS)) { val = tr32(0x7c00); tw32(0x7c00, val | (1 << 25)); } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { + val = tr32(TG3_CPMU_CLCK_ORIDE); + tw32(TG3_CPMU_CLCK_ORIDE, val & ~CPMU_CLCK_ORIDE_MAC_ORIDE_EN); + } + /* Reprobe ASF enable state. */ - tp->tg3_flags &= ~TG3_FLAG_ENABLE_ASF; - tp->tg3_flags2 &= ~TG3_FLG2_ASF_NEW_HANDSHAKE; + tg3_flag_clear(tp, ENABLE_ASF); + tg3_flag_clear(tp, ASF_NEW_HANDSHAKE); tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { u32 nic_cfg; tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg); if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { - tp->tg3_flags |= TG3_FLAG_ENABLE_ASF; + tg3_flag_set(tp, ENABLE_ASF); tp->last_event_jiffies = jiffies; - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) - tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; + if (tg3_flag(tp, 5750_PLUS)) + tg3_flag_set(tp, ASF_NEW_HANDSHAKE); } } @@ -7278,8 +7327,7 @@ static int tg3_chip_reset(struct tg3 *tp) /* tp->lock is held. */ static void tg3_stop_fw(struct tg3 *tp) { - if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && - !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) { + if (tg3_flag(tp, ENABLE_ASF) && !tg3_flag(tp, ENABLE_APE)) { /* Wait for RX cpu to ACK the previous event. */ tg3_wait_for_event_ack(tp); @@ -7325,8 +7373,7 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset) { int i; - BUG_ON(offset == TX_CPU_BASE && - (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)); + BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { u32 val = tr32(GRC_VCPU_EXT_CTRL); @@ -7361,7 +7408,7 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset) } /* Clear firmware's nvram arbitration. */ - if (tp->tg3_flags & TG3_FLAG_NVRAM) + if (tg3_flag(tp, NVRAM)) tw32(NVRAM_SWARB, SWARB_REQ_CLR0); return 0; } @@ -7379,15 +7426,14 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b int err, lock_err, i; void (*write_op)(struct tg3 *, u32, u32); - if (cpu_base == TX_CPU_BASE && - (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)) { netdev_err(tp->dev, "%s: Trying to load TX cpu firmware which is 5705\n", __func__); return -EINVAL; } - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + if (tg3_flag(tp, 5705_PLUS)) write_op = tg3_write_mem; else write_op = tg3_write_indirect_reg32; @@ -7473,8 +7519,6 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp) return 0; } -/* 5705 needs a special version of the TSO firmware. */ - /* tp->lock is held. */ static int tg3_load_tso_firmware(struct tg3 *tp) { @@ -7483,7 +7527,9 @@ static int tg3_load_tso_firmware(struct tg3 *tp) unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size; int err, i; - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) return 0; fw_data = (void *)tp->fw->data; @@ -7552,7 +7598,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p) if (!netif_running(dev)) return 0; - if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { + if (tg3_flag(tp, ENABLE_ASF)) { u32 addr0_high, addr0_low, addr1_high, addr1_low; addr0_high = tr32(MAC_ADDR_0_HIGH); @@ -7587,7 +7633,7 @@ static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr, (bdinfo_addr + TG3_BDINFO_MAXLEN_FLAGS), maxlen_flags); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) tg3_write_mem(tp, (bdinfo_addr + TG3_BDINFO_NIC_ADDR), nic_addr); @@ -7598,7 +7644,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) { int i; - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)) { + if (!tg3_flag(tp, ENABLE_TSS)) { tw32(HOSTCC_TXCOL_TICKS, ec->tx_coalesce_usecs); tw32(HOSTCC_TXMAX_FRAMES, ec->tx_max_coalesced_frames); tw32(HOSTCC_TXCOAL_MAXF_INT, ec->tx_max_coalesced_frames_irq); @@ -7608,7 +7654,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) tw32(HOSTCC_TXCOAL_MAXF_INT, 0); } - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) { + if (!tg3_flag(tp, ENABLE_RSS)) { tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs); tw32(HOSTCC_RXMAX_FRAMES, ec->rx_max_coalesced_frames); tw32(HOSTCC_RXCOAL_MAXF_INT, ec->rx_max_coalesced_frames_irq); @@ -7618,7 +7664,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) tw32(HOSTCC_RXCOAL_MAXF_INT, 0); } - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { u32 val = ec->stats_block_coalesce_usecs; tw32(HOSTCC_RXCOAL_TICK_INT, ec->rx_coalesce_usecs_irq); @@ -7640,7 +7686,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) reg = HOSTCC_RXCOAL_MAXF_INT_VEC1 + i * 0x18; tw32(reg, ec->rx_max_coalesced_frames_irq); - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) { + if (tg3_flag(tp, ENABLE_TSS)) { reg = HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18; tw32(reg, ec->tx_coalesce_usecs); reg = HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18; @@ -7655,7 +7701,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) tw32(HOSTCC_RXMAX_FRAMES_VEC1 + i * 0x18, 0); tw32(HOSTCC_RXCOAL_MAXF_INT_VEC1 + i * 0x18, 0); - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) { + if (tg3_flag(tp, ENABLE_TSS)) { tw32(HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18, 0); tw32(HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18, 0); tw32(HOSTCC_TXCOAL_MAXF_INT_VEC1 + i * 0x18, 0); @@ -7671,10 +7717,9 @@ static void tg3_rings_reset(struct tg3 *tp) struct tg3_napi *tnapi = &tp->napi[0]; /* Disable all transmit rings but the first. */ - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16; - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + else if (tg3_flag(tp, 5717_PLUS)) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 4; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 2; @@ -7688,10 +7733,9 @@ static void tg3_rings_reset(struct tg3 *tp) /* Disable all receive return rings but the first. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (tg3_flag(tp, 5717_PLUS)) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17; - else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + else if (!tg3_flag(tp, 5705_PLUS)) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) @@ -7708,16 +7752,16 @@ static void tg3_rings_reset(struct tg3 *tp) tw32_mailbox_f(tp->napi[0].int_mbox, 1); /* Zero mailbox registers. */ - if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) { + if (tg3_flag(tp, SUPPORT_MSIX)) { for (i = 1; i < tp->irq_max; i++) { tp->napi[i].tx_prod = 0; tp->napi[i].tx_cons = 0; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + if (tg3_flag(tp, ENABLE_TSS)) tw32_mailbox(tp->napi[i].prodmbox, 0); tw32_rx_mbox(tp->napi[i].consmbox, 0); tw32_mailbox_f(tp->napi[i].int_mbox, 1); } - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)) + if (!tg3_flag(tp, ENABLE_TSS)) tw32_mailbox(tp->napi[0].prodmbox, 0); } else { tp->napi[0].tx_prod = 0; @@ -7727,7 +7771,7 @@ static void tg3_rings_reset(struct tg3 *tp) } /* Make sure the NIC-based send BD rings are disabled. */ - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { u32 mbox = MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW; for (i = 0; i < 16; i++) tw32_tx_mbox(mbox + i * 8, 0); @@ -7787,6 +7831,47 @@ static void tg3_rings_reset(struct tg3 *tp) } } +static void tg3_setup_rxbd_thresholds(struct tg3 *tp) +{ + u32 val, bdcache_maxcnt, host_rep_thresh, nic_rep_thresh; + + if (!tg3_flag(tp, 5750_PLUS) || + tg3_flag(tp, 5780_CLASS) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) + bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5700; + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5755; + else + bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5906; + + nic_rep_thresh = min(bdcache_maxcnt / 2, tp->rx_std_max_post); + host_rep_thresh = max_t(u32, tp->rx_pending / 8, 1); + + val = min(nic_rep_thresh, host_rep_thresh); + tw32(RCVBDI_STD_THRESH, val); + + if (tg3_flag(tp, 57765_PLUS)) + tw32(STD_REPLENISH_LWM, bdcache_maxcnt); + + if (!tg3_flag(tp, JUMBO_CAPABLE) || tg3_flag(tp, 5780_CLASS)) + return; + + if (!tg3_flag(tp, 5705_PLUS)) + bdcache_maxcnt = TG3_SRAM_RX_JMB_BDCACHE_SIZE_5700; + else + bdcache_maxcnt = TG3_SRAM_RX_JMB_BDCACHE_SIZE_5717; + + host_rep_thresh = max_t(u32, tp->rx_jumbo_pending / 8, 1); + + val = min(bdcache_maxcnt / 2, host_rep_thresh); + tw32(RCVBDI_JUMBO_THRESH, val); + + if (tg3_flag(tp, 57765_PLUS)) + tw32(JMB_REPLENISH_LWM, bdcache_maxcnt); +} + /* tp->lock is held. */ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) { @@ -7800,7 +7885,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_write_sig_pre_reset(tp, RESET_KIND_INIT); - if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) + if (tg3_flag(tp, INIT_COMPLETE)) tg3_abort_hw(tp, 1); /* Enable MAC control of LPI */ @@ -7820,7 +7905,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) val |= TG3_CPMU_EEEMD_APE_TX_DET_EN; tw32_f(TG3_CPMU_EEE_MODE, val); @@ -7879,7 +7964,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS); } - if (tp->tg3_flags3 & TG3_FLG3_L1PLLPD_EN) { + if (tg3_flag(tp, L1PLLPD_EN)) { u32 grc_mode = tr32(GRC_MODE); /* Access the lower 1K of PL PCIE block registers. */ @@ -7909,6 +7994,22 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(GRC_MODE, grc_mode); } + if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_57765_AX) { + u32 grc_mode = tr32(GRC_MODE); + + /* Access the lower 1K of DL PCIE block registers. */ + val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK; + tw32(GRC_MODE, val | GRC_MODE_PCIE_DL_SEL); + + val = tr32(TG3_PCIE_TLDLPL_PORT + + TG3_PCIE_DL_LO_FTSMAX); + val &= ~TG3_PCIE_DL_LO_FTSMAX_MSK; + tw32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_DL_LO_FTSMAX, + val | TG3_PCIE_DL_LO_FTSMAX_VAL); + + tw32(GRC_MODE, grc_mode); + } + val = tr32(TG3_CPMU_LSPD_10MB_CLK); val &= ~CPMU_LSPD_10MB_MACCLK_MASK; val |= CPMU_LSPD_10MB_MACCLK_6_25; @@ -7920,20 +8021,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) * other revision. But do not set this on PCI Express * chips and don't even touch the clocks if the CPMU is present. */ - if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) { - if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) + if (!tg3_flag(tp, CPMU_PRESENT)) { + if (!tg3_flag(tp, PCI_EXPRESS)) tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT; tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); } if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && - (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { + tg3_flag(tp, PCIX_MODE)) { val = tr32(TG3PCI_PCISTATE); val |= PCISTATE_RETRY_SAME_DMA; tw32(TG3PCI_PCISTATE, val); } - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { + if (tg3_flag(tp, ENABLE_APE)) { /* Allow reads and writes to the * APE register and memory space. */ @@ -7960,11 +8061,14 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (err) return err; - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tg3_flag(tp, 57765_PLUS)) { val = tr32(TG3PCI_DMA_RW_CTRL) & ~DMA_RWCTRL_DIS_CACHE_ALIGNMENT; if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) val &= ~DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK; + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) + val |= DMA_RWCTRL_TAGGED_STAT_WA; tw32(TG3PCI_DMA_RW_CTRL, val | tp->dma_rwctrl); } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) { @@ -7999,7 +8103,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(GRC_MISC_CFG, val); /* Initialize MBUF/DESC pool. */ - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { + if (tg3_flag(tp, 5750_PLUS)) { /* Do nothing. */ } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) { tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE); @@ -8009,7 +8113,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96); tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE); tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE); - } else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) { + } else if (tg3_flag(tp, TSO_CAPABLE)) { int fw_len; fw_len = tp->fw_len; @@ -8043,6 +8147,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) val = BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) val |= BUFMGR_MODE_NO_TX_UNDERRUN; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5720_A0) + val |= BUFMGR_MODE_MBLOW_ATTN_ENAB; tw32(BUFMGR_MODE, val); for (i = 0; i < 2000; i++) { if (tr32(BUFMGR_MODE) & BUFMGR_MODE_ENABLE) @@ -8054,21 +8162,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return -ENODEV; } - /* Setup replenish threshold. */ - val = tp->rx_pending / 8; - if (val == 0) - val = 1; - else if (val > tp->rx_std_max_post) - val = tp->rx_std_max_post; - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1) - tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2); + if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1) + tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2); - if (val > (TG3_RX_INTERNAL_RING_SZ_5906 / 2)) - val = TG3_RX_INTERNAL_RING_SZ_5906 / 2; - } - - tw32(RCVBDI_STD_THRESH, val); + tg3_setup_rxbd_thresholds(tp); /* Initialize TG3_BDINFO's at: * RCVDBDI_STD_BD: standard eth size rx ring @@ -8091,13 +8188,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) ((u64) tpr->rx_std_mapping >> 32)); tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tpr->rx_std_mapping & 0xffffffff)); - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) + if (!tg3_flag(tp, 5717_PLUS)) tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_BUFFER_DESC); /* Disable the mini ring */ - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED); @@ -8105,20 +8201,18 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) * blocks on those devices that have them. */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || - ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))) { - /* Setup replenish threshold. */ - tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8); + (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS))) { - if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { + if (tg3_flag(tp, JUMBO_RING_ENABLE)) { tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, ((u64) tpr->rx_jmb_mapping >> 32)); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tpr->rx_jmb_mapping & 0xffffffff)); + val = TG3_RX_JMB_RING_SIZE(tp) << + BDINFO_FLAGS_MAXLEN_SHIFT; tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, - (RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT) | - BDINFO_FLAGS_USE_EXT_RECV); - if (!(tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) || + val | BDINFO_FLAGS_USE_EXT_RECV); + if (!tg3_flag(tp, USE_JUMBO_BDFLAG) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_JUMBO_BUFFER_DESC); @@ -8127,32 +8221,27 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_DISABLED); } - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tg3_flag(tp, 57765_PLUS)) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) - val = RX_STD_MAX_SIZE_5705; + val = TG3_RX_STD_MAX_SIZE_5700; else - val = RX_STD_MAX_SIZE_5717; + val = TG3_RX_STD_MAX_SIZE_5717; val <<= BDINFO_FLAGS_MAXLEN_SHIFT; val |= (TG3_RX_STD_DMA_SZ << 2); } else val = TG3_RX_STD_DMA_SZ << BDINFO_FLAGS_MAXLEN_SHIFT; } else - val = RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT; + val = TG3_RX_STD_MAX_SIZE_5700 << BDINFO_FLAGS_MAXLEN_SHIFT; tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, val); tpr->rx_std_prod_idx = tp->rx_pending; tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG, tpr->rx_std_prod_idx); - tpr->rx_jmb_prod_idx = (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) ? - tp->rx_jumbo_pending : 0; + tpr->rx_jmb_prod_idx = + tg3_flag(tp, JUMBO_RING_ENABLE) ? tp->rx_jumbo_pending : 0; tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, tpr->rx_jmb_prod_idx); - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { - tw32(STD_REPLENISH_LWM, 32); - tw32(JMB_REPLENISH_LWM, 16); - } - tg3_rings_reset(tp); /* Initialize MAC address and backoff seed. */ @@ -8165,10 +8254,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* The slot time is changed by tg3_setup_phy if we * run at gigabit with half duplex. */ - tw32(MAC_TX_LENGTHS, - (2 << TX_LENGTHS_IPG_CRS_SHIFT) | - (6 << TX_LENGTHS_IPG_SHIFT) | - (32 << TX_LENGTHS_SLOT_TIME_SHIFT)); + val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT) | + (32 << TX_LENGTHS_SLOT_TIME_SHIFT); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + val |= tr32(MAC_TX_LENGTHS) & + (TX_LENGTHS_JMB_FRM_LEN_MSK | + TX_LENGTHS_CNT_DWN_VAL_MSK); + + tw32(MAC_TX_LENGTHS, val); /* Receive rules. */ tw32(MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS); @@ -8195,33 +8290,39 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) { - if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE && + if (tg3_flag(tp, TSO_CAPABLE) && GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) { rdmac_mode |= RDMAC_MODE_FIFO_SIZE_128; } else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) && - !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) { + !tg3_flag(tp, IS_5788)) { rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST; } } - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) + if (tg3_flag(tp, PCI_EXPRESS)) rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST; - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) rdmac_mode |= RDMAC_MODE_IPV4_LSO_EN; - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) || + if (tg3_flag(tp, 57765_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + rdmac_mode |= tr32(RDMAC_MODE) & RDMAC_MODE_H2BNC_VLAN_DET; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { + tg3_flag(tp, 57765_PLUS)) { val = tr32(TG3_RDMA_RSRVCTRL_REG); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK | TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK | TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK); @@ -8233,7 +8334,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX); } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL); tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val | TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K | @@ -8241,12 +8343,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) } /* Receive/send statistics. */ - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { + if (tg3_flag(tp, 5750_PLUS)) { val = tr32(RCVLPC_STATS_ENABLE); val &= ~RCVLPC_STATSENAB_DACK_FIX; tw32(RCVLPC_STATS_ENABLE, val); } else if ((rdmac_mode & RDMAC_MODE_FIFO_SIZE_128) && - (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) { + tg3_flag(tp, TSO_CAPABLE)) { val = tr32(RCVLPC_STATS_ENABLE); val &= ~RCVLPC_STATSENAB_LNGBRST_RFIX; tw32(RCVLPC_STATS_ENABLE, val); @@ -8269,7 +8371,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) __tg3_set_coalesce(tp, &tp->coal); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { /* Status/statistics block address. See tg3_timer, * the tg3_periodic_fetch_stats call there, and * tg3_get_stats to see how this works for 5705/5750 chips. @@ -8295,7 +8397,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(RCVCC_MODE, RCVCC_MODE_ENABLE | RCVCC_MODE_ATTN_ENABLE); tw32(RCVLPC_MODE, RCVLPC_MODE_ENABLE); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE); if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) { @@ -8305,13 +8407,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(10); } - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN; else tp->mac_mode = 0; tp->mac_mode |= MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE | MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && + if (!tg3_flag(tp, 5705_PLUS) && !(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) tp->mac_mode |= MAC_MODE_LINK_POLARITY; @@ -8319,12 +8421,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(40); /* tp->grc_local_ctrl is partially set up during tg3_get_invariants(). - * If TG3_FLG2_IS_NIC is zero, we should read the + * If TG3_FLAG_IS_NIC is zero, we should read the * register to preserve the GPIO settings for LOMs. The GPIOs, * whether used as inputs or outputs, are set by boot code after * reset. */ - if (!(tp->tg3_flags2 & TG3_FLG2_IS_NIC)) { + if (!tg3_flag(tp, IS_NIC)) { u32 gpio_mask; gpio_mask = GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | @@ -8342,21 +8444,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tp->grc_local_ctrl |= tr32(GRC_LOCAL_CTRL) & gpio_mask; /* GPIO1 must be driven high for eeprom write protect */ - if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) + if (tg3_flag(tp, EEPROM_WRITE_PROT)) tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1); } tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); - if ((tp->tg3_flags2 & TG3_FLG2_USING_MSIX) && - tp->irq_cnt > 1) { + if (tg3_flag(tp, USING_MSIX) && tp->irq_cnt > 1) { val = tr32(MSGINT_MODE); val |= MSGINT_MODE_MULTIVEC_EN | MSGINT_MODE_ENABLE; tw32(MSGINT_MODE, val); } - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); udelay(40); } @@ -8369,18 +8470,18 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) { - if ((tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && + if (tg3_flag(tp, TSO_CAPABLE) && (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) { /* nothing */ } else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) && - !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) { + !tg3_flag(tp, IS_5788)) { val |= WDMAC_MODE_RX_ACCEL; } } /* Enable host coalescing bug fix */ - if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) + if (tg3_flag(tp, 5755_PLUS)) val |= WDMAC_MODE_STATUS_TAG_FIX; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) @@ -8389,7 +8490,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(WDMAC_MODE, val); udelay(40); - if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { + if (tg3_flag(tp, PCIX_MODE)) { u16 pcix_cmd; pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, @@ -8409,7 +8510,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(40); tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) tw32(MBFREE_MODE, MBFREE_MODE_ENABLE); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) @@ -8421,15 +8522,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE); tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB); val = RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (tg3_flag(tp, LRG_PROD_RING_CAP)) val |= RCVDBDI_MODE_LRG_RING_SZ; tw32(RCVDBDI_MODE, val); tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE); - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8); val = SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + if (tg3_flag(tp, ENABLE_TSS)) val |= SNDBDI_MODE_MULTI_TXQ_EN; tw32(SNDBDI_MODE, val); tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE); @@ -8440,20 +8542,28 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return err; } - if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) { + if (tg3_flag(tp, TSO_CAPABLE)) { err = tg3_load_tso_firmware(tp); if (err) return err; } tp->tx_mode = TX_MODE_ENABLE; - if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || + + if (tg3_flag(tp, 5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->tx_mode |= TX_MODE_MBUF_LOCKUP_FIX; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { + val = TX_MODE_JMB_FRM_LEN | TX_MODE_CNT_DN_MODE; + tp->tx_mode &= ~val; + tp->tx_mode |= tr32(MAC_TX_MODE) & val; + } + tw32_f(MAC_TX_MODE, tp->tx_mode); udelay(100); - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) { + if (tg3_flag(tp, ENABLE_RSS)) { u32 reg = MAC_RSS_INDIR_TBL_0; u8 *ent = (u8 *)&val; @@ -8482,10 +8592,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) } tp->rx_mode = RX_MODE_ENABLE; - if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) + if (tg3_flag(tp, 5755_PLUS)) tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) + if (tg3_flag(tp, ENABLE_RSS)) tp->rx_mode |= RX_MODE_RSS_ENABLE | RX_MODE_RSS_ITBL_HASH_BITS_7 | RX_MODE_RSS_IPV6_HASH_EN | @@ -8532,11 +8642,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) { /* Use hardware link auto-negotiation */ - tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG; + tg3_flag_set(tp, HW_AUTONEG); } if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) && - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { u32 tmp; tmp = tr32(SERDES_RX_CTRL); @@ -8546,7 +8656,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); } - if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { + if (!tg3_flag(tp, USE_PHYLIB)) { if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) { tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER; tp->link_config.speed = tp->link_config.orig_speed; @@ -8579,12 +8689,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(MAC_RCV_RULE_1, 0x86000004 & RCV_RULE_DISABLE_MASK); tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK); - if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + if (tg3_flag(tp, 5705_PLUS) && !tg3_flag(tp, 5780_CLASS)) limit = 8; else limit = 16; - if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) + if (tg3_flag(tp, ENABLE_ASF)) limit -= 4; switch (limit) { case 16: @@ -8622,7 +8731,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) break; } - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) /* Write our heartbeat update interval to APE. */ tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS, APE_HOST_HEARTBEAT_INT_DISABLE); @@ -8688,7 +8797,21 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp) TG3_STAT_ADD32(&sp->rx_undersize_packets, MAC_RX_STATS_UNDERSIZE); TG3_STAT_ADD32(&sp->rxbds_empty, RCVLPC_NO_RCV_BD_CNT); - TG3_STAT_ADD32(&sp->rx_discards, RCVLPC_IN_DISCARDS_CNT); + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && + tp->pci_chip_rev_id != CHIPREV_ID_5719_A0 && + tp->pci_chip_rev_id != CHIPREV_ID_5720_A0) { + TG3_STAT_ADD32(&sp->rx_discards, RCVLPC_IN_DISCARDS_CNT); + } else { + u32 val = tr32(HOSTCC_FLOW_ATTN); + val = (val & HOSTCC_FLOW_ATTN_MBUF_LWM) ? 1 : 0; + if (val) { + tw32(HOSTCC_FLOW_ATTN, HOSTCC_FLOW_ATTN_MBUF_LWM); + sp->rx_discards.low += val; + if (sp->rx_discards.low < val) + sp->rx_discards.high += 1; + } + sp->mbuf_lwm_thresh_hit = sp->rx_discards; + } TG3_STAT_ADD32(&sp->rx_errors, RCVLPC_IN_ERRORS_CNT); } @@ -8701,7 +8824,7 @@ static void tg3_timer(unsigned long __opaque) spin_lock(&tp->lock); - if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { + if (!tg3_flag(tp, TAGGED_STATUS)) { /* All of this garbage is because when using non-tagged * IRQ status the mailbox/status_block protocol the chip * uses with the cpu is race prone. @@ -8715,7 +8838,7 @@ static void tg3_timer(unsigned long __opaque) } if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { - tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER; + tg3_flag_set(tp, RESTART_TIMER); spin_unlock(&tp->lock); schedule_work(&tp->reset_task); return; @@ -8724,16 +8847,13 @@ static void tg3_timer(unsigned long __opaque) /* This part only runs once per second. */ if (!--tp->timer_counter) { - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + if (tg3_flag(tp, 5705_PLUS)) tg3_periodic_fetch_stats(tp); - if (tp->setlpicnt && !--tp->setlpicnt) { - u32 val = tr32(TG3_CPMU_EEE_MODE); - tw32(TG3_CPMU_EEE_MODE, - val | TG3_CPMU_EEEMD_LPI_ENABLE); - } + if (tp->setlpicnt && !--tp->setlpicnt) + tg3_phy_eee_enable(tp); - if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) { + if (tg3_flag(tp, USE_LINKCHG_REG)) { u32 mac_stat; int phy_event; @@ -8748,7 +8868,7 @@ static void tg3_timer(unsigned long __opaque) if (phy_event) tg3_setup_phy(tp, 0); - } else if (tp->tg3_flags & TG3_FLAG_POLL_SERDES) { + } else if (tg3_flag(tp, POLL_SERDES)) { u32 mac_stat = tr32(MAC_STATUS); int need_setup = 0; @@ -8773,7 +8893,7 @@ static void tg3_timer(unsigned long __opaque) tg3_setup_phy(tp, 0); } } else if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) && - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + tg3_flag(tp, 5780_CLASS)) { tg3_serdes_parallel_detect(tp); } @@ -8798,8 +8918,7 @@ static void tg3_timer(unsigned long __opaque) * resets. */ if (!--tp->asf_counter) { - if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && - !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) { + if (tg3_flag(tp, ENABLE_ASF) && !tg3_flag(tp, ENABLE_APE)) { tg3_wait_for_event_ack(tp); tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, @@ -8835,16 +8954,16 @@ static int tg3_request_irq(struct tg3 *tp, int irq_num) name[IFNAMSIZ-1] = 0; } - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { + if (tg3_flag(tp, USING_MSI) || tg3_flag(tp, USING_MSIX)) { fn = tg3_msi; - if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) + if (tg3_flag(tp, 1SHOT_MSI)) fn = tg3_msi_1shot; - flags = IRQF_SAMPLE_RANDOM; + flags = 0; } else { fn = tg3_interrupt; - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) + if (tg3_flag(tp, TAGGED_STATUS)) fn = tg3_interrupt_tagged; - flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM; + flags = IRQF_SHARED; } return request_irq(tnapi->irq_vec, fn, flags, name, tnapi); @@ -8868,8 +8987,7 @@ static int tg3_test_interrupt(struct tg3 *tp) * Turn off MSI one shot mode. Otherwise this test has no * observable way to know whether the interrupt was delivered. */ - if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && - (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { + if (tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) { val = tr32(MSGINT_MODE) | MSGINT_MODE_ONE_SHOT_DISABLE; tw32(MSGINT_MODE, val); } @@ -8911,8 +9029,7 @@ static int tg3_test_interrupt(struct tg3 *tp) if (intr_ok) { /* Reenable MSI one shot mode. */ - if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && - (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { + if (tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) { val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE; tw32(MSGINT_MODE, val); } @@ -8930,7 +9047,7 @@ static int tg3_test_msi(struct tg3 *tp) int err; u16 pci_cmd; - if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSI)) + if (!tg3_flag(tp, USING_MSI)) return 0; /* Turn off SERR reporting in case MSI terminates with Master @@ -8960,7 +9077,7 @@ static int tg3_test_msi(struct tg3 *tp) pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; + tg3_flag_clear(tp, USING_MSI); tp->napi[0].irq_vec = tp->pdev->irq; err = tg3_request_irq(tp, 0); @@ -9057,9 +9174,11 @@ static bool tg3_enable_msix(struct tg3 *tp) } if (tp->irq_cnt > 1) { - tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { - tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS; + tg3_flag_set(tp, ENABLE_RSS); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { + tg3_flag_set(tp, ENABLE_TSS); netif_set_real_num_tx_queues(tp->dev, tp->irq_cnt - 1); } } @@ -9069,8 +9188,8 @@ static bool tg3_enable_msix(struct tg3 *tp) static void tg3_ints_init(struct tg3 *tp) { - if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI_OR_MSIX) && - !(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { + if ((tg3_flag(tp, SUPPORT_MSI) || tg3_flag(tp, SUPPORT_MSIX)) && + !tg3_flag(tp, TAGGED_STATUS)) { /* All MSI supporting chips should support tagged * status. Assert that this is the case. */ @@ -9079,21 +9198,19 @@ static void tg3_ints_init(struct tg3 *tp) goto defcfg; } - if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) && tg3_enable_msix(tp)) - tp->tg3_flags2 |= TG3_FLG2_USING_MSIX; - else if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) && - pci_enable_msi(tp->pdev) == 0) - tp->tg3_flags2 |= TG3_FLG2_USING_MSI; + if (tg3_flag(tp, SUPPORT_MSIX) && tg3_enable_msix(tp)) + tg3_flag_set(tp, USING_MSIX); + else if (tg3_flag(tp, SUPPORT_MSI) && pci_enable_msi(tp->pdev) == 0) + tg3_flag_set(tp, USING_MSI); - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { + if (tg3_flag(tp, USING_MSI) || tg3_flag(tp, USING_MSIX)) { u32 msi_mode = tr32(MSGINT_MODE); - if ((tp->tg3_flags2 & TG3_FLG2_USING_MSIX) && - tp->irq_cnt > 1) + if (tg3_flag(tp, USING_MSIX) && tp->irq_cnt > 1) msi_mode |= MSGINT_MODE_MULTIVEC_EN; tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); } defcfg: - if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) { + if (!tg3_flag(tp, USING_MSIX)) { tp->irq_cnt = 1; tp->napi[0].irq_vec = tp->pdev->irq; netif_set_real_num_tx_queues(tp->dev, 1); @@ -9103,12 +9220,14 @@ static void tg3_ints_init(struct tg3 *tp) static void tg3_ints_fini(struct tg3 *tp) { - if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + if (tg3_flag(tp, USING_MSIX)) pci_disable_msix(tp->pdev); - else if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) + else if (tg3_flag(tp, USING_MSI)) pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI_OR_MSIX; - tp->tg3_flags3 &= ~(TG3_FLG3_ENABLE_RSS | TG3_FLG3_ENABLE_TSS); + tg3_flag_clear(tp, USING_MSI); + tg3_flag_clear(tp, USING_MSIX); + tg3_flag_clear(tp, ENABLE_RSS); + tg3_flag_clear(tp, ENABLE_TSS); } static int tg3_open(struct net_device *dev) @@ -9123,10 +9242,10 @@ static int tg3_open(struct net_device *dev) return err; } else if (err) { netdev_warn(tp->dev, "TSO capability disabled\n"); - tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; - } else if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) { + tg3_flag_clear(tp, TSO_CAPABLE); + } else if (!tg3_flag(tp, TSO_CAPABLE)) { netdev_notice(tp->dev, "TSO capability restored\n"); - tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; + tg3_flag_set(tp, TSO_CAPABLE); } } @@ -9139,7 +9258,7 @@ static int tg3_open(struct net_device *dev) tg3_full_lock(tp, 0); tg3_disable_ints(tp); - tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; + tg3_flag_clear(tp, INIT_COMPLETE); tg3_full_unlock(tp); @@ -9180,7 +9299,7 @@ static int tg3_open(struct net_device *dev) tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); } else { - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) + if (tg3_flag(tp, TAGGED_STATUS)) tp->timer_offset = HZ; else tp->timer_offset = HZ / 10; @@ -9202,7 +9321,7 @@ static int tg3_open(struct net_device *dev) if (err) goto err_out3; - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + if (tg3_flag(tp, USING_MSI)) { err = tg3_test_msi(tp); if (err) { @@ -9214,8 +9333,7 @@ static int tg3_open(struct net_device *dev) goto err_out2; } - if (!(tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && - (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { + if (!tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) { u32 val = tr32(PCIE_TRANSACTION_CFG); tw32(PCIE_TRANSACTION_CFG, @@ -9228,13 +9346,20 @@ static int tg3_open(struct net_device *dev) tg3_full_lock(tp, 0); add_timer(&tp->timer); - tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; + tg3_flag_set(tp, INIT_COMPLETE); tg3_enable_ints(tp); tg3_full_unlock(tp); netif_tx_start_all_queues(dev); + /* + * Reset loopback feature if it was turned on while the device was down + * make sure that it's installed properly now. + */ + if (dev->features & NETIF_F_LOOPBACK) + tg3_set_loopback(dev, dev->features); + return 0; err_out3: @@ -9277,7 +9402,7 @@ static int tg3_close(struct net_device *dev) tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); - tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; + tg3_flag_clear(tp, INIT_COMPLETE); tg3_full_unlock(tp); @@ -9424,6 +9549,8 @@ static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp) ESTAT_ADD(nic_avoided_irqs); ESTAT_ADD(nic_tx_threshold_hit); + ESTAT_ADD(mbuf_lwm_thresh_hit); + return estats; } @@ -9534,7 +9661,7 @@ static void __tg3_set_rx_mode(struct net_device *dev) /* When ASF is in use, we always keep the RX_MODE_KEEP_VLAN_TAG * flag clear. */ - if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (!tg3_flag(tp, ENABLE_ASF)) rx_mode |= RX_MODE_KEEP_VLAN_TAG; #endif @@ -9588,82 +9715,26 @@ static void tg3_set_rx_mode(struct net_device *dev) tg3_full_unlock(tp); } -#define TG3_REGDUMP_LEN (32 * 1024) - static int tg3_get_regs_len(struct net_device *dev) { - return TG3_REGDUMP_LEN; + return TG3_REG_BLK_SIZE; } static void tg3_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) { - u32 *p = _p; struct tg3 *tp = netdev_priv(dev); - u8 *orig_p = _p; - int i; regs->version = 0; - memset(p, 0, TG3_REGDUMP_LEN); + memset(_p, 0, TG3_REG_BLK_SIZE); if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) return; tg3_full_lock(tp, 0); -#define __GET_REG32(reg) (*(p)++ = tr32(reg)) -#define GET_REG32_LOOP(base, len) \ -do { p = (u32 *)(orig_p + (base)); \ - for (i = 0; i < len; i += 4) \ - __GET_REG32((base) + i); \ -} while (0) -#define GET_REG32_1(reg) \ -do { p = (u32 *)(orig_p + (reg)); \ - __GET_REG32((reg)); \ -} while (0) - - GET_REG32_LOOP(TG3PCI_VENDOR, 0xb0); - GET_REG32_LOOP(MAILBOX_INTERRUPT_0, 0x200); - GET_REG32_LOOP(MAC_MODE, 0x4f0); - GET_REG32_LOOP(SNDDATAI_MODE, 0xe0); - GET_REG32_1(SNDDATAC_MODE); - GET_REG32_LOOP(SNDBDS_MODE, 0x80); - GET_REG32_LOOP(SNDBDI_MODE, 0x48); - GET_REG32_1(SNDBDC_MODE); - GET_REG32_LOOP(RCVLPC_MODE, 0x20); - GET_REG32_LOOP(RCVLPC_SELLST_BASE, 0x15c); - GET_REG32_LOOP(RCVDBDI_MODE, 0x0c); - GET_REG32_LOOP(RCVDBDI_JUMBO_BD, 0x3c); - GET_REG32_LOOP(RCVDBDI_BD_PROD_IDX_0, 0x44); - GET_REG32_1(RCVDCC_MODE); - GET_REG32_LOOP(RCVBDI_MODE, 0x20); - GET_REG32_LOOP(RCVCC_MODE, 0x14); - GET_REG32_LOOP(RCVLSC_MODE, 0x08); - GET_REG32_1(MBFREE_MODE); - GET_REG32_LOOP(HOSTCC_MODE, 0x100); - GET_REG32_LOOP(MEMARB_MODE, 0x10); - GET_REG32_LOOP(BUFMGR_MODE, 0x58); - GET_REG32_LOOP(RDMAC_MODE, 0x08); - GET_REG32_LOOP(WDMAC_MODE, 0x08); - GET_REG32_1(RX_CPU_MODE); - GET_REG32_1(RX_CPU_STATE); - GET_REG32_1(RX_CPU_PGMCTR); - GET_REG32_1(RX_CPU_HWBKPT); - GET_REG32_1(TX_CPU_MODE); - GET_REG32_1(TX_CPU_STATE); - GET_REG32_1(TX_CPU_PGMCTR); - GET_REG32_LOOP(GRCMBOX_INTERRUPT_0, 0x110); - GET_REG32_LOOP(FTQ_RESET, 0x120); - GET_REG32_LOOP(MSGINT_MODE, 0x0c); - GET_REG32_1(DMAC_MODE); - GET_REG32_LOOP(GRC_MODE, 0x4c); - if (tp->tg3_flags & TG3_FLAG_NVRAM) - GET_REG32_LOOP(NVRAM_CMD, 0x24); - -#undef __GET_REG32 -#undef GET_REG32_LOOP -#undef GET_REG32_1 + tg3_dump_legacy_regs(tp, (u32 *)_p); tg3_full_unlock(tp); } @@ -9683,7 +9754,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u32 i, offset, len, b_offset, b_count; __be32 val; - if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) + if (tg3_flag(tp, NO_NVRAM)) return -EINVAL; if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) @@ -9751,7 +9822,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) return -EAGAIN; - if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || + if (tg3_flag(tp, NO_NVRAM) || eeprom->magic != TG3_EEPROM_MAGIC) return -EINVAL; @@ -9803,7 +9874,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct tg3 *tp = netdev_priv(dev); - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { struct phy_device *phydev; if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)) return -EAGAIN; @@ -9831,10 +9902,10 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = tp->link_config.advertising; if (netif_running(dev)) { - cmd->speed = tp->link_config.active_speed; + ethtool_cmd_speed_set(cmd, tp->link_config.active_speed); cmd->duplex = tp->link_config.active_duplex; } else { - cmd->speed = SPEED_INVALID; + ethtool_cmd_speed_set(cmd, SPEED_INVALID); cmd->duplex = DUPLEX_INVALID; } cmd->phy_address = tp->phy_addr; @@ -9848,8 +9919,9 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct tg3 *tp = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(cmd); - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { struct phy_device *phydev; if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)) return -EAGAIN; @@ -9897,14 +9969,14 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising &= mask; } else { if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES) { - if (cmd->speed != SPEED_1000) + if (speed != SPEED_1000) return -EINVAL; if (cmd->duplex != DUPLEX_FULL) return -EINVAL; } else { - if (cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) + if (speed != SPEED_100 && + speed != SPEED_10) return -EINVAL; } } @@ -9919,7 +9991,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) tp->link_config.duplex = DUPLEX_INVALID; } else { tp->link_config.advertising = 0; - tp->link_config.speed = cmd->speed; + tp->link_config.speed = speed; tp->link_config.duplex = cmd->duplex; } @@ -9949,14 +10021,12 @@ static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct tg3 *tp = netdev_priv(dev); - if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) && - device_can_wakeup(&tp->pdev->dev)) + if (tg3_flag(tp, WOL_CAP) && device_can_wakeup(&tp->pdev->dev)) wol->supported = WAKE_MAGIC; else wol->supported = 0; wol->wolopts = 0; - if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) && - device_can_wakeup(&tp->pdev->dev)) + if (tg3_flag(tp, WOL_ENABLE) && device_can_wakeup(&tp->pdev->dev)) wol->wolopts = WAKE_MAGIC; memset(&wol->sopass, 0, sizeof(wol->sopass)); } @@ -9969,19 +10039,18 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; if ((wol->wolopts & WAKE_MAGIC) && - !((tp->tg3_flags & TG3_FLAG_WOL_CAP) && device_can_wakeup(dp))) + !(tg3_flag(tp, WOL_CAP) && device_can_wakeup(dp))) return -EINVAL; device_set_wakeup_enable(dp, wol->wolopts & WAKE_MAGIC); spin_lock_bh(&tp->lock); if (device_may_wakeup(dp)) - tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + tg3_flag_set(tp, WOL_ENABLE); else - tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE; + tg3_flag_clear(tp, WOL_ENABLE); spin_unlock_bh(&tp->lock); - return 0; } @@ -9997,33 +10066,6 @@ static void tg3_set_msglevel(struct net_device *dev, u32 value) tp->msg_enable = value; } -static int tg3_set_tso(struct net_device *dev, u32 value) -{ - struct tg3 *tp = netdev_priv(dev); - - if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) { - if (value) - return -EINVAL; - return 0; - } - if ((dev->features & NETIF_F_IPV6_CSUM) && - ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) || - (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3))) { - if (value) { - dev->features |= NETIF_F_TSO6; - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && - GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) - dev->features |= NETIF_F_TSO_ECN; - } else - dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN); - } - return ethtool_op_set_tso(dev, value); -} - static int tg3_nway_reset(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); @@ -10035,7 +10077,7 @@ static int tg3_nway_reset(struct net_device *dev) if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) return -EINVAL; - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)) return -EAGAIN; r = phy_start_aneg(tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]); @@ -10064,7 +10106,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam * ering->rx_max_pending = tp->rx_std_ring_mask; ering->rx_mini_max_pending = 0; - if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) + if (tg3_flag(tp, JUMBO_RING_ENABLE)) ering->rx_jumbo_max_pending = tp->rx_jmb_ring_mask; else ering->rx_jumbo_max_pending = 0; @@ -10073,7 +10115,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam * ering->rx_pending = tp->rx_pending; ering->rx_mini_pending = 0; - if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) + if (tg3_flag(tp, JUMBO_RING_ENABLE)) ering->rx_jumbo_pending = tp->rx_jumbo_pending; else ering->rx_jumbo_pending = 0; @@ -10090,7 +10132,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e (ering->rx_jumbo_pending > tp->rx_jmb_ring_mask) || (ering->tx_pending > TG3_TX_RING_SIZE - 1) || (ering->tx_pending <= MAX_SKB_FRAGS) || - ((tp->tg3_flags2 & TG3_FLG2_TSO_BUG) && + (tg3_flag(tp, TSO_BUG) && (ering->tx_pending <= (MAX_SKB_FRAGS * 3)))) return -EINVAL; @@ -10104,7 +10146,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tp->rx_pending = ering->rx_pending; - if ((tp->tg3_flags2 & TG3_FLG2_MAX_RXPEND_64) && + if (tg3_flag(tp, MAX_RXPEND_64) && tp->rx_pending > 63) tp->rx_pending = 63; tp->rx_jumbo_pending = ering->rx_jumbo_pending; @@ -10131,7 +10173,7 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam { struct tg3 *tp = netdev_priv(dev); - epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0; + epause->autoneg = !!tg3_flag(tp, PAUSE_AUTONEG); if (tp->link_config.active_flowctrl & FLOW_CTRL_RX) epause->rx_pause = 1; @@ -10149,7 +10191,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam struct tg3 *tp = netdev_priv(dev); int err = 0; - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { u32 newadv; struct phy_device *phydev; @@ -10177,9 +10219,9 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam newadv = 0; if (epause->autoneg) - tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + tg3_flag_set(tp, PAUSE_AUTONEG); else - tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; + tg3_flag_clear(tp, PAUSE_AUTONEG); if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) { u32 oldadv = phydev->advertising & @@ -10221,9 +10263,9 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam tg3_full_lock(tp, irq_sync); if (epause->autoneg) - tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + tg3_flag_set(tp, PAUSE_AUTONEG); else - tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; + tg3_flag_clear(tp, PAUSE_AUTONEG); if (epause->rx_pause) tp->link_config.flowctrl |= FLOW_CTRL_RX; else @@ -10246,50 +10288,6 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam return err; } -static u32 tg3_get_rx_csum(struct net_device *dev) -{ - struct tg3 *tp = netdev_priv(dev); - return (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0; -} - -static int tg3_set_rx_csum(struct net_device *dev, u32 data) -{ - struct tg3 *tp = netdev_priv(dev); - - if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) { - if (data != 0) - return -EINVAL; - return 0; - } - - spin_lock_bh(&tp->lock); - if (data) - tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; - else - tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS; - spin_unlock_bh(&tp->lock); - - return 0; -} - -static int tg3_set_tx_csum(struct net_device *dev, u32 data) -{ - struct tg3 *tp = netdev_priv(dev); - - if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) { - if (data != 0) - return -EINVAL; - return 0; - } - - if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) - ethtool_op_set_tx_ipv6_csum(dev, data); - else - ethtool_op_set_tx_csum(dev, data); - - return 0; -} - static int tg3_get_sset_count(struct net_device *dev, int sset) { switch (sset) { @@ -10317,35 +10315,38 @@ static void tg3_get_strings(struct net_device *dev, u32 stringset, u8 *buf) } } -static int tg3_phys_id(struct net_device *dev, u32 data) +static int tg3_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct tg3 *tp = netdev_priv(dev); - int i; if (!netif_running(tp->dev)) return -EAGAIN; - if (data == 0) - data = UINT_MAX / 2; + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ - for (i = 0; i < (data * 2); i++) { - if ((i % 2) == 0) - tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | - LED_CTRL_1000MBPS_ON | - LED_CTRL_100MBPS_ON | - LED_CTRL_10MBPS_ON | - LED_CTRL_TRAFFIC_OVERRIDE | - LED_CTRL_TRAFFIC_BLINK | - LED_CTRL_TRAFFIC_LED); + case ETHTOOL_ID_ON: + tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | + LED_CTRL_1000MBPS_ON | + LED_CTRL_100MBPS_ON | + LED_CTRL_10MBPS_ON | + LED_CTRL_TRAFFIC_OVERRIDE | + LED_CTRL_TRAFFIC_BLINK | + LED_CTRL_TRAFFIC_LED); + break; - else - tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | - LED_CTRL_TRAFFIC_OVERRIDE); + case ETHTOOL_ID_OFF: + tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | + LED_CTRL_TRAFFIC_OVERRIDE); + break; - if (msleep_interruptible(500)) - break; + case ETHTOOL_ID_INACTIVE: + tw32(MAC_LED_CTRL, tp->led_ctrl); + break; } - tw32(MAC_LED_CTRL, tp->led_ctrl); + return 0; } @@ -10356,6 +10357,80 @@ static void tg3_get_ethtool_stats(struct net_device *dev, memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats)); } +static __be32 * tg3_vpd_readblock(struct tg3 *tp) +{ + int i; + __be32 *buf; + u32 offset = 0, len = 0; + u32 magic, val; + + if (tg3_flag(tp, NO_NVRAM) || tg3_nvram_read(tp, 0, &magic)) + return NULL; + + if (magic == TG3_EEPROM_MAGIC) { + for (offset = TG3_NVM_DIR_START; + offset < TG3_NVM_DIR_END; + offset += TG3_NVM_DIRENT_SIZE) { + if (tg3_nvram_read(tp, offset, &val)) + return NULL; + + if ((val >> TG3_NVM_DIRTYPE_SHIFT) == + TG3_NVM_DIRTYPE_EXTVPD) + break; + } + + if (offset != TG3_NVM_DIR_END) { + len = (val & TG3_NVM_DIRTYPE_LENMSK) * 4; + if (tg3_nvram_read(tp, offset + 4, &offset)) + return NULL; + + offset = tg3_nvram_logical_addr(tp, offset); + } + } + + if (!offset || !len) { + offset = TG3_NVM_VPD_OFF; + len = TG3_NVM_VPD_LEN; + } + + buf = kmalloc(len, GFP_KERNEL); + if (buf == NULL) + return NULL; + + if (magic == TG3_EEPROM_MAGIC) { + for (i = 0; i < len; i += 4) { + /* The data is in little-endian format in NVRAM. + * Use the big-endian read routines to preserve + * the byte order as it exists in NVRAM. + */ + if (tg3_nvram_read_be32(tp, offset + i, &buf[i/4])) + goto error; + } + } else { + u8 *ptr; + ssize_t cnt; + unsigned int pos = 0; + + ptr = (u8 *)&buf[0]; + for (i = 0; pos < len && i < 3; i++, pos += cnt, ptr += cnt) { + cnt = pci_read_vpd(tp->pdev, pos, + len - pos, ptr); + if (cnt == -ETIMEDOUT || cnt == -EINTR) + cnt = 0; + else if (cnt < 0) + goto error; + } + if (pos != len) + goto error; + } + + return buf; + +error: + kfree(buf); + return NULL; +} + #define NVRAM_TEST_SIZE 0x100 #define NVRAM_SELFBOOT_FORMAT1_0_SIZE 0x14 #define NVRAM_SELFBOOT_FORMAT1_2_SIZE 0x18 @@ -10369,7 +10444,7 @@ static int tg3_test_nvram(struct tg3 *tp) __be32 *buf; int i, j, k, err = 0, size; - if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) + if (tg3_flag(tp, NO_NVRAM)) return 0; if (tg3_nvram_read(tp, 0, &magic) != 0) @@ -10495,14 +10570,11 @@ static int tg3_test_nvram(struct tg3 *tp) if (csum != le32_to_cpu(buf[0xfc/4])) goto out; - for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) { - /* The data is in little-endian format in NVRAM. - * Use the big-endian read routines to preserve - * the byte order as it exists in NVRAM. - */ - if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &buf[i/4])) - goto out; - } + kfree(buf); + + buf = tg3_vpd_readblock(tp); + if (!buf) + return -ENOMEM; i = pci_vpd_find_tag((u8 *)buf, 0, TG3_NVM_VPD_LEN, PCI_VPD_LRDT_RO_DATA); @@ -10714,9 +10786,9 @@ static int tg3_test_registers(struct tg3 *tp) }; is_5705 = is_5750 = 0; - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if (tg3_flag(tp, 5705_PLUS)) { is_5705 = 1; - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) + if (tg3_flag(tp, 5750_PLUS)) is_5750 = 1; } @@ -10727,7 +10799,7 @@ static int tg3_test_registers(struct tg3 *tp) if (!is_5705 && (reg_tbl[i].flags & TG3_FL_5705)) continue; - if ((tp->tg3_flags2 & TG3_FLG2_IS_5788) && + if (tg3_flag(tp, IS_5788) && (reg_tbl[i].flags & TG3_FL_NOT_5788)) continue; @@ -10850,16 +10922,15 @@ static int tg3_test_memory(struct tg3 *tp) int err = 0; int i; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (tg3_flag(tp, 5717_PLUS)) mem_tbl = mem_tbl_5717; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) mem_tbl = mem_tbl_57765; - else if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) + else if (tg3_flag(tp, 5755_PLUS)) mem_tbl = mem_tbl_5755; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) mem_tbl = mem_tbl_5906; - else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + else if (tg3_flag(tp, 5705_PLUS)) mem_tbl = mem_tbl_5705; else mem_tbl = mem_tbl_570x; @@ -10875,11 +10946,35 @@ static int tg3_test_memory(struct tg3 *tp) #define TG3_MAC_LOOPBACK 0 #define TG3_PHY_LOOPBACK 1 +#define TG3_TSO_LOOPBACK 2 -static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) +#define TG3_TSO_MSS 500 + +#define TG3_TSO_IP_HDR_LEN 20 +#define TG3_TSO_TCP_HDR_LEN 20 +#define TG3_TSO_TCP_OPT_LEN 12 + +static const u8 tg3_tso_header[] = { +0x08, 0x00, +0x45, 0x00, 0x00, 0x00, +0x00, 0x00, 0x40, 0x00, +0x40, 0x06, 0x00, 0x00, +0x0a, 0x00, 0x00, 0x01, +0x0a, 0x00, 0x00, 0x02, +0x0d, 0x00, 0xe0, 0x00, +0x00, 0x00, 0x01, 0x00, +0x00, 0x00, 0x02, 0x00, +0x80, 0x10, 0x10, 0x00, +0x14, 0x09, 0x00, 0x00, +0x01, 0x01, 0x08, 0x0a, +0x11, 0x11, 0x11, 0x11, +0x11, 0x11, 0x11, 0x11, +}; + +static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) { u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key; - u32 desc_idx, coal_now; + u32 base_flags = 0, mss = 0, desc_idx, coal_now, data_off, val; struct sk_buff *skb, *rx_skb; u8 *tx_data; dma_addr_t map; @@ -10891,9 +10986,9 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) tnapi = &tp->napi[0]; rnapi = &tp->napi[0]; if (tp->irq_cnt > 1) { - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) + if (tg3_flag(tp, ENABLE_RSS)) rnapi = &tp->napi[1]; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + if (tg3_flag(tp, ENABLE_TSS)) tnapi = &tp->napi[1]; } coal_now = tnapi->coal_now | rnapi->coal_now; @@ -10905,22 +11000,20 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) * all newer ASIC revisions. */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 || - (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) + tg3_flag(tp, CPMU_PRESENT)) return 0; mac_mode = tp->mac_mode & ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); mac_mode |= MAC_MODE_PORT_INT_LPBACK; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) mac_mode |= MAC_MODE_LINK_POLARITY; if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) mac_mode |= MAC_MODE_PORT_MODE_MII; else mac_mode |= MAC_MODE_PORT_MODE_GMII; tw32(MAC_MODE, mac_mode); - } else if (loopback_mode == TG3_PHY_LOOPBACK) { - u32 val; - + } else { if (tp->phy_flags & TG3_PHYFLG_IS_FET) { tg3_phy_fet_toggle_apd(tp, false); val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100; @@ -10968,13 +11061,11 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) break; mdelay(1); } - } else { - return -EINVAL; } err = -EIO; - tx_len = 1514; + tx_len = pktsz; skb = netdev_alloc_skb(tp->dev, tx_len); if (!skb) return -ENOMEM; @@ -10983,9 +11074,58 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) memcpy(tx_data, tp->dev->dev_addr, 6); memset(tx_data + 6, 0x0, 8); - tw32(MAC_RX_MTU_SIZE, tx_len + 4); + tw32(MAC_RX_MTU_SIZE, tx_len + ETH_FCS_LEN); - for (i = 14; i < tx_len; i++) + if (loopback_mode == TG3_TSO_LOOPBACK) { + struct iphdr *iph = (struct iphdr *)&tx_data[ETH_HLEN]; + + u32 hdr_len = TG3_TSO_IP_HDR_LEN + TG3_TSO_TCP_HDR_LEN + + TG3_TSO_TCP_OPT_LEN; + + memcpy(tx_data + ETH_ALEN * 2, tg3_tso_header, + sizeof(tg3_tso_header)); + mss = TG3_TSO_MSS; + + val = tx_len - ETH_ALEN * 2 - sizeof(tg3_tso_header); + num_pkts = DIV_ROUND_UP(val, TG3_TSO_MSS); + + /* Set the total length field in the IP header */ + iph->tot_len = htons((u16)(mss + hdr_len)); + + base_flags = (TXD_FLAG_CPU_PRE_DMA | + TXD_FLAG_CPU_POST_DMA); + + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) { + struct tcphdr *th; + val = ETH_HLEN + TG3_TSO_IP_HDR_LEN; + th = (struct tcphdr *)&tx_data[val]; + th->check = 0; + } else + base_flags |= TXD_FLAG_TCPUDP_CSUM; + + if (tg3_flag(tp, HW_TSO_3)) { + mss |= (hdr_len & 0xc) << 12; + if (hdr_len & 0x10) + base_flags |= 0x00000010; + base_flags |= (hdr_len & 0x3e0) << 5; + } else if (tg3_flag(tp, HW_TSO_2)) + mss |= hdr_len << 9; + else if (tg3_flag(tp, HW_TSO_1) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) { + mss |= (TG3_TSO_TCP_OPT_LEN << 9); + } else { + base_flags |= (TG3_TSO_TCP_OPT_LEN << 10); + } + + data_off = ETH_ALEN * 2 + sizeof(tg3_tso_header); + } else { + num_pkts = 1; + data_off = ETH_HLEN; + } + + for (i = data_off; i < tx_len; i++) tx_data[i] = (u8) (i & 0xff); map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE); @@ -11001,12 +11141,10 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) rx_start_idx = rnapi->hw_status->idx[0].rx_producer; - num_pkts = 0; - - tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len, 0, 1); + tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len, + base_flags, (mss << 1) | 1); tnapi->tx_prod++; - num_pkts++; tw32_tx_mbox(tnapi->prodmbox, tnapi->tx_prod); tr32_mailbox(tnapi->prodmbox); @@ -11036,29 +11174,56 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) if (rx_idx != rx_start_idx + num_pkts) goto out; - desc = &rnapi->rx_rcb[rx_start_idx]; - desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; - opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; - if (opaque_key != RXD_OPAQUE_RING_STD) - goto out; + val = data_off; + while (rx_idx != rx_start_idx) { + desc = &rnapi->rx_rcb[rx_start_idx++]; + desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; + opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; - if ((desc->err_vlan & RXD_ERR_MASK) != 0 && - (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) - goto out; - - rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; - if (rx_len != tx_len) - goto out; - - rx_skb = tpr->rx_std_buffers[desc_idx].skb; - - map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx], mapping); - pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE); - - for (i = 14; i < tx_len; i++) { - if (*(rx_skb->data + i) != (u8) (i & 0xff)) + if ((desc->err_vlan & RXD_ERR_MASK) != 0 && + (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) goto out; + + rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) + - ETH_FCS_LEN; + + if (loopback_mode != TG3_TSO_LOOPBACK) { + if (rx_len != tx_len) + goto out; + + if (pktsz <= TG3_RX_STD_DMA_SZ - ETH_FCS_LEN) { + if (opaque_key != RXD_OPAQUE_RING_STD) + goto out; + } else { + if (opaque_key != RXD_OPAQUE_RING_JUMBO) + goto out; + } + } else if ((desc->type_flags & RXD_FLAG_TCPUDP_CSUM) && + (desc->ip_tcp_csum & RXD_TCPCSUM_MASK) + >> RXD_TCPCSUM_SHIFT != 0xffff) { + goto out; + } + + if (opaque_key == RXD_OPAQUE_RING_STD) { + rx_skb = tpr->rx_std_buffers[desc_idx].skb; + map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx], + mapping); + } else if (opaque_key == RXD_OPAQUE_RING_JUMBO) { + rx_skb = tpr->rx_jmb_buffers[desc_idx].skb; + map = dma_unmap_addr(&tpr->rx_jmb_buffers[desc_idx], + mapping); + } else + goto out; + + pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, + PCI_DMA_FROMDEVICE); + + for (i = data_off; i < rx_len; i++, val++) { + if (*(rx_skb->data + i) != (u8) (val & 0xff)) + goto out; + } } + err = 0; /* tg3_free_rings will unmap and free the rx_skb */ @@ -11066,10 +11231,13 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) return err; } -#define TG3_MAC_LOOPBACK_FAILED 1 -#define TG3_PHY_LOOPBACK_FAILED 2 -#define TG3_LOOPBACK_FAILED (TG3_MAC_LOOPBACK_FAILED | \ - TG3_PHY_LOOPBACK_FAILED) +#define TG3_STD_LOOPBACK_FAILED 1 +#define TG3_JMB_LOOPBACK_FAILED 2 +#define TG3_TSO_LOOPBACK_FAILED 4 + +#define TG3_MAC_LOOPBACK_SHIFT 0 +#define TG3_PHY_LOOPBACK_SHIFT 4 +#define TG3_LOOPBACK_FAILED 0x00000077 static int tg3_test_loopback(struct tg3 *tp) { @@ -11088,11 +11256,20 @@ static int tg3_test_loopback(struct tg3 *tp) goto done; } + if (tg3_flag(tp, ENABLE_RSS)) { + int i; + + /* Reroute all rx packets to the 1st queue */ + for (i = MAC_RSS_INDIR_TBL_0; + i < MAC_RSS_INDIR_TBL_0 + TG3_RSS_INDIR_TBL_SIZE; i += 4) + tw32(i, 0x0); + } + /* Turn off gphy autopowerdown. */ if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD) tg3_phy_toggle_apd(tp, false); - if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { + if (tg3_flag(tp, CPMU_PRESENT)) { int i; u32 status; @@ -11118,10 +11295,14 @@ static int tg3_test_loopback(struct tg3 *tp) CPMU_CTRL_LINK_AWARE_MODE)); } - if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK)) - err |= TG3_MAC_LOOPBACK_FAILED; + if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_MAC_LOOPBACK)) + err |= TG3_STD_LOOPBACK_FAILED << TG3_MAC_LOOPBACK_SHIFT; - if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { + if (tg3_flag(tp, JUMBO_RING_ENABLE) && + tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_MAC_LOOPBACK)) + err |= TG3_JMB_LOOPBACK_FAILED << TG3_MAC_LOOPBACK_SHIFT; + + if (tg3_flag(tp, CPMU_PRESENT)) { tw32(TG3_CPMU_CTRL, cpmuctrl); /* Release the mutex */ @@ -11129,9 +11310,18 @@ static int tg3_test_loopback(struct tg3 *tp) } if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) && - !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { - if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK)) - err |= TG3_PHY_LOOPBACK_FAILED; + !tg3_flag(tp, USE_PHYLIB)) { + if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_PHY_LOOPBACK)) + err |= TG3_STD_LOOPBACK_FAILED << + TG3_PHY_LOOPBACK_SHIFT; + if (tg3_flag(tp, TSO_CAPABLE) && + tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_TSO_LOOPBACK)) + err |= TG3_TSO_LOOPBACK_FAILED << + TG3_PHY_LOOPBACK_SHIFT; + if (tg3_flag(tp, JUMBO_RING_ENABLE) && + tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_PHY_LOOPBACK)) + err |= TG3_JMB_LOOPBACK_FAILED << + TG3_PHY_LOOPBACK_SHIFT; } /* Re-enable gphy autopowerdown. */ @@ -11176,7 +11366,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, tg3_halt(tp, RESET_KIND_SUSPEND, 1); err = tg3_nvram_lock(tp); tg3_halt_cpu(tp, RX_CPU_BASE); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) tg3_halt_cpu(tp, TX_CPU_BASE); if (!err) tg3_nvram_unlock(tp); @@ -11206,7 +11396,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); if (netif_running(dev)) { - tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; + tg3_flag_set(tp, INIT_COMPLETE); err2 = tg3_restart_hw(tp, 1); if (!err2) tg3_netif_start(tp); @@ -11228,7 +11418,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct tg3 *tp = netdev_priv(dev); int err; - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { struct phy_device *phydev; if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)) return -EAGAIN; @@ -11247,9 +11437,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) break; /* We have no PHY */ - if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) || - ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && - !netif_running(dev))) + if (!netif_running(dev)) return -EAGAIN; spin_lock_bh(&tp->lock); @@ -11265,9 +11453,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) break; /* We have no PHY */ - if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) || - ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && - !netif_running(dev))) + if (!netif_running(dev)) return -EAGAIN; spin_lock_bh(&tp->lock); @@ -11297,7 +11483,7 @@ static int tg3_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) u32 max_rxcoal_tick_int = 0, max_txcoal_tick_int = 0; u32 max_stat_coal_ticks = 0, min_stat_coal_ticks = 0; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { max_rxcoal_tick_int = MAX_RXCOAL_TICK_INT; max_txcoal_tick_int = MAX_TXCOAL_TICK_INT; max_stat_coal_ticks = MAX_STAT_COAL_TICKS; @@ -11364,14 +11550,9 @@ static const struct ethtool_ops tg3_ethtool_ops = { .set_ringparam = tg3_set_ringparam, .get_pauseparam = tg3_get_pauseparam, .set_pauseparam = tg3_set_pauseparam, - .get_rx_csum = tg3_get_rx_csum, - .set_rx_csum = tg3_set_rx_csum, - .set_tx_csum = tg3_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = tg3_set_tso, .self_test = tg3_self_test, .get_strings = tg3_get_strings, - .phys_id = tg3_phys_id, + .set_phys_id = tg3_set_phys_id, .get_ethtool_stats = tg3_get_ethtool_stats, .get_coalesce = tg3_get_coalesce, .set_coalesce = tg3_set_coalesce, @@ -11416,8 +11597,7 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp) { u32 val; - if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || - tg3_nvram_read(tp, 0, &val) != 0) + if (tg3_flag(tp, NO_NVRAM) || tg3_nvram_read(tp, 0, &val) != 0) return; /* Selfboot format */ @@ -11452,19 +11632,19 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) nvcfg1 = tr32(NVRAM_CFG1); if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) { - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, FLASH); } else { nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; tw32(NVRAM_CFG1, nvcfg1); } - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + tg3_flag(tp, 5780_CLASS)) { switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); break; case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; @@ -11473,12 +11653,12 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) case FLASH_VENDOR_ATMEL_EEPROM: tp->nvram_jedecnum = JEDEC_ATMEL; tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); break; case FLASH_VENDOR_ST: tp->nvram_jedecnum = JEDEC_ST; tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); break; case FLASH_VENDOR_SAIFUN: tp->nvram_jedecnum = JEDEC_SAIFUN; @@ -11493,7 +11673,7 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) } else { tp->nvram_jedecnum = JEDEC_ATMEL; tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); } } @@ -11532,29 +11712,29 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) /* NVRAM protection for TPM */ if (nvcfg1 & (1 << 27)) - tp->tg3_flags3 |= TG3_FLG3_PROTECTED_NVRAM; + tg3_flag_set(tp, PROTECTED_NVRAM); switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ: case FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); break; case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); break; case FLASH_5752VENDOR_ST_M45PE10: case FLASH_5752VENDOR_ST_M45PE20: case FLASH_5752VENDOR_ST_M45PE40: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); break; } - if (tp->tg3_flags2 & TG3_FLG2_FLASH) { + if (tg3_flag(tp, FLASH)) { tg3_nvram_get_pagesize(tp, nvcfg1); } else { /* For eeprom, set pagesize to maximum eeprom size */ @@ -11573,7 +11753,7 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp) /* NVRAM protection for TPM */ if (nvcfg1 & (1 << 27)) { - tp->tg3_flags3 |= TG3_FLG3_PROTECTED_NVRAM; + tg3_flag_set(tp, PROTECTED_NVRAM); protect = 1; } @@ -11584,8 +11764,8 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp) case FLASH_5755VENDOR_ATMEL_FLASH_3: case FLASH_5755VENDOR_ATMEL_FLASH_5: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); tp->nvram_pagesize = 264; if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1 || nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_5) @@ -11602,8 +11782,8 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp) case FLASH_5752VENDOR_ST_M45PE20: case FLASH_5752VENDOR_ST_M45PE40: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); tp->nvram_pagesize = 256; if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE10) tp->nvram_size = (protect ? @@ -11633,7 +11813,7 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp) case FLASH_5787VENDOR_MICRO_EEPROM_64KHZ: case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; @@ -11644,16 +11824,16 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp) case FLASH_5755VENDOR_ATMEL_FLASH_2: case FLASH_5755VENDOR_ATMEL_FLASH_3: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); tp->nvram_pagesize = 264; break; case FLASH_5752VENDOR_ST_M45PE10: case FLASH_5752VENDOR_ST_M45PE20: case FLASH_5752VENDOR_ST_M45PE40: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); tp->nvram_pagesize = 256; break; } @@ -11667,7 +11847,7 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp) /* NVRAM protection for TPM */ if (nvcfg1 & (1 << 27)) { - tp->tg3_flags3 |= TG3_FLG3_PROTECTED_NVRAM; + tg3_flag_set(tp, PROTECTED_NVRAM); protect = 1; } @@ -11682,9 +11862,9 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp) case FLASH_5761VENDOR_ATMEL_MDB081D: case FLASH_5761VENDOR_ATMEL_MDB161D: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); + tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS); tp->nvram_pagesize = 256; break; case FLASH_5761VENDOR_ST_A_M45PE20: @@ -11696,8 +11876,8 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp) case FLASH_5761VENDOR_ST_M_M45PE80: case FLASH_5761VENDOR_ST_M_M45PE16: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); tp->nvram_pagesize = 256; break; } @@ -11737,7 +11917,7 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp) static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp) { tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; } @@ -11751,7 +11931,7 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) case FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ: case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; @@ -11765,8 +11945,8 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) case FLASH_57780VENDOR_ATMEL_AT45DB041D: case FLASH_57780VENDOR_ATMEL_AT45DB041B: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: @@ -11788,8 +11968,8 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) case FLASH_5752VENDOR_ST_M45PE20: case FLASH_5752VENDOR_ST_M45PE40: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5752VENDOR_ST_M45PE10: @@ -11804,13 +11984,13 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) } break; default: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM; + tg3_flag_set(tp, NO_NVRAM); return; } tg3_nvram_get_pagesize(tp, nvcfg1); if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528) - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS); } @@ -11824,7 +12004,7 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) case FLASH_5717VENDOR_ATMEL_EEPROM: case FLASH_5717VENDOR_MICRO_EEPROM: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; @@ -11838,11 +12018,13 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) case FLASH_5717VENDOR_ATMEL_ADB021D: case FLASH_5717VENDOR_ATMEL_45USPT: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5717VENDOR_ATMEL_MDB021D: + /* Detect size with tg3_nvram_get_size() */ + break; case FLASH_5717VENDOR_ATMEL_ADB021B: case FLASH_5717VENDOR_ATMEL_ADB021D: tp->nvram_size = TG3_NVRAM_SIZE_256KB; @@ -11863,13 +12045,15 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) case FLASH_5717VENDOR_ST_25USPT: case FLASH_5717VENDOR_ST_45USPT: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5717VENDOR_ST_M_M25PE20: - case FLASH_5717VENDOR_ST_A_M25PE20: case FLASH_5717VENDOR_ST_M_M45PE20: + /* Detect size with tg3_nvram_get_size() */ + break; + case FLASH_5717VENDOR_ST_A_M25PE20: case FLASH_5717VENDOR_ST_A_M45PE20: tp->nvram_size = TG3_NVRAM_SIZE_256KB; break; @@ -11879,13 +12063,125 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) } break; default: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM; + tg3_flag_set(tp, NO_NVRAM); return; } tg3_nvram_get_pagesize(tp, nvcfg1); if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528) - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS); +} + +static void __devinit tg3_get_5720_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1, nvmpinstrp; + + nvcfg1 = tr32(NVRAM_CFG1); + nvmpinstrp = nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK; + + switch (nvmpinstrp) { + case FLASH_5720_EEPROM_HD: + case FLASH_5720_EEPROM_LD: + tp->nvram_jedecnum = JEDEC_ATMEL; + tg3_flag_set(tp, NVRAM_BUFFERED); + + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + if (nvmpinstrp == FLASH_5720_EEPROM_HD) + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + else + tp->nvram_pagesize = ATMEL_AT24C02_CHIP_SIZE; + return; + case FLASH_5720VENDOR_M_ATMEL_DB011D: + case FLASH_5720VENDOR_A_ATMEL_DB011B: + case FLASH_5720VENDOR_A_ATMEL_DB011D: + case FLASH_5720VENDOR_M_ATMEL_DB021D: + case FLASH_5720VENDOR_A_ATMEL_DB021B: + case FLASH_5720VENDOR_A_ATMEL_DB021D: + case FLASH_5720VENDOR_M_ATMEL_DB041D: + case FLASH_5720VENDOR_A_ATMEL_DB041B: + case FLASH_5720VENDOR_A_ATMEL_DB041D: + case FLASH_5720VENDOR_M_ATMEL_DB081D: + case FLASH_5720VENDOR_A_ATMEL_DB081D: + case FLASH_5720VENDOR_ATMEL_45USPT: + tp->nvram_jedecnum = JEDEC_ATMEL; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); + + switch (nvmpinstrp) { + case FLASH_5720VENDOR_M_ATMEL_DB021D: + case FLASH_5720VENDOR_A_ATMEL_DB021B: + case FLASH_5720VENDOR_A_ATMEL_DB021D: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + case FLASH_5720VENDOR_M_ATMEL_DB041D: + case FLASH_5720VENDOR_A_ATMEL_DB041B: + case FLASH_5720VENDOR_A_ATMEL_DB041D: + tp->nvram_size = TG3_NVRAM_SIZE_512KB; + break; + case FLASH_5720VENDOR_M_ATMEL_DB081D: + case FLASH_5720VENDOR_A_ATMEL_DB081D: + tp->nvram_size = TG3_NVRAM_SIZE_1MB; + break; + default: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + } + break; + case FLASH_5720VENDOR_M_ST_M25PE10: + case FLASH_5720VENDOR_M_ST_M45PE10: + case FLASH_5720VENDOR_A_ST_M25PE10: + case FLASH_5720VENDOR_A_ST_M45PE10: + case FLASH_5720VENDOR_M_ST_M25PE20: + case FLASH_5720VENDOR_M_ST_M45PE20: + case FLASH_5720VENDOR_A_ST_M25PE20: + case FLASH_5720VENDOR_A_ST_M45PE20: + case FLASH_5720VENDOR_M_ST_M25PE40: + case FLASH_5720VENDOR_M_ST_M45PE40: + case FLASH_5720VENDOR_A_ST_M25PE40: + case FLASH_5720VENDOR_A_ST_M45PE40: + case FLASH_5720VENDOR_M_ST_M25PE80: + case FLASH_5720VENDOR_M_ST_M45PE80: + case FLASH_5720VENDOR_A_ST_M25PE80: + case FLASH_5720VENDOR_A_ST_M45PE80: + case FLASH_5720VENDOR_ST_25USPT: + case FLASH_5720VENDOR_ST_45USPT: + tp->nvram_jedecnum = JEDEC_ST; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); + + switch (nvmpinstrp) { + case FLASH_5720VENDOR_M_ST_M25PE20: + case FLASH_5720VENDOR_M_ST_M45PE20: + case FLASH_5720VENDOR_A_ST_M25PE20: + case FLASH_5720VENDOR_A_ST_M45PE20: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + case FLASH_5720VENDOR_M_ST_M25PE40: + case FLASH_5720VENDOR_M_ST_M45PE40: + case FLASH_5720VENDOR_A_ST_M25PE40: + case FLASH_5720VENDOR_A_ST_M45PE40: + tp->nvram_size = TG3_NVRAM_SIZE_512KB; + break; + case FLASH_5720VENDOR_M_ST_M25PE80: + case FLASH_5720VENDOR_M_ST_M45PE80: + case FLASH_5720VENDOR_A_ST_M25PE80: + case FLASH_5720VENDOR_A_ST_M45PE80: + tp->nvram_size = TG3_NVRAM_SIZE_1MB; + break; + default: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + } + break; + default: + tg3_flag_set(tp, NO_NVRAM); + return; + } + + tg3_nvram_get_pagesize(tp, nvcfg1); + if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528) + tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS); } /* Chips other than 5700/5701 use the NVRAM for fetching info. */ @@ -11905,7 +12201,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) { - tp->tg3_flags |= TG3_FLAG_NVRAM; + tg3_flag_set(tp, NVRAM); if (tg3_nvram_lock(tp)) { netdev_warn(tp->dev, @@ -11935,6 +12231,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) tg3_get_5717_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + tg3_get_5720_nvram_info(tp); else tg3_get_nvram_info(tp); @@ -11945,7 +12243,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_nvram_unlock(tp); } else { - tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED); + tg3_flag_clear(tp, NVRAM); + tg3_flag_clear(tp, NVRAM_BUFFERED); tg3_get_eeprom_size(tp); } @@ -12128,7 +12427,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, nvram_cmd |= NVRAM_CMD_LAST; if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && - !(tp->tg3_flags3 & TG3_FLG3_5755_PLUS) && + !tg3_flag(tp, 5755_PLUS) && (tp->nvram_jedecnum == JEDEC_ST) && (nvram_cmd & NVRAM_CMD_FIRST)) { @@ -12138,7 +12437,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, break; } - if (!(tp->tg3_flags2 & TG3_FLG2_FLASH)) { + if (!tg3_flag(tp, FLASH)) { /* We always do complete word writes to eeprom. */ nvram_cmd |= (NVRAM_CMD_FIRST | NVRAM_CMD_LAST); } @@ -12154,13 +12453,13 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) { int ret; - if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { + if (tg3_flag(tp, EEPROM_WRITE_PROT)) { tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl & ~GRC_LCLCTRL_GPIO_OUTPUT1); udelay(40); } - if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) { + if (!tg3_flag(tp, NVRAM)) { ret = tg3_nvram_write_block_using_eeprom(tp, offset, len, buf); } else { u32 grc_mode; @@ -12170,16 +12469,13 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) return ret; tg3_enable_nvram_access(tp); - if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && - !(tp->tg3_flags3 & TG3_FLG3_PROTECTED_NVRAM)) + if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM)) tw32(NVRAM_WRITE1, 0x406); grc_mode = tr32(GRC_MODE); tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE); - if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) || - !(tp->tg3_flags2 & TG3_FLG2_FLASH)) { - + if (tg3_flag(tp, NVRAM_BUFFERED) || !tg3_flag(tp, FLASH)) { ret = tg3_nvram_write_block_buffered(tp, offset, len, buf); } else { @@ -12194,7 +12490,7 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) tg3_nvram_unlock(tp); } - if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { + if (tg3_flag(tp, EEPROM_WRITE_PROT)) { tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(40); } @@ -12316,19 +12612,22 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->led_ctrl = LED_CTRL_MODE_PHY_1; /* Assume an onboard device and WOL capable by default. */ - tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT | TG3_FLAG_WOL_CAP; + tg3_flag_set(tp, EEPROM_WRITE_PROT); + tg3_flag_set(tp, WOL_CAP); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM)) { - tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; - tp->tg3_flags2 |= TG3_FLG2_IS_NIC; + tg3_flag_clear(tp, EEPROM_WRITE_PROT); + tg3_flag_set(tp, IS_NIC); } val = tr32(VCPU_CFGSHDW); if (val & VCPU_CFGSHDW_ASPM_DBNC) - tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; + tg3_flag_set(tp, ASPM_WORKAROUND); if ((val & VCPU_CFGSHDW_WOL_ENABLE) && - (val & VCPU_CFGSHDW_WOL_MAGPKT)) - tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + (val & VCPU_CFGSHDW_WOL_MAGPKT)) { + tg3_flag_set(tp, WOL_ENABLE); + device_set_wakeup_enable(&tp->pdev->dev, true); + } goto done; } @@ -12343,9 +12642,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tg3_read_mem(tp, NIC_SRAM_DATA_VER, &ver); ver >>= NIC_SRAM_DATA_VER_SHIFT; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5703) && + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5703 && (ver > 0) && (ver < 0x100)) tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2); @@ -12369,13 +12668,13 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->phy_id = eeprom_phy_id; if (eeprom_phy_serdes) { - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) tp->phy_flags |= TG3_PHYFLG_PHY_SERDES; else tp->phy_flags |= TG3_PHYFLG_MII_SERDES; } - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) + if (tg3_flag(tp, 5750_PLUS)) led_cfg = cfg2 & (NIC_SRAM_DATA_CFG_LED_MODE_MASK | SHASTA_EXT_LED_MODE_MASK); else @@ -12435,34 +12734,36 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->led_ctrl = LED_CTRL_MODE_PHY_1; if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) { - tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; + tg3_flag_set(tp, EEPROM_WRITE_PROT); if ((tp->pdev->subsystem_vendor == PCI_VENDOR_ID_ARIMA) && (tp->pdev->subsystem_device == 0x205a || tp->pdev->subsystem_device == 0x2063)) - tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; + tg3_flag_clear(tp, EEPROM_WRITE_PROT); } else { - tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; - tp->tg3_flags2 |= TG3_FLG2_IS_NIC; + tg3_flag_clear(tp, EEPROM_WRITE_PROT); + tg3_flag_set(tp, IS_NIC); } if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { - tp->tg3_flags |= TG3_FLAG_ENABLE_ASF; - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) - tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; + tg3_flag_set(tp, ENABLE_ASF); + if (tg3_flag(tp, 5750_PLUS)) + tg3_flag_set(tp, ASF_NEW_HANDSHAKE); } if ((nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE) && - (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) - tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE; + tg3_flag(tp, 5750_PLUS)) + tg3_flag_set(tp, ENABLE_APE); if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES && !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)) - tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; + tg3_flag_clear(tp, WOL_CAP); - if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) && - (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) - tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + if (tg3_flag(tp, WOL_CAP) && + (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) { + tg3_flag_set(tp, WOL_ENABLE); + device_set_wakeup_enable(&tp->pdev->dev, true); + } if (cfg2 & (1 << 17)) tp->phy_flags |= TG3_PHYFLG_CAPACITIVE_COUPLING; @@ -12472,33 +12773,33 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (cfg2 & (1 << 18)) tp->phy_flags |= TG3_PHYFLG_SERDES_PREEMPHASIS; - if (((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) || - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && - GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX))) && + if ((tg3_flag(tp, 57765_PLUS) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX)) && (cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN)) tp->phy_flags |= TG3_PHYFLG_ENABLE_APD; - if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && + if (tg3_flag(tp, PCI_EXPRESS) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { + !tg3_flag(tp, 57765_PLUS)) { u32 cfg3; tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3); if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE) - tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; + tg3_flag_set(tp, ASPM_WORKAROUND); } if (cfg4 & NIC_SRAM_RGMII_INBAND_DISABLE) - tp->tg3_flags3 |= TG3_FLG3_RGMII_INBAND_DISABLE; + tg3_flag_set(tp, RGMII_INBAND_DISABLE); if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_RX_EN) - tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_RX_EN; + tg3_flag_set(tp, RGMII_EXT_IBND_RX_EN); if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN) - tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_TX_EN; + tg3_flag_set(tp, RGMII_EXT_IBND_TX_EN); } done: - if (tp->tg3_flags & TG3_FLAG_WOL_CAP) + if (tg3_flag(tp, WOL_CAP)) device_set_wakeup_enable(&tp->pdev->dev, - tp->tg3_flags & TG3_FLAG_WOL_ENABLE); + tg3_flag(tp, WOL_ENABLE)); else device_set_wakeup_capable(&tp->pdev->dev, false); } @@ -12588,18 +12889,17 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) int err; /* flow control autonegotiation is default behavior */ - tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + tg3_flag_set(tp, PAUSE_AUTONEG); tp->link_config.flowctrl = FLOW_CTRL_TX | FLOW_CTRL_RX; - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) + if (tg3_flag(tp, USE_PHYLIB)) return tg3_phy_init(tp); /* Reading the PHY ID register can conflict with ASF * firmware access to the PHY hardware. */ err = 0; - if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || - (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) { + if (tg3_flag(tp, ENABLE_ASF) || tg3_flag(tp, ENABLE_APE)) { hw_phy_id = hw_phy_id_masked = TG3_PHY_ID_INVALID; } else { /* Now read the physical PHY_ID from the chip and verify @@ -12655,9 +12955,9 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) tg3_phy_init_link_config(tp); if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) && - !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) && - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { - u32 bmsr, adv_reg, tg3_ctrl, mask; + !tg3_flag(tp, ENABLE_APE) && + !tg3_flag(tp, ENABLE_ASF)) { + u32 bmsr, mask; tg3_readphy(tp, MII_BMSR, &bmsr); if (!tg3_readphy(tp, MII_BMSR, &bmsr) && @@ -12668,36 +12968,18 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) if (err) return err; - adv_reg = (ADVERTISE_10HALF | ADVERTISE_10FULL | - ADVERTISE_100HALF | ADVERTISE_100FULL | - ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - tg3_ctrl = 0; - if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) { - tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF | - MII_TG3_CTRL_ADV_1000_FULL); - if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) - tg3_ctrl |= (MII_TG3_CTRL_AS_MASTER | - MII_TG3_CTRL_ENABLE_AS_MASTER); - } + tg3_phy_set_wirespeed(tp); mask = (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full); if (!tg3_copper_is_advertising_all(tp, mask)) { - tg3_writephy(tp, MII_ADVERTISE, adv_reg); - - if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) - tg3_writephy(tp, MII_TG3_CTRL, tg3_ctrl); + tg3_phy_autoneg_cfg(tp, tp->link_config.advertising, + tp->link_config.flowctrl); tg3_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); } - tg3_phy_set_wirespeed(tp); - - tg3_writephy(tp, MII_ADVERTISE, adv_reg); - if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) - tg3_writephy(tp, MII_TG3_CTRL, tg3_ctrl); } skip_phy_reset: @@ -12717,46 +12999,11 @@ static void __devinit tg3_read_vpd(struct tg3 *tp) u8 *vpd_data; unsigned int block_end, rosize, len; int j, i = 0; - u32 magic; - if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || - tg3_nvram_read(tp, 0x0, &magic)) - goto out_no_vpd; - - vpd_data = kmalloc(TG3_NVM_VPD_LEN, GFP_KERNEL); + vpd_data = (u8 *)tg3_vpd_readblock(tp); if (!vpd_data) goto out_no_vpd; - if (magic == TG3_EEPROM_MAGIC) { - for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) { - u32 tmp; - - /* The data is in little-endian format in NVRAM. - * Use the big-endian read routines to preserve - * the byte order as it exists in NVRAM. - */ - if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &tmp)) - goto out_not_found; - - memcpy(&vpd_data[i], &tmp, sizeof(tmp)); - } - } else { - ssize_t cnt; - unsigned int pos = 0; - - for (; pos < TG3_NVM_VPD_LEN && i < 3; i++, pos += cnt) { - cnt = pci_read_vpd(tp->pdev, pos, - TG3_NVM_VPD_LEN - pos, - &vpd_data[pos]); - if (cnt == -ETIMEDOUT || cnt == -EINTR) - cnt = 0; - else if (cnt < 0) - goto out_not_found; - } - if (pos != TG3_NVM_VPD_LEN) - goto out_not_found; - } - i = pci_vpd_find_tag(vpd_data, 0, TG3_NVM_VPD_LEN, PCI_VPD_LRDT_RO_DATA); if (i < 0) @@ -13010,7 +13257,7 @@ static void __devinit tg3_read_mgmtfw_ver(struct tg3 *tp) if (offset == TG3_NVM_DIR_END) return; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) start = 0x08000000; else if (tg3_nvram_read(tp, offset - 4, &start)) return; @@ -13050,8 +13297,7 @@ static void __devinit tg3_read_dash_ver(struct tg3 *tp) u32 apedata; char *fwtype; - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) || - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (!tg3_flag(tp, ENABLE_APE) || !tg3_flag(tp, ENABLE_ASF)) return; apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG); @@ -13065,7 +13311,7 @@ static void __devinit tg3_read_dash_ver(struct tg3 *tp) apedata = tg3_ape_read32(tp, TG3_APE_FW_VERSION); if (tg3_ape_read32(tp, TG3_APE_FW_FEATURES) & TG3_APE_FW_FEATURE_NCSI) { - tp->tg3_flags3 |= TG3_FLG3_APE_HAS_NCSI; + tg3_flag_set(tp, APE_HAS_NCSI); fwtype = "NCSI"; } else { fwtype = "DASH"; @@ -13089,7 +13335,7 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp) if (tp->fw_ver[0] != 0) vpd_vers = true; - if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) { + if (tg3_flag(tp, NO_NVRAM)) { strcat(tp->fw_ver, "sb"); return; } @@ -13106,8 +13352,7 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp) else return; - if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || - (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) || vpd_vers) + if (!tg3_flag(tp, ENABLE_ASF) || tg3_flag(tp, ENABLE_APE) || vpd_vers) goto done; tg3_read_mgmtfw_ver(tp); @@ -13118,21 +13363,14 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp) static struct pci_dev * __devinit tg3_find_peer(struct tg3 *); -static inline void vlan_features_add(struct net_device *dev, unsigned long flags) -{ - dev->vlan_features |= flags; -} - static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) - return 4096; - else if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) - return 1024; + if (tg3_flag(tp, LRG_PROD_RING_CAP)) + return TG3_RX_RET_MAX_SIZE_5717; + else if (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS)) + return TG3_RX_RET_MAX_SIZE_5700; else - return 512; + return TG3_RX_RET_MAX_SIZE_5705; } static DEFINE_PCI_DEVICE_TABLE(tg3_write_reorder_chipsets) = { @@ -13177,7 +13415,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 || tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 || - tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719) + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720) pci_read_config_dword(tp->pdev, TG3PCI_GEN2_PRODID_ASICREV, &prod_id_asic_rev); @@ -13254,15 +13493,14 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (bridge->subordinate && (bridge->subordinate->number == tp->pdev->bus->number)) { - - tp->tg3_flags2 |= TG3_FLG2_ICH_WORKAROUND; + tg3_flag_set(tp, ICH_WORKAROUND); pci_dev_put(bridge); break; } } } - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) { static struct tg3_dev_id { u32 vendor; u32 device; @@ -13287,7 +13525,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev->bus->number) && (bridge->subordinate->subordinate >= tp->pdev->bus->number)) { - tp->tg3_flags3 |= TG3_FLG3_5701_DMA_BUG; + tg3_flag_set(tp, 5701_DMA_BUG); pci_dev_put(bridge); break; } @@ -13302,8 +13540,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { - tp->tg3_flags2 |= TG3_FLG2_5780_CLASS; - tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG; + tg3_flag_set(tp, 5780_CLASS); + tg3_flag_set(tp, 40BIT_DMA_BUG); tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI); } else { struct pci_dev *bridge = NULL; @@ -13317,7 +13555,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev->bus->number) && (bridge->subordinate->subordinate >= tp->pdev->bus->number)) { - tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG; + tg3_flag_set(tp, 40BIT_DMA_BUG); pci_dev_put(bridge); break; } @@ -13332,13 +13570,18 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) tp->pdev_peer = tg3_find_peer(tp); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) - tp->tg3_flags3 |= TG3_FLG3_5717_PLUS; + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + tg3_flag_set(tp, 5717_PLUS); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 || + tg3_flag(tp, 5717_PLUS)) + tg3_flag_set(tp, 57765_PLUS); /* Intentionally exclude ASIC_REV_5906 */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || @@ -13347,97 +13590,102 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) - tp->tg3_flags3 |= TG3_FLG3_5755_PLUS; + tg3_flag(tp, 57765_PLUS)) + tg3_flag_set(tp, 5755_PLUS); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || - (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) - tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; + tg3_flag(tp, 5755_PLUS) || + tg3_flag(tp, 5780_CLASS)) + tg3_flag_set(tp, 5750_PLUS); - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || - (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) - tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; - - /* 5700 B0 chips do not support checksumming correctly due - * to hardware bugs. - */ - if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0) - tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS; - else { - unsigned long features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO; - - tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; - if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) - features |= NETIF_F_IPV6_CSUM; - tp->dev->features |= features; - vlan_features_add(tp->dev, features); - } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || + tg3_flag(tp, 5750_PLUS)) + tg3_flag_set(tp, 5705_PLUS); /* Determine TSO capabilities */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ; /* Do nothing. HW bug. */ - else if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) - tp->tg3_flags2 |= TG3_FLG2_HW_TSO_3; - else if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || + else if (tg3_flag(tp, 57765_PLUS)) + tg3_flag_set(tp, HW_TSO_3); + else if (tg3_flag(tp, 5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) - tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; - else if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 | TG3_FLG2_TSO_BUG; + tg3_flag_set(tp, HW_TSO_2); + else if (tg3_flag(tp, 5750_PLUS)) { + tg3_flag_set(tp, HW_TSO_1); + tg3_flag_set(tp, TSO_BUG); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 && tp->pci_chip_rev_id >= CHIPREV_ID_5750_C2) - tp->tg3_flags2 &= ~TG3_FLG2_TSO_BUG; + tg3_flag_clear(tp, TSO_BUG); } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 && tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) { - tp->tg3_flags2 |= TG3_FLG2_TSO_BUG; + tg3_flag_set(tp, TSO_BUG); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) tp->fw_needed = FIRMWARE_TG3TSO5; else tp->fw_needed = FIRMWARE_TG3TSO; } + /* Selectively allow TSO based on operating conditions */ + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3) || + (tp->fw_needed && !tg3_flag(tp, ENABLE_ASF))) + tg3_flag_set(tp, TSO_CAPABLE); + else { + tg3_flag_clear(tp, TSO_CAPABLE); + tg3_flag_clear(tp, TSO_BUG); + tp->fw_needed = NULL; + } + + if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) + tp->fw_needed = FIRMWARE_TG3; + tp->irq_max = 1; - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - tp->tg3_flags |= TG3_FLAG_SUPPORT_MSI; + if (tg3_flag(tp, 5750_PLUS)) { + tg3_flag_set(tp, SUPPORT_MSI); if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX || GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 && tp->pci_chip_rev_id <= CHIPREV_ID_5714_A2 && tp->pdev_peer == tp->pdev)) - tp->tg3_flags &= ~TG3_FLAG_SUPPORT_MSI; + tg3_flag_clear(tp, SUPPORT_MSI); - if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || + if (tg3_flag(tp, 5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; + tg3_flag_set(tp, 1SHOT_MSI); } - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { - tp->tg3_flags |= TG3_FLAG_SUPPORT_MSIX; + if (tg3_flag(tp, 57765_PLUS)) { + tg3_flag_set(tp, SUPPORT_MSIX); tp->irq_max = TG3_IRQ_MAX_VECS; } } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) - tp->tg3_flags3 |= TG3_FLG3_SHORT_DMA_BUG; - else if (!(tp->tg3_flags3 & TG3_FLG3_5755_PLUS)) { - tp->tg3_flags3 |= TG3_FLG3_4G_DMA_BNDRY_BUG; - tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG; - } + /* All chips can get confused if TX buffers + * straddle the 4GB address boundary. + */ + tg3_flag_set(tp, 4G_DMA_BNDRY_BUG); - if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + if (tg3_flag(tp, 5755_PLUS)) + tg3_flag_set(tp, SHORT_DMA_BUG); + else + tg3_flag_set(tp, 40BIT_DMA_LIMIT_BUG); + + if (tg3_flag(tp, 5717_PLUS)) + tg3_flag_set(tp, LRG_PROD_RING_CAP); + + if (tg3_flag(tp, 57765_PLUS) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) - tp->tg3_flags3 |= TG3_FLG3_USE_JUMBO_BDFLAG; + tg3_flag_set(tp, USE_JUMBO_BDFLAG); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || - (tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG)) - tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE; + if (!tg3_flag(tp, 5705_PLUS) || + tg3_flag(tp, 5780_CLASS) || + tg3_flag(tp, USE_JUMBO_BDFLAG)) + tg3_flag_set(tp, JUMBO_CAPABLE); pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &pci_state_reg); @@ -13446,10 +13694,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pcie_cap != 0) { u16 lnkctl; - tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; + tg3_flag_set(tp, PCI_EXPRESS); tp->pcie_readrq = 4096; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) tp->pcie_readrq = 2048; pcie_set_readrq(tp->pdev, tp->pcie_readrq); @@ -13458,20 +13707,23 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pcie_cap + PCI_EXP_LNKCTL, &lnkctl); if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) - tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == + ASIC_REV_5906) { + tg3_flag_clear(tp, HW_TSO_2); + tg3_flag_clear(tp, TSO_CAPABLE); + } if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || tp->pci_chip_rev_id == CHIPREV_ID_57780_A0 || tp->pci_chip_rev_id == CHIPREV_ID_57780_A1) - tp->tg3_flags3 |= TG3_FLG3_CLKREQ_BUG; + tg3_flag_set(tp, CLKREQ_BUG); } else if (tp->pci_chip_rev_id == CHIPREV_ID_5717_A0) { - tp->tg3_flags3 |= TG3_FLG3_L1PLLPD_EN; + tg3_flag_set(tp, L1PLLPD_EN); } } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { - tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; - } else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + tg3_flag_set(tp, PCI_EXPRESS); + } else if (!tg3_flag(tp, 5705_PLUS) || + tg3_flag(tp, 5780_CLASS)) { tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX); if (!tp->pcix_cap) { dev_err(&tp->pdev->dev, @@ -13480,7 +13732,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } if (!(pci_state_reg & PCISTATE_CONV_PCI_MODE)) - tp->tg3_flags |= TG3_FLAG_PCIX_MODE; + tg3_flag_set(tp, PCIX_MODE); } /* If we have an AMD 762 or VIA K8T800 chipset, write @@ -13490,8 +13742,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * posted to the chip in order. */ if (pci_dev_present(tg3_write_reorder_chipsets) && - !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) - tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER; + !tg3_flag(tp, PCI_EXPRESS)) + tg3_flag_set(tp, MBOX_WRITE_REORDER); pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, &tp->pci_cacheline_sz); @@ -13508,17 +13760,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* 5700 BX chips need to have their TX producer index * mailboxes written twice to workaround a bug. */ - tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG; + tg3_flag_set(tp, TXD_MBOX_HWBUG); /* If we are in PCI-X mode, enable register write workaround. * * The workaround is to use indirect register accesses * for all chip writes not to mailbox registers. */ - if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { + if (tg3_flag(tp, PCIX_MODE)) { u32 pm_reg; - tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; + tg3_flag_set(tp, PCIX_TARGET_HWBUG); /* The chip can have it's power management PCI config * space registers clobbered due to this bug. @@ -13541,9 +13793,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0) - tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED; + tg3_flag_set(tp, PCI_HIGH_SPEED); if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0) - tp->tg3_flags |= TG3_FLAG_PCI_32BIT; + tg3_flag_set(tp, PCI_32BIT); /* Chip-specific fixup from Broadcom driver */ if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) && @@ -13561,10 +13813,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->write32_rx_mbox = tg3_write32; /* Various workaround register access methods */ - if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) + if (tg3_flag(tp, PCIX_TARGET_HWBUG)) tp->write32 = tg3_write_indirect_reg32; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 || - ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && + (tg3_flag(tp, PCI_EXPRESS) && tp->pci_chip_rev_id == CHIPREV_ID_5750_A0)) { /* * Back to back register writes can cause problems on these @@ -13576,14 +13828,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->write32 = tg3_write_flush_reg32; } - if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) || - (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) { + if (tg3_flag(tp, TXD_MBOX_HWBUG) || tg3_flag(tp, MBOX_WRITE_REORDER)) { tp->write32_tx_mbox = tg3_write32_tx_mbox; - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + if (tg3_flag(tp, MBOX_WRITE_REORDER)) tp->write32_rx_mbox = tg3_write_flush_reg32; } - if (tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND) { + if (tg3_flag(tp, ICH_WORKAROUND)) { tp->read32 = tg3_read_indirect_reg32; tp->write32 = tg3_write_indirect_reg32; tp->read32_mbox = tg3_read_indirect_mbox; @@ -13606,13 +13857,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } if (tp->write32 == tg3_write_indirect_reg32 || - ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) && + (tg3_flag(tp, PCIX_MODE) && (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701))) - tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG; + tg3_flag_set(tp, SRAM_USE_CONFIG); /* Get eeprom hw config before calling tg3_set_power_state(). - * In particular, the TG3_FLG2_IS_NIC flag must be + * In particular, the TG3_FLAG_IS_NIC flag must be * determined before calling tg3_set_power_state() so that * we know whether or not to switch out of Vaux power. * When the flag is set, it means that GPIO1 is used for eeprom @@ -13621,7 +13872,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ tg3_get_eeprom_hw_cfg(tp); - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { + if (tg3_flag(tp, ENABLE_APE)) { /* Allow reads and writes to the * APE register and memory space. */ @@ -13636,16 +13887,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) - tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; + tg3_flag(tp, 57765_PLUS)) + tg3_flag_set(tp, CPMU_PRESENT); - /* Set up tp->grc_local_ctrl before calling tg_power_up(). + /* Set up tp->grc_local_ctrl before calling tg3_power_up(). * GPIO1 driven high will bring 5700's external PHY out of reset. * It is also used as eeprom write protect on LOMs. */ tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) || - (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT)) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + tg3_flag(tp, EEPROM_WRITE_PROT)) tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1); /* Unused GPIO3 must be driven as output on 5752 because there @@ -13663,7 +13914,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev->device == TG3PCI_DEVICE_TIGON3_5761S) { /* Turn off the debug UART. */ tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; - if (tp->tg3_flags2 & TG3_FLG2_IS_NIC) + if (tg3_flag(tp, IS_NIC)) /* Keep VMain power. */ tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OUTPUT0; @@ -13679,26 +13930,25 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* Derive initial jumbo mode from MTU assigned in * ether_setup() via the alloc_etherdev() call */ - if (tp->dev->mtu > ETH_DATA_LEN && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) - tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; + if (tp->dev->mtu > ETH_DATA_LEN && !tg3_flag(tp, 5780_CLASS)) + tg3_flag_set(tp, JUMBO_RING_ENABLE); /* Determine WakeOnLan speed to use. */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || tp->pci_chip_rev_id == CHIPREV_ID_5701_B0 || tp->pci_chip_rev_id == CHIPREV_ID_5701_B2) { - tp->tg3_flags &= ~(TG3_FLAG_WOL_SPEED_100MB); + tg3_flag_clear(tp, WOL_SPEED_100MB); } else { - tp->tg3_flags |= TG3_FLAG_WOL_SPEED_100MB; + tg3_flag_set(tp, WOL_SPEED_100MB); } if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->phy_flags |= TG3_PHYFLG_IS_FET; /* A few boards don't want Ethernet@WireSpeed phy feature */ - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) || - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) && + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) && (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) || (tp->phy_flags & TG3_PHYFLG_IS_FET) || @@ -13711,11 +13961,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) tp->phy_flags |= TG3_PHYFLG_5704_A0_BUG; - if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && + if (tg3_flag(tp, 5705_PLUS) && !(tp->phy_flags & TG3_PHYFLG_IS_FET) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { + !tg3_flag(tp, 57765_PLUS)) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || @@ -13736,7 +13986,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->phy_otp = TG3_OTP_DEFAULT; } - if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) + if (tg3_flag(tp, CPMU_PRESENT)) tp->mi_mode = MAC_MI_MODE_500KHZ_CONST; else tp->mi_mode = MAC_MI_MODE_BASE; @@ -13746,9 +13996,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) tp->coalesce_mode |= HOSTCC_MODE_32BYTE; + /* Set these bits to enable statistics workaround. */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5720_A0) { + tp->coalesce_mode |= HOSTCC_MODE_ATTN; + tp->grc_mode |= GRC_MODE_IRQ_ON_FLOW_ATTN; + } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) - tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB; + tg3_flag_set(tp, USE_PHYLIB); err = tg3_mdio_init(tp); if (err) @@ -13756,7 +14014,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* Initialize data/descriptor byte/word swapping. */ val = tr32(GRC_MODE); - val &= GRC_MODE_HOST_STACKUP; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + val &= (GRC_MODE_BYTE_SWAP_B2HRX_DATA | + GRC_MODE_WORD_SWAP_B2HRX_DATA | + GRC_MODE_B2HRX_ENABLE | + GRC_MODE_HTX2B_ENABLE | + GRC_MODE_HOST_STACKUP); + else + val &= GRC_MODE_HOST_STACKUP; + tw32(GRC_MODE, val | tp->grc_mode); tg3_switch_clocks(tp); @@ -13767,7 +14033,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &pci_state_reg); if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0 && - (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) == 0) { + !tg3_flag(tp, PCIX_TARGET_HWBUG)) { u32 chiprevid = GET_CHIP_REV_ID(tp->misc_host_ctrl); if (chiprevid == CHIPREV_ID_5701_A0 || @@ -13786,7 +14052,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) writel(0x00000000, sram_base + 4); writel(0xffffffff, sram_base + 4); if (readl(sram_base) != 0x00000000) - tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; + tg3_flag_set(tp, PCIX_TARGET_HWBUG); } } @@ -13799,12 +14065,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 || grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M)) - tp->tg3_flags2 |= TG3_FLG2_IS_5788; + tg3_flag_set(tp, IS_5788); - if (!(tp->tg3_flags2 & TG3_FLG2_IS_5788) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)) - tp->tg3_flags |= TG3_FLAG_TAGGED_STATUS; - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { + if (!tg3_flag(tp, IS_5788) && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) + tg3_flag_set(tp, TAGGED_STATUS); + if (tg3_flag(tp, TAGGED_STATUS)) { tp->coalesce_mode |= (HOSTCC_MODE_CLRTICK_RXBD | HOSTCC_MODE_CLRTICK_TXBD); @@ -13814,7 +14080,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } /* Preserve the APE MAC_MODE bits */ - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN; else tp->mac_mode = TG3_DEF_MAC_MODE; @@ -13861,9 +14127,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * status register in those cases. */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) - tp->tg3_flags |= TG3_FLAG_USE_LINKCHG_REG; + tg3_flag_set(tp, USE_LINKCHG_REG); else - tp->tg3_flags &= ~TG3_FLAG_USE_LINKCHG_REG; + tg3_flag_clear(tp, USE_LINKCHG_REG); /* The led_ctrl is set during tg3_phy_probe, here we might * have to force the link status polling mechanism based @@ -13873,19 +14139,19 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 && !(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) { tp->phy_flags |= TG3_PHYFLG_USE_MI_INTERRUPT; - tp->tg3_flags |= TG3_FLAG_USE_LINKCHG_REG; + tg3_flag_set(tp, USE_LINKCHG_REG); } /* For all SERDES we poll the MAC status register. */ if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) - tp->tg3_flags |= TG3_FLAG_POLL_SERDES; + tg3_flag_set(tp, POLL_SERDES); else - tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES; + tg3_flag_clear(tp, POLL_SERDES); tp->rx_offset = NET_IP_ALIGN; tp->rx_copy_thresh = TG3_RX_COPY_THRESHOLD; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 && - (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) { + tg3_flag(tp, PCIX_MODE)) { tp->rx_offset = 0; #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS tp->rx_copy_thresh = ~(u16)0; @@ -13906,7 +14172,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) tp->rx_std_max_post = 8; - if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) + if (tg3_flag(tp, ASPM_WORKAROUND)) tp->pwrmgmt_thresh = tr32(PCIE_PWR_MGMT_THRESH) & PCIE_PWR_MGMT_L1_THRESH_MSK; @@ -13953,16 +14219,15 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) #endif mac_offset = 0x7c; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || + tg3_flag(tp, 5780_CLASS)) { if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) mac_offset = 0xcc; if (tg3_nvram_lock(tp)) tw32_f(NVRAM_CMD, NVRAM_CMD_RESET); else tg3_nvram_unlock(tp); - } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + } else if (tg3_flag(tp, 5717_PLUS)) { if (PCI_FUNC(tp->pdev->devfn) & 1) mac_offset = 0xcc; if (PCI_FUNC(tp->pdev->devfn) > 1) @@ -13987,7 +14252,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) } if (!addr_ok) { /* Next, try NVRAM. */ - if (!(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) && + if (!tg3_flag(tp, NO_NVRAM) && !tg3_nvram_read_be32(tp, mac_offset + 0, &hi) && !tg3_nvram_read_be32(tp, mac_offset + 4, &lo)) { memcpy(&dev->dev_addr[0], ((char *)&hi) + 2, 2); @@ -14038,7 +14303,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) */ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 && - !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) + !tg3_flag(tp, PCI_EXPRESS)) goto out; #if defined(CONFIG_PPC64) || defined(CONFIG_IA64) || defined(CONFIG_PARISC) @@ -14051,7 +14316,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) #endif #endif - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tg3_flag(tp, 57765_PLUS)) { val = goal ? 0 : DMA_RWCTRL_DIS_CACHE_ALIGNMENT; goto out; } @@ -14070,8 +14335,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) * other than 5700 and 5701 which do not implement the * boundary bits. */ - if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) && - !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) { + if (tg3_flag(tp, PCIX_MODE) && !tg3_flag(tp, PCI_EXPRESS)) { switch (cacheline_size) { case 16: case 32: @@ -14096,7 +14360,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) DMA_RWCTRL_WRITE_BNDRY_384_PCIX); break; } - } else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + } else if (tg3_flag(tp, PCI_EXPRESS)) { switch (cacheline_size) { case 16: case 32: @@ -14268,13 +14532,13 @@ static int __devinit tg3_test_dma(struct tg3 *tp) tp->dma_rwctrl = tg3_calc_dma_bndry(tp, tp->dma_rwctrl); - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) + if (tg3_flag(tp, 57765_PLUS)) goto out; - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + if (tg3_flag(tp, PCI_EXPRESS)) { /* DMA read watermark not used on PCIE */ tp->dma_rwctrl |= 0x00180000; - } else if (!(tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { + } else if (!tg3_flag(tp, PCIX_MODE)) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) tp->dma_rwctrl |= 0x003f0000; @@ -14290,7 +14554,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp) * do the less restrictive ONE_DMA workaround for * better performance. */ - if ((tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG) && + if (tg3_flag(tp, 40BIT_DMA_BUG) && GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) tp->dma_rwctrl |= 0x8000; else if (ccval == 0x6 || ccval == 0x7) @@ -14419,7 +14683,6 @@ static int __devinit tg3_test_dma(struct tg3 *tp) } if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) != DMA_RWCTRL_WRITE_BNDRY_16) { - /* DMA test passed without adjusting DMA boundary, * now look for chipsets that are known to expose the * DMA bug without failing the test. @@ -14443,7 +14706,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp) static void __devinit tg3_init_bufmgr_config(struct tg3 *tp) { - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tg3_flag(tp, 57765_PLUS)) { tp->bufmgr_config.mbuf_read_dma_low_water = DEFAULT_MB_RDMA_LOW_WATER_5705; tp->bufmgr_config.mbuf_mac_rx_low_water = @@ -14457,7 +14720,7 @@ static void __devinit tg3_init_bufmgr_config(struct tg3 *tp) DEFAULT_MB_MACRX_LOW_WATER_JUMBO_57765; tp->bufmgr_config.mbuf_high_water_jumbo = DEFAULT_MB_HIGH_WATER_JUMBO_57765; - } else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + } else if (tg3_flag(tp, 5705_PLUS)) { tp->bufmgr_config.mbuf_read_dma_low_water = DEFAULT_MB_RDMA_LOW_WATER_5705; tp->bufmgr_config.mbuf_mac_rx_low_water = @@ -14521,6 +14784,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case TG3_PHY_ID_BCM5718S: return "5718S"; case TG3_PHY_ID_BCM57765: return "57765"; case TG3_PHY_ID_BCM5719C: return "5719C"; + case TG3_PHY_ID_BCM5720C: return "5720C"; case TG3_PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; @@ -14529,10 +14793,10 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) static char * __devinit tg3_bus_string(struct tg3 *tp, char *str) { - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + if (tg3_flag(tp, PCI_EXPRESS)) { strcpy(str, "PCI Express"); return str; - } else if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { + } else if (tg3_flag(tp, PCIX_MODE)) { u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL) & 0x1f; strcpy(str, "PCIX:"); @@ -14551,12 +14815,12 @@ static char * __devinit tg3_bus_string(struct tg3 *tp, char *str) strcat(str, "100MHz"); } else { strcpy(str, "PCI:"); - if (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED) + if (tg3_flag(tp, PCI_HIGH_SPEED)) strcat(str, "66MHz"); else strcat(str, "33MHz"); } - if (tp->tg3_flags & TG3_FLAG_PCI_32BIT) + if (tg3_flag(tp, PCI_32BIT)) strcat(str, ":32-bit"); else strcat(str, ":64-bit"); @@ -14615,7 +14879,7 @@ static void __devinit tg3_init_coal(struct tg3 *tp) ec->tx_coalesce_usecs_irq = DEFAULT_TXCOAL_TICK_INT_CLRTCKS; } - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if (tg3_flag(tp, 5705_PLUS)) { ec->rx_coalesce_usecs_irq = 0; ec->tx_coalesce_usecs_irq = 0; ec->stats_block_coalesce_usecs = 0; @@ -14633,22 +14897,8 @@ static const struct net_device_ops tg3_netdev_ops = { .ndo_do_ioctl = tg3_ioctl, .ndo_tx_timeout = tg3_tx_timeout, .ndo_change_mtu = tg3_change_mtu, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = tg3_poll_controller, -#endif -}; - -static const struct net_device_ops tg3_netdev_ops_dma_bug = { - .ndo_open = tg3_open, - .ndo_stop = tg3_close, - .ndo_start_xmit = tg3_start_xmit_dma_bug, - .ndo_get_stats64 = tg3_get_stats64, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = tg3_set_rx_mode, - .ndo_set_mac_address = tg3_set_mac_addr, - .ndo_do_ioctl = tg3_ioctl, - .ndo_tx_timeout = tg3_tx_timeout, - .ndo_change_mtu = tg3_change_mtu, + .ndo_fix_features = tg3_fix_features, + .ndo_set_features = tg3_set_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = tg3_poll_controller, #endif @@ -14663,6 +14913,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, u32 sndmbx, rcvmbx, intmbx; char str[40]; u64 dma_mask, persist_dma_mask; + u32 features = 0; printk_once(KERN_INFO "%s\n", version); @@ -14698,8 +14949,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - tp = netdev_priv(dev); tp->pdev = pdev; tp->dev = dev; @@ -14749,6 +14998,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; + dev->netdev_ops = &tg3_netdev_ops; dev->irq = pdev->irq; err = tg3_get_invariants(tp); @@ -14758,23 +15008,15 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_iounmap; } - if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) - dev->netdev_ops = &tg3_netdev_ops; - else - dev->netdev_ops = &tg3_netdev_ops_dma_bug; - - /* The EPB bridge inside 5714, 5715, and 5780 and any * device behind the EPB cannot support DMA addresses > 40-bit. * On 64-bit systems with IOMMU, use 40-bit dma_mask. * On 64-bit systems without IOMMU, use 64-bit dma_mask and * do DMA address check in tg3_start_xmit(). */ - if (tp->tg3_flags2 & TG3_FLG2_IS_5788) + if (tg3_flag(tp, IS_5788)) persist_dma_mask = dma_mask = DMA_BIT_MASK(32); - else if (tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG) { + else if (tg3_flag(tp, 40BIT_DMA_BUG)) { persist_dma_mask = dma_mask = DMA_BIT_MASK(40); #ifdef CONFIG_HIGHMEM dma_mask = DMA_BIT_MASK(64); @@ -14786,7 +15028,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if (dma_mask > DMA_BIT_MASK(32)) { err = pci_set_dma_mask(pdev, dma_mask); if (!err) { - dev->features |= NETIF_F_HIGHDMA; + features |= NETIF_F_HIGHDMA; err = pci_set_consistent_dma_mask(pdev, persist_dma_mask); if (err < 0) { @@ -14807,48 +15049,58 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3_init_bufmgr_config(tp); - /* Selectively allow TSO based on operating conditions */ - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) || - (tp->fw_needed && !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) - tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; - else { - tp->tg3_flags2 &= ~(TG3_FLG2_TSO_CAPABLE | TG3_FLG2_TSO_BUG); - tp->fw_needed = NULL; - } + features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) - tp->fw_needed = FIRMWARE_TG3; + /* 5700 B0 chips do not support checksumming correctly due + * to hardware bugs. + */ + if (tp->pci_chip_rev_id != CHIPREV_ID_5700_B0) { + features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM; + + if (tg3_flag(tp, 5755_PLUS)) + features |= NETIF_F_IPV6_CSUM; + } /* TSO is on by default on chips that support hardware TSO. * Firmware TSO on older chips gives lower performance, so it * is off by default, but can be enabled using ethtool. */ - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) && - (dev->features & NETIF_F_IP_CSUM)) { - dev->features |= NETIF_F_TSO; - vlan_features_add(dev, NETIF_F_TSO); - } - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) || - (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3)) { - if (dev->features & NETIF_F_IPV6_CSUM) { - dev->features |= NETIF_F_TSO6; - vlan_features_add(dev, NETIF_F_TSO6); - } - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) || + if ((tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) && + (features & NETIF_F_IP_CSUM)) + features |= NETIF_F_TSO; + if (tg3_flag(tp, HW_TSO_2) || tg3_flag(tp, HW_TSO_3)) { + if (features & NETIF_F_IPV6_CSUM) + features |= NETIF_F_TSO6; + if (tg3_flag(tp, HW_TSO_3) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) { - dev->features |= NETIF_F_TSO_ECN; - vlan_features_add(dev, NETIF_F_TSO_ECN); - } + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + features |= NETIF_F_TSO_ECN; } + dev->features |= features; + dev->vlan_features |= features; + + /* + * Add loopback capability only for a subset of devices that support + * MAC-LOOPBACK. Eventually this need to be enhanced to allow INT-PHY + * loopback for the remaining devices. + */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780 && + !tg3_flag(tp, CPMU_PRESENT)) + /* Add the loopback capability */ + features |= NETIF_F_LOOPBACK; + + dev->hw_features |= features; + if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 && - !(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && + !tg3_flag(tp, TSO_CAPABLE) && !(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH)) { - tp->tg3_flags2 |= TG3_FLG2_MAX_RXPEND_64; + tg3_flag_set(tp, MAX_RXPEND_64); tp->rx_pending = 63; } @@ -14859,7 +15111,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_iounmap; } - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { + if (tg3_flag(tp, ENABLE_APE)) { tp->aperegs = pci_ioremap_bar(pdev, BAR_2); if (!tp->aperegs) { dev_err(&pdev->dev, @@ -14870,7 +15122,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3_ape_lock_init(tp); - if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) + if (tg3_flag(tp, ENABLE_ASF)) tg3_read_dash_ver(tp); } @@ -14914,7 +15166,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, else tnapi->coal_now = HOSTCC_MODE_NOW; - if (!(tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX)) + if (!tg3_flag(tp, SUPPORT_MSIX)) break; /* @@ -14968,21 +15220,25 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, ethtype = "10/100/1000Base-T"; netdev_info(dev, "attached PHY is %s (%s Ethernet) " - "(WireSpeed[%d])\n", tg3_phy_string(tp), ethtype, - (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED) == 0); + "(WireSpeed[%d], EEE[%d])\n", + tg3_phy_string(tp), ethtype, + (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED) == 0, + (tp->phy_flags & TG3_PHYFLG_EEE_CAP) != 0); } netdev_info(dev, "RXcsums[%d] LinkChgREG[%d] MIirq[%d] ASF[%d] TSOcap[%d]\n", - (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0, - (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0, + (dev->features & NETIF_F_RXCSUM) != 0, + tg3_flag(tp, USE_LINKCHG_REG) != 0, (tp->phy_flags & TG3_PHYFLG_USE_MI_INTERRUPT) != 0, - (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0, - (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0); + tg3_flag(tp, ENABLE_ASF) != 0, + tg3_flag(tp, TSO_CAPABLE) != 0); netdev_info(dev, "dma_rwctrl[%08x] dma_mask[%d-bit]\n", tp->dma_rwctrl, pdev->dma_mask == DMA_BIT_MASK(32) ? 32 : ((u64)pdev->dma_mask) == DMA_BIT_MASK(40) ? 40 : 64); + pci_save_state(pdev); + return 0; err_out_apeunmap: @@ -15021,7 +15277,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) cancel_work_sync(&tp->reset_task); - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (!tg3_flag(tp, USE_PHYLIB)) { tg3_phy_fini(tp); tg3_mdio_fini(tp); } @@ -15067,7 +15323,7 @@ static int tg3_suspend(struct device *device) tg3_full_lock(tp, 0); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; + tg3_flag_clear(tp, INIT_COMPLETE); tg3_full_unlock(tp); err = tg3_power_down_prepare(tp); @@ -15076,7 +15332,7 @@ static int tg3_suspend(struct device *device) tg3_full_lock(tp, 0); - tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; + tg3_flag_set(tp, INIT_COMPLETE); err2 = tg3_restart_hw(tp, 1); if (err2) goto out; @@ -15111,7 +15367,7 @@ static int tg3_resume(struct device *device) tg3_full_lock(tp, 0); - tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; + tg3_flag_set(tp, INIT_COMPLETE); err = tg3_restart_hw(tp, 1); if (err) goto out; @@ -15139,11 +15395,156 @@ static SIMPLE_DEV_PM_OPS(tg3_pm_ops, tg3_suspend, tg3_resume); #endif /* CONFIG_PM_SLEEP */ +/** + * tg3_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct tg3 *tp = netdev_priv(netdev); + pci_ers_result_t err = PCI_ERS_RESULT_NEED_RESET; + + netdev_info(netdev, "PCI I/O error detected\n"); + + rtnl_lock(); + + if (!netif_running(netdev)) + goto done; + + tg3_phy_stop(tp); + + tg3_netif_stop(tp); + + del_timer_sync(&tp->timer); + tg3_flag_clear(tp, RESTART_TIMER); + + /* Want to make sure that the reset task doesn't run */ + cancel_work_sync(&tp->reset_task); + tg3_flag_clear(tp, TX_RECOVERY_PENDING); + tg3_flag_clear(tp, RESTART_TIMER); + + netif_device_detach(netdev); + + /* Clean up software state, even if MMIO is blocked */ + tg3_full_lock(tp, 0); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); + tg3_full_unlock(tp); + +done: + if (state == pci_channel_io_perm_failure) + err = PCI_ERS_RESULT_DISCONNECT; + else + pci_disable_device(pdev); + + rtnl_unlock(); + + return err; +} + +/** + * tg3_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + * At this point, the card has exprienced a hard reset, + * followed by fixups by BIOS, and has its config space + * set up identically to what it was at cold boot. + */ +static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct tg3 *tp = netdev_priv(netdev); + pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; + int err; + + rtnl_lock(); + + if (pci_enable_device(pdev)) { + netdev_err(netdev, "Cannot re-enable PCI device after reset.\n"); + goto done; + } + + pci_set_master(pdev); + pci_restore_state(pdev); + pci_save_state(pdev); + + if (!netif_running(netdev)) { + rc = PCI_ERS_RESULT_RECOVERED; + goto done; + } + + err = tg3_power_up(tp); + if (err) { + netdev_err(netdev, "Failed to restore register access.\n"); + goto done; + } + + rc = PCI_ERS_RESULT_RECOVERED; + +done: + rtnl_unlock(); + + return rc; +} + +/** + * tg3_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells + * us that its OK to resume normal operation. + */ +static void tg3_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct tg3 *tp = netdev_priv(netdev); + int err; + + rtnl_lock(); + + if (!netif_running(netdev)) + goto done; + + tg3_full_lock(tp, 0); + tg3_flag_set(tp, INIT_COMPLETE); + err = tg3_restart_hw(tp, 1); + tg3_full_unlock(tp); + if (err) { + netdev_err(netdev, "Cannot restart hardware after reset.\n"); + goto done; + } + + netif_device_attach(netdev); + + tp->timer.expires = jiffies + tp->timer_offset; + add_timer(&tp->timer); + + tg3_netif_start(tp); + + tg3_phy_start(tp); + +done: + rtnl_unlock(); +} + +static struct pci_error_handlers tg3_err_handler = { + .error_detected = tg3_io_error_detected, + .slot_reset = tg3_io_slot_reset, + .resume = tg3_io_resume +}; + static struct pci_driver tg3_driver = { .name = DRV_MODULE_NAME, .id_table = tg3_pci_tbl, .probe = tg3_init_one, .remove = __devexit_p(tg3_remove_one), + .err_handler = &tg3_err_handler, .driver.pm = TG3_PM_OPS, }; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 5e96706ad108..5b3d2f34da7a 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -23,11 +23,13 @@ #define TG3_BDINFO_NIC_ADDR 0xcUL /* 32-bit */ #define TG3_BDINFO_SIZE 0x10UL -#define TG3_RX_INTERNAL_RING_SZ_5906 32 - -#define RX_STD_MAX_SIZE_5705 512 -#define RX_STD_MAX_SIZE_5717 2048 -#define RX_JUMBO_MAX_SIZE 0xdeadbeef /* XXX */ +#define TG3_RX_STD_MAX_SIZE_5700 512 +#define TG3_RX_STD_MAX_SIZE_5717 2048 +#define TG3_RX_JMB_MAX_SIZE_5700 256 +#define TG3_RX_JMB_MAX_SIZE_5717 1024 +#define TG3_RX_RET_MAX_SIZE_5700 1024 +#define TG3_RX_RET_MAX_SIZE_5705 512 +#define TG3_RX_RET_MAX_SIZE_5717 4096 /* First 256 bytes are a mirror of PCI config space. */ #define TG3PCI_VENDOR 0x00000000 @@ -54,6 +56,7 @@ #define TG3PCI_DEVICE_TIGON3_57791 0x16b2 #define TG3PCI_DEVICE_TIGON3_57795 0x16b6 #define TG3PCI_DEVICE_TIGON3_5719 0x1657 +#define TG3PCI_DEVICE_TIGON3_5720 0x165f /* 0x04 --> 0x2c unused */ #define TG3PCI_SUBVENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM #define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6 0x1644 @@ -142,6 +145,7 @@ #define CHIPREV_ID_5717_A0 0x05717000 #define CHIPREV_ID_57765_A0 0x57785000 #define CHIPREV_ID_5719_A0 0x05719000 +#define CHIPREV_ID_5720_A0 0x05720000 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -163,6 +167,7 @@ #define ASIC_REV_5717 0x5717 #define ASIC_REV_57765 0x57785 #define ASIC_REV_5719 0x5719 +#define ASIC_REV_5720 0x5720 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -175,6 +180,7 @@ #define CHIPREV_5750_BX 0x41 #define CHIPREV_5784_AX 0x57840 #define CHIPREV_5761_AX 0x57610 +#define CHIPREV_57765_AX 0x577650 #define GET_METAL_REV(CHIP_REV_ID) ((CHIP_REV_ID) & 0xff) #define METAL_REV_A0 0x00 #define METAL_REV_A1 0x01 @@ -183,6 +189,7 @@ #define METAL_REV_B2 0x02 #define TG3PCI_DMA_RW_CTRL 0x0000006c #define DMA_RWCTRL_DIS_CACHE_ALIGNMENT 0x00000001 +#define DMA_RWCTRL_TAGGED_STAT_WA 0x00000080 #define DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK 0x00000380 #define DMA_RWCTRL_READ_BNDRY_MASK 0x00000700 #define DMA_RWCTRL_READ_BNDRY_DISAB 0x00000000 @@ -473,6 +480,8 @@ #define TX_MODE_BIG_BCKOFF_ENABLE 0x00000020 #define TX_MODE_LONG_PAUSE_ENABLE 0x00000040 #define TX_MODE_MBUF_LOCKUP_FIX 0x00000100 +#define TX_MODE_JMB_FRM_LEN 0x00400000 +#define TX_MODE_CNT_DN_MODE 0x00800000 #define MAC_TX_STATUS 0x00000460 #define TX_STATUS_XOFFED 0x00000001 #define TX_STATUS_SENT_XOFF 0x00000002 @@ -487,6 +496,8 @@ #define TX_LENGTHS_IPG_SHIFT 8 #define TX_LENGTHS_IPG_CRS_MASK 0x00003000 #define TX_LENGTHS_IPG_CRS_SHIFT 12 +#define TX_LENGTHS_JMB_FRM_LEN_MSK 0x00ff0000 +#define TX_LENGTHS_CNT_DWN_VAL_MSK 0xff000000 #define MAC_RX_MODE 0x00000468 #define RX_MODE_RESET 0x00000001 #define RX_MODE_ENABLE 0x00000002 @@ -1079,6 +1090,9 @@ #define CPMU_HST_ACC_MACCLK_6_25 0x00130000 /* 0x3620 --> 0x3630 unused */ +#define TG3_CPMU_CLCK_ORIDE 0x00003624 +#define CPMU_CLCK_ORIDE_MAC_ORIDE_EN 0x80000000 + #define TG3_CPMU_CLCK_STAT 0x00003630 #define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000 #define CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000 @@ -1188,6 +1202,7 @@ #define HOSTCC_STATS_BLK_NIC_ADDR 0x00003c40 #define HOSTCC_STATUS_BLK_NIC_ADDR 0x00003c44 #define HOSTCC_FLOW_ATTN 0x00003c48 +#define HOSTCC_FLOW_ATTN_MBUF_LWM 0x00000040 /* 0x3c4c --> 0x3c50 unused */ #define HOSTCC_JUMBO_CON_IDX 0x00003c50 #define HOSTCC_STD_CON_IDX 0x00003c54 @@ -1321,6 +1336,7 @@ #define RDMAC_MODE_MULT_DMA_RD_DIS 0x01000000 #define RDMAC_MODE_IPV4_LSO_EN 0x08000000 #define RDMAC_MODE_IPV6_LSO_EN 0x10000000 +#define RDMAC_MODE_H2BNC_VLAN_DET 0x20000000 #define RDMAC_STATUS 0x00004804 #define RDMAC_STATUS_TGTABORT 0x00000004 #define RDMAC_STATUS_MSTABORT 0x00000008 @@ -1597,6 +1613,7 @@ #define MSGINT_MODE_ONE_SHOT_DISABLE 0x00000020 #define MSGINT_MODE_MULTIVEC_EN 0x00000080 #define MSGINT_STATUS 0x00006004 +#define MSGINT_STATUS_MSI_REQ 0x00000001 #define MSGINT_FIFO 0x00006008 /* 0x600c --> 0x6400 unused */ @@ -1613,6 +1630,8 @@ #define GRC_MODE_WSWAP_NONFRM_DATA 0x00000004 #define GRC_MODE_BSWAP_DATA 0x00000010 #define GRC_MODE_WSWAP_DATA 0x00000020 +#define GRC_MODE_BYTE_SWAP_B2HRX_DATA 0x00000040 +#define GRC_MODE_WORD_SWAP_B2HRX_DATA 0x00000080 #define GRC_MODE_SPLITHDR 0x00000100 #define GRC_MODE_NOFRM_CRACKING 0x00000200 #define GRC_MODE_INCL_CRC 0x00000400 @@ -1620,8 +1639,10 @@ #define GRC_MODE_NOIRQ_ON_SENDS 0x00002000 #define GRC_MODE_NOIRQ_ON_RCV 0x00004000 #define GRC_MODE_FORCE_PCI32BIT 0x00008000 +#define GRC_MODE_B2HRX_ENABLE 0x00008000 #define GRC_MODE_HOST_STACKUP 0x00010000 #define GRC_MODE_HOST_SENDBDS 0x00020000 +#define GRC_MODE_HTX2B_ENABLE 0x00040000 #define GRC_MODE_NO_TX_PHDR_CSUM 0x00100000 #define GRC_MODE_NVRAM_WR_ENABLE 0x00200000 #define GRC_MODE_PCIE_TL_SEL 0x00000000 @@ -1818,6 +1839,38 @@ #define FLASH_5717VENDOR_ATMEL_45USPT 0x03400000 #define FLASH_5717VENDOR_ST_25USPT 0x03400002 #define FLASH_5717VENDOR_ST_45USPT 0x03400001 +#define FLASH_5720_EEPROM_HD 0x00000001 +#define FLASH_5720_EEPROM_LD 0x00000003 +#define FLASH_5720VENDOR_M_ATMEL_DB011D 0x01000000 +#define FLASH_5720VENDOR_M_ATMEL_DB021D 0x01000002 +#define FLASH_5720VENDOR_M_ATMEL_DB041D 0x01000001 +#define FLASH_5720VENDOR_M_ATMEL_DB081D 0x01000003 +#define FLASH_5720VENDOR_M_ST_M25PE10 0x02000000 +#define FLASH_5720VENDOR_M_ST_M25PE20 0x02000002 +#define FLASH_5720VENDOR_M_ST_M25PE40 0x02000001 +#define FLASH_5720VENDOR_M_ST_M25PE80 0x02000003 +#define FLASH_5720VENDOR_M_ST_M45PE10 0x03000000 +#define FLASH_5720VENDOR_M_ST_M45PE20 0x03000002 +#define FLASH_5720VENDOR_M_ST_M45PE40 0x03000001 +#define FLASH_5720VENDOR_M_ST_M45PE80 0x03000003 +#define FLASH_5720VENDOR_A_ATMEL_DB011B 0x01800000 +#define FLASH_5720VENDOR_A_ATMEL_DB021B 0x01800002 +#define FLASH_5720VENDOR_A_ATMEL_DB041B 0x01800001 +#define FLASH_5720VENDOR_A_ATMEL_DB011D 0x01c00000 +#define FLASH_5720VENDOR_A_ATMEL_DB021D 0x01c00002 +#define FLASH_5720VENDOR_A_ATMEL_DB041D 0x01c00001 +#define FLASH_5720VENDOR_A_ATMEL_DB081D 0x01c00003 +#define FLASH_5720VENDOR_A_ST_M25PE10 0x02800000 +#define FLASH_5720VENDOR_A_ST_M25PE20 0x02800002 +#define FLASH_5720VENDOR_A_ST_M25PE40 0x02800001 +#define FLASH_5720VENDOR_A_ST_M25PE80 0x02800003 +#define FLASH_5720VENDOR_A_ST_M45PE10 0x02c00000 +#define FLASH_5720VENDOR_A_ST_M45PE20 0x02c00002 +#define FLASH_5720VENDOR_A_ST_M45PE40 0x02c00001 +#define FLASH_5720VENDOR_A_ST_M45PE80 0x02c00003 +#define FLASH_5720VENDOR_ATMEL_45USPT 0x03c00000 +#define FLASH_5720VENDOR_ST_25USPT 0x03c00002 +#define FLASH_5720VENDOR_ST_45USPT 0x03c00001 #define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000 #define FLASH_5752PAGE_SIZE_256 0x00000000 #define FLASH_5752PAGE_SIZE_512 0x10000000 @@ -1899,11 +1952,16 @@ /* Alternate PCIE definitions */ #define TG3_PCIE_TLDLPL_PORT 0x00007c00 +#define TG3_PCIE_DL_LO_FTSMAX 0x0000000c +#define TG3_PCIE_DL_LO_FTSMAX_MSK 0x000000ff +#define TG3_PCIE_DL_LO_FTSMAX_VAL 0x0000002c #define TG3_PCIE_PL_LO_PHYCTL1 0x00000004 #define TG3_PCIE_PL_LO_PHYCTL1_L1PLLPD_EN 0x00001000 #define TG3_PCIE_PL_LO_PHYCTL5 0x00000014 #define TG3_PCIE_PL_LO_PHYCTL5_DIS_L2CLKREQ 0x80000000 +#define TG3_REG_BLK_SIZE 0x00008000 + /* OTP bit definitions */ #define TG3_OTP_AGCTGT_MASK 0x000000e0 #define TG3_OTP_AGCTGT_SHIFT 1 @@ -1955,7 +2013,9 @@ #define TG3_NVM_DIR_END 0x78 #define TG3_NVM_DIRENT_SIZE 0xc #define TG3_NVM_DIRTYPE_SHIFT 24 +#define TG3_NVM_DIRTYPE_LENMSK 0x003fffff #define TG3_NVM_DIRTYPE_ASFINI 1 +#define TG3_NVM_DIRTYPE_EXTVPD 20 #define TG3_NVM_PTREV_BCVER 0x94 #define TG3_NVM_BCVER_MAJMSK 0x0000ff00 #define TG3_NVM_BCVER_MAJSFT 8 @@ -2079,6 +2139,13 @@ #define NIC_SRAM_MBUF_POOL_BASE5705 0x00010000 #define NIC_SRAM_MBUF_POOL_SIZE5705 0x0000e000 +#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5700 128 +#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5755 64 +#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5906 32 + +#define TG3_SRAM_RX_JMB_BDCACHE_SIZE_5700 64 +#define TG3_SRAM_RX_JMB_BDCACHE_SIZE_5717 16 + /* Currently this is fixed. */ #define TG3_PHY_MII_ADDR 0x01 @@ -2119,7 +2186,7 @@ #define MII_TG3_DSP_TAP26_OPCSINPT 0x0004 #define MII_TG3_DSP_AADJ1CH0 0x001f #define MII_TG3_DSP_CH34TP2 0x4022 -#define MII_TG3_DSP_CH34TP2_HIBW01 0x0010 +#define MII_TG3_DSP_CH34TP2_HIBW01 0x017b #define MII_TG3_DSP_AADJ1CH3 0x601f #define MII_TG3_DSP_AADJ1CH3_ADCCKADJ 0x0002 #define MII_TG3_DSP_EXP1_INT_STAT 0x0f01 @@ -2132,19 +2199,26 @@ #define MII_TG3_AUX_CTRL 0x18 /* auxiliary control register */ +#define MII_TG3_AUXCTL_SHDWSEL_AUXCTL 0x0000 +#define MII_TG3_AUXCTL_ACTL_TX_6DB 0x0400 +#define MII_TG3_AUXCTL_ACTL_SMDSP_ENA 0x0800 +#define MII_TG3_AUXCTL_ACTL_EXTPKTLEN 0x4000 + +#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL 0x0002 +#define MII_TG3_AUXCTL_PCTL_WOL_EN 0x0008 #define MII_TG3_AUXCTL_PCTL_100TX_LPWR 0x0010 #define MII_TG3_AUXCTL_PCTL_SPR_ISOLATE 0x0020 +#define MII_TG3_AUXCTL_PCTL_CL_AB_TXDAC 0x0040 #define MII_TG3_AUXCTL_PCTL_VREG_11V 0x0180 -#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL 0x0002 -#define MII_TG3_AUXCTL_MISC_WREN 0x8000 -#define MII_TG3_AUXCTL_MISC_FORCE_AMDIX 0x0200 -#define MII_TG3_AUXCTL_MISC_RDSEL_MISC 0x7000 +#define MII_TG3_AUXCTL_SHDWSEL_MISCTEST 0x0004 + #define MII_TG3_AUXCTL_SHDWSEL_MISC 0x0007 +#define MII_TG3_AUXCTL_MISC_WIRESPD_EN 0x0010 +#define MII_TG3_AUXCTL_MISC_FORCE_AMDIX 0x0200 +#define MII_TG3_AUXCTL_MISC_RDSEL_SHIFT 12 +#define MII_TG3_AUXCTL_MISC_WREN 0x8000 -#define MII_TG3_AUXCTL_ACTL_SMDSP_ENA 0x0800 -#define MII_TG3_AUXCTL_ACTL_TX_6DB 0x0400 -#define MII_TG3_AUXCTL_SHDWSEL_AUXCTL 0x0000 #define MII_TG3_AUX_STAT 0x19 /* auxiliary status register */ #define MII_TG3_AUX_STAT_LPASS 0x0004 @@ -2564,7 +2638,12 @@ struct tg3_hw_stats { tg3_stat64_t nic_avoided_irqs; tg3_stat64_t nic_tx_threshold_hit; - u8 __reserved4[0xb00-0x9c0]; + /* NOT a part of the hardware statistics block format. + * These stats are here as storage for tg3_periodic_fetch_stats(). + */ + tg3_stat64_t mbuf_lwm_thresh_hit; + + u8 __reserved4[0xb00-0x9c8]; }; /* 'mapping' is superfluous as the chip does not write into @@ -2696,6 +2775,8 @@ struct tg3_ethtool_stats { u64 nic_irqs; u64 nic_avoided_irqs; u64 nic_tx_threshold_hit; + + u64 mbuf_lwm_thresh_hit; }; struct tg3_rx_prodring_set { @@ -2745,6 +2826,86 @@ struct tg3_napi { unsigned int irq_vec; }; +enum TG3_FLAGS { + TG3_FLAG_TAGGED_STATUS = 0, + TG3_FLAG_TXD_MBOX_HWBUG, + TG3_FLAG_USE_LINKCHG_REG, + TG3_FLAG_ERROR_PROCESSED, + TG3_FLAG_ENABLE_ASF, + TG3_FLAG_ASPM_WORKAROUND, + TG3_FLAG_POLL_SERDES, + TG3_FLAG_MBOX_WRITE_REORDER, + TG3_FLAG_PCIX_TARGET_HWBUG, + TG3_FLAG_WOL_SPEED_100MB, + TG3_FLAG_WOL_ENABLE, + TG3_FLAG_EEPROM_WRITE_PROT, + TG3_FLAG_NVRAM, + TG3_FLAG_NVRAM_BUFFERED, + TG3_FLAG_SUPPORT_MSI, + TG3_FLAG_SUPPORT_MSIX, + TG3_FLAG_PCIX_MODE, + TG3_FLAG_PCI_HIGH_SPEED, + TG3_FLAG_PCI_32BIT, + TG3_FLAG_SRAM_USE_CONFIG, + TG3_FLAG_TX_RECOVERY_PENDING, + TG3_FLAG_WOL_CAP, + TG3_FLAG_JUMBO_RING_ENABLE, + TG3_FLAG_PAUSE_AUTONEG, + TG3_FLAG_CPMU_PRESENT, + TG3_FLAG_40BIT_DMA_BUG, + TG3_FLAG_BROKEN_CHECKSUMS, + TG3_FLAG_JUMBO_CAPABLE, + TG3_FLAG_CHIP_RESETTING, + TG3_FLAG_INIT_COMPLETE, + TG3_FLAG_RESTART_TIMER, + TG3_FLAG_TSO_BUG, + TG3_FLAG_IS_5788, + TG3_FLAG_MAX_RXPEND_64, + TG3_FLAG_TSO_CAPABLE, + TG3_FLAG_PCI_EXPRESS, + TG3_FLAG_ASF_NEW_HANDSHAKE, + TG3_FLAG_HW_AUTONEG, + TG3_FLAG_IS_NIC, + TG3_FLAG_FLASH, + TG3_FLAG_HW_TSO_1, + TG3_FLAG_5705_PLUS, + TG3_FLAG_5750_PLUS, + TG3_FLAG_HW_TSO_3, + TG3_FLAG_USING_MSI, + TG3_FLAG_USING_MSIX, + TG3_FLAG_ICH_WORKAROUND, + TG3_FLAG_5780_CLASS, + TG3_FLAG_HW_TSO_2, + TG3_FLAG_1SHOT_MSI, + TG3_FLAG_NO_FWARE_REPORTED, + TG3_FLAG_NO_NVRAM_ADDR_TRANS, + TG3_FLAG_ENABLE_APE, + TG3_FLAG_PROTECTED_NVRAM, + TG3_FLAG_5701_DMA_BUG, + TG3_FLAG_USE_PHYLIB, + TG3_FLAG_MDIOBUS_INITED, + TG3_FLAG_LRG_PROD_RING_CAP, + TG3_FLAG_RGMII_INBAND_DISABLE, + TG3_FLAG_RGMII_EXT_IBND_RX_EN, + TG3_FLAG_RGMII_EXT_IBND_TX_EN, + TG3_FLAG_CLKREQ_BUG, + TG3_FLAG_5755_PLUS, + TG3_FLAG_NO_NVRAM, + TG3_FLAG_ENABLE_RSS, + TG3_FLAG_ENABLE_TSS, + TG3_FLAG_4G_DMA_BNDRY_BUG, + TG3_FLAG_40BIT_DMA_LIMIT_BUG, + TG3_FLAG_SHORT_DMA_BUG, + TG3_FLAG_USE_JUMBO_BDFLAG, + TG3_FLAG_L1PLLPD_EN, + TG3_FLAG_57765_PLUS, + TG3_FLAG_APE_HAS_NCSI, + TG3_FLAG_5717_PLUS, + + /* Add new flags before this comment and TG3_FLAG_NUMBER_OF_FLAGS */ + TG3_FLAG_NUMBER_OF_FLAGS, /* Last entry in enum TG3_FLAGS */ +}; + struct tg3 { /* begin "general, frequently-used members" cacheline section */ @@ -2768,7 +2929,7 @@ struct tg3 { /* SMP locking strategy: * * lock: Held during reset, PHY access, timer, and when - * updating tg3_flags and tg3_flags2. + * updating tg3_flags. * * netif_tx_lock: Held during tg3_start_xmit. tg3_tx holds * netif_tx_lock when it needs to call @@ -2825,94 +2986,13 @@ struct tg3 { struct tg3_ethtool_stats estats; struct tg3_ethtool_stats estats_prev; + DECLARE_BITMAP(tg3_flags, TG3_FLAG_NUMBER_OF_FLAGS); + union { unsigned long phy_crc_errors; unsigned long last_event_jiffies; }; - u32 tg3_flags; -#define TG3_FLAG_TAGGED_STATUS 0x00000001 -#define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002 -#define TG3_FLAG_RX_CHECKSUMS 0x00000004 -#define TG3_FLAG_USE_LINKCHG_REG 0x00000008 -#define TG3_FLAG_ENABLE_ASF 0x00000020 -#define TG3_FLAG_ASPM_WORKAROUND 0x00000040 -#define TG3_FLAG_POLL_SERDES 0x00000080 -#define TG3_FLAG_MBOX_WRITE_REORDER 0x00000100 -#define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200 -#define TG3_FLAG_WOL_SPEED_100MB 0x00000400 -#define TG3_FLAG_WOL_ENABLE 0x00000800 -#define TG3_FLAG_EEPROM_WRITE_PROT 0x00001000 -#define TG3_FLAG_NVRAM 0x00002000 -#define TG3_FLAG_NVRAM_BUFFERED 0x00004000 -#define TG3_FLAG_SUPPORT_MSI 0x00008000 -#define TG3_FLAG_SUPPORT_MSIX 0x00010000 -#define TG3_FLAG_SUPPORT_MSI_OR_MSIX (TG3_FLAG_SUPPORT_MSI | \ - TG3_FLAG_SUPPORT_MSIX) -#define TG3_FLAG_PCIX_MODE 0x00020000 -#define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 -#define TG3_FLAG_PCI_32BIT 0x00080000 -#define TG3_FLAG_SRAM_USE_CONFIG 0x00100000 -#define TG3_FLAG_TX_RECOVERY_PENDING 0x00200000 -#define TG3_FLAG_WOL_CAP 0x00400000 -#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000 -#define TG3_FLAG_PAUSE_AUTONEG 0x02000000 -#define TG3_FLAG_CPMU_PRESENT 0x04000000 -#define TG3_FLAG_40BIT_DMA_BUG 0x08000000 -#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 -#define TG3_FLAG_JUMBO_CAPABLE 0x20000000 -#define TG3_FLAG_CHIP_RESETTING 0x40000000 -#define TG3_FLAG_INIT_COMPLETE 0x80000000 - u32 tg3_flags2; -#define TG3_FLG2_RESTART_TIMER 0x00000001 -#define TG3_FLG2_TSO_BUG 0x00000002 -#define TG3_FLG2_IS_5788 0x00000008 -#define TG3_FLG2_MAX_RXPEND_64 0x00000010 -#define TG3_FLG2_TSO_CAPABLE 0x00000020 -#define TG3_FLG2_PCI_EXPRESS 0x00000200 -#define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400 -#define TG3_FLG2_HW_AUTONEG 0x00000800 -#define TG3_FLG2_IS_NIC 0x00001000 -#define TG3_FLG2_FLASH 0x00008000 -#define TG3_FLG2_HW_TSO_1 0x00010000 -#define TG3_FLG2_5705_PLUS 0x00040000 -#define TG3_FLG2_5750_PLUS 0x00080000 -#define TG3_FLG2_HW_TSO_3 0x00100000 -#define TG3_FLG2_USING_MSI 0x00200000 -#define TG3_FLG2_USING_MSIX 0x00400000 -#define TG3_FLG2_USING_MSI_OR_MSIX (TG3_FLG2_USING_MSI | \ - TG3_FLG2_USING_MSIX) -#define TG3_FLG2_ICH_WORKAROUND 0x02000000 -#define TG3_FLG2_5780_CLASS 0x04000000 -#define TG3_FLG2_HW_TSO_2 0x08000000 -#define TG3_FLG2_HW_TSO (TG3_FLG2_HW_TSO_1 | \ - TG3_FLG2_HW_TSO_2 | \ - TG3_FLG2_HW_TSO_3) -#define TG3_FLG2_1SHOT_MSI 0x10000000 -#define TG3_FLG2_NO_FWARE_REPORTED 0x40000000 - u32 tg3_flags3; -#define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001 -#define TG3_FLG3_ENABLE_APE 0x00000002 -#define TG3_FLG3_PROTECTED_NVRAM 0x00000004 -#define TG3_FLG3_5701_DMA_BUG 0x00000008 -#define TG3_FLG3_USE_PHYLIB 0x00000010 -#define TG3_FLG3_MDIOBUS_INITED 0x00000020 -#define TG3_FLG3_RGMII_INBAND_DISABLE 0x00000100 -#define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200 -#define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400 -#define TG3_FLG3_CLKREQ_BUG 0x00000800 -#define TG3_FLG3_5755_PLUS 0x00002000 -#define TG3_FLG3_NO_NVRAM 0x00004000 -#define TG3_FLG3_ENABLE_RSS 0x00020000 -#define TG3_FLG3_ENABLE_TSS 0x00040000 -#define TG3_FLG3_4G_DMA_BNDRY_BUG 0x00080000 -#define TG3_FLG3_40BIT_DMA_LIMIT_BUG 0x00100000 -#define TG3_FLG3_SHORT_DMA_BUG 0x00200000 -#define TG3_FLG3_USE_JUMBO_BDFLAG 0x00400000 -#define TG3_FLG3_L1PLLPD_EN 0x00800000 -#define TG3_FLG3_5717_PLUS 0x01000000 -#define TG3_FLG3_APE_HAS_NCSI 0x02000000 - struct timer_list timer; u16 timer_counter; u16 timer_multiplier; @@ -2983,6 +3063,7 @@ struct tg3 { #define TG3_PHY_ID_BCM5718S 0xbc050ff0 #define TG3_PHY_ID_BCM57765 0x5c0d8a40 #define TG3_PHY_ID_BCM5719C 0x5c0d8a20 +#define TG3_PHY_ID_BCM5720C 0x5c0d8b60 #define TG3_PHY_ID_BCM5906 0xdc00ac40 #define TG3_PHY_ID_BCM8002 0x60010140 #define TG3_PHY_ID_INVALID 0xffffffff @@ -3049,6 +3130,7 @@ struct tg3 { int nvram_lock_cnt; u32 nvram_size; +#define TG3_NVRAM_SIZE_2KB 0x00000800 #define TG3_NVRAM_SIZE_64KB 0x00010000 #define TG3_NVRAM_SIZE_128KB 0x00020000 #define TG3_NVRAM_SIZE_256KB 0x00040000 @@ -3064,6 +3146,9 @@ struct tg3 { #define JEDEC_SAIFUN 0x4f #define JEDEC_SST 0xbf +#define ATMEL_AT24C02_CHIP_SIZE TG3_NVRAM_SIZE_2KB +#define ATMEL_AT24C02_PAGE_SIZE (8) + #define ATMEL_AT24C64_CHIP_SIZE TG3_NVRAM_SIZE_64KB #define ATMEL_AT24C64_PAGE_SIZE (32) diff --git a/drivers/net/tile/tilepro.c b/drivers/net/tile/tilepro.c index 0825db6d883f..1e980fdd9d77 100644 --- a/drivers/net/tile/tilepro.c +++ b/drivers/net/tile/tilepro.c @@ -1930,7 +1930,7 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev) unsigned int len = skb->len; unsigned char *data = skb->data; - unsigned int csum_start = skb->csum_start - skb_headroom(skb); + unsigned int csum_start = skb_checksum_start_offset(skb); lepp_frag_t frags[LEPP_MAX_FRAGS]; diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 8a3b191b195b..ff32befd8443 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -1251,7 +1251,7 @@ static netdev_tx_t xl_xmit(struct sk_buff *skb, struct net_device *dev) /* * 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 tranmitted packets + * then advance around the ring for all transmitted packets */ static void xl_dn_comp(struct net_device *dev) @@ -1568,7 +1568,7 @@ static void xl_arb_cmd(struct net_device *dev) 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 tranmitting the beacon, aaah\n",dev->name); + 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) diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 5bd140704533..9354ca9da576 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -1675,7 +1675,7 @@ static void streamer_arb_cmd(struct net_device *dev) 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 tranmitting the beacon, aaah\n", dev->name); + 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) diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 2bedc0ace812..1313aa1315f0 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -727,7 +727,7 @@ static int __devexit madgemc_remove(struct device *device) return 0; } -static short madgemc_adapter_ids[] __initdata = { +static const short madgemc_adapter_ids[] __devinitconst = { 0x002d, 0x0000 }; diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 3d2fbe60b46e..e3855aeb13d4 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -86,6 +86,7 @@ #include #include #include +#include #include #include #include @@ -193,7 +194,7 @@ 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 int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) ; +static const struct file_operations olympic_proc_ops; static const struct net_device_ops olympic_netdev_ops = { .ndo_open = olympic_open, @@ -272,7 +273,7 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device char proc_name[20] ; strcpy(proc_name,"olympic_") ; strcat(proc_name,dev->name) ; - create_proc_read_entry(proc_name,0,init_net.proc_net,olympic_proc_info,(void *)dev) ; + 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 ; @@ -1500,7 +1501,7 @@ static void olympic_arb_cmd(struct net_device *dev) 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 tranmitting the beacon, aaah\n",dev->name); + 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) @@ -1615,29 +1616,25 @@ static int olympic_change_mtu(struct net_device *dev, int mtu) return 0 ; } -static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +static int olympic_proc_show(struct seq_file *m, void *v) { - struct net_device *dev = (struct net_device *)data ; + 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) ; - int size = 0 ; - int len=0; - off_t begin=0; - off_t pos=0; u8 addr[6]; u8 addr2[6]; int i; - size = sprintf(buffer, + seq_printf(m, "IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name); - size += sprintf(buffer+size, "\n%6s: Adapter Address : Node Address : Functional Addr\n", + 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); - size += sprintf(buffer+size, "%6s: %pM : %pM : %02x:%02x:%02x:%02x\n", + 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)), @@ -1645,9 +1642,9 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3)); - size += sprintf(buffer+size, "\n%6s: Token Ring Parameters Table:\n", dev->name); + seq_printf(m, "\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", + 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++) @@ -1655,7 +1652,7 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt for (i = 0 ; i < 6 ; i++) addr2[i] = readb(opt+offsetof(struct olympic_parameters_table, poll_addr) + i); - size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %pM : %pM : %04x : %04x : %04x :\n", + 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), @@ -1666,12 +1663,12 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))), swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code)))); - size += sprintf(buffer+size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", + 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); - size += sprintf(buffer+size, "%6s: %pM : %04x : %04x : %04x : %04x : %04x : %04x : \n", + 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))), @@ -1680,12 +1677,12 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt swab16(readw(opt+offsetof(struct olympic_parameters_table, mon_error))), swab16(readw(opt+offsetof(struct olympic_parameters_table, frame_correl)))); - size += sprintf(buffer+size, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n", + 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); - size += sprintf(buffer+size, "%6s: : %02x : %02x : %pM : %02x:%02x:%02x:%02x : \n", + 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))), @@ -1695,19 +1692,21 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2), readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+3)); - len=size; - pos=begin+size; - if (poslength) - len=length; /* Ending slop */ - return len; + 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) ; diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c index 007d8e75666d..092c3faa882a 100644 --- a/drivers/net/tulip/21142.c +++ b/drivers/net/tulip/21142.c @@ -122,8 +122,8 @@ void t21142_start_nway(struct net_device *dev) tp->nway = tp->mediasense = 1; tp->nwayset = tp->lpar = 0; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%08x\n", - dev->name, csr14); + netdev_dbg(dev, "Restarting 21143 autonegotiation, csr14=%08x\n", + csr14); iowrite32(0x0001, ioaddr + CSR13); udelay(100); iowrite32(csr14, ioaddr + CSR14); @@ -206,14 +206,14 @@ void t21142_lnk_change(struct net_device *dev, int csr5) #if 0 /* Restart shouldn't be needed. */ iowrite32(tp->csr6 | RxOn, ioaddr + CSR6); if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %08x\n", - dev->name, ioread32(ioaddr + CSR5)); + netdev_dbg(dev, " Restarting Tx and Rx, CSR5 is %08x\n", + ioread32(ioaddr + CSR5)); #endif tulip_start_rxtx(tp); if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Setting CSR6 %08x/%x CSR12 %08x\n", - dev->name, tp->csr6, ioread32(ioaddr + CSR6), - ioread32(ioaddr + CSR12)); + netdev_dbg(dev, " Setting CSR6 %08x/%x CSR12 %08x\n", + tp->csr6, ioread32(ioaddr + CSR6), + ioread32(ioaddr + CSR12)); } else if ((tp->nwayset && (csr5 & 0x08000000) && (dev->if_port == 3 || dev->if_port == 5) && (csr12 & 2) == 2) || diff --git a/drivers/net/tulip/Makefile b/drivers/net/tulip/Makefile index 200cbf7c815c..5e8be38b45bb 100644 --- a/drivers/net/tulip/Makefile +++ b/drivers/net/tulip/Makefile @@ -2,6 +2,8 @@ # Makefile for the Linux "Tulip" family network device drivers. # +ccflags-$(CONFIG_NET_TULIP) := -DDEBUG + obj-$(CONFIG_PCMCIA_XIRCOM) += xircom_cb.o obj-$(CONFIG_DM9102) += dmfe.o obj-$(CONFIG_WINBOND_840) += winbond-840.o diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index b13c6b040be3..e2f692351180 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -27,6 +27,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DRV_NAME "de2104x" #define DRV_VERSION "0.7" #define DRV_RELDATE "Mar 17, 2004" @@ -51,7 +53,7 @@ /* These identify the driver base version and may not be removed. */ static char version[] = -KERN_INFO DRV_NAME " PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; +"PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")"; MODULE_AUTHOR("Jeff Garzik "); MODULE_DESCRIPTION("Intel/Digital 21040/1 series PCI Ethernet driver"); @@ -73,8 +75,6 @@ static int rx_copybreak = 100; module_param (rx_copybreak, int, 0); MODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copied"); -#define PFX DRV_NAME ": " - #define DE_DEF_MSG_ENABLE (NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ NETIF_MSG_LINK | \ @@ -377,18 +377,16 @@ static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; static void de_rx_err_acct (struct de_private *de, unsigned rx_tail, u32 status, u32 len) { - if (netif_msg_rx_err (de)) - printk (KERN_DEBUG - "%s: rx err, slot %d status 0x%x len %d\n", - de->dev->name, rx_tail, status, len); + netif_dbg(de, rx_err, de->dev, + "rx err, slot %d status 0x%x len %d\n", + rx_tail, status, len); if ((status & 0x38000300) != 0x0300) { /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) { - if (netif_msg_rx_err(de)) - dev_warn(&de->dev->dev, - "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", - status); + netif_warn(de, rx_err, de->dev, + "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", + status); de->net_stats.rx_length_errors++; } } else if (status & RxError) { @@ -435,10 +433,9 @@ static void de_rx (struct de_private *de) copying_skb = (len <= rx_copybreak); - if (unlikely(netif_msg_rx_status(de))) - printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d copying? %d\n", - de->dev->name, rx_tail, status, len, - copying_skb); + netif_dbg(de, rx_status, de->dev, + "rx slot %d status 0x%x len %d copying? %d\n", + rx_tail, status, len, copying_skb); buflen = copying_skb ? (len + RX_OFFSET) : de->rx_buf_sz; copy_skb = dev_alloc_skb (buflen); @@ -491,7 +488,7 @@ static void de_rx (struct de_private *de) } if (!rx_work) - dev_warn(&de->dev->dev, "rx work limit reached\n"); + netdev_warn(de->dev, "rx work limit reached\n"); de->rx_tail = rx_tail; } @@ -506,10 +503,9 @@ static irqreturn_t de_interrupt (int irq, void *dev_instance) if ((!(status & (IntrOK|IntrErr))) || (status == 0xFFFF)) return IRQ_NONE; - if (netif_msg_intr(de)) - printk(KERN_DEBUG "%s: intr, status %08x mode %08x desc %u/%u/%u\n", - dev->name, status, dr32(MacMode), - de->rx_tail, de->tx_head, de->tx_tail); + netif_dbg(de, intr, dev, "intr, status %08x mode %08x desc %u/%u/%u\n", + status, dr32(MacMode), + de->rx_tail, de->tx_head, de->tx_tail); dw32(MacStatus, status); @@ -534,9 +530,9 @@ static irqreturn_t de_interrupt (int irq, void *dev_instance) pci_read_config_word(de->pdev, PCI_STATUS, &pci_status); pci_write_config_word(de->pdev, PCI_STATUS, pci_status); - dev_err(&de->dev->dev, - "PCI bus error, status=%08x, PCI status=%04x\n", - status, pci_status); + netdev_err(de->dev, + "PCI bus error, status=%08x, PCI status=%04x\n", + status, pci_status); } return IRQ_HANDLED; @@ -572,9 +568,9 @@ static void de_tx (struct de_private *de) if (status & LastFrag) { if (status & TxError) { - if (netif_msg_tx_err(de)) - printk(KERN_DEBUG "%s: tx err, status 0x%x\n", - de->dev->name, status); + netif_dbg(de, tx_err, de->dev, + "tx err, status 0x%x\n", + status); de->net_stats.tx_errors++; if (status & TxOWC) de->net_stats.tx_window_errors++; @@ -587,9 +583,8 @@ static void de_tx (struct de_private *de) } else { de->net_stats.tx_packets++; de->net_stats.tx_bytes += skb->len; - if (netif_msg_tx_done(de)) - printk(KERN_DEBUG "%s: tx done, slot %d\n", - de->dev->name, tx_tail); + netif_dbg(de, tx_done, de->dev, + "tx done, slot %d\n", tx_tail); } dev_kfree_skb_irq(skb); } @@ -646,9 +641,8 @@ static netdev_tx_t de_start_xmit (struct sk_buff *skb, wmb(); de->tx_head = NEXT_TX(entry); - if (netif_msg_tx_queued(de)) - printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n", - dev->name, entry, skb->len); + netif_dbg(de, tx_queued, dev, "tx queued, slot %d, skblen %d\n", + entry, skb->len); if (tx_free == 0) netif_stop_queue(dev); @@ -873,7 +867,7 @@ static void de_stop_rxtx (struct de_private *de) udelay(100); } - dev_warn(&de->dev->dev, "timeout expired stopping DMA\n"); + netdev_warn(de->dev, "timeout expired, stopping DMA\n"); } static inline void de_start_rxtx (struct de_private *de) @@ -907,9 +901,8 @@ static void de_link_up(struct de_private *de) { if (!netif_carrier_ok(de->dev)) { netif_carrier_on(de->dev); - if (netif_msg_link(de)) - dev_info(&de->dev->dev, "link up, media %s\n", - media_name[de->media_type]); + netif_info(de, link, de->dev, "link up, media %s\n", + media_name[de->media_type]); } } @@ -917,8 +910,7 @@ static void de_link_down(struct de_private *de) { if (netif_carrier_ok(de->dev)) { netif_carrier_off(de->dev); - if (netif_msg_link(de)) - dev_info(&de->dev->dev, "link down\n"); + netif_info(de, link, de->dev, "link down\n"); } } @@ -928,8 +920,7 @@ static void de_set_media (struct de_private *de) u32 macmode = dr32(MacMode); if (de_is_running(de)) - dev_warn(&de->dev->dev, - "chip is running while changing media!\n"); + netdev_warn(de->dev, "chip is running while changing media!\n"); if (de->de21040) dw32(CSR11, FULL_DUPLEX_MAGIC); @@ -948,18 +939,13 @@ static void de_set_media (struct de_private *de) else macmode &= ~FullDuplex; - if (netif_msg_link(de)) - dev_info(&de->dev->dev, "set link %s\n", media_name[media]); - if (netif_msg_hw(de)) { - dev_info(&de->dev->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n", - dr32(MacMode), dr32(SIAStatus), - dr32(CSR13), dr32(CSR14), dr32(CSR15)); - - dev_info(&de->dev->dev, - "set mode 0x%x, set sia 0x%x,0x%x,0x%x\n", - macmode, de->media[media].csr13, - de->media[media].csr14, de->media[media].csr15); - } + netif_info(de, link, de->dev, "set link %s\n", media_name[media]); + netif_info(de, hw, de->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n", + dr32(MacMode), dr32(SIAStatus), + dr32(CSR13), dr32(CSR14), dr32(CSR15)); + netif_info(de, hw, de->dev, "set mode 0x%x, set sia 0x%x,0x%x,0x%x\n", + macmode, de->media[media].csr13, + de->media[media].csr14, de->media[media].csr15); if (macmode != dr32(MacMode)) dw32(MacMode, macmode); } @@ -996,9 +982,8 @@ static void de21040_media_timer (unsigned long data) if (!netif_carrier_ok(dev)) de_link_up(de); else - if (netif_msg_timer(de)) - dev_info(&dev->dev, "%s link ok, status %x\n", - media_name[de->media_type], status); + netif_info(de, timer, dev, "%s link ok, status %x\n", + media_name[de->media_type], status); return; } @@ -1025,9 +1010,8 @@ static void de21040_media_timer (unsigned long data) de->media_timer.expires = jiffies + DE_TIMER_NO_LINK; add_timer(&de->media_timer); - if (netif_msg_timer(de)) - dev_info(&dev->dev, "no link, trying media %s, status %x\n", - media_name[de->media_type], status); + netif_info(de, timer, dev, "no link, trying media %s, status %x\n", + media_name[de->media_type], status); } static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media) @@ -1085,11 +1069,10 @@ static void de21041_media_timer (unsigned long data) if (!netif_carrier_ok(dev)) de_link_up(de); else - if (netif_msg_timer(de)) - dev_info(&dev->dev, - "%s link ok, mode %x status %x\n", - media_name[de->media_type], - dr32(MacMode), status); + netif_info(de, timer, dev, + "%s link ok, mode %x status %x\n", + media_name[de->media_type], + dr32(MacMode), status); return; } @@ -1163,9 +1146,8 @@ static void de21041_media_timer (unsigned long data) de->media_timer.expires = jiffies + DE_TIMER_NO_LINK; add_timer(&de->media_timer); - if (netif_msg_timer(de)) - dev_info(&dev->dev, "no link, trying media %s, status %x\n", - media_name[de->media_type], status); + netif_info(de, timer, dev, "no link, trying media %s, status %x\n", + media_name[de->media_type], status); } static void de_media_interrupt (struct de_private *de, u32 status) @@ -1401,14 +1383,13 @@ static int de_open (struct net_device *dev) struct de_private *de = netdev_priv(dev); int rc; - if (netif_msg_ifup(de)) - printk(KERN_DEBUG "%s: enabling interface\n", dev->name); + netif_dbg(de, ifup, dev, "enabling interface\n"); de->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); rc = de_alloc_rings(de); if (rc) { - dev_err(&dev->dev, "ring allocation failure, err=%d\n", rc); + netdev_err(dev, "ring allocation failure, err=%d\n", rc); return rc; } @@ -1416,14 +1397,14 @@ static int de_open (struct net_device *dev) rc = request_irq(dev->irq, de_interrupt, IRQF_SHARED, dev->name, dev); if (rc) { - dev_err(&dev->dev, "IRQ %d request failure, err=%d\n", - dev->irq, rc); + netdev_err(dev, "IRQ %d request failure, err=%d\n", + dev->irq, rc); goto err_out_free; } rc = de_init_hw(de); if (rc) { - dev_err(&dev->dev, "h/w init failure, err=%d\n", rc); + netdev_err(dev, "h/w init failure, err=%d\n", rc); goto err_out_free_irq; } @@ -1444,8 +1425,7 @@ static int de_close (struct net_device *dev) struct de_private *de = netdev_priv(dev); unsigned long flags; - if (netif_msg_ifdown(de)) - printk(KERN_DEBUG "%s: disabling interface\n", dev->name); + netif_dbg(de, ifdown, dev, "disabling interface\n"); del_timer_sync(&de->media_timer); @@ -1466,9 +1446,9 @@ static void de_tx_timeout (struct net_device *dev) { struct de_private *de = netdev_priv(dev); - printk(KERN_DEBUG "%s: NIC status %08x mode %08x sia %08x desc %u/%u/%u\n", - dev->name, dr32(MacStatus), dr32(MacMode), dr32(SIAStatus), - de->rx_tail, de->tx_head, de->tx_tail); + netdev_dbg(dev, "NIC status %08x mode %08x sia %08x desc %u/%u/%u\n", + dr32(MacStatus), dr32(MacMode), dr32(SIAStatus), + de->rx_tail, de->tx_head, de->tx_tail); del_timer_sync(&de->media_timer); @@ -1518,18 +1498,17 @@ static int __de_get_settings(struct de_private *de, struct ethtool_cmd *ecmd) switch (de->media_type) { case DE_MEDIA_AUI: ecmd->port = PORT_AUI; - ecmd->speed = 5; break; case DE_MEDIA_BNC: ecmd->port = PORT_BNC; - ecmd->speed = 2; break; default: ecmd->port = PORT_TP; - ecmd->speed = SPEED_10; break; } + ethtool_cmd_speed_set(ecmd, 10); + if (dr32(MacMode) & FullDuplex) ecmd->duplex = DUPLEX_FULL; else @@ -1550,9 +1529,7 @@ static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd) u32 new_media; unsigned int media_lock; - if (ecmd->speed != SPEED_10 && ecmd->speed != 5 && ecmd->speed != 2) - return -EINVAL; - if (de->de21040 && ecmd->speed == 2) + if (ethtool_cmd_speed(ecmd) != 10) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; @@ -1696,9 +1673,8 @@ static int de_nway_reset(struct net_device *dev) status = dr32(SIAStatus); dw32(SIAStatus, (status & ~NWayState) | NWayRestart); - if (netif_msg_link(de)) - dev_info(&de->dev->dev, "link nway restart, status %x,%x\n", - status, dr32(SIAStatus)); + netif_info(de, link, dev, "link nway restart, status %x,%x\n", + status, dr32(SIAStatus)); return 0; } @@ -1743,7 +1719,8 @@ static void __devinit de21040_get_mac_address (struct de_private *de) de->dev->dev_addr[i] = value; udelay(1); if (boguscnt <= 0) - pr_warning(PFX "timeout reading 21040 MAC address byte %u\n", i); + pr_warn("timeout reading 21040 MAC address byte %u\n", + i); } } @@ -1929,8 +1906,10 @@ static void __devinit de21041_get_srom_info (struct de_private *de) de->media[idx].csr14, de->media[idx].csr15); - } else if (netif_msg_probe(de)) - pr_cont("\n"); + } else { + if (netif_msg_probe(de)) + pr_cont("\n"); + } if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3])) break; @@ -1999,7 +1978,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, #ifndef MODULE if (board_idx == 0) - printk("%s", version); + pr_info("%s\n", version); #endif /* allocate a new ethernet device structure, and fill in defaults */ @@ -2041,7 +2020,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, /* check for invalid IRQ value */ if (pdev->irq < 2) { rc = -EIO; - pr_err(PFX "invalid irq (%d) for pci dev %s\n", + pr_err("invalid irq (%d) for pci dev %s\n", pdev->irq, pci_name(pdev)); goto err_out_res; } @@ -2052,12 +2031,12 @@ static int __devinit de_init_one (struct pci_dev *pdev, pciaddr = pci_resource_start(pdev, 1); if (!pciaddr) { rc = -EIO; - pr_err(PFX "no MMIO resource for pci dev %s\n", pci_name(pdev)); + pr_err("no MMIO resource for pci dev %s\n", pci_name(pdev)); goto err_out_res; } if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) { rc = -EIO; - pr_err(PFX "MMIO resource (%llx) too small on pci dev %s\n", + pr_err("MMIO resource (%llx) too small on pci dev %s\n", (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev)); goto err_out_res; @@ -2067,7 +2046,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, regs = ioremap_nocache(pciaddr, DE_REGS_SIZE); if (!regs) { rc = -EIO; - pr_err(PFX "Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n", + pr_err("Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n", (unsigned long long)pci_resource_len(pdev, 1), pciaddr, pci_name(pdev)); goto err_out_res; @@ -2080,7 +2059,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, /* make sure hardware is not running */ rc = de_reset_mac(de); if (rc) { - pr_err(PFX "Cannot reset MAC, pci dev %s\n", pci_name(pdev)); + pr_err("Cannot reset MAC, pci dev %s\n", pci_name(pdev)); goto err_out_iomap; } @@ -2100,11 +2079,11 @@ static int __devinit de_init_one (struct pci_dev *pdev, goto err_out_iomap; /* print info about board and interface just registered */ - dev_info(&dev->dev, "%s at 0x%lx, %pM, IRQ %d\n", - de->de21040 ? "21040" : "21041", - dev->base_addr, - dev->dev_addr, - dev->irq); + netdev_info(dev, "%s at 0x%lx, %pM, IRQ %d\n", + de->de21040 ? "21040" : "21041", + dev->base_addr, + dev->dev_addr, + dev->irq); pci_set_drvdata(pdev, dev); @@ -2192,7 +2171,7 @@ static int de_resume (struct pci_dev *pdev) if (!netif_running(dev)) goto out_attach; if ((retval = pci_enable_device(pdev))) { - dev_err(&dev->dev, "pci_enable_device failed in resume\n"); + netdev_err(dev, "pci_enable_device failed in resume\n"); goto out; } pci_set_master(pdev); @@ -2221,7 +2200,7 @@ static struct pci_driver de_driver = { static int __init de_init (void) { #ifdef MODULE - printk("%s", version); + pr_info("%s\n", version); #endif return pci_register_driver(&de_driver); } diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index efaa1d69b720..45144d5bd11b 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1995,7 +1995,7 @@ SetMulticastFilter(struct net_device *dev) static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; -static int __init de4x5_eisa_probe (struct device *gendev) +static int __devinit de4x5_eisa_probe (struct device *gendev) { struct eisa_device *edev; u_long iobase; @@ -2097,7 +2097,7 @@ static int __devexit de4x5_eisa_remove (struct device *device) return 0; } -static struct eisa_device_id de4x5_eisa_ids[] = { +static const struct eisa_device_id de4x5_eisa_ids[] __devinitconst = { { "DEC4250", 0 }, /* 0 is the board name index... */ { "" } }; diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index fb07f48910ae..468512731966 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -295,8 +295,7 @@ enum dmfe_CR6_bits { /* Global variable declaration ----------------------------- */ static int __devinitdata printed_version; static const char version[] __devinitconst = - KERN_INFO DRV_NAME ": Davicom DM9xxx net driver, version " - DRV_VERSION " (" DRV_RELDATE ")\n"; + "Davicom DM9xxx net driver, version " DRV_VERSION " (" DRV_RELDATE ")"; static int dmfe_debug; static unsigned char dmfe_media_mode = DMFE_AUTO; @@ -381,7 +380,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, DMFE_DBUG(0, "dmfe_init_one()", 0); if (!printed_version++) - printk(version); + pr_info("%s\n", version); /* * SPARC on-board DM910x chips should be handled by the main @@ -406,7 +405,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - pr_warning("32-bit PCI DMA not available\n"); + pr_warn("32-bit PCI DMA not available\n"); err = -ENODEV; goto err_out_free; } @@ -2203,7 +2202,7 @@ static int __init dmfe_init_module(void) { int rc; - printk(version); + pr_info("%s\n", version); printed_version = 1; DMFE_DBUG(0, "init_module() ", debug); diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index 296486bf0956..fa5eee925f25 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -222,8 +222,8 @@ void __devinit tulip_parse_eeprom(struct net_device *dev) /* there is no phy information, don't even try to build mtable */ if (count == 0) { if (tulip_debug > 0) - pr_warning("%s: no phy info, aborting mtable build\n", - dev->name); + pr_warn("%s: no phy info, aborting mtable build\n", + dev->name); return; } diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index 0013642903ee..5350d753e0ff 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -125,12 +125,12 @@ int tulip_poll(struct napi_struct *napi, int budget) #endif if (tulip_debug > 4) - printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n", - entry, tp->rx_ring[entry].status); + netdev_dbg(dev, " In tulip_rx(), entry %d %08x\n", + entry, tp->rx_ring[entry].status); do { if (ioread32(tp->base_addr + CSR5) == 0xffffffff) { - printk(KERN_DEBUG " In tulip_poll(), hardware disappeared\n"); + netdev_dbg(dev, " In tulip_poll(), hardware disappeared\n"); break; } /* Acknowledge current RX interrupt sources. */ @@ -145,9 +145,9 @@ int tulip_poll(struct napi_struct *napi, int budget) if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) break; - if (tulip_debug > 5) - printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n", - dev->name, entry, status); + if (tulip_debug > 5) + netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", + entry, status); if (++work_done >= budget) goto not_done; @@ -184,9 +184,9 @@ int tulip_poll(struct napi_struct *napi, int budget) } } else { /* There was a fatal error. */ - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n", - dev->name, status); + if (tulip_debug > 2) + netdev_dbg(dev, "Receive error, Rx status %08x\n", + status); dev->stats.rx_errors++; /* end of a packet.*/ if (pkt_len > 1518 || (status & RxDescRunt)) @@ -367,16 +367,16 @@ static int tulip_rx(struct net_device *dev) int received = 0; if (tulip_debug > 4) - printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n", - entry, tp->rx_ring[entry].status); + netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", + entry, tp->rx_ring[entry].status); /* If we own the next entry, it is a new packet. Send it up. */ while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { s32 status = le32_to_cpu(tp->rx_ring[entry].status); short pkt_len; if (tulip_debug > 5) - printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n", - dev->name, entry, status); + netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", + entry, status); if (--rx_work_limit < 0) break; @@ -404,16 +404,16 @@ static int tulip_rx(struct net_device *dev) /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) { if (tulip_debug > 1) - dev_warn(&dev->dev, - "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", - status); + netdev_warn(dev, + "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", + status); dev->stats.rx_length_errors++; } } else { /* There was a fatal error. */ if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n", - dev->name, status); + netdev_dbg(dev, "Receive error, Rx status %08x\n", + status); dev->stats.rx_errors++; /* end of a packet.*/ if (pkt_len > 1518 || (status & RxDescRunt)) @@ -573,8 +573,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) #endif /* CONFIG_TULIP_NAPI */ if (tulip_debug > 4) - printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x\n", - dev->name, csr5, ioread32(ioaddr + CSR5)); + netdev_dbg(dev, "interrupt csr5=%#8.8x new csr5=%#8.8x\n", + csr5, ioread32(ioaddr + CSR5)); if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { @@ -605,8 +605,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) /* There was an major error, log it. */ #ifndef final_version if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n", - dev->name, status); + netdev_dbg(dev, "Transmit error, Tx status %08x\n", + status); #endif dev->stats.tx_errors++; if (status & 0x4104) @@ -804,8 +804,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) } if (tulip_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#04x\n", - dev->name, ioread32(ioaddr + CSR5)); + netdev_dbg(dev, "exiting interrupt, csr5=%#04x\n", + ioread32(ioaddr + CSR5)); return IRQ_HANDLED; } diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c index a0c770ee4b64..4bd13922875d 100644 --- a/drivers/net/tulip/media.c +++ b/drivers/net/tulip/media.c @@ -182,8 +182,8 @@ void tulip_select_media(struct net_device *dev, int startup) switch (mleaf->type) { case 0: /* 21140 non-MII xcvr. */ if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver with control setting %02x\n", - dev->name, p[1]); + netdev_dbg(dev, "Using a 21140 non-MII transceiver with control setting %02x\n", + p[1]); dev->if_port = p[0]; if (startup) iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12); @@ -204,15 +204,14 @@ void tulip_select_media(struct net_device *dev, int startup) struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; unsigned char *rst = rleaf->leafdata; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Resetting the transceiver\n", - dev->name); + netdev_dbg(dev, "Resetting the transceiver\n"); for (i = 0; i < rst[0]; i++) iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); } if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control %04x/%04x\n", - dev->name, medianame[dev->if_port], - setup[0], setup[1]); + netdev_dbg(dev, "21143 non-MII %s transceiver control %04x/%04x\n", + medianame[dev->if_port], + setup[0], setup[1]); if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ csr13val = setup[0]; csr14val = setup[1]; @@ -239,8 +238,8 @@ void tulip_select_media(struct net_device *dev, int startup) if (startup) iowrite32(csr13val, ioaddr + CSR13); } if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Setting CSR15 to %08x/%08x\n", - dev->name, csr15dir, csr15val); + netdev_dbg(dev, "Setting CSR15 to %08x/%08x\n", + csr15dir, csr15val); if (mleaf->type == 4) new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); else @@ -316,9 +315,9 @@ void tulip_select_media(struct net_device *dev, int startup) if (tp->mii_advertise == 0) tp->mii_advertise = tp->advertising[phy_num]; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Advertising %04x on MII %d\n", - dev->name, tp->mii_advertise, - tp->phys[phy_num]); + netdev_dbg(dev, " Advertising %04x on MII %d\n", + tp->mii_advertise, + tp->phys[phy_num]); tulip_mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise); } break; @@ -335,8 +334,7 @@ void tulip_select_media(struct net_device *dev, int startup) struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; unsigned char *rst = rleaf->leafdata; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Resetting the transceiver\n", - dev->name); + netdev_dbg(dev, "Resetting the transceiver\n"); for (i = 0; i < rst[0]; i++) iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); } @@ -344,20 +342,21 @@ void tulip_select_media(struct net_device *dev, int startup) break; } default: - printk(KERN_DEBUG "%s: Invalid media table selection %d\n", - dev->name, mleaf->type); + netdev_dbg(dev, " Invalid media table selection %d\n", + mleaf->type); new_csr6 = 0x020E0000; } if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %02x\n", - dev->name, medianame[dev->if_port], + netdev_dbg(dev, "Using media type %s, CSR12 is %02x\n", + medianame[dev->if_port], ioread32(ioaddr + CSR12) & 0xff); } else if (tp->chip_id == LC82C168) { if (startup && ! tp->medialock) dev->if_port = tp->mii_cnt ? 11 : 0; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s\n", - dev->name, ioread32(ioaddr + 0xB8), medianame[dev->if_port]); + netdev_dbg(dev, "PNIC PHY status is %3.3x, media %s\n", + ioread32(ioaddr + 0xB8), + medianame[dev->if_port]); if (tp->mii_cnt) { new_csr6 = 0x810C0000; iowrite32(0x0001, ioaddr + CSR15); @@ -388,9 +387,9 @@ void tulip_select_media(struct net_device *dev, int startup) } else new_csr6 = 0x03860000; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No media description table, assuming %s transceiver, CSR12 %02x\n", - dev->name, medianame[dev->if_port], - ioread32(ioaddr + CSR12)); + netdev_dbg(dev, "No media description table, assuming %s transceiver, CSR12 %02x\n", + medianame[dev->if_port], + ioread32(ioaddr + CSR12)); } tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); @@ -504,8 +503,8 @@ void __devinit tulip_find_mii (struct net_device *dev, int board_idx) /* Fixup for DLink with miswired PHY. */ if (mii_advert != to_advert) { - printk(KERN_DEBUG "tulip%d: Advertising %04x on PHY %d, previously advertising %04x\n", - board_idx, to_advert, phy, mii_advert); + pr_debug("tulip%d: Advertising %04x on PHY %d, previously advertising %04x\n", + board_idx, to_advert, phy, mii_advert); tulip_mdio_write (dev, phy, 4, to_advert); } diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c index a63e64b6863d..aa4d9dad0395 100644 --- a/drivers/net/tulip/pnic.c +++ b/drivers/net/tulip/pnic.c @@ -40,8 +40,8 @@ void pnic_do_nway(struct net_device *dev) new_csr6 |= 0x00000200; } if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC autonegotiated status %08x, %s\n", - dev->name, phy_reg, medianame[dev->if_port]); + netdev_dbg(dev, "PNIC autonegotiated status %08x, %s\n", + phy_reg, medianame[dev->if_port]); if (tp->csr6 != new_csr6) { tp->csr6 = new_csr6; /* Restart Tx */ @@ -58,8 +58,8 @@ void pnic_lnk_change(struct net_device *dev, int csr5) int phy_reg = ioread32(ioaddr + 0xB8); if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC link changed state %08x, CSR5 %08x\n", - dev->name, phy_reg, csr5); + netdev_dbg(dev, "PNIC link changed state %08x, CSR5 %08x\n", + phy_reg, csr5); if (ioread32(ioaddr + CSR5) & TPLnkFail) { iowrite32((ioread32(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); /* If we use an external MII, then we mustn't use the @@ -114,8 +114,8 @@ void pnic_timer(unsigned long data) int csr5 = ioread32(ioaddr + CSR5); if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC timer PHY status %08x, %s CSR5 %08x\n", - dev->name, phy_reg, medianame[dev->if_port], csr5); + netdev_dbg(dev, "PNIC timer PHY status %08x, %s CSR5 %08x\n", + phy_reg, medianame[dev->if_port], csr5); if (phy_reg & 0x04000000) { /* Remote link fault */ iowrite32(0x0201F078, ioaddr + 0xB8); next_tick = 1*HZ; @@ -125,11 +125,11 @@ void pnic_timer(unsigned long data) next_tick = 60*HZ; } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */ if (tulip_debug > 1) - printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %04x, CSR5 %08x, PHY %03x\n", - dev->name, medianame[dev->if_port], - csr12, - ioread32(ioaddr + CSR5), - ioread32(ioaddr + 0xB8)); + netdev_dbg(dev, "%s link beat failed, CSR12 %04x, CSR5 %08x, PHY %03x\n", + medianame[dev->if_port], + csr12, + ioread32(ioaddr + CSR5), + ioread32(ioaddr + 0xB8)); next_tick = 3*HZ; if (tp->medialock) { } else if (tp->nwayset && (dev->if_port & 1)) { diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c index 4690c8e69207..93358ee4d830 100644 --- a/drivers/net/tulip/pnic2.c +++ b/drivers/net/tulip/pnic2.c @@ -125,8 +125,8 @@ void pnic2_start_nway(struct net_device *dev) csr14 |= 0x00001184; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Restarting PNIC2 autonegotiation, csr14=%08x\n", - dev->name, csr14); + netdev_dbg(dev, "Restarting PNIC2 autonegotiation, csr14=%08x\n", + csr14); /* tell pnic2_lnk_change we are doing an nway negotiation */ dev->if_port = 0; @@ -137,8 +137,7 @@ void pnic2_start_nway(struct net_device *dev) tp->csr6 = ioread32(ioaddr + CSR6); if (tulip_debug > 1) - printk(KERN_DEBUG "%s: On Entry to Nway, csr6=%08x\n", - dev->name, tp->csr6); + netdev_dbg(dev, "On Entry to Nway, csr6=%08x\n", tp->csr6); /* mask off any bits not to touch * comment at top of file explains mask value @@ -271,9 +270,10 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) iowrite32(1, ioaddr + CSR13); if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Setting CSR6 %08x/%x CSR12 %08x\n", - dev->name, tp->csr6, - ioread32(ioaddr + CSR6), ioread32(ioaddr + CSR12)); + netdev_dbg(dev, "Setting CSR6 %08x/%x CSR12 %08x\n", + tp->csr6, + ioread32(ioaddr + CSR6), + ioread32(ioaddr + CSR12)); /* now the following actually writes out the * new csr6 values @@ -324,7 +324,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) /* Link blew? Maybe restart NWay. */ if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Ugh! Link blew?\n", dev->name); + netdev_dbg(dev, "Ugh! Link blew?\n"); del_timer_sync(&tp->timer); pnic2_start_nway(dev); diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c index 36c2725ec886..2017faf2d0e6 100644 --- a/drivers/net/tulip/timer.c +++ b/drivers/net/tulip/timer.c @@ -28,11 +28,11 @@ void tulip_media_task(struct work_struct *work) unsigned long flags; if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Media selection tick, %s, status %08x mode %08x SIA %08x %08x %08x %08x\n", - dev->name, medianame[dev->if_port], - ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR6), - csr12, ioread32(ioaddr + CSR13), - ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15)); + netdev_dbg(dev, "Media selection tick, %s, status %08x mode %08x SIA %08x %08x %08x %08x\n", + medianame[dev->if_port], + ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR6), + csr12, ioread32(ioaddr + CSR13), + ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15)); } switch (tp->chip_id) { case DC21140: @@ -48,9 +48,9 @@ void tulip_media_task(struct work_struct *work) Assume this a generic MII or SYM transceiver. */ next_tick = 60*HZ; if (tulip_debug > 2) - printk(KERN_DEBUG "%s: network media monitor CSR6 %08x CSR12 0x%02x\n", - dev->name, - ioread32(ioaddr + CSR6), csr12 & 0xff); + netdev_dbg(dev, "network media monitor CSR6 %08x CSR12 0x%02x\n", + ioread32(ioaddr + CSR6), + csr12 & 0xff); break; } mleaf = &tp->mtable->mleaf[tp->cur_index]; @@ -62,8 +62,8 @@ void tulip_media_task(struct work_struct *work) s8 bitnum = p[offset]; if (p[offset+1] & 0x80) { if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Transceiver monitor tick CSR12=%#02x, no media sense\n", - dev->name, csr12); + netdev_dbg(dev, "Transceiver monitor tick CSR12=%#02x, no media sense\n", + csr12); if (mleaf->type == 4) { if (mleaf->media == 3 && (csr12 & 0x02)) goto select_next_media; @@ -71,17 +71,16 @@ void tulip_media_task(struct work_struct *work) break; } if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#02x bit %d is %d, expecting %d\n", - dev->name, csr12, (bitnum >> 1) & 7, - (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, - (bitnum >= 0)); + netdev_dbg(dev, "Transceiver monitor tick: CSR12=%#02x bit %d is %d, expecting %d\n", + csr12, (bitnum >> 1) & 7, + (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, + (bitnum >= 0)); /* Check that the specified bit has the proper value. */ if ((bitnum < 0) != ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Link beat detected for %s\n", - dev->name, - medianame[mleaf->media & MEDIA_MASK]); + netdev_dbg(dev, "Link beat detected for %s\n", + medianame[mleaf->media & MEDIA_MASK]); if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ goto actually_mii; netif_carrier_on(dev); @@ -99,10 +98,9 @@ void tulip_media_task(struct work_struct *work) if (tulip_media_cap[dev->if_port] & MediaIsFD) goto select_next_media; /* Skip FD entries. */ if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No link beat on media %s, trying transceiver type %s\n", - dev->name, - medianame[mleaf->media & MEDIA_MASK], - medianame[tp->mtable->mleaf[tp->cur_index].media]); + netdev_dbg(dev, "No link beat on media %s, trying transceiver type %s\n", + medianame[mleaf->media & MEDIA_MASK], + medianame[tp->mtable->mleaf[tp->cur_index].media]); tulip_select_media(dev, 0); /* Restart the transmit process. */ tulip_restart_rxtx(tp); @@ -166,10 +164,9 @@ void comet_timer(unsigned long data) int next_tick = 60*HZ; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Comet link status %04x partner capability %04x\n", - dev->name, - tulip_mdio_read(dev, tp->phys[0], 1), - tulip_mdio_read(dev, tp->phys[0], 5)); + netdev_dbg(dev, "Comet link status %04x partner capability %04x\n", + tulip_mdio_read(dev, tp->phys[0], 1), + tulip_mdio_read(dev, tp->phys[0], 5)); /* mod_timer synchronizes us with potential add_timer calls * from interrupts. */ diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index ed66a16711dc..9db528967da9 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -547,11 +547,9 @@ static inline void tulip_stop_rxtx(struct tulip_private *tp) udelay(10); if (!i) - printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed" - " (CSR5 0x%x CSR6 0x%x)\n", - pci_name(tp->pdev), - ioread32(ioaddr + CSR5), - ioread32(ioaddr + CSR6)); + netdev_dbg(tp->dev, "tulip_stop_rxtx() failed (CSR5 0x%x CSR6 0x%x)\n", + ioread32(ioaddr + CSR5), + ioread32(ioaddr + CSR6)); } } diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 5c01e260f1ba..82f87647207e 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -12,6 +12,7 @@ Please submit bugs to http://bugzilla.kernel.org/ . */ +#define pr_fmt(fmt) "tulip: " fmt #define DRV_NAME "tulip" #ifdef CONFIG_TULIP_NAPI @@ -119,8 +120,6 @@ module_param(csr0, int, 0); module_param_array(options, int, NULL, 0); module_param_array(full_duplex, int, NULL, 0); -#define PFX DRV_NAME ": " - #ifdef TULIP_DEBUG int tulip_debug = TULIP_DEBUG; #else @@ -331,8 +330,7 @@ static void tulip_up(struct net_device *dev) udelay(100); if (tulip_debug > 1) - printk(KERN_DEBUG "%s: tulip_up(), irq==%d\n", - dev->name, dev->irq); + netdev_dbg(dev, "tulip_up(), irq==%d\n", dev->irq); iowrite32(tp->rx_ring_dma, ioaddr + CSR3); iowrite32(tp->tx_ring_dma, ioaddr + CSR4); @@ -499,10 +497,10 @@ static void tulip_up(struct net_device *dev) iowrite32(0, ioaddr + CSR2); /* Rx poll demand */ if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %08x, CSR5 %08x CSR6 %08x\n", - dev->name, ioread32(ioaddr + CSR0), - ioread32(ioaddr + CSR5), - ioread32(ioaddr + CSR6)); + netdev_dbg(dev, "Done tulip_up(), CSR0 %08x, CSR5 %08x CSR6 %08x\n", + ioread32(ioaddr + CSR0), + ioread32(ioaddr + CSR5), + ioread32(ioaddr + CSR6)); } /* Set the timer to switch to check for link beat and perhaps switch @@ -843,8 +841,7 @@ static int tulip_close (struct net_device *dev) tulip_down (dev); if (tulip_debug > 1) - dev_printk(KERN_DEBUG, &dev->dev, - "Shutting down ethercard, status was %02x\n", + netdev_dbg(dev, "Shutting down ethercard, status was %02x\n", ioread32 (ioaddr + CSR5)); free_irq (dev->irq, dev); @@ -1207,7 +1204,7 @@ static void __devinit tulip_mwi_config (struct pci_dev *pdev, u32 csr0; if (tulip_debug > 3) - printk(KERN_DEBUG "%s: tulip_mwi_config()\n", pci_name(pdev)); + netdev_dbg(dev, "tulip_mwi_config()\n"); tp->csr0 = csr0 = 0; @@ -1269,8 +1266,8 @@ static void __devinit tulip_mwi_config (struct pci_dev *pdev, out: tp->csr0 = csr0; if (tulip_debug > 2) - printk(KERN_DEBUG "%s: MWI config cacheline=%d, csr0=%08x\n", - pci_name(pdev), cache, csr0); + netdev_dbg(dev, "MWI config cacheline=%d, csr0=%08x\n", + cache, csr0); } #endif @@ -1340,13 +1337,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, */ if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) { - pr_err(PFX "skipping LMC card\n"); + pr_err("skipping LMC card\n"); return -ENODEV; } else if (pdev->subsystem_vendor == PCI_VENDOR_ID_SBE && (pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_T3E3 || pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_2T3E3_P0 || pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_2T3E3_P1)) { - pr_err(PFX "skipping SBE T3E3 port\n"); + pr_err("skipping SBE T3E3 port\n"); return -ENODEV; } @@ -1362,13 +1359,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, if (pdev->vendor == 0x1282 && pdev->device == 0x9100 && pdev->revision < 0x30) { - pr_info(PFX "skipping early DM9100 with Crc bug (use dmfe)\n"); + pr_info("skipping early DM9100 with Crc bug (use dmfe)\n"); return -ENODEV; } dp = pci_device_to_OF_node(pdev); if (!(dp && of_get_property(dp, "local-mac-address", NULL))) { - pr_info(PFX "skipping DM910x expansion card (use dmfe)\n"); + pr_info("skipping DM910x expansion card (use dmfe)\n"); return -ENODEV; } } @@ -1415,16 +1412,14 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, i = pci_enable_device(pdev); if (i) { - pr_err(PFX "Cannot enable tulip board #%d, aborting\n", - board_idx); + pr_err("Cannot enable tulip board #%d, aborting\n", board_idx); return i; } /* The chip will fail to enter a low-power state later unless * first explicitly commanded into D0 */ if (pci_set_power_state(pdev, PCI_D0)) { - printk (KERN_NOTICE PFX - "Failed to set power state to D0\n"); + pr_notice("Failed to set power state to D0\n"); } irq = pdev->irq; @@ -1432,13 +1427,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, /* alloc_etherdev ensures aligned and zeroed private structures */ dev = alloc_etherdev (sizeof (*tp)); if (!dev) { - pr_err(PFX "ether device alloc failed, aborting\n"); + pr_err("ether device alloc failed, aborting\n"); return -ENOMEM; } SET_NETDEV_DEV(dev, &pdev->dev); if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) { - pr_err(PFX "%s: I/O region (0x%llx@0x%llx) too small, aborting\n", + pr_err("%s: I/O region (0x%llx@0x%llx) too small, aborting\n", pci_name(pdev), (unsigned long long)pci_resource_len (pdev, 0), (unsigned long long)pci_resource_start (pdev, 0)); @@ -1483,7 +1478,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, if (sig == 0x09811317) { tp->flags |= COMET_PM; tp->wolinfo.supported = WAKE_PHY | WAKE_MAGIC; - printk(KERN_INFO "tulip_init_one: Enabled WOL support for AN983B\n"); + pr_info("%s: Enabled WOL support for AN983B\n", + __func__); } } tp->pdev = pdev; @@ -1879,7 +1875,7 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state) tulip_set_wolopts(pdev, tp->wolinfo.wolopts); rc = pci_enable_wake(pdev, pstate, tp->wolinfo.wolopts); if (rc) - printk("tulip: pci_enable_wake failed (%d)\n", rc); + pr_err("pci_enable_wake failed (%d)\n", rc); } pci_set_power_state(pdev, pstate); @@ -1905,12 +1901,12 @@ static int tulip_resume(struct pci_dev *pdev) return 0; if ((retval = pci_enable_device(pdev))) { - pr_err(PFX "pci_enable_device failed in resume\n"); + pr_err("pci_enable_device failed in resume\n"); return retval; } if ((retval = request_irq(dev->irq, tulip_interrupt, IRQF_SHARED, dev->name, dev))) { - pr_err(PFX "request_irq failed in resume\n"); + pr_err("request_irq failed in resume\n"); return retval; } diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 74217dbf0143..9e63f406f72d 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -209,8 +209,7 @@ enum uli526x_CR6_bits { /* Global variable declaration ----------------------------- */ static int __devinitdata printed_version; static const char version[] __devinitconst = - KERN_INFO DRV_NAME ": ULi M5261/M5263 net driver, version " - DRV_VERSION " (" DRV_RELDATE ")\n"; + "ULi M5261/M5263 net driver, version " DRV_VERSION " (" DRV_RELDATE ")"; static int uli526x_debug; static unsigned char uli526x_media_mode = ULI526X_AUTO; @@ -283,7 +282,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, ULI526X_DBUG(0, "uli526x_init_one()", 0); if (!printed_version++) - printk(version); + pr_info("%s\n", version); /* Init network device */ dev = alloc_etherdev(sizeof(*db)); @@ -292,7 +291,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - pr_warning("32-bit PCI DMA not available\n"); + pr_warn("32-bit PCI DMA not available\n"); err = -ENODEV; goto err_out_free; } @@ -390,9 +389,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, if (err) goto err_out_res; - dev_info(&dev->dev, "ULi M%04lx at pci%s, %pM, irq %d\n", - ent->driver_data >> 16, pci_name(pdev), - dev->dev_addr, dev->irq); + netdev_info(dev, "ULi M%04lx at pci%s, %pM, irq %d\n", + ent->driver_data >> 16, pci_name(pdev), + dev->dev_addr, dev->irq); pci_set_master(pdev); @@ -524,7 +523,7 @@ static void uli526x_init(struct net_device *dev) } } if(phy_tmp == 32) - pr_warning("Can not find the phy address!!!"); + pr_warn("Can not find the phy address!!!\n"); /* Parser SROM and media mode */ db->media_mode = uli526x_media_mode; @@ -590,7 +589,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb, /* Too large packet check */ if (skb->len > MAX_PACKET_SIZE) { - pr_err("big packet = %d\n", (u16)skb->len); + netdev_err(dev, "big packet = %d\n", (u16)skb->len); dev_kfree_skb(skb); return NETDEV_TX_OK; } @@ -600,7 +599,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb, /* No Tx resource check, it never happen nromally */ if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) { spin_unlock_irqrestore(&db->lock, flags); - pr_err("No Tx resource %ld\n", db->tx_packet_cnt); + netdev_err(dev, "No Tx resource %ld\n", db->tx_packet_cnt); return NETDEV_TX_BUSY; } @@ -667,15 +666,6 @@ static int uli526x_stop(struct net_device *dev) /* free allocated rx buffer */ uli526x_free_rxbuffer(db); -#if 0 - /* show statistic counter */ - printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", - db->tx_fifo_underrun, db->tx_excessive_collision, - db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier, - db->tx_jabber_timeout, db->reset_count, db->reset_cr8, - db->reset_fatal, db->reset_TXtimeout); -#endif - return 0; } @@ -755,7 +745,6 @@ static void uli526x_free_tx_pkt(struct net_device *dev, txptr = db->tx_remove_ptr; while(db->tx_packet_cnt) { tdes0 = le32_to_cpu(txptr->tdes0); - /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ if (tdes0 & 0x80000000) break; @@ -765,7 +754,6 @@ static void uli526x_free_tx_pkt(struct net_device *dev, /* Transmit statistic counter */ if ( tdes0 != 0x7fffffff ) { - /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ dev->stats.collisions += (tdes0 >> 3) & 0xf; dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff; if (tdes0 & TDES0_ERR_MASK) { @@ -838,7 +826,6 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info /* error summary bit check */ if (rdes0 & 0x8000) { /* This is a error packet */ - //printk(DRV_NAME ": rdes0: %lx\n", rdes0); dev->stats.rx_errors++; if (rdes0 & 1) dev->stats.rx_fifo_errors++; @@ -945,12 +932,12 @@ ULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd) ecmd->transceiver = XCVR_EXTERNAL; - ecmd->speed = 10; + ethtool_cmd_speed_set(ecmd, SPEED_10); ecmd->duplex = DUPLEX_HALF; if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD) { - ecmd->speed = 100; + ethtool_cmd_speed_set(ecmd, SPEED_100); } if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD) { @@ -958,7 +945,7 @@ ULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd) } if(db->link_failed) { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } @@ -1024,7 +1011,6 @@ static void uli526x_timer(unsigned long data) struct net_device *dev = (struct net_device *) data; struct uli526x_board_info *db = netdev_priv(dev); unsigned long flags; - u8 TmpSpeed=10; //ULI526X_DBUG(0, "uli526x_timer()", 0); spin_lock_irqsave(&db->lock, flags); @@ -1047,8 +1033,7 @@ static void uli526x_timer(unsigned long data) if ( time_after(jiffies, dev_trans_start(dev) + ULI526X_TX_TIMEOUT) ) { db->reset_TXtimeout++; db->wait_reset = 1; - printk( "%s: Tx timeout - resetting\n", - dev->name); + netdev_err(dev, " Tx timeout - resetting\n"); } } @@ -1070,7 +1055,7 @@ static void uli526x_timer(unsigned long data) /* Link Failed */ ULI526X_DBUG(0, "Link Failed", tmp_cr12); netif_carrier_off(dev); - pr_info("%s NIC Link is Down\n",dev->name); + netdev_info(dev, "NIC Link is Down\n"); db->link_failed = 1; /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */ @@ -1096,18 +1081,13 @@ static void uli526x_timer(unsigned long data) if(db->link_failed==0) { - if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD) - { - TmpSpeed = 100; - } - if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD) - { - pr_info("%s NIC Link is Up %d Mbps Full duplex\n",dev->name,TmpSpeed); - } - else - { - pr_info("%s NIC Link is Up %d Mbps Half duplex\n",dev->name,TmpSpeed); - } + netdev_info(dev, "NIC Link is Up %d Mbps %s duplex\n", + (db->op_mode == ULI526X_100MHF || + db->op_mode == ULI526X_100MFD) + ? 100 : 10, + (db->op_mode == ULI526X_10MFD || + db->op_mode == ULI526X_100MFD) + ? "Full" : "Half"); netif_carrier_on(dev); } /* SHOW_MEDIA_TYPE(db->op_mode); */ @@ -1116,7 +1096,7 @@ static void uli526x_timer(unsigned long data) { if(db->init==1) { - pr_info("%s NIC Link is Down\n",dev->name); + netdev_info(dev, "NIC Link is Down\n"); netif_carrier_off(dev); } } @@ -1242,7 +1222,7 @@ static int uli526x_resume(struct pci_dev *pdev) err = pci_set_power_state(pdev, PCI_D0); if (err) { - dev_warn(&dev->dev, "Could not put device into D0\n"); + netdev_warn(dev, "Could not put device into D0\n"); return err; } @@ -1443,7 +1423,7 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt) update_cr6(db->cr6_data, dev->base_addr); dev->trans_start = jiffies; } else - pr_err("No Tx resource - Send_filter_frame!\n"); + netdev_err(dev, "No Tx resource - Send_filter_frame!\n"); } @@ -1540,7 +1520,6 @@ static u8 uli526x_sense_speed(struct uli526x_board_info * db) else phy_mode = 0x1000; - /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */ switch (phy_mode) { case 0x1000: db->op_mode = ULI526X_10MHF; break; case 0x2000: db->op_mode = ULI526X_10MFD; break; @@ -1829,7 +1808,7 @@ MODULE_PARM_DESC(mode, "ULi M5261/M5263: Bit 0: 10/100Mbps, bit 2: duplex, bit 8 static int __init uli526x_init_module(void) { - printk(version); + pr_info("%s\n", version); printed_version = 1; ULI526X_DBUG(0, "init_module() ", debug); diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index f0b231035dee..862eadf07191 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -44,6 +44,8 @@ * Wake-On-LAN */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DRV_NAME "winbond-840" #define DRV_VERSION "1.01-e" #define DRV_RELDATE "Sep-11-2006" @@ -139,7 +141,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* These identify the driver base version and may not be removed. */ static const char version[] __initconst = - KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) " + "v" DRV_VERSION " (2.4 port) " DRV_RELDATE " Donald Becker \n" " http://www.scyld.com/network/drivers.html\n"; @@ -375,8 +377,8 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, irq = pdev->irq; if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - pr_warning("Winbond-840: Device %s disabled due to DMA limitations\n", - pci_name(pdev)); + pr_warn("Device %s disabled due to DMA limitations\n", + pci_name(pdev)); return -EIO; } dev = alloc_etherdev(sizeof(*np)); @@ -643,8 +645,7 @@ static int netdev_open(struct net_device *dev) goto out_err; if (debug > 1) - printk(KERN_DEBUG "%s: w89c840_open() irq %d\n", - dev->name, dev->irq); + netdev_dbg(dev, "w89c840_open() irq %d\n", dev->irq); if((i=alloc_ringdesc(dev))) goto out_err; @@ -656,7 +657,7 @@ static int netdev_open(struct net_device *dev) netif_start_queue(dev); if (debug > 2) - printk(KERN_DEBUG "%s: Done netdev_open()\n", dev->name); + netdev_dbg(dev, "Done netdev_open()\n"); /* Set the timer to check for link beat. */ init_timer(&np->timer); @@ -785,9 +786,9 @@ static void netdev_timer(unsigned long data) void __iomem *ioaddr = np->base_addr; if (debug > 2) - printk(KERN_DEBUG "%s: Media selection timer tick, status %08x config %08x\n", - dev->name, ioread32(ioaddr + IntrStatus), - ioread32(ioaddr + NetworkConfig)); + netdev_dbg(dev, "Media selection timer tick, status %08x config %08x\n", + ioread32(ioaddr + IntrStatus), + ioread32(ioaddr + NetworkConfig)); spin_lock_irq(&np->lock); update_csr6(dev, update_link(dev)); spin_unlock_irq(&np->lock); @@ -1054,8 +1055,8 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&np->lock); if (debug > 4) { - printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d\n", - dev->name, np->cur_tx, entry); + netdev_dbg(dev, "Transmit frame #%d queued in slot %d\n", + np->cur_tx, entry); } return NETDEV_TX_OK; } @@ -1072,8 +1073,8 @@ static void netdev_tx_done(struct net_device *dev) if (tx_status & 0x8000) { /* There was an error, log it. */ #ifndef final_version if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n", - dev->name, tx_status); + netdev_dbg(dev, "Transmit error, Tx status %08x\n", + tx_status); #endif np->stats.tx_errors++; if (tx_status & 0x0104) np->stats.tx_aborted_errors++; @@ -1085,8 +1086,8 @@ static void netdev_tx_done(struct net_device *dev) } else { #ifndef final_version if (debug > 3) - printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %08x\n", - dev->name, entry, tx_status); + netdev_dbg(dev, "Transmit slot %d ok, Tx status %08x\n", + entry, tx_status); #endif np->stats.tx_bytes += np->tx_skbuff[entry]->len; np->stats.collisions += (tx_status >> 3) & 15; @@ -1129,8 +1130,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) iowrite32(intr_status & 0x001ffff, ioaddr + IntrStatus); if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status %04x\n", - dev->name, intr_status); + netdev_dbg(dev, "Interrupt, status %04x\n", intr_status); if ((intr_status & (NormalIntr|AbnormalIntr)) == 0) break; @@ -1171,8 +1171,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) } while (1); if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x\n", - dev->name, ioread32(ioaddr + IntrStatus)); + netdev_dbg(dev, "exiting interrupt, status=%#4.4x\n", + ioread32(ioaddr + IntrStatus)); return IRQ_RETVAL(handled); } @@ -1185,8 +1185,8 @@ static int netdev_rx(struct net_device *dev) int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx; if (debug > 4) { - printk(KERN_DEBUG " In netdev_rx(), entry %d status %04x\n", - entry, np->rx_ring[entry].status); + netdev_dbg(dev, " In netdev_rx(), entry %d status %04x\n", + entry, np->rx_ring[entry].status); } /* If EOP is set on the next entry, it's a new packet. Send it up. */ @@ -1195,8 +1195,8 @@ static int netdev_rx(struct net_device *dev) s32 status = desc->status; if (debug > 4) - printk(KERN_DEBUG " netdev_rx() status was %08x\n", - status); + netdev_dbg(dev, " netdev_rx() status was %08x\n", + status); if (status < 0) break; if ((status & 0x38008300) != 0x0300) { @@ -1211,8 +1211,8 @@ static int netdev_rx(struct net_device *dev) } else if (status & 0x8000) { /* There was a fatal error. */ if (debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n", - dev->name, status); + netdev_dbg(dev, "Receive error, Rx status %08x\n", + status); np->stats.rx_errors++; /* end of a packet.*/ if (status & 0x0890) np->stats.rx_length_errors++; if (status & 0x004C) np->stats.rx_frame_errors++; @@ -1225,8 +1225,8 @@ static int netdev_rx(struct net_device *dev) #ifndef final_version if (debug > 4) - printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d status %x\n", - pkt_len, status); + netdev_dbg(dev, " netdev_rx() normal Rx pkt length %d status %x\n", + pkt_len, status); #endif /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ @@ -1251,10 +1251,10 @@ static int netdev_rx(struct net_device *dev) #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ if (debug > 5) - printk(KERN_DEBUG " Rx data %pM %pM %02x%02x %pI4\n", - &skb->data[0], &skb->data[6], - skb->data[12], skb->data[13], - &skb->data[14]); + netdev_dbg(dev, " Rx data %pM %pM %02x%02x %pI4\n", + &skb->data[0], &skb->data[6], + skb->data[12], skb->data[13], + &skb->data[14]); #endif skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); @@ -1292,8 +1292,7 @@ static void netdev_error(struct net_device *dev, int intr_status) void __iomem *ioaddr = np->base_addr; if (debug > 2) - printk(KERN_DEBUG "%s: Abnormal event, %08x\n", - dev->name, intr_status); + netdev_dbg(dev, "Abnormal event, %08x\n", intr_status); if (intr_status == 0xffffffff) return; spin_lock(&np->lock); @@ -1313,8 +1312,7 @@ static void netdev_error(struct net_device *dev, int intr_status) new = 127; /* load full packet before starting */ new = (np->csr6 & ~(0x7F << 14)) | (new<<14); #endif - printk(KERN_DEBUG "%s: Tx underflow, new csr6 %08x\n", - dev->name, new); + netdev_dbg(dev, "Tx underflow, new csr6 %08x\n", new); update_csr6(dev, new); } if (intr_status & RxDied) { /* Missed a Rx frame. */ @@ -1487,13 +1485,12 @@ static int netdev_close(struct net_device *dev) netif_stop_queue(dev); if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %08x Config %08x\n", - dev->name, ioread32(ioaddr + IntrStatus), - ioread32(ioaddr + NetworkConfig)); - printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d\n", - dev->name, - np->cur_tx, np->dirty_tx, - np->cur_rx, np->dirty_rx); + netdev_dbg(dev, "Shutting down ethercard, status was %08x Config %08x\n", + ioread32(ioaddr + IntrStatus), + ioread32(ioaddr + NetworkConfig)); + netdev_dbg(dev, "Queue pointers were Tx %d / %d, Rx %d / %d\n", + np->cur_tx, np->dirty_tx, + np->cur_rx, np->dirty_rx); } /* Stop the chip's Tx and Rx processes. */ diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 5a73752be2ca..988b8eb24d37 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -37,15 +37,6 @@ #include #endif -#ifdef DEBUG -#define enter(x) printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__) -#define leave(x) printk("Leave: %s, %s line %i\n",x,__FILE__,__LINE__) -#else -#define enter(x) do {} while (0) -#define leave(x) do {} while (0) -#endif - - MODULE_DESCRIPTION("Xircom Cardbus ethernet driver"); MODULE_AUTHOR("Arjan van de Ven "); MODULE_LICENSE("GPL"); @@ -161,7 +152,7 @@ static struct pci_driver xircom_ops = { }; -#ifdef DEBUG +#if defined DEBUG && DEBUG > 1 static void print_binary(unsigned int number) { int i,i2; @@ -176,7 +167,7 @@ static void print_binary(unsigned int number) if ((i&3)==0) buffer[i2++]=' '; } - printk("%s\n",buffer); + pr_debug("%s\n",buffer); } #endif @@ -205,7 +196,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ struct xircom_private *private; unsigned long flags; unsigned short tmp16; - enter("xircom_probe"); /* First do the PCI initialisation */ @@ -272,8 +262,8 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ goto reg_fail; } - dev_info(&dev->dev, "Xircom cardbus revision %i at irq %i\n", - pdev->revision, pdev->irq); + netdev_info(dev, "Xircom cardbus revision %i at irq %i\n", + pdev->revision, pdev->irq); /* start the transmitter to get a heartbeat */ /* TODO: send 2 dummy packets here */ transceiver_voodoo(private); @@ -285,7 +275,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ trigger_receive(private); - leave("xircom_probe"); return 0; reg_fail: @@ -310,7 +299,6 @@ static void __devexit xircom_remove(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *card = netdev_priv(dev); - enter("xircom_remove"); pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle); pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle); @@ -318,7 +306,6 @@ static void __devexit xircom_remove(struct pci_dev *pdev) unregister_netdev(dev); free_netdev(dev); pci_set_drvdata(pdev, NULL); - leave("xircom_remove"); } static irqreturn_t xircom_interrupt(int irq, void *dev_instance) @@ -328,17 +315,15 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance) unsigned int status; int i; - enter("xircom_interrupt\n"); - spin_lock(&card->lock); status = inl(card->io_port+CSR5); -#ifdef DEBUG +#if defined DEBUG && DEBUG > 1 print_binary(status); - printk("tx status 0x%08x 0x%08x\n", - card->tx_buffer[0], card->tx_buffer[4]); - printk("rx status 0x%08x 0x%08x\n", - card->rx_buffer[0], card->rx_buffer[4]); + pr_debug("tx status 0x%08x 0x%08x\n", + card->tx_buffer[0], card->tx_buffer[4]); + pr_debug("rx status 0x%08x 0x%08x\n", + card->rx_buffer[0], card->rx_buffer[4]); #endif /* Handle shared irq and hotplug */ if (status == 0 || status == 0xffffffff) { @@ -348,9 +333,9 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance) if (link_status_changed(card)) { int newlink; - printk(KERN_DEBUG "xircom_cb: Link status has changed\n"); + netdev_dbg(dev, "Link status has changed\n"); newlink = link_status(card); - dev_info(&dev->dev, "Link is %i mbit\n", newlink); + netdev_info(dev, "Link is %d mbit\n", newlink); if (newlink) netif_carrier_on(dev); else @@ -369,9 +354,7 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance) for (i=0;ilock); - leave("xircom_interrupt"); return IRQ_HANDLED; } @@ -382,7 +365,6 @@ static netdev_tx_t xircom_start_xmit(struct sk_buff *skb, unsigned long flags; int nextdescriptor; int desc; - enter("xircom_start_xmit"); card = netdev_priv(dev); spin_lock_irqsave(&card->lock,flags); @@ -424,13 +406,10 @@ static netdev_tx_t xircom_start_xmit(struct sk_buff *skb, netif_stop_queue(dev); } card->transmit_used = nextdescriptor; - leave("xircom-start_xmit - sent"); spin_unlock_irqrestore(&card->lock,flags); return NETDEV_TX_OK; } - - /* Uh oh... no free descriptor... drop the packet */ netif_stop_queue(dev); spin_unlock_irqrestore(&card->lock,flags); @@ -446,18 +425,16 @@ static int xircom_open(struct net_device *dev) { struct xircom_private *xp = netdev_priv(dev); int retval; - enter("xircom_open"); - pr_info("xircom cardbus adaptor found, registering as %s, using irq %i\n", - dev->name, dev->irq); + + netdev_info(dev, "xircom cardbus adaptor found, using irq %i\n", + dev->irq); retval = request_irq(dev->irq, xircom_interrupt, IRQF_SHARED, dev->name, dev); - if (retval) { - leave("xircom_open - No IRQ"); + if (retval) return retval; - } xircom_up(xp); xp->open = 1; - leave("xircom_open"); + return 0; } @@ -466,7 +443,6 @@ static int xircom_close(struct net_device *dev) struct xircom_private *card; unsigned long flags; - enter("xircom_close"); card = netdev_priv(dev); netif_stop_queue(dev); /* we don't want new packets */ @@ -486,8 +462,6 @@ static int xircom_close(struct net_device *dev) card->open = 0; free_irq(dev->irq,dev); - leave("xircom_close"); - return 0; } @@ -507,8 +481,6 @@ static void initialize_card(struct xircom_private *card) { unsigned int val; unsigned long flags; - enter("initialize_card"); - spin_lock_irqsave(&card->lock, flags); @@ -534,8 +506,6 @@ static void initialize_card(struct xircom_private *card) deactivate_transmitter(card); spin_unlock_irqrestore(&card->lock, flags); - - leave("initialize_card"); } /* @@ -547,12 +517,9 @@ ignored; I chose zero. static void trigger_transmit(struct xircom_private *card) { unsigned int val; - enter("trigger_transmit"); val = 0; outl(val, card->io_port + CSR1); - - leave("trigger_transmit"); } /* @@ -565,12 +532,9 @@ ignored; I chose zero. static void trigger_receive(struct xircom_private *card) { unsigned int val; - enter("trigger_receive"); val = 0; outl(val, card->io_port + CSR2); - - leave("trigger_receive"); } /* @@ -581,8 +545,6 @@ static void setup_descriptors(struct xircom_private *card) { u32 address; int i; - enter("setup_descriptors"); - BUG_ON(card->rx_buffer == NULL); BUG_ON(card->tx_buffer == NULL); @@ -636,8 +598,6 @@ static void setup_descriptors(struct xircom_private *card) /* wite the transmit descriptor ring to the card */ address = card->tx_dma_handle; outl(address, card->io_port + CSR4); /* xmit descr list address */ - - leave("setup_descriptors"); } /* @@ -647,13 +607,10 @@ valid by setting the address in the card to 0x00. static void remove_descriptors(struct xircom_private *card) { unsigned int val; - enter("remove_descriptors"); val = 0; outl(val, card->io_port + CSR3); /* Receive descriptor address */ outl(val, card->io_port + CSR4); /* Send descriptor address */ - - leave("remove_descriptors"); } /* @@ -665,21 +622,17 @@ This function also clears the status-bit. static int link_status_changed(struct xircom_private *card) { unsigned int val; - enter("link_status_changed"); val = inl(card->io_port + CSR5); /* Status register */ - if ((val & (1 << 27)) == 0) { /* no change */ - leave("link_status_changed - nochange"); + if ((val & (1 << 27)) == 0) /* no change */ return 0; - } /* clear the event by writing a 1 to the bit in the status register. */ val = (1 << 27); outl(val, card->io_port + CSR5); - leave("link_status_changed - changed"); return 1; } @@ -691,16 +644,12 @@ in a non-stopped state. static int transmit_active(struct xircom_private *card) { unsigned int val; - enter("transmit_active"); val = inl(card->io_port + CSR5); /* Status register */ - if ((val & (7 << 20)) == 0) { /* transmitter disabled */ - leave("transmit_active - inactive"); + if ((val & (7 << 20)) == 0) /* transmitter disabled */ return 0; - } - leave("transmit_active - active"); return 1; } @@ -711,17 +660,12 @@ in a non-stopped state. static int receive_active(struct xircom_private *card) { unsigned int val; - enter("receive_active"); - val = inl(card->io_port + CSR5); /* Status register */ - if ((val & (7 << 17)) == 0) { /* receiver disabled */ - leave("receive_active - inactive"); + if ((val & (7 << 17)) == 0) /* receiver disabled */ return 0; - } - leave("receive_active - active"); return 1; } @@ -739,8 +683,6 @@ static void activate_receiver(struct xircom_private *card) { unsigned int val; int counter; - enter("activate_receiver"); - val = inl(card->io_port + CSR6); /* Operation mode */ @@ -761,7 +703,7 @@ static void activate_receiver(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - pr_err("Receiver failed to deactivate\n"); + netdev_err(card->dev, "Receiver failed to deactivate\n"); } /* enable the receiver */ @@ -778,10 +720,9 @@ static void activate_receiver(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - pr_err("Receiver failed to re-activate\n"); + netdev_err(card->dev, + "Receiver failed to re-activate\n"); } - - leave("activate_receiver"); } /* @@ -795,7 +736,6 @@ static void deactivate_receiver(struct xircom_private *card) { unsigned int val; int counter; - enter("deactivate_receiver"); val = inl(card->io_port + CSR6); /* Operation mode */ val = val & ~2; /* disable the receiver */ @@ -809,11 +749,8 @@ static void deactivate_receiver(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - pr_err("Receiver failed to deactivate\n"); + netdev_err(card->dev, "Receiver failed to deactivate\n"); } - - - leave("deactivate_receiver"); } @@ -831,8 +768,6 @@ static void activate_transmitter(struct xircom_private *card) { unsigned int val; int counter; - enter("activate_transmitter"); - val = inl(card->io_port + CSR6); /* Operation mode */ @@ -852,7 +787,8 @@ static void activate_transmitter(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - pr_err("Transmitter failed to deactivate\n"); + netdev_err(card->dev, + "Transmitter failed to deactivate\n"); } /* enable the transmitter */ @@ -869,10 +805,9 @@ static void activate_transmitter(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - pr_err("Transmitter failed to re-activate\n"); + netdev_err(card->dev, + "Transmitter failed to re-activate\n"); } - - leave("activate_transmitter"); } /* @@ -886,7 +821,6 @@ static void deactivate_transmitter(struct xircom_private *card) { unsigned int val; int counter; - enter("deactivate_transmitter"); val = inl(card->io_port + CSR6); /* Operation mode */ val = val & ~2; /* disable the transmitter */ @@ -900,11 +834,9 @@ static void deactivate_transmitter(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - pr_err("Transmitter failed to deactivate\n"); + netdev_err(card->dev, + "Transmitter failed to deactivate\n"); } - - - leave("deactivate_transmitter"); } @@ -916,13 +848,10 @@ must be called with the lock held and interrupts disabled. static void enable_transmit_interrupt(struct xircom_private *card) { unsigned int val; - enter("enable_transmit_interrupt"); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val |= 1; /* enable the transmit interrupt */ outl(val, card->io_port + CSR7); - - leave("enable_transmit_interrupt"); } @@ -934,13 +863,10 @@ must be called with the lock held and interrupts disabled. static void enable_receive_interrupt(struct xircom_private *card) { unsigned int val; - enter("enable_receive_interrupt"); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val = val | (1 << 6); /* enable the receive interrupt */ outl(val, card->io_port + CSR7); - - leave("enable_receive_interrupt"); } /* @@ -951,13 +877,10 @@ must be called with the lock held and interrupts disabled. static void enable_link_interrupt(struct xircom_private *card) { unsigned int val; - enter("enable_link_interrupt"); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val = val | (1 << 27); /* enable the link status chage interrupt */ outl(val, card->io_port + CSR7); - - leave("enable_link_interrupt"); } @@ -970,12 +893,9 @@ must be called with the lock held and interrupts disabled. static void disable_all_interrupts(struct xircom_private *card) { unsigned int val; - enter("enable_all_interrupts"); val = 0; /* disable all interrupts */ outl(val, card->io_port + CSR7); - - leave("disable_all_interrupts"); } /* @@ -986,7 +906,6 @@ must be called with the lock held and interrupts disabled. static void enable_common_interrupts(struct xircom_private *card) { unsigned int val; - enter("enable_link_interrupt"); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val |= (1<<16); /* Normal Interrupt Summary */ @@ -998,8 +917,6 @@ static void enable_common_interrupts(struct xircom_private *card) val |= (1<<2); /* Transmit Buffer Unavailable */ val |= (1<<1); /* Transmit Process Stopped */ outl(val, card->io_port + CSR7); - - leave("enable_link_interrupt"); } /* @@ -1010,13 +927,11 @@ must be called with the lock held and interrupts disabled. static int enable_promisc(struct xircom_private *card) { unsigned int val; - enter("enable_promisc"); val = inl(card->io_port + CSR6); val = val | (1 << 6); outl(val, card->io_port + CSR6); - leave("enable_promisc"); return 1; } @@ -1031,7 +946,6 @@ Must be called in locked state with interrupts disabled static int link_status(struct xircom_private *card) { unsigned int val; - enter("link_status"); val = inb(card->io_port + CSR12); @@ -1042,7 +956,6 @@ static int link_status(struct xircom_private *card) /* If we get here -> no link at all */ - leave("link_status"); return 0; } @@ -1061,8 +974,6 @@ static void read_mac_address(struct xircom_private *card) unsigned long flags; int i; - enter("read_mac_address"); - spin_lock_irqsave(&card->lock, flags); outl(1 << 12, card->io_port + CSR9); /* enable boot rom access */ @@ -1090,7 +1001,6 @@ static void read_mac_address(struct xircom_private *card) } spin_unlock_irqrestore(&card->lock, flags); pr_debug(" %pM\n", card->dev->dev_addr); - leave("read_mac_address"); } @@ -1103,8 +1013,6 @@ static void transceiver_voodoo(struct xircom_private *card) { unsigned long flags; - enter("transceiver_voodoo"); - /* disable all powermanagement */ pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000); @@ -1122,7 +1030,6 @@ static void transceiver_voodoo(struct xircom_private *card) spin_unlock_irqrestore(&card->lock, flags); netif_start_queue(card->dev); - leave("transceiver_voodoo"); } @@ -1131,8 +1038,6 @@ static void xircom_up(struct xircom_private *card) unsigned long flags; int i; - enter("xircom_up"); - /* disable all powermanagement */ pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000); @@ -1156,87 +1061,84 @@ static void xircom_up(struct xircom_private *card) trigger_receive(card); trigger_transmit(card); netif_start_queue(card->dev); - leave("xircom_up"); } /* Bufferoffset is in BYTES */ -static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset) +static void +investigate_read_descriptor(struct net_device *dev, struct xircom_private *card, + int descnr, unsigned int bufferoffset) { - int status; + int status; - enter("investigate_read_descriptor"); - status = le32_to_cpu(card->rx_buffer[4*descnr]); + status = le32_to_cpu(card->rx_buffer[4*descnr]); - if ((status > 0)) { /* packet received */ + if (status > 0) { /* packet received */ - /* TODO: discard error packets */ + /* TODO: discard error packets */ - short pkt_len = ((status >> 16) & 0x7ff) - 4; /* minus 4, we don't want the CRC */ - struct sk_buff *skb; + short pkt_len = ((status >> 16) & 0x7ff) - 4; + /* minus 4, we don't want the CRC */ + struct sk_buff *skb; - if (pkt_len > 1518) { - pr_err("Packet length %i is bogus\n", pkt_len); - pkt_len = 1518; - } - - skb = dev_alloc_skb(pkt_len + 2); - if (skb == NULL) { - dev->stats.rx_dropped++; - goto out; - } - skb_reserve(skb, 2); - skb_copy_to_linear_data(skb, (unsigned char*)&card->rx_buffer[bufferoffset / 4], pkt_len); - skb_put(skb, pkt_len); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - - out: - /* give the buffer back to the card */ - card->rx_buffer[4*descnr] = cpu_to_le32(0x80000000); - trigger_receive(card); + if (pkt_len > 1518) { + netdev_err(dev, "Packet length %i is bogus\n", pkt_len); + pkt_len = 1518; } - leave("investigate_read_descriptor"); + skb = dev_alloc_skb(pkt_len + 2); + if (skb == NULL) { + dev->stats.rx_dropped++; + goto out; + } + skb_reserve(skb, 2); + skb_copy_to_linear_data(skb, + &card->rx_buffer[bufferoffset / 4], + pkt_len); + skb_put(skb, pkt_len); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; +out: + /* give the buffer back to the card */ + card->rx_buffer[4*descnr] = cpu_to_le32(0x80000000); + trigger_receive(card); + } } /* Bufferoffset is in BYTES */ -static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset) +static void +investigate_write_descriptor(struct net_device *dev, + struct xircom_private *card, + int descnr, unsigned int bufferoffset) { - int status; + int status; - enter("investigate_write_descriptor"); - - status = le32_to_cpu(card->tx_buffer[4*descnr]); + status = le32_to_cpu(card->tx_buffer[4*descnr]); #if 0 - if (status & 0x8000) { /* Major error */ - pr_err("Major transmit error status %x\n", status); - card->tx_buffer[4*descnr] = 0; - netif_wake_queue (dev); - } + if (status & 0x8000) { /* Major error */ + pr_err("Major transmit error status %x\n", status); + card->tx_buffer[4*descnr] = 0; + netif_wake_queue (dev); + } #endif - if (status > 0) { /* bit 31 is 0 when done */ - if (card->tx_skb[descnr]!=NULL) { - dev->stats.tx_bytes += card->tx_skb[descnr]->len; - dev_kfree_skb_irq(card->tx_skb[descnr]); - } - card->tx_skb[descnr] = NULL; - /* Bit 8 in the status field is 1 if there was a collision */ - if (status&(1<<8)) - dev->stats.collisions++; - card->tx_buffer[4*descnr] = 0; /* descriptor is free again */ - netif_wake_queue (dev); - dev->stats.tx_packets++; + if (status > 0) { /* bit 31 is 0 when done */ + if (card->tx_skb[descnr]!=NULL) { + dev->stats.tx_bytes += card->tx_skb[descnr]->len; + dev_kfree_skb_irq(card->tx_skb[descnr]); } - - leave("investigate_write_descriptor"); - + card->tx_skb[descnr] = NULL; + /* Bit 8 in the status field is 1 if there was a collision */ + if (status & (1 << 8)) + dev->stats.collisions++; + card->tx_buffer[4*descnr] = 0; /* descriptor is free again */ + netif_wake_queue (dev); + dev->stats.tx_packets++; + } } - static int __init xircom_init(void) { return pci_register_driver(&xircom_ops); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index f5e9ac00a07b..74e94054ab1a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -123,6 +123,9 @@ struct tun_struct { gid_t group; struct net_device *dev; + u32 set_features; +#define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \ + NETIF_F_TSO6|NETIF_F_UFO) struct fasync_struct *fasync; struct tap_filter txflt; @@ -451,12 +454,20 @@ tun_net_change_mtu(struct net_device *dev, int new_mtu) return 0; } +static u32 tun_net_fix_features(struct net_device *dev, u32 features) +{ + struct tun_struct *tun = netdev_priv(dev); + + return (features & tun->set_features) | (features & ~TUN_USER_FEATURES); +} + static const struct net_device_ops tun_netdev_ops = { .ndo_uninit = tun_net_uninit, .ndo_open = tun_net_open, .ndo_stop = tun_net_close, .ndo_start_xmit = tun_net_xmit, .ndo_change_mtu = tun_net_change_mtu, + .ndo_fix_features = tun_net_fix_features, }; static const struct net_device_ops tap_netdev_ops = { @@ -465,6 +476,7 @@ static const struct net_device_ops tap_netdev_ops = { .ndo_stop = tun_net_close, .ndo_start_xmit = tun_net_xmit, .ndo_change_mtu = tun_net_change_mtu, + .ndo_fix_features = tun_net_fix_features, .ndo_set_multicast_list = tun_net_mclist, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, @@ -628,8 +640,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, kfree_skb(skb); return -EINVAL; } - } else if (tun->flags & TUN_NOCHECKSUM) - skb->ip_summed = CHECKSUM_UNNECESSARY; + } switch (tun->flags & TUN_TYPE_MASK) { case TUN_TUN_DEV: @@ -1088,11 +1099,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) tun_net_init(dev); - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto err_free_sk; - } + dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | + TUN_USER_FEATURES; + dev->features = dev->hw_features; err = register_netdevice(tun->dev); if (err < 0) @@ -1158,18 +1167,12 @@ static int tun_get_iff(struct net *net, struct tun_struct *tun, /* This is like a cut-down ethtool ops, except done via tun fd so no * privs required. */ -static int set_offload(struct net_device *dev, unsigned long arg) +static int set_offload(struct tun_struct *tun, unsigned long arg) { - u32 old_features, features; - - old_features = dev->features; - /* Unset features, set them as we chew on the arg. */ - features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST - |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6 - |NETIF_F_UFO)); + u32 features = 0; if (arg & TUN_F_CSUM) { - features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + features |= NETIF_F_HW_CSUM; arg &= ~TUN_F_CSUM; if (arg & (TUN_F_TSO4|TUN_F_TSO6)) { @@ -1195,9 +1198,8 @@ static int set_offload(struct net_device *dev, unsigned long arg) if (arg) return -EINVAL; - dev->features = features; - if (old_features != dev->features) - netdev_features_change(dev); + tun->set_features = features; + netdev_update_features(tun->dev); return 0; } @@ -1262,12 +1264,9 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, case TUNSETNOCSUM: /* Disable/Enable checksum */ - if (arg) - tun->flags |= TUN_NOCHECKSUM; - else - tun->flags &= ~TUN_NOCHECKSUM; - tun_debug(KERN_INFO, tun, "checksum %s\n", + /* [unimplemented] */ + tun_debug(KERN_INFO, tun, "ignored: set checksum %s\n", arg ? "disabled" : "enabled"); break; @@ -1316,7 +1315,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, break; #endif case TUNSETOFFLOAD: - ret = set_offload(tun->dev, arg); + ret = set_offload(tun, arg); break; case TUNSETTXFILTER: @@ -1548,7 +1547,7 @@ static int tun_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { cmd->supported = 0; cmd->advertising = 0; - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); cmd->duplex = DUPLEX_FULL; cmd->port = PORT_TP; cmd->phy_address = 0; @@ -1595,30 +1594,12 @@ static void tun_set_msglevel(struct net_device *dev, u32 value) #endif } -static u32 tun_get_rx_csum(struct net_device *dev) -{ - struct tun_struct *tun = netdev_priv(dev); - return (tun->flags & TUN_NOCHECKSUM) == 0; -} - -static int tun_set_rx_csum(struct net_device *dev, u32 data) -{ - struct tun_struct *tun = netdev_priv(dev); - if (data) - tun->flags &= ~TUN_NOCHECKSUM; - else - tun->flags |= TUN_NOCHECKSUM; - return 0; -} - static const struct ethtool_ops tun_ethtool_ops = { .get_settings = tun_get_settings, .get_drvinfo = tun_get_drvinfo, .get_msglevel = tun_get_msglevel, .set_msglevel = tun_set_msglevel, .get_link = ethtool_op_get_link, - .get_rx_csum = tun_get_rx_csum, - .set_rx_csum = tun_set_rx_csum }; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 82653cb07857..3de4283344e9 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1050,7 +1050,7 @@ typhoon_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) /* need to get stats to make these link speed/duplex valid */ typhoon_do_get_stats(tp); - cmd->speed = tp->speed; + ethtool_cmd_speed_set(cmd, tp->speed); cmd->duplex = tp->duplex; cmd->phy_address = 0; cmd->transceiver = XCVR_INTERNAL; @@ -1068,25 +1068,26 @@ static int typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct typhoon *tp = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(cmd); struct cmd_desc xp_cmd; __le16 xcvr; int err; err = -EINVAL; - if(cmd->autoneg == AUTONEG_ENABLE) { + if (cmd->autoneg == AUTONEG_ENABLE) { xcvr = TYPHOON_XCVR_AUTONEG; } else { - if(cmd->duplex == DUPLEX_HALF) { - if(cmd->speed == SPEED_10) + if (cmd->duplex == DUPLEX_HALF) { + if (speed == SPEED_10) xcvr = TYPHOON_XCVR_10HALF; - else if(cmd->speed == SPEED_100) + else if (speed == SPEED_100) xcvr = TYPHOON_XCVR_100HALF; else goto out; - } else if(cmd->duplex == DUPLEX_FULL) { - if(cmd->speed == SPEED_10) + } else if (cmd->duplex == DUPLEX_FULL) { + if (speed == SPEED_10) xcvr = TYPHOON_XCVR_10FULL; - else if(cmd->speed == SPEED_100) + else if (speed == SPEED_100) xcvr = TYPHOON_XCVR_100FULL; else goto out; @@ -1105,7 +1106,7 @@ typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) tp->speed = 0xff; /* invalid */ tp->duplex = 0xff; /* invalid */ } else { - tp->speed = cmd->speed; + tp->speed = speed; tp->duplex = cmd->duplex; } @@ -1144,28 +1145,6 @@ typhoon_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return 0; } -static u32 -typhoon_get_rx_csum(struct net_device *dev) -{ - /* For now, we don't allow turning off RX checksums. - */ - return 1; -} - -static int -typhoon_set_flags(struct net_device *dev, u32 data) -{ - /* There's no way to turn off the RX VLAN offloading and stripping - * on the current 3XP firmware -- it does not respect the offload - * settings -- so we only allow the user to toggle the TX processing. - */ - if (!(data & ETH_FLAG_RXVLAN)) - return -EINVAL; - - return ethtool_op_set_flags(dev, data, - ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN); -} - static void typhoon_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { @@ -1187,13 +1166,7 @@ static const struct ethtool_ops typhoon_ethtool_ops = { .get_wol = typhoon_get_wol, .set_wol = typhoon_set_wol, .get_link = ethtool_op_get_link, - .get_rx_csum = typhoon_get_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, .get_ringparam = typhoon_get_ringparam, - .set_flags = typhoon_set_flags, - .get_flags = ethtool_op_get_flags, }; static int @@ -2482,10 +2455,15 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* We can handle scatter gather, up to 16 entries, and * we can do IP checksumming (only version 4, doh...) + * + * There's no way to turn off the RX VLAN offloading and stripping + * on the current 3XP firmware -- it does not respect the offload + * settings -- so we only allow the user to toggle the TX processing. */ - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->features |= NETIF_F_TSO; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_HW_VLAN_TX; + dev->features = dev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_RXCSUM; if(register_netdev(dev) < 0) { err_msg = "unable to register netdev"; diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 6f92e48f02d3..537fbc0a4401 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -410,7 +410,6 @@ static const struct ethtool_ops uec_ethtool_ops = { .set_ringparam = uec_set_ringparam, .get_pauseparam = uec_get_pauseparam, .set_pauseparam = uec_set_pauseparam, - .set_sg = ethtool_op_set_sg, .get_sset_count = uec_get_sset_count, .get_strings = uec_get_strings, .get_ethtool_stats = uec_get_ethtool_stats, diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 3ec22c307797..9d4f9117260f 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -258,7 +258,7 @@ config USB_NET_NET1080 optionally with LEDs that indicate traffic config USB_NET_PLUSB - tristate "Prolific PL-2301/2302 based cables" + tristate "Prolific PL-2301/2302/25A1 based cables" # if the handshake/init/reset problems, from original 'plusb', # are ever resolved ... then remove "experimental" depends on USB_USBNET && EXPERIMENTAL diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 6140b56cce53..6998aa6b7bb7 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -847,7 +847,7 @@ static void ax88172_set_multicast(struct net_device *net) static int ax88172_link_reset(struct usbnet *dev) { u8 mode; - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; mii_check_media(&dev->mii, 1, 1); mii_ethtool_gset(&dev->mii, &ecmd); @@ -856,8 +856,8 @@ static int ax88172_link_reset(struct usbnet *dev) if (ecmd.duplex != DUPLEX_FULL) mode |= ~AX88172_MEDIUM_FD; - netdev_dbg(dev->net, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", - ecmd.speed, ecmd.duplex, mode); + netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", + ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); asix_write_medium_mode(dev, mode); @@ -947,20 +947,20 @@ static const struct ethtool_ops ax88772_ethtool_ops = { static int ax88772_link_reset(struct usbnet *dev) { u16 mode; - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; mii_check_media(&dev->mii, 1, 1); mii_ethtool_gset(&dev->mii, &ecmd); mode = AX88772_MEDIUM_DEFAULT; - if (ecmd.speed != SPEED_100) + if (ethtool_cmd_speed(&ecmd) != SPEED_100) mode &= ~AX_MEDIUM_PS; if (ecmd.duplex != DUPLEX_FULL) mode &= ~AX_MEDIUM_FD; - netdev_dbg(dev->net, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", - ecmd.speed, ecmd.duplex, mode); + netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", + ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); asix_write_medium_mode(dev, mode); @@ -1173,18 +1173,20 @@ static int marvell_led_status(struct usbnet *dev, u16 speed) static int ax88178_link_reset(struct usbnet *dev) { u16 mode; - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; struct asix_data *data = (struct asix_data *)&dev->data; + u32 speed; netdev_dbg(dev->net, "ax88178_link_reset()\n"); mii_check_media(&dev->mii, 1, 1); mii_ethtool_gset(&dev->mii, &ecmd); mode = AX88178_MEDIUM_DEFAULT; + speed = ethtool_cmd_speed(&ecmd); - if (ecmd.speed == SPEED_1000) + if (speed == SPEED_1000) mode |= AX_MEDIUM_GM; - else if (ecmd.speed == SPEED_100) + else if (speed == SPEED_100) mode |= AX_MEDIUM_PS; else mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); @@ -1196,13 +1198,13 @@ static int ax88178_link_reset(struct usbnet *dev) else mode &= ~AX_MEDIUM_FD; - netdev_dbg(dev->net, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", - ecmd.speed, ecmd.duplex, mode); + netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", + speed, ecmd.duplex, mode); asix_write_medium_mode(dev, mode); if (data->phymode == PHY_MODE_MARVELL && data->ledmode) - marvell_led_status(dev, ecmd.speed); + marvell_led_status(dev, speed); return 0; } diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 97687d335903..d7221c4a5dcf 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -686,7 +686,7 @@ static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP; cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP; - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); cmd->duplex = DUPLEX_HALF; cmd->port = PORT_TP; cmd->phy_address = 0; diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 341f7056a800..c924ea2bce07 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -460,7 +460,7 @@ static const struct driver_info cdc_info = { .manage_power = cdc_manage_power, }; -static const struct driver_info mbm_info = { +static const struct driver_info wwan_info = { .description = "Mobile Broadband Network Device", .flags = FLAG_WWAN, .bind = usbnet_cdc_bind, @@ -471,6 +471,7 @@ static const struct driver_info mbm_info = { /*-------------------------------------------------------------------------*/ +#define HUAWEI_VENDOR_ID 0x12D1 static const struct usb_device_id products [] = { /* @@ -566,7 +567,7 @@ static const struct usb_device_id products [] = { { USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), - .driver_info = 0, + .driver_info = (unsigned long)&wwan_info, }, /* @@ -587,8 +588,17 @@ static const struct usb_device_id products [] = { }, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), - .driver_info = (unsigned long)&mbm_info, + .driver_info = (unsigned long)&wwan_info, +}, { + /* Various Huawei modems with a network port like the UMG1831 */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = HUAWEI_VENDOR_ID, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = 255, + .driver_info = (unsigned long)&wwan_info, }, { }, // END }; diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 967371f04454..4ab557d0287d 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -54,7 +54,7 @@ #include #include -#define DRIVER_VERSION "7-Feb-2011" +#define DRIVER_VERSION "06-May-2011" /* CDC NCM subclass 3.2.1 */ #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 @@ -722,7 +722,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) } else { /* reset variables */ - skb_out = alloc_skb(ctx->tx_max, GFP_ATOMIC); + skb_out = alloc_skb((ctx->tx_max + 1), GFP_ATOMIC); if (skb_out == NULL) { if (skb != NULL) { dev_kfree_skb_any(skb); @@ -861,8 +861,11 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) /* store last offset */ last_offset = offset; - if ((last_offset < ctx->tx_max) && ((last_offset % - le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) { + if (((last_offset < ctx->tx_max) && ((last_offset % + le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) || + (((last_offset == ctx->tx_max) && ((ctx->tx_max % + le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) && + (ctx->tx_max < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)))) { /* force short packet */ *(((u8 *)skb_out->data) + last_offset) = 0; last_offset++; diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 5002f5be47be..1d93133e9b74 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -599,13 +599,13 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb) static int dm9601_link_reset(struct usbnet *dev) { - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; mii_check_media(&dev->mii, 1, 1); mii_ethtool_gset(&dev->mii, &ecmd); - netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n", - ecmd.speed, ecmd.duplex); + netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n", + ethtool_cmd_speed(&ecmd), ecmd.duplex); return 0; } diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 7d42f9a2c068..81126ff85e05 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -65,6 +65,7 @@ #define IPHETH_USBINTF_PROTO 1 #define IPHETH_BUF_SIZE 1516 +#define IPHETH_IP_ALIGN 2 /* padding at front of URB */ #define IPHETH_TX_TIMEOUT (5 * HZ) #define IPHETH_INTFNUM 2 @@ -202,18 +203,21 @@ static void ipheth_rcvbulk_callback(struct urb *urb) return; } - len = urb->actual_length; - buf = urb->transfer_buffer; + if (urb->actual_length <= IPHETH_IP_ALIGN) { + dev->net->stats.rx_length_errors++; + return; + } + len = urb->actual_length - IPHETH_IP_ALIGN; + buf = urb->transfer_buffer + IPHETH_IP_ALIGN; - skb = dev_alloc_skb(NET_IP_ALIGN + len); + skb = dev_alloc_skb(len); if (!skb) { err("%s: dev_alloc_skb: -ENOMEM", __func__); dev->net->stats.rx_dropped++; return; } - skb_reserve(skb, NET_IP_ALIGN); - memcpy(skb_put(skb, len), buf + NET_IP_ALIGN, len - NET_IP_ALIGN); + memcpy(skb_put(skb, len), buf, len); skb->dev = dev->net; skb->protocol = eth_type_trans(skb, dev->net); diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 823c53751307..217aec8a768f 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -45,6 +45,14 @@ * seems to get wedged under load. Prolific docs are weak, and * don't identify differences between PL2301 and PL2302, much less * anything to explain the different PL2302 versions observed. + * + * NOTE: pl2501 has several modes, including pl2301 and pl2302 + * compatibility. Some docs suggest the difference between 2301 + * and 2302 is only to make MS-Windows use a different driver... + * + * pl25a1 glue based on patch from Tony Gibbs. Prolific "docs" on + * this chip are as usual incomplete about what control messages + * are supported. */ /* @@ -86,16 +94,20 @@ pl_set_QuickLink_features(struct usbnet *dev, int val) static int pl_reset(struct usbnet *dev) { + int status; + /* some units seem to need this reset, others reject it utterly. * FIXME be more like "naplink" or windows drivers. */ - (void) pl_set_QuickLink_features(dev, + status = pl_set_QuickLink_features(dev, PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); + if (status != 0 && netif_msg_probe(dev)) + netif_dbg(dev, link, dev->net, "pl_reset --> %d\n", status); return 0; } static const struct driver_info prolific_info = { - .description = "Prolific PL-2301/PL-2302", + .description = "Prolific PL-2301/PL-2302/PL-25A1", .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT, /* some PL-2302 versions seem to fail usb_set_interface() */ .reset = pl_reset, @@ -111,6 +123,7 @@ static const struct driver_info prolific_info = { static const struct usb_device_id products [] = { +/* full speed cables */ { USB_DEVICE(0x067b, 0x0000), // PL-2301 .driver_info = (unsigned long) &prolific_info, @@ -119,6 +132,15 @@ static const struct usb_device_id products [] = { .driver_info = (unsigned long) &prolific_info, }, +/* high speed cables */ +{ + USB_DEVICE(0x067b, 0x25a1), /* PL-25A1, no eeprom */ + .driver_info = (unsigned long) &prolific_info, +}, { + USB_DEVICE(0x050d, 0x258a), /* Belkin F5U258/F5U279 (PL-25A1) */ + .driver_info = (unsigned long) &prolific_info, +}, + { }, // END }; MODULE_DEVICE_TABLE(usb, products); @@ -134,16 +156,16 @@ static struct usb_driver plusb_driver = { static int __init plusb_init(void) { - return usb_register(&plusb_driver); + return usb_register(&plusb_driver); } module_init(plusb_init); static void __exit plusb_exit(void) { - usb_deregister(&plusb_driver); + usb_deregister(&plusb_driver); } module_exit(plusb_exit); MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("Prolific PL-2301/2302 USB Host to Host Link Driver"); +MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1 USB Host to Host Link Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 5994a25c56ac..255d6a424a6b 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -104,8 +104,10 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) { struct cdc_state *info = (void *) &dev->data; + struct usb_cdc_notification notification; int master_ifnum; int retval; + int partial; unsigned count; __le32 rsp; u32 xid = 0, msg_len, request_id; @@ -133,13 +135,20 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) if (unlikely(retval < 0 || xid == 0)) return retval; - // FIXME Seems like some devices discard responses when - // we time out and cancel our "get response" requests... - // so, this is fragile. Probably need to poll for status. + /* Some devices don't respond on the control channel until + * polled on the status channel, so do that first. */ + if (dev->driver_info->data & RNDIS_DRIVER_DATA_POLL_STATUS) { + retval = usb_interrupt_msg( + dev->udev, + usb_rcvintpipe(dev->udev, + dev->status->desc.bEndpointAddress), + ¬ification, sizeof(notification), &partial, + RNDIS_CONTROL_TIMEOUT_MS); + if (unlikely(retval < 0)) + return retval; + } - /* ignore status endpoint, just poll the control channel; - * the request probably completed immediately - */ + /* Poll the control channel; the request probably completed immediately */ rsp = buf->msg_type | RNDIS_MSG_COMPLETION; for (count = 0; count < 10; count++) { memset(buf, 0, CONTROL_BUFFER_SIZE); @@ -581,17 +590,33 @@ static const struct driver_info rndis_info = { .tx_fixup = rndis_tx_fixup, }; +static const struct driver_info rndis_poll_status_info = { + .description = "RNDIS device (poll status before control)", + .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .data = RNDIS_DRIVER_DATA_POLL_STATUS, + .bind = rndis_bind, + .unbind = rndis_unbind, + .status = rndis_status, + .rx_fixup = rndis_rx_fixup, + .tx_fixup = rndis_tx_fixup, +}; + /*-------------------------------------------------------------------------*/ static const struct usb_device_id products [] = { { + /* 2Wire HomePortal 1000SW */ + USB_DEVICE_AND_INTERFACE_INFO(0x1630, 0x0042, + USB_CLASS_COMM, 2 /* ACM */, 0x0ff), + .driver_info = (unsigned long) &rndis_poll_status_info, +}, { /* RNDIS is MSFT's un-official variant of CDC ACM */ USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), .driver_info = (unsigned long) &rndis_info, }, { /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), - .driver_info = (unsigned long) &rndis_info, + .driver_info = (unsigned long) &rndis_poll_status_info, }, { /* RNDIS for tethering */ USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index e85c89c6706d..041fb7d43c4f 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -843,10 +843,11 @@ static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *e get_registers(dev, BMCR, 2, &bmcr); get_registers(dev, ANLP, 2, &lpa); if (bmcr & BMCR_ANENABLE) { + u32 speed = ((lpa & (LPA_100HALF | LPA_100FULL)) ? + SPEED_100 : SPEED_10); + ethtool_cmd_speed_set(ecmd, speed); ecmd->autoneg = AUTONEG_ENABLE; - ecmd->speed = (lpa & (LPA_100HALF | LPA_100FULL)) ? - SPEED_100 : SPEED_10; - if (ecmd->speed == SPEED_100) + if (speed == SPEED_100) ecmd->duplex = (lpa & LPA_100FULL) ? DUPLEX_FULL : DUPLEX_HALF; else @@ -854,8 +855,8 @@ static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *e DUPLEX_FULL : DUPLEX_HALF; } else { ecmd->autoneg = AUTONEG_DISABLE; - ecmd->speed = (bmcr & BMCR_SPEED100) ? - SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(ecmd, ((bmcr & BMCR_SPEED100) ? + SPEED_100 : SPEED_10)); ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 753ee6eb7edd..15b3d6888ae9 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -65,7 +65,6 @@ struct smsc75xx_priv { struct usbnet *dev; u32 rfe_ctl; u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN]; - bool use_rx_csum; struct mutex dataport_mutex; spinlock_t rfe_ctl_lock; struct work_struct set_multicast; @@ -504,7 +503,7 @@ static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex, static int smsc75xx_link_reset(struct usbnet *dev) { struct mii_if_info *mii = &dev->mii; - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; u16 lcladv, rmtadv; int ret; @@ -520,8 +519,9 @@ static int smsc75xx_link_reset(struct usbnet *dev) lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA); - netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x" - " rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv); + netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x" + " rmtadv: %04x", ethtool_cmd_speed(&ecmd), + ecmd.duplex, lcladv, rmtadv); return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); } @@ -548,28 +548,6 @@ static void smsc75xx_status(struct usbnet *dev, struct urb *urb) "unexpected interrupt, intdata=0x%08X", intdata); } -/* Enable or disable Rx checksum offload engine */ -static int smsc75xx_set_rx_csum_offload(struct usbnet *dev) -{ - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - unsigned long flags; - int ret; - - spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); - - if (pdata->use_rx_csum) - pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; - else - pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); - - spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); - - ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); - check_warn_return(ret, "Error writing RFE_CTL"); - - return 0; -} - static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net) { return MAX_EEPROM_SIZE; @@ -599,34 +577,6 @@ static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev, return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data); } -static u32 smsc75xx_ethtool_get_rx_csum(struct net_device *netdev) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - - return pdata->use_rx_csum; -} - -static int smsc75xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - - pdata->use_rx_csum = !!val; - - return smsc75xx_set_rx_csum_offload(dev); -} - -static int smsc75xx_ethtool_set_tso(struct net_device *netdev, u32 data) -{ - if (data) - netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; - else - netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - static const struct ethtool_ops smsc75xx_ethtool_ops = { .get_link = usbnet_get_link, .nway_reset = usbnet_nway_reset, @@ -638,12 +588,6 @@ static const struct ethtool_ops smsc75xx_ethtool_ops = { .get_eeprom_len = smsc75xx_ethtool_get_eeprom_len, .get_eeprom = smsc75xx_ethtool_get_eeprom, .set_eeprom = smsc75xx_ethtool_set_eeprom, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_rx_csum = smsc75xx_ethtool_get_rx_csum, - .set_rx_csum = smsc75xx_ethtool_set_rx_csum, - .get_tso = ethtool_op_get_tso, - .set_tso = smsc75xx_ethtool_set_tso, }; static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@ -782,6 +726,30 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu) return usbnet_change_mtu(netdev, new_mtu); } +/* Enable or disable Rx checksum offload engine */ +static int smsc75xx_set_features(struct net_device *netdev, u32 features) +{ + struct usbnet *dev = netdev_priv(netdev); + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + unsigned long flags; + int ret; + + spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); + + if (features & NETIF_F_RXCSUM) + pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; + else + pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); + + spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); + /* it's racing here! */ + + ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); + check_warn_return(ret, "Error writing RFE_CTL"); + + return 0; +} + static int smsc75xx_reset(struct usbnet *dev) { struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); @@ -960,11 +928,7 @@ static int smsc75xx_reset(struct usbnet *dev) netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl); /* Enable or disable checksum offload engines */ - ethtool_op_set_tx_hw_csum(dev->net, DEFAULT_TX_CSUM_ENABLE); - ret = smsc75xx_set_rx_csum_offload(dev); - check_warn_return(ret, "Failed to set rx csum offload: %d", ret); - - smsc75xx_ethtool_set_tso(dev->net, DEFAULT_TSO_ENABLE); + smsc75xx_set_features(dev->net, dev->net->features); smsc75xx_set_multicast(dev->net); @@ -1037,6 +1001,7 @@ static const struct net_device_ops smsc75xx_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = smsc75xx_ioctl, .ndo_set_multicast_list = smsc75xx_set_multicast, + .ndo_set_features = smsc75xx_set_features, }; static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) @@ -1065,10 +1030,17 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); - pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; + if (DEFAULT_TX_CSUM_ENABLE) { + dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + if (DEFAULT_TSO_ENABLE) + dev->net->features |= NETIF_F_SG | + NETIF_F_TSO | NETIF_F_TSO6; + } + if (DEFAULT_RX_CSUM_ENABLE) + dev->net->features |= NETIF_F_RXCSUM; - /* We have to advertise SG otherwise TSO cannot be enabled */ - dev->net->features |= NETIF_F_SG; + dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM; /* Init all registers */ ret = smsc75xx_reset(dev); @@ -1091,10 +1063,11 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf) } } -static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, - u32 rx_cmd_b) +static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb, + u32 rx_cmd_a, u32 rx_cmd_b) { - if (unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { + if (!(dev->net->features & NETIF_F_RXCSUM) || + unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { skb->ip_summed = CHECKSUM_NONE; } else { skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT)); @@ -1104,8 +1077,6 @@ static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - while (skb->len > 0) { u32 rx_cmd_a, rx_cmd_b, align_count, size; struct sk_buff *ax_skb; @@ -1145,11 +1116,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) /* last frame in this batch */ if (skb->len == size) { - if (pdata->use_rx_csum) - smsc75xx_rx_csum_offload(skb, rx_cmd_a, - rx_cmd_b); - else - skb->ip_summed = CHECKSUM_NONE; + smsc75xx_rx_csum_offload(dev, skb, rx_cmd_a, + rx_cmd_b); skb_trim(skb, skb->len - 4); /* remove fcs */ skb->truesize = size + sizeof(struct sk_buff); @@ -1167,11 +1135,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) ax_skb->data = packet; skb_set_tail_pointer(ax_skb, size); - if (pdata->use_rx_csum) - smsc75xx_rx_csum_offload(ax_skb, rx_cmd_a, - rx_cmd_b); - else - ax_skb->ip_summed = CHECKSUM_NONE; + smsc75xx_rx_csum_offload(dev, ax_skb, rx_cmd_a, + rx_cmd_b); skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ ax_skb->truesize = size + sizeof(struct sk_buff); diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 47a6c870b51f..f74f3ce71526 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -52,8 +52,6 @@ struct smsc95xx_priv { u32 hash_hi; u32 hash_lo; spinlock_t mac_cr_lock; - bool use_tx_csum; - bool use_rx_csum; }; struct usb_context { @@ -459,7 +457,7 @@ static int smsc95xx_link_reset(struct usbnet *dev) { struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); struct mii_if_info *mii = &dev->mii; - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; unsigned long flags; u16 lcladv, rmtadv; u32 intdata; @@ -474,8 +472,9 @@ static int smsc95xx_link_reset(struct usbnet *dev) lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA); - netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x rmtadv: %04x\n", - ecmd.speed, ecmd.duplex, lcladv, rmtadv); + netif_dbg(dev, link, dev->net, + "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n", + ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv); spin_lock_irqsave(&pdata->mac_cr_lock, flags); if (ecmd.duplex != DUPLEX_FULL) { @@ -517,22 +516,24 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb) } /* Enable or disable Tx & Rx checksum offload engines */ -static int smsc95xx_set_csums(struct usbnet *dev) +static int smsc95xx_set_features(struct net_device *netdev, u32 features) { - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + struct usbnet *dev = netdev_priv(netdev); u32 read_buf; - int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); + int ret; + + ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); if (ret < 0) { netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret); return ret; } - if (pdata->use_tx_csum) + if (features & NETIF_F_HW_CSUM) read_buf |= Tx_COE_EN_; else read_buf &= ~Tx_COE_EN_; - if (pdata->use_rx_csum) + if (features & NETIF_F_RXCSUM) read_buf |= Rx_COE_EN_; else read_buf &= ~Rx_COE_EN_; @@ -576,43 +577,6 @@ static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev, return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); } -static u32 smsc95xx_ethtool_get_rx_csum(struct net_device *netdev) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - - return pdata->use_rx_csum; -} - -static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - - pdata->use_rx_csum = !!val; - - return smsc95xx_set_csums(dev); -} - -static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - - return pdata->use_tx_csum; -} - -static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - - pdata->use_tx_csum = !!val; - - ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); - return smsc95xx_set_csums(dev); -} - static const struct ethtool_ops smsc95xx_ethtool_ops = { .get_link = usbnet_get_link, .nway_reset = usbnet_nway_reset, @@ -624,10 +588,6 @@ static const struct ethtool_ops smsc95xx_ethtool_ops = { .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, .get_eeprom = smsc95xx_ethtool_get_eeprom, .set_eeprom = smsc95xx_ethtool_set_eeprom, - .get_tx_csum = smsc95xx_ethtool_get_tx_csum, - .set_tx_csum = smsc95xx_ethtool_set_tx_csum, - .get_rx_csum = smsc95xx_ethtool_get_rx_csum, - .set_rx_csum = smsc95xx_ethtool_set_rx_csum, }; static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@ -730,7 +690,7 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) msleep(10); bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); timeout++; - } while ((bmcr & MII_BMCR) && (timeout < 100)); + } while ((bmcr & BMCR_RESET) && (timeout < 100)); if (timeout >= 100) { netdev_warn(dev->net, "timeout on PHY Reset"); @@ -755,7 +715,6 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) static int smsc95xx_reset(struct usbnet *dev) { struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - struct net_device *netdev = dev->net; u32 read_buf, write_buf, burst_cap; int ret = 0, timeout; @@ -975,12 +934,7 @@ static int smsc95xx_reset(struct usbnet *dev) } /* Enable or disable checksum offload engines */ - ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); - ret = smsc95xx_set_csums(dev); - if (ret < 0) { - netdev_warn(dev->net, "Failed to set csum offload: %d\n", ret); - return ret; - } + smsc95xx_set_features(dev->net, dev->net->features); smsc95xx_set_multicast(dev->net); @@ -1019,6 +973,7 @@ static const struct net_device_ops smsc95xx_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = smsc95xx_ioctl, .ndo_set_multicast_list = smsc95xx_set_multicast, + .ndo_set_features = smsc95xx_set_features, }; static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) @@ -1045,8 +1000,12 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) spin_lock_init(&pdata->mac_cr_lock); - pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE; - pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; + if (DEFAULT_TX_CSUM_ENABLE) + dev->net->features |= NETIF_F_HW_CSUM; + if (DEFAULT_RX_CSUM_ENABLE) + dev->net->features |= NETIF_F_RXCSUM; + + dev->net->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; smsc95xx_init_mac_address(dev); @@ -1056,7 +1015,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->netdev_ops = &smsc95xx_netdev_ops; dev->net->ethtool_ops = &smsc95xx_ethtool_ops; dev->net->flags |= IFF_MULTICAST; - dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD; + dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM; return 0; } @@ -1080,8 +1039,6 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb) static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - while (skb->len > 0) { u32 header, align_count; struct sk_buff *ax_skb; @@ -1123,7 +1080,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) /* last frame in this batch */ if (skb->len == size) { - if (pdata->use_rx_csum) + if (dev->net->features & NETIF_F_RXCSUM) smsc95xx_rx_csum_offload(skb); skb_trim(skb, skb->len - 4); /* remove fcs */ skb->truesize = size + sizeof(struct sk_buff); @@ -1141,7 +1098,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) ax_skb->data = packet; skb_set_tail_pointer(ax_skb, size); - if (pdata->use_rx_csum) + if (dev->net->features & NETIF_F_RXCSUM) smsc95xx_rx_csum_offload(ax_skb); skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ ax_skb->truesize = size + sizeof(struct sk_buff); @@ -1174,8 +1131,7 @@ static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb) static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - bool csum = pdata->use_tx_csum && (skb->ip_summed == CHECKSUM_PARTIAL); + bool csum = skb->ip_summed == CHECKSUM_PARTIAL; int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD; u32 tx_cmd_a, tx_cmd_b; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 069c1cf0fdf7..e6dd24466965 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -645,6 +645,7 @@ int usbnet_stop (struct net_device *net) struct driver_info *info = dev->driver_info; int retval; + clear_bit(EVENT_DEV_OPEN, &dev->flags); netif_stop_queue (net); netif_info(dev, ifdown, dev->net, @@ -736,6 +737,7 @@ int usbnet_open (struct net_device *net) } } + set_bit(EVENT_DEV_OPEN, &dev->flags); netif_start_queue (net); netif_info(dev, ifup, dev->net, "open: enable queueing (rx %d, tx %d) mtu %d %s framing\n", @@ -1259,6 +1261,9 @@ void usbnet_disconnect (struct usb_interface *intf) if (dev->driver_info->unbind) dev->driver_info->unbind (dev, intf); + usb_kill_urb(dev->interrupt); + usb_free_urb(dev->interrupt); + free_netdev(net); usb_put_dev (xdev); } @@ -1498,6 +1503,10 @@ int usbnet_resume (struct usb_interface *intf) int retval; if (!--dev->suspend_count) { + /* resume interrupt URBs */ + if (dev->interrupt && test_bit(EVENT_DEV_OPEN, &dev->flags)) + usb_submit_urb(dev->interrupt, GFP_NOIO); + spin_lock_irq(&dev->txq.lock); while ((res = usb_get_from_anchor(&dev->deferred))) { @@ -1516,9 +1525,12 @@ int usbnet_resume (struct usb_interface *intf) smp_mb(); clear_bit(EVENT_DEV_ASLEEP, &dev->flags); spin_unlock_irq(&dev->txq.lock); - if (!(dev->txq.qlen >= TX_QLEN(dev))) - netif_start_queue(dev->net); - tasklet_schedule (&dev->bh); + + if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { + if (!(dev->txq.qlen >= TX_QLEN(dev))) + netif_start_queue(dev->net); + tasklet_schedule (&dev->bh); + } } return 0; } @@ -1529,9 +1541,9 @@ EXPORT_SYMBOL_GPL(usbnet_resume); static int __init usbnet_init(void) { - /* compiler should optimize this out */ - BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb) - < sizeof (struct skb_data)); + /* Compiler should optimize this out. */ + BUILD_BUG_ON( + FIELD_SIZEOF(struct sk_buff, cb) < sizeof(struct skb_data)); random_ether_addr(node_id); return 0; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 2de9b90c5f8f..8461576fa015 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -22,7 +22,6 @@ #define MIN_MTU 68 /* Min L3 MTU */ #define MAX_MTU 65535 /* Max L3 MTU (arbitrary) */ -#define MTU_PAD (ETH_HLEN + 4) /* Max difference between L2 and L3 size MTU */ struct veth_net_stats { unsigned long rx_packets; @@ -36,7 +35,6 @@ struct veth_net_stats { struct veth_priv { struct net_device *peer; struct veth_net_stats __percpu *stats; - unsigned ip_summed; }; /* @@ -53,7 +51,7 @@ static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { cmd->supported = 0; cmd->advertising = 0; - cmd->speed = SPEED_10000; + ethtool_cmd_speed_set(cmd, SPEED_10000); cmd->duplex = DUPLEX_FULL; cmd->port = PORT_TP; cmd->phy_address = 0; @@ -99,47 +97,10 @@ static void veth_get_ethtool_stats(struct net_device *dev, data[0] = priv->peer->ifindex; } -static u32 veth_get_rx_csum(struct net_device *dev) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - return priv->ip_summed == CHECKSUM_UNNECESSARY; -} - -static int veth_set_rx_csum(struct net_device *dev, u32 data) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE; - return 0; -} - -static u32 veth_get_tx_csum(struct net_device *dev) -{ - return (dev->features & NETIF_F_NO_CSUM) != 0; -} - -static int veth_set_tx_csum(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_NO_CSUM; - else - dev->features &= ~NETIF_F_NO_CSUM; - return 0; -} - static const struct ethtool_ops veth_ethtool_ops = { .get_settings = veth_get_settings, .get_drvinfo = veth_get_drvinfo, .get_link = ethtool_op_get_link, - .get_rx_csum = veth_get_rx_csum, - .set_rx_csum = veth_set_rx_csum, - .get_tx_csum = veth_get_tx_csum, - .set_tx_csum = veth_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, .get_strings = veth_get_strings, .get_sset_count = veth_get_sset_count, .get_ethtool_stats = veth_get_ethtool_stats, @@ -168,8 +129,9 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) /* don't change ip_summed == CHECKSUM_PARTIAL, as that will cause bad checksum on forwarded packets */ - if (skb->ip_summed == CHECKSUM_NONE) - skb->ip_summed = rcv_priv->ip_summed; + if (skb->ip_summed == CHECKSUM_NONE && + rcv->features & NETIF_F_RXCSUM) + skb->ip_summed = CHECKSUM_UNNECESSARY; length = skb->len; if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS) @@ -304,6 +266,8 @@ static void veth_setup(struct net_device *dev) dev->ethtool_ops = &veth_ethtool_ops; dev->features |= NETIF_F_LLTX; dev->destructor = veth_dev_free; + + dev->hw_features = NETIF_F_NO_CSUM | NETIF_F_SG | NETIF_F_RXCSUM; } /* @@ -403,6 +367,17 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, if (tb[IFLA_ADDRESS] == NULL) random_ether_addr(dev->dev_addr); + if (tb[IFLA_IFNAME]) + nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ); + else + snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d"); + + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto err_alloc_name; + } + err = register_netdevice(dev); if (err < 0) goto err_register_dev; @@ -422,6 +397,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, err_register_dev: /* nothing to do */ +err_alloc_name: err_configure_peer: unregister_netdevice(peer); return err; diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index eb5d75df5d5d..7f23ab913fd9 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -29,6 +29,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DRV_NAME "via-rhine" #define DRV_VERSION "1.5.0" #define DRV_RELDATE "2010-10-09" @@ -37,6 +39,7 @@ /* A few user-configurable values. These may be modified when a driver module is loaded. */ +#define DEBUG static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int max_interrupt_work = 20; @@ -111,8 +114,7 @@ static const int multicast_filter_limit = 32; /* These identify the driver base version and may not be removed. */ static const char version[] __devinitconst = - KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION " " DRV_RELDATE - " Written by Donald Becker\n"; + "v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker"; /* This driver was written to use PCI memory space. Some early versions of the Rhine may only work correctly with I/O space accesses. */ @@ -495,14 +497,15 @@ static void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask); static void rhine_init_cam_filter(struct net_device *dev); static void rhine_update_vcam(struct net_device *dev); -#define RHINE_WAIT_FOR(condition) do { \ - int i=1024; \ - while (!(condition) && --i) \ - ; \ - if (debug > 1 && i < 512) \ - printk(KERN_INFO "%s: %4d cycles used @ %s:%d\n", \ - DRV_NAME, 1024-i, __func__, __LINE__); \ -} while(0) +#define RHINE_WAIT_FOR(condition) \ +do { \ + int i = 1024; \ + while (!(condition) && --i) \ + ; \ + if (debug > 1 && i < 512) \ + pr_info("%4d cycles used @ %s:%d\n", \ + 1024 - i, __func__, __LINE__); \ +} while (0) static inline u32 get_intr_status(struct net_device *dev) { @@ -571,8 +574,8 @@ static void rhine_power_init(struct net_device *dev) default: reason = "Unknown"; } - printk(KERN_INFO "%s: Woke system up. Reason: %s.\n", - DRV_NAME, reason); + netdev_info(dev, "Woke system up. Reason: %s\n", + reason); } } } @@ -586,8 +589,7 @@ static void rhine_chip_reset(struct net_device *dev) IOSYNC; if (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) { - printk(KERN_INFO "%s: Reset not complete yet. " - "Trying harder.\n", DRV_NAME); + netdev_info(dev, "Reset not complete yet. Trying harder.\n"); /* Force reset */ if (rp->quirks & rqForceReset) @@ -598,9 +600,9 @@ static void rhine_chip_reset(struct net_device *dev) } if (debug > 1) - printk(KERN_INFO "%s: Reset %s.\n", dev->name, - (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) ? - "failed" : "succeeded"); + netdev_info(dev, "Reset %s\n", + (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) ? + "failed" : "succeeded"); } #ifdef USE_MMIO @@ -728,9 +730,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, /* when built into the kernel, we only print version if device is found */ #ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(version); + pr_info_once("%s\n", version); #endif io_size = 256; @@ -765,8 +765,8 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, /* this should always be supported */ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - printk(KERN_ERR "32-bit PCI DMA addresses not supported by " - "the card!?\n"); + dev_err(&pdev->dev, + "32-bit PCI DMA addresses not supported by the card!?\n"); goto err_out; } @@ -774,7 +774,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if ((pci_resource_len(pdev, 0) < io_size) || (pci_resource_len(pdev, 1) < io_size)) { rc = -EIO; - printk(KERN_ERR "Insufficient PCI resources, aborting\n"); + dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n"); goto err_out; } @@ -786,7 +786,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, dev = alloc_etherdev(sizeof(struct rhine_private)); if (!dev) { rc = -ENOMEM; - printk(KERN_ERR "alloc_etherdev failed\n"); + dev_err(&pdev->dev, "alloc_etherdev failed\n"); goto err_out; } SET_NETDEV_DEV(dev, &pdev->dev); @@ -804,8 +804,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, ioaddr = pci_iomap(pdev, bar, io_size); if (!ioaddr) { rc = -EIO; - printk(KERN_ERR "ioremap failed for device %s, region 0x%X " - "@ 0x%lX\n", pci_name(pdev), io_size, memaddr); + dev_err(&pdev->dev, + "ioremap failed for device %s, region 0x%X @ 0x%lX\n", + pci_name(pdev), io_size, memaddr); goto err_out_free_res; } @@ -820,8 +821,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, unsigned char b = readb(ioaddr+reg); if (a != b) { rc = -EIO; - printk(KERN_ERR "MMIO do not match PIO [%02x] " - "(%02x != %02x)\n", reg, a, b); + dev_err(&pdev->dev, + "MMIO do not match PIO [%02x] (%02x != %02x)\n", + reg, a, b); goto err_out_unmap; } } @@ -836,13 +838,15 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, for (i = 0; i < 6; i++) dev->dev_addr[i] = ioread8(ioaddr + StationAddr + i); - memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - if (!is_valid_ether_addr(dev->perm_addr)) { - rc = -EIO; - printk(KERN_ERR "Invalid MAC address\n"); - goto err_out_unmap; + if (!is_valid_ether_addr(dev->dev_addr)) { + /* Report it and use a random ethernet address instead */ + netdev_err(dev, "Invalid MAC address: %pM\n", dev->dev_addr); + random_ether_addr(dev->dev_addr); + netdev_info(dev, "Using random MAC address: %pM\n", + dev->dev_addr); } + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* For Rhine-I/II, phy_id is loaded from EEPROM */ if (!phy_id) @@ -878,14 +882,14 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (rc) goto err_out_unmap; - printk(KERN_INFO "%s: VIA %s at 0x%lx, %pM, IRQ %d.\n", - dev->name, name, + netdev_info(dev, "VIA %s at 0x%lx, %pM, IRQ %d\n", + name, #ifdef USE_MMIO - memaddr, + memaddr, #else - (long)ioaddr, + (long)ioaddr, #endif - dev->dev_addr, pdev->irq); + dev->dev_addr, pdev->irq); pci_set_drvdata(pdev, dev); @@ -896,11 +900,11 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, mdio_write(dev, phy_id, MII_BMCR, mii_cmd); if (mii_status != 0xffff && mii_status != 0x0000) { rp->mii_if.advertising = mdio_read(dev, phy_id, 4); - printk(KERN_INFO "%s: MII PHY found at address " - "%d, status 0x%4.4x advertising %4.4x " - "Link %4.4x.\n", dev->name, phy_id, - mii_status, rp->mii_if.advertising, - mdio_read(dev, phy_id, 5)); + netdev_info(dev, + "MII PHY found at address %d, status 0x%04x advertising %04x Link %04x\n", + phy_id, + mii_status, rp->mii_if.advertising, + mdio_read(dev, phy_id, 5)); /* set IFF_RUNNING */ if (mii_status & BMSR_LSTATUS) @@ -912,8 +916,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, } rp->mii_if.phy_id = phy_id; if (debug > 1 && avoid_D3) - printk(KERN_INFO "%s: No D3 power state at shutdown.\n", - dev->name); + netdev_info(dev, "No D3 power state at shutdown\n"); return 0; @@ -938,7 +941,7 @@ static int alloc_ring(struct net_device* dev) TX_RING_SIZE * sizeof(struct tx_desc), &ring_dma); if (!ring) { - printk(KERN_ERR "Could not allocate DMA memory.\n"); + netdev_err(dev, "Could not allocate DMA memory\n"); return -ENOMEM; } if (rp->quirks & rqRhineI) { @@ -1098,8 +1101,8 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex, ioaddr + ChipCmd1); if (debug > 1) - printk(KERN_INFO "%s: force_media %d, carrier %d\n", dev->name, - rp->mii_if.force_media, netif_carrier_ok(dev)); + netdev_info(dev, "force_media %d, carrier %d\n", + rp->mii_if.force_media, netif_carrier_ok(dev)); } /* Called after status of force_media possibly changed */ @@ -1113,9 +1116,8 @@ static void rhine_set_carrier(struct mii_if_info *mii) else /* Let MMI library update carrier status */ rhine_check_media(mii->dev, 0); if (debug > 1) - printk(KERN_INFO "%s: force_media %d, carrier %d\n", - mii->dev->name, mii->force_media, - netif_carrier_ok(mii->dev)); + netdev_info(mii->dev, "force_media %d, carrier %d\n", + mii->force_media, netif_carrier_ok(mii->dev)); } /** @@ -1402,8 +1404,7 @@ static int rhine_open(struct net_device *dev) return rc; if (debug > 1) - printk(KERN_DEBUG "%s: rhine_open() irq %d.\n", - dev->name, rp->pdev->irq); + netdev_dbg(dev, "%s() irq %d\n", __func__, rp->pdev->irq); rc = alloc_ring(dev); if (rc) { @@ -1415,10 +1416,9 @@ static int rhine_open(struct net_device *dev) rhine_chip_reset(dev); init_registers(dev); if (debug > 2) - printk(KERN_DEBUG "%s: Done rhine_open(), status %4.4x " - "MII status: %4.4x.\n", - dev->name, ioread16(ioaddr + ChipCmd), - mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); + netdev_dbg(dev, "%s() Done - status %04x MII status: %04x\n", + __func__, ioread16(ioaddr + ChipCmd), + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); netif_start_queue(dev); @@ -1461,10 +1461,9 @@ static void rhine_tx_timeout(struct net_device *dev) struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; - printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " - "%4.4x, resetting...\n", - dev->name, ioread16(ioaddr + IntrStatus), - mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); + netdev_warn(dev, "Transmit timed out, status %04x, PHY status %04x, resetting...\n", + ioread16(ioaddr + IntrStatus), + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); schedule_work(&rp->reset_task); } @@ -1551,8 +1550,8 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb, spin_unlock_irqrestore(&rp->lock, flags); if (debug > 4) { - printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", - dev->name, rp->cur_tx-1, entry); + netdev_dbg(dev, "Transmit frame #%d queued in slot %d\n", + rp->cur_tx-1, entry); } return NETDEV_TX_OK; } @@ -1578,8 +1577,8 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) IOSYNC; if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status %8.8x.\n", - dev->name, intr_status); + netdev_dbg(dev, "Interrupt, status %08x\n", + intr_status); if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped | IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) { @@ -1597,9 +1596,9 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) RHINE_WAIT_FOR(!(ioread8(ioaddr+ChipCmd) & CmdTxOn)); if (debug > 2 && ioread8(ioaddr+ChipCmd) & CmdTxOn) - printk(KERN_WARNING "%s: " - "rhine_interrupt() Tx engine " - "still on.\n", dev->name); + netdev_warn(dev, + "%s: Tx engine still on\n", + __func__); } rhine_tx(dev); } @@ -1611,16 +1610,15 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) rhine_error(dev, intr_status); if (--boguscnt < 0) { - printk(KERN_WARNING "%s: Too much work at interrupt, " - "status=%#8.8x.\n", - dev->name, intr_status); + netdev_warn(dev, "Too much work at interrupt, status=%#08x\n", + intr_status); break; } } if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, status=%8.8x.\n", - dev->name, ioread16(ioaddr + IntrStatus)); + netdev_dbg(dev, "exiting interrupt, status=%08x\n", + ioread16(ioaddr + IntrStatus)); return IRQ_RETVAL(handled); } @@ -1637,15 +1635,14 @@ static void rhine_tx(struct net_device *dev) while (rp->dirty_tx != rp->cur_tx) { txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status); if (debug > 6) - printk(KERN_DEBUG "Tx scavenge %d status %8.8x.\n", - entry, txstatus); + netdev_dbg(dev, "Tx scavenge %d status %08x\n", + entry, txstatus); if (txstatus & DescOwn) break; if (txstatus & 0x8000) { if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, " - "Tx status %8.8x.\n", - dev->name, txstatus); + netdev_dbg(dev, "Transmit error, Tx status %08x\n", + txstatus); dev->stats.tx_errors++; if (txstatus & 0x0400) dev->stats.tx_carrier_errors++; @@ -1668,9 +1665,9 @@ static void rhine_tx(struct net_device *dev) else dev->stats.collisions += txstatus & 0x0F; if (debug > 6) - printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n", - (txstatus >> 3) & 0xF, - txstatus & 0xF); + netdev_dbg(dev, "collisions: %1.1x:%1.1x\n", + (txstatus >> 3) & 0xF, + txstatus & 0xF); dev->stats.tx_bytes += rp->tx_skbuff[entry]->len; dev->stats.tx_packets++; } @@ -1703,7 +1700,7 @@ static void rhine_tx(struct net_device *dev) static inline u16 rhine_get_vlan_tci(struct sk_buff *skb, int data_size) { u8 *trailer = (u8 *)skb->data + ((data_size + 3) & ~3) + 2; - return ntohs(*(u16 *)trailer); + return be16_to_cpup((__be16 *)trailer); } /* Process up to limit frames from receive ring */ @@ -1714,9 +1711,9 @@ static int rhine_rx(struct net_device *dev, int limit) int entry = rp->cur_rx % RX_RING_SIZE; if (debug > 4) { - printk(KERN_DEBUG "%s: rhine_rx(), entry %d status %8.8x.\n", - dev->name, entry, - le32_to_cpu(rp->rx_head_desc->rx_status)); + netdev_dbg(dev, "%s(), entry %d status %08x\n", + __func__, entry, + le32_to_cpu(rp->rx_head_desc->rx_status)); } /* If EOP is set on the next entry, it's a new packet. Send it up. */ @@ -1730,26 +1727,26 @@ static int rhine_rx(struct net_device *dev, int limit) break; if (debug > 4) - printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n", - desc_status); + netdev_dbg(dev, "%s() status is %08x\n", + __func__, desc_status); if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) { if ((desc_status & RxWholePkt) != RxWholePkt) { - printk(KERN_WARNING "%s: Oversized Ethernet " - "frame spanned multiple buffers, entry " - "%#x length %d status %8.8x!\n", - dev->name, entry, data_size, - desc_status); - printk(KERN_WARNING "%s: Oversized Ethernet " - "frame %p vs %p.\n", dev->name, - rp->rx_head_desc, &rp->rx_ring[entry]); + netdev_warn(dev, + "Oversized Ethernet frame spanned multiple buffers, " + "entry %#x length %d status %08x!\n", + entry, data_size, + desc_status); + netdev_warn(dev, + "Oversized Ethernet frame %p vs %p\n", + rp->rx_head_desc, + &rp->rx_ring[entry]); dev->stats.rx_length_errors++; } else if (desc_status & RxErr) { /* There was a error. */ if (debug > 2) - printk(KERN_DEBUG "rhine_rx() Rx " - "error was %8.8x.\n", - desc_status); + netdev_dbg(dev, "%s() Rx error was %08x\n", + __func__, desc_status); dev->stats.rx_errors++; if (desc_status & 0x0030) dev->stats.rx_length_errors++; @@ -1791,9 +1788,7 @@ static int rhine_rx(struct net_device *dev, int limit) } else { skb = rp->rx_skbuff[entry]; if (skb == NULL) { - printk(KERN_ERR "%s: Inconsistent Rx " - "descriptor chain.\n", - dev->name); + netdev_err(dev, "Inconsistent Rx descriptor chain\n"); break; } rp->rx_skbuff[entry] = NULL; @@ -1886,9 +1881,8 @@ static void rhine_restart_tx(struct net_device *dev) { else { /* This should never happen */ if (debug > 1) - printk(KERN_WARNING "%s: rhine_restart_tx() " - "Another error occurred %8.8x.\n", - dev->name, intr_status); + netdev_warn(dev, "%s() Another error occurred %08x\n", + __func__, intr_status); } } @@ -1909,21 +1903,19 @@ static void rhine_error(struct net_device *dev, int intr_status) } if (intr_status & IntrTxAborted) { if (debug > 1) - printk(KERN_INFO "%s: Abort %8.8x, frame dropped.\n", - dev->name, intr_status); + netdev_info(dev, "Abort %08x, frame dropped\n", + intr_status); } if (intr_status & IntrTxUnderrun) { if (rp->tx_thresh < 0xE0) BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig); if (debug > 1) - printk(KERN_INFO "%s: Transmitter underrun, Tx " - "threshold now %2.2x.\n", - dev->name, rp->tx_thresh); + netdev_info(dev, "Transmitter underrun, Tx threshold now %02x\n", + rp->tx_thresh); } if (intr_status & IntrTxDescRace) { if (debug > 2) - printk(KERN_INFO "%s: Tx descriptor write-back race.\n", - dev->name); + netdev_info(dev, "Tx descriptor write-back race\n"); } if ((intr_status & IntrTxError) && (intr_status & (IntrTxAborted | @@ -1932,9 +1924,8 @@ static void rhine_error(struct net_device *dev, int intr_status) BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig); } if (debug > 1) - printk(KERN_INFO "%s: Unspecified error. Tx " - "threshold now %2.2x.\n", - dev->name, rp->tx_thresh); + netdev_info(dev, "Unspecified error. Tx threshold now %02x\n", + rp->tx_thresh); } if (intr_status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace | IntrTxError)) @@ -1944,8 +1935,8 @@ static void rhine_error(struct net_device *dev, int intr_status) IntrTxError | IntrTxAborted | IntrNormalSummary | IntrTxDescRace)) { if (debug > 1) - printk(KERN_ERR "%s: Something Wicked happened! " - "%8.8x.\n", dev->name, intr_status); + netdev_err(dev, "Something Wicked happened! %08x\n", + intr_status); } spin_unlock(&rp->lock); @@ -2145,9 +2136,8 @@ static int rhine_close(struct net_device *dev) spin_lock_irq(&rp->lock); if (debug > 1) - printk(KERN_DEBUG "%s: Shutting down ethercard, " - "status was %4.4x.\n", - dev->name, ioread16(ioaddr + ChipCmd)); + netdev_dbg(dev, "Shutting down ethercard, status was %04x\n", + ioread16(ioaddr + ChipCmd)); /* Switch to loopback mode to avoid hardware races. */ iowrite8(rp->tx_thresh | 0x02, ioaddr + TxConfig); @@ -2265,12 +2255,12 @@ static int rhine_resume(struct pci_dev *pdev) return 0; if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev)) - printk(KERN_ERR "via-rhine %s: request_irq failed\n", dev->name); + netdev_err(dev, "request_irq failed\n"); ret = pci_set_power_state(pdev, PCI_D0); if (debug > 1) - printk(KERN_INFO "%s: Entering power state D0 %s (%d).\n", - dev->name, ret ? "failed" : "succeeded", ret); + netdev_info(dev, "Entering power state D0 %s (%d)\n", + ret ? "failed" : "succeeded", ret); pci_restore_state(pdev); @@ -2326,17 +2316,15 @@ static int __init rhine_init(void) { /* when a module, this is printed whether or not devices are found in probe */ #ifdef MODULE - printk(version); + pr_info("%s\n", version); #endif if (dmi_check_system(rhine_dmi_table)) { /* these BIOSes fail at PXE boot if chip is in D3 */ avoid_D3 = 1; - printk(KERN_WARNING "%s: Broken BIOS detected, avoid_D3 " - "enabled.\n", - DRV_NAME); + pr_warn("Broken BIOS detected, avoid_D3 enabled\n"); } else if (avoid_D3) - printk(KERN_INFO "%s: avoid_D3 set.\n", DRV_NAME); + pr_info("avoid_D3 set\n"); return pci_register_driver(&rhine_driver); } diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 4fe051753842..06daa9d6fee8 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2600,8 +2600,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, /* * Handle hardware checksum */ - if ((dev->features & NETIF_F_IP_CSUM) && - (skb->ip_summed == CHECKSUM_PARTIAL)) { + if (skb->ip_summed == CHECKSUM_PARTIAL) { const struct iphdr *ip = ip_hdr(skb); if (ip->protocol == IPPROTO_TCP) td_ptr->tdesc1.TCR |= TCR0_TCPCK; @@ -2841,6 +2840,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi dev->ethtool_ops = &velocity_ethtool_ops; netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT); + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HW_VLAN_TX; dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM; @@ -3182,7 +3182,8 @@ static void velocity_ethtool_down(struct net_device *dev) pci_set_power_state(vptr->pdev, PCI_D3hot); } -static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int velocity_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) { struct velocity_info *vptr = netdev_priv(dev); struct mac_regs __iomem *regs = vptr->mac_regs; @@ -3228,12 +3229,14 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd break; } } + if (status & VELOCITY_SPEED_1000) - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); else if (status & VELOCITY_SPEED_100) - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); else - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); + cmd->autoneg = (status & VELOCITY_AUTONEG_ENABLE) ? AUTONEG_ENABLE : AUTONEG_DISABLE; cmd->port = PORT_TP; cmd->transceiver = XCVR_INTERNAL; @@ -3247,9 +3250,11 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd return 0; } -static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int velocity_set_settings(struct net_device *dev, + struct ethtool_cmd *cmd) { struct velocity_info *vptr = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(cmd); u32 curr_status; u32 new_status = 0; int ret = 0; @@ -3258,9 +3263,9 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd curr_status &= (~VELOCITY_LINK_FAIL); new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0); - new_status |= ((cmd->speed == SPEED_1000) ? VELOCITY_SPEED_1000 : 0); - new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0); - new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0); + new_status |= ((speed == SPEED_1000) ? VELOCITY_SPEED_1000 : 0); + new_status |= ((speed == SPEED_100) ? VELOCITY_SPEED_100 : 0); + new_status |= ((speed == SPEED_10) ? VELOCITY_SPEED_10 : 0); new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0); if ((new_status & VELOCITY_AUTONEG_ENABLE) && @@ -3457,13 +3462,10 @@ static const struct ethtool_ops velocity_ethtool_ops = { .get_settings = velocity_get_settings, .set_settings = velocity_set_settings, .get_drvinfo = velocity_get_drvinfo, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .get_wol = velocity_ethtool_get_wol, .set_wol = velocity_ethtool_set_wol, .get_msglevel = velocity_get_msglevel, .set_msglevel = velocity_set_msglevel, - .set_sg = ethtool_op_set_sg, .get_link = velocity_get_link, .get_coalesce = velocity_get_coalesce, .set_coalesce = velocity_set_coalesce, diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 82dba5aaf423..0cb0b0632672 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -710,17 +710,6 @@ static int virtnet_close(struct net_device *dev) return 0; } -static int virtnet_set_tx_csum(struct net_device *dev, u32 data) -{ - struct virtnet_info *vi = netdev_priv(dev); - struct virtio_device *vdev = vi->vdev; - - if (data && !virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) - return -ENOSYS; - - return ethtool_op_set_tx_hw_csum(dev, data); -} - static void virtnet_set_rx_mode(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); @@ -822,10 +811,6 @@ static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid) } static const struct ethtool_ops virtnet_ethtool_ops = { - .set_tx_csum = virtnet_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, - .set_ufo = ethtool_op_set_ufo, .get_link = ethtool_op_get_link, }; @@ -912,22 +897,29 @@ static int virtnet_probe(struct virtio_device *vdev) SET_NETDEV_DEV(dev, &vdev->dev); /* Do we support "hardware" checksums? */ - if (csum && virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { + if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { /* This opens up the world of extra features. */ - dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { - dev->features |= NETIF_F_TSO | NETIF_F_UFO + dev->hw_features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + if (csum) + dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + + if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { + dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO | NETIF_F_TSO_ECN | NETIF_F_TSO6; } /* Individual feature bits: what can host handle? */ - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4)) - dev->features |= NETIF_F_TSO; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6)) - dev->features |= NETIF_F_TSO6; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN)) - dev->features |= NETIF_F_TSO_ECN; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO)) - dev->features |= NETIF_F_UFO; + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4)) + dev->hw_features |= NETIF_F_TSO; + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6)) + dev->hw_features |= NETIF_F_TSO6; + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN)) + dev->hw_features |= NETIF_F_TSO_ECN; + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO)) + dev->hw_features |= NETIF_F_UFO; + + if (gso) + dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO); + /* (!csum && gso) case will be fixed by register_netdev() */ } /* Configuration may specify what MAC to use. Otherwise random. */ diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 0d47c3a05307..fa6e2ac7475a 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -178,6 +178,7 @@ static void vmxnet3_process_events(struct vmxnet3_adapter *adapter) { int i; + unsigned long flags; u32 events = le32_to_cpu(adapter->shared->ecr); if (!events) return; @@ -190,10 +191,10 @@ vmxnet3_process_events(struct vmxnet3_adapter *adapter) /* Check if there is an error on xmit/recv queues */ if (events & (VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR)) { - spin_lock(&adapter->cmd_lock); + spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_QUEUE_STATUS); - spin_unlock(&adapter->cmd_lock); + spin_unlock_irqrestore(&adapter->cmd_lock, flags); for (i = 0; i < adapter->num_tx_queues; i++) if (adapter->tqd_start[i].status.stopped) @@ -1082,7 +1083,7 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter, struct sk_buff *skb, union Vmxnet3_GenericDesc *gdesc) { - if (!gdesc->rcd.cnc && adapter->rxcsum) { + if (!gdesc->rcd.cnc && adapter->netdev->features & NETIF_F_RXCSUM) { /* typical case: TCP/UDP over IP and both csums are correct */ if ((le32_to_cpu(gdesc->dword[3]) & VMXNET3_RCD_CSUM_OK) == VMXNET3_RCD_CSUM_OK) { @@ -2081,10 +2082,10 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter) devRead->misc.ddLen = cpu_to_le32(sizeof(struct vmxnet3_adapter)); /* set up feature flags */ - if (adapter->rxcsum) + if (adapter->netdev->features & NETIF_F_RXCSUM) devRead->misc.uptFeatures |= UPT1_F_RXCSUM; - if (adapter->lro) { + if (adapter->netdev->features & NETIF_F_LRO) { devRead->misc.uptFeatures |= UPT1_F_LRO; devRead->misc.maxNumRxSG = cpu_to_le16(1 + MAX_SKB_FRAGS); } @@ -2593,9 +2594,6 @@ vmxnet3_change_mtu(struct net_device *netdev, int new_mtu) if (new_mtu < VMXNET3_MIN_MTU || new_mtu > VMXNET3_MAX_MTU) return -EINVAL; - if (new_mtu > 1500 && !adapter->jumbo_frame) - return -EINVAL; - netdev->mtu = new_mtu; /* @@ -2641,28 +2639,18 @@ vmxnet3_declare_features(struct vmxnet3_adapter *adapter, bool dma64) { struct net_device *netdev = adapter->netdev; - netdev->features = NETIF_F_SG | - NETIF_F_HW_CSUM | - NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER | - NETIF_F_TSO | - NETIF_F_TSO6 | - NETIF_F_LRO; - - printk(KERN_INFO "features: sg csum vlan jf tso tsoIPv6 lro"); - - adapter->rxcsum = true; - adapter->jumbo_frame = true; - adapter->lro = true; - - if (dma64) { + netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX | + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_LRO; + if (dma64) netdev->features |= NETIF_F_HIGHDMA; - printk(" highDMA"); - } + netdev->vlan_features = netdev->hw_features & ~NETIF_F_HW_VLAN_TX; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; - netdev->vlan_features = netdev->features; - printk("\n"); + netdev_info(adapter->netdev, + "features: sg csum vlan jf tso tsoIPv6 lro%s\n", + dma64 ? " highDMA" : ""); } @@ -2733,13 +2721,14 @@ static void vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter) { u32 cfg; + unsigned long flags; /* intr settings */ - spin_lock(&adapter->cmd_lock); + spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_CONF_INTR); cfg = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD); - spin_unlock(&adapter->cmd_lock); + spin_unlock_irqrestore(&adapter->cmd_lock, flags); adapter->intr.type = cfg & 0x3; adapter->intr.mask_mode = (cfg >> 2) & 0x3; @@ -2874,6 +2863,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, .ndo_start_xmit = vmxnet3_xmit_frame, .ndo_set_mac_address = vmxnet3_set_mac_addr, .ndo_change_mtu = vmxnet3_change_mtu, + .ndo_set_features = vmxnet3_set_features, .ndo_get_stats = vmxnet3_get_stats, .ndo_tx_timeout = vmxnet3_tx_timeout, .ndo_set_multicast_list = vmxnet3_set_mc, @@ -2894,6 +2884,9 @@ vmxnet3_probe_device(struct pci_dev *pdev, int num_tx_queues; int num_rx_queues; + if (!pci_msi_enabled()) + enable_mq = 0; + #ifdef VMXNET3_RSS if (enable_mq) num_rx_queues = min(VMXNET3_DEVICE_MAX_RX_QUEUES, diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 51f2ef142a5b..dc959fe27aa5 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -33,40 +33,6 @@ struct vmxnet3_stat_desc { }; -static u32 -vmxnet3_get_rx_csum(struct net_device *netdev) -{ - struct vmxnet3_adapter *adapter = netdev_priv(netdev); - return adapter->rxcsum; -} - - -static int -vmxnet3_set_rx_csum(struct net_device *netdev, u32 val) -{ - struct vmxnet3_adapter *adapter = netdev_priv(netdev); - unsigned long flags; - - if (adapter->rxcsum != val) { - adapter->rxcsum = val; - if (netif_running(netdev)) { - if (val) - adapter->shared->devRead.misc.uptFeatures |= - UPT1_F_RXCSUM; - else - adapter->shared->devRead.misc.uptFeatures &= - ~UPT1_F_RXCSUM; - - spin_lock_irqsave(&adapter->cmd_lock, flags); - VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, - VMXNET3_CMD_UPDATE_FEATURE); - spin_unlock_irqrestore(&adapter->cmd_lock, flags); - } - } - return 0; -} - - /* per tq stats maintained by the device */ static const struct vmxnet3_stat_desc vmxnet3_tq_dev_stats[] = { @@ -296,28 +262,28 @@ vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) } } -static int -vmxnet3_set_flags(struct net_device *netdev, u32 data) +int vmxnet3_set_features(struct net_device *netdev, u32 features) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); - u8 lro_requested = (data & ETH_FLAG_LRO) == 0 ? 0 : 1; - u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1; unsigned long flags; + u32 changed = features ^ netdev->features; - if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) - return -EINVAL; - - if (lro_requested ^ lro_present) { - /* toggle the LRO feature*/ - netdev->features ^= NETIF_F_LRO; + if (changed & (NETIF_F_RXCSUM|NETIF_F_LRO)) { + if (features & NETIF_F_RXCSUM) + adapter->shared->devRead.misc.uptFeatures |= + UPT1_F_RXCSUM; + else + adapter->shared->devRead.misc.uptFeatures &= + ~UPT1_F_RXCSUM; /* update harware LRO capability accordingly */ - if (lro_requested) + if (features & NETIF_F_LRO) adapter->shared->devRead.misc.uptFeatures |= UPT1_F_LRO; else adapter->shared->devRead.misc.uptFeatures &= ~UPT1_F_LRO; + spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_FEATURE); @@ -459,10 +425,10 @@ vmxnet3_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->transceiver = XCVR_INTERNAL; if (adapter->link_speed) { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } return 0; @@ -654,17 +620,7 @@ static struct ethtool_ops vmxnet3_ethtool_ops = { .get_wol = vmxnet3_get_wol, .set_wol = vmxnet3_set_wol, .get_link = ethtool_op_get_link, - .get_rx_csum = vmxnet3_get_rx_csum, - .set_rx_csum = vmxnet3_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, .get_strings = vmxnet3_get_strings, - .get_flags = ethtool_op_get_flags, - .set_flags = vmxnet3_set_flags, .get_sset_count = vmxnet3_get_sset_count, .get_ethtool_stats = vmxnet3_get_ethtool_stats, .get_ringparam = vmxnet3_get_ringparam, diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index fb5d245ac878..f50d36fdf405 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -68,10 +68,10 @@ /* * Version numbers */ -#define VMXNET3_DRIVER_VERSION_STRING "1.0.25.0-k" +#define VMXNET3_DRIVER_VERSION_STRING "1.1.9.0-k" /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01001900 +#define VMXNET3_DRIVER_VERSION_NUM 0x01010900 #if defined(CONFIG_PCI_MSI) /* RSS only makes sense if MSI-X is supported. */ @@ -329,10 +329,6 @@ struct vmxnet3_adapter { u8 __iomem *hw_addr0; /* for BAR 0 */ u8 __iomem *hw_addr1; /* for BAR 1 */ - /* feature control */ - bool rxcsum; - bool lro; - bool jumbo_frame; #ifdef VMXNET3_RSS struct UPT1_RSSConf *rss_conf; bool rss; @@ -403,6 +399,9 @@ vmxnet3_tq_destroy_all(struct vmxnet3_adapter *adapter); void vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter); +int +vmxnet3_set_features(struct net_device *netdev, u32 features); + int vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size, u32 rx_ring_size, u32 rx_ring2_size); diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 401bebf59502..32763b2dd73f 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -159,16 +159,15 @@ vxge_hw_vpath_fw_api(struct __vxge_hw_virtualpath *vpath, u32 action, u32 fw_memo, u32 offset, u64 *data0, u64 *data1, u64 *steer_ctrl) { - struct vxge_hw_vpath_reg __iomem *vp_reg; + struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg; enum vxge_hw_status status; u64 val64; - u32 retry = 0, max_retry = 100; + u32 retry = 0, max_retry = 3; - vp_reg = vpath->vp_reg; - - if (vpath->vp_open) { - max_retry = 3; - spin_lock(&vpath->lock); + spin_lock(&vpath->lock); + if (!vpath->vp_open) { + spin_unlock(&vpath->lock); + max_retry = 100; } writeq(*data0, &vp_reg->rts_access_steer_data0); @@ -1000,7 +999,7 @@ __vxge_hw_vpath_addr_get(struct __vxge_hw_virtualpath *vpath, /** * vxge_hw_device_hw_info_get - Get the hw information * Returns the vpath mask that has the bits set for each vpath allocated - * for the driver, FW version information and the first mac addresse for + * for the driver, FW version information, and the first mac address for * each vpath */ enum vxge_hw_status __devinit @@ -1064,9 +1063,10 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, val64 = readq(&toc->toc_vpath_pointer[i]); + spin_lock_init(&vpath.lock); vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *) (bar0 + val64); - vpath.vp_open = 0; + vpath.vp_open = VXGE_HW_VP_NOT_OPEN; status = __vxge_hw_vpath_pci_func_mode_get(&vpath, hw_info); if (status != VXGE_HW_OK) @@ -1090,7 +1090,7 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, val64 = readq(&toc->toc_vpath_pointer[i]); vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *) (bar0 + val64); - vpath.vp_open = 0; + vpath.vp_open = VXGE_HW_VP_NOT_OPEN; status = __vxge_hw_vpath_addr_get(&vpath, hw_info->mac_addrs[i], @@ -4646,7 +4646,27 @@ static void __vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id) vpath->hldev->tim_int_mask1, vpath->vp_id); hldev->stats.hw_dev_info_stats.vpath_info[vpath->vp_id] = NULL; - memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath)); + /* If the whole struct __vxge_hw_virtualpath is zeroed, nothing will + * work after the interface is brought down. + */ + spin_lock(&vpath->lock); + vpath->vp_open = VXGE_HW_VP_NOT_OPEN; + spin_unlock(&vpath->lock); + + vpath->vpmgmt_reg = NULL; + vpath->nofl_db = NULL; + vpath->max_mtu = 0; + vpath->vsport_number = 0; + vpath->max_kdfc_db = 0; + vpath->max_nofl_db = 0; + vpath->ringh = NULL; + vpath->fifoh = NULL; + memset(&vpath->vpath_handles, 0, sizeof(struct list_head)); + vpath->stats_block = 0; + vpath->hw_stats = NULL; + vpath->hw_stats_sav = NULL; + vpath->sw_stats = NULL; + exit: return; } @@ -4670,7 +4690,7 @@ __vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id, vpath = &hldev->virtual_paths[vp_id]; - spin_lock_init(&hldev->virtual_paths[vp_id].lock); + spin_lock_init(&vpath->lock); vpath->vp_id = vp_id; vpath->vp_open = VXGE_HW_VP_OPEN; vpath->hldev = hldev; @@ -5019,10 +5039,6 @@ enum vxge_hw_status vxge_hw_vpath_close(struct __vxge_hw_vpath_handle *vp) __vxge_hw_vp_terminate(devh, vp_id); - spin_lock(&vpath->lock); - vpath->vp_open = VXGE_HW_VP_NOT_OPEN; - spin_unlock(&vpath->lock); - vpath_close_exit: return status; } diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index 3c53aa732c9d..359b9b9f8041 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -412,44 +412,48 @@ struct vxge_hw_vp_config { * See also: struct vxge_hw_tim_intr_config{}. */ struct vxge_hw_device_config { - u32 dma_blockpool_initial; - u32 dma_blockpool_max; -#define VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE 0 -#define VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE 0 -#define VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE 4 -#define VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE 4096 + u32 device_poll_millis; +#define VXGE_HW_MIN_DEVICE_POLL_MILLIS 1 +#define VXGE_HW_MAX_DEVICE_POLL_MILLIS 100000 +#define VXGE_HW_DEF_DEVICE_POLL_MILLIS 1000 -#define VXGE_HW_MAX_PAYLOAD_SIZE_512 2 + u32 dma_blockpool_initial; + u32 dma_blockpool_max; +#define VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE 0 +#define VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE 0 +#define VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE 4 +#define VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE 4096 - u32 intr_mode; -#define VXGE_HW_INTR_MODE_IRQLINE 0 -#define VXGE_HW_INTR_MODE_MSIX 1 -#define VXGE_HW_INTR_MODE_MSIX_ONE_SHOT 2 +#define VXGE_HW_MAX_PAYLOAD_SIZE_512 2 -#define VXGE_HW_INTR_MODE_DEF 0 + u32 intr_mode:2, +#define VXGE_HW_INTR_MODE_IRQLINE 0 +#define VXGE_HW_INTR_MODE_MSIX 1 +#define VXGE_HW_INTR_MODE_MSIX_ONE_SHOT 2 - u32 rth_en; -#define VXGE_HW_RTH_DISABLE 0 -#define VXGE_HW_RTH_ENABLE 1 -#define VXGE_HW_RTH_DEFAULT 0 +#define VXGE_HW_INTR_MODE_DEF 0 - u32 rth_it_type; -#define VXGE_HW_RTH_IT_TYPE_SOLO_IT 0 -#define VXGE_HW_RTH_IT_TYPE_MULTI_IT 1 -#define VXGE_HW_RTH_IT_TYPE_DEFAULT 0 + rth_en:1, +#define VXGE_HW_RTH_DISABLE 0 +#define VXGE_HW_RTH_ENABLE 1 +#define VXGE_HW_RTH_DEFAULT 0 - u32 rts_mac_en; + rth_it_type:1, +#define VXGE_HW_RTH_IT_TYPE_SOLO_IT 0 +#define VXGE_HW_RTH_IT_TYPE_MULTI_IT 1 +#define VXGE_HW_RTH_IT_TYPE_DEFAULT 0 + + rts_mac_en:1, #define VXGE_HW_RTS_MAC_DISABLE 0 #define VXGE_HW_RTS_MAC_ENABLE 1 #define VXGE_HW_RTS_MAC_DEFAULT 0 - struct vxge_hw_vp_config vp_config[VXGE_HW_MAX_VIRTUAL_PATHS]; - - u32 device_poll_millis; -#define VXGE_HW_MIN_DEVICE_POLL_MILLIS 1 -#define VXGE_HW_MAX_DEVICE_POLL_MILLIS 100000 -#define VXGE_HW_DEF_DEVICE_POLL_MILLIS 1000 + hwts_en:1; +#define VXGE_HW_HWTS_DISABLE 0 +#define VXGE_HW_HWTS_ENABLE 1 +#define VXGE_HW_HWTS_DEFAULT 1 + struct vxge_hw_vp_config vp_config[VXGE_HW_MAX_VIRTUAL_PATHS]; }; /** diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index c5eb034107fd..92dd72d3f9de 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c @@ -33,7 +33,8 @@ static int vxge_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info) { /* We currently only support 10Gb/FULL */ if ((info->autoneg == AUTONEG_ENABLE) || - (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL)) + (ethtool_cmd_speed(info) != SPEED_10000) || + (info->duplex != DUPLEX_FULL)) return -EINVAL; return 0; @@ -58,10 +59,10 @@ static int vxge_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) info->transceiver = XCVR_EXTERNAL; if (netif_carrier_ok(dev)) { - info->speed = SPEED_10000; + ethtool_cmd_speed_set(info, SPEED_10000); info->duplex = DUPLEX_FULL; } else { - info->speed = -1; + ethtool_cmd_speed_set(info, -1); info->duplex = -1; } @@ -134,22 +135,29 @@ static void vxge_ethtool_gregs(struct net_device *dev, /** * vxge_ethtool_idnic - To physically identify the nic on the system. * @dev : device pointer. - * @id : pointer to the structure with identification parameters given by - * ethtool. + * @state : requested LED state * * Used to physically identify the NIC on the system. - * The Link LED will blink for a time specified by the user. - * Return value: * 0 on success */ -static int vxge_ethtool_idnic(struct net_device *dev, u32 data) +static int vxge_ethtool_idnic(struct net_device *dev, + enum ethtool_phys_id_state state) { struct vxgedev *vdev = netdev_priv(dev); struct __vxge_hw_device *hldev = vdev->devh; - vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON); - msleep_interruptible(data ? (data * HZ) : VXGE_MAX_FLICKER_TIME); - vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_OFF); + switch (state) { + case ETHTOOL_ID_ACTIVE: + vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON); + break; + + case ETHTOOL_ID_INACTIVE: + vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_OFF); + break; + + default: + return -EINVAL; + } return 0; } @@ -1064,35 +1072,6 @@ static int vxge_ethtool_get_regs_len(struct net_device *dev) return sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath; } -static u32 vxge_get_rx_csum(struct net_device *dev) -{ - struct vxgedev *vdev = netdev_priv(dev); - - return vdev->rx_csum; -} - -static int vxge_set_rx_csum(struct net_device *dev, u32 data) -{ - struct vxgedev *vdev = netdev_priv(dev); - - if (data) - vdev->rx_csum = 1; - else - vdev->rx_csum = 0; - - return 0; -} - -static int vxge_ethtool_op_set_tso(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset) { struct vxgedev *vdev = netdev_priv(dev); @@ -1112,40 +1091,6 @@ static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset) } } -static int vxge_set_flags(struct net_device *dev, u32 data) -{ - struct vxgedev *vdev = netdev_priv(dev); - enum vxge_hw_status status; - - if (ethtool_invalid_flags(dev, data, ETH_FLAG_RXHASH)) - return -EINVAL; - - if (!!(data & ETH_FLAG_RXHASH) == vdev->devh->config.rth_en) - return 0; - - if (netif_running(dev) || (vdev->config.rth_steering == NO_STEERING)) - return -EINVAL; - - vdev->devh->config.rth_en = !!(data & ETH_FLAG_RXHASH); - - /* Enabling RTH requires some of the logic in vxge_device_register and a - * vpath reset. Due to these restrictions, only allow modification - * while the interface is down. - */ - status = vxge_reset_all_vpaths(vdev); - if (status != VXGE_HW_OK) { - vdev->devh->config.rth_en = !vdev->devh->config.rth_en; - return -EFAULT; - } - - if (vdev->devh->config.rth_en) - dev->features |= NETIF_F_RXHASH; - else - dev->features &= ~NETIF_F_RXHASH; - - return 0; -} - static int vxge_fw_flash(struct net_device *dev, struct ethtool_flash *parms) { struct vxgedev *vdev = netdev_priv(dev); @@ -1174,19 +1119,10 @@ static const struct ethtool_ops vxge_ethtool_ops = { .get_link = ethtool_op_get_link, .get_pauseparam = vxge_ethtool_getpause_data, .set_pauseparam = vxge_ethtool_setpause_data, - .get_rx_csum = vxge_get_rx_csum, - .set_rx_csum = vxge_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = vxge_ethtool_op_set_tso, .get_strings = vxge_ethtool_get_strings, - .phys_id = vxge_ethtool_idnic, + .set_phys_id = vxge_ethtool_idnic, .get_sset_count = vxge_ethtool_get_sset_count, .get_ethtool_stats = vxge_get_ethtool_stats, - .set_flags = vxge_set_flags, .flash_device = vxge_fw_flash, }; diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index aff68c1118d4..fc837cf6bd4d 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -304,22 +304,14 @@ vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan, "%s: %s:%d skb protocol = %d", ring->ndev->name, __func__, __LINE__, skb->protocol); - if (ring->gro_enable) { - if (ring->vlgrp && ext_info->vlan && - (ring->vlan_tag_strip == - VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) - vlan_gro_receive(ring->napi_p, ring->vlgrp, - ext_info->vlan, skb); - else - napi_gro_receive(ring->napi_p, skb); - } else { - if (ring->vlgrp && vlan && - (ring->vlan_tag_strip == - VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) - vlan_hwaccel_receive_skb(skb, ring->vlgrp, vlan); - else - netif_receive_skb(skb); - } + if (ring->vlgrp && ext_info->vlan && + (ring->vlan_tag_strip == + VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) + vlan_gro_receive(ring->napi_p, ring->vlgrp, + ext_info->vlan, skb); + else + napi_gro_receive(ring->napi_p, skb); + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); } @@ -490,7 +482,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, if ((ext_info.proto & VXGE_HW_FRAME_PROTO_TCP_OR_UDP) && !(ext_info.proto & VXGE_HW_FRAME_PROTO_IP_FRAG) && - ring->rx_csum && /* Offload Rx side CSUM */ + (dev->features & NETIF_F_RXCSUM) && /* Offload Rx side CSUM */ ext_info.l3_cksum == VXGE_HW_L3_CKSUM_OK && ext_info.l4_cksum == VXGE_HW_L4_CKSUM_OK) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2094,11 +2086,9 @@ static int vxge_open_vpaths(struct vxgedev *vdev) vdev->config.fifo_indicate_max_pkts; vpath->fifo.tx_vector_no = 0; vpath->ring.rx_vector_no = 0; - vpath->ring.rx_csum = vdev->rx_csum; vpath->ring.rx_hwts = vdev->rx_hwts; vpath->is_open = 1; vdev->vp_handles[i] = vpath->handle; - vpath->ring.gro_enable = vdev->config.gro_enable; vpath->ring.vlan_tag_strip = vdev->vlan_tag_strip; vdev->stats.vpaths_open++; } else { @@ -2670,6 +2660,40 @@ static void vxge_poll_vp_lockup(unsigned long data) mod_timer(&vdev->vp_lockup_timer, jiffies + HZ / 1000); } +static u32 vxge_fix_features(struct net_device *dev, u32 features) +{ + u32 changed = dev->features ^ features; + + /* Enabling RTH requires some of the logic in vxge_device_register and a + * vpath reset. Due to these restrictions, only allow modification + * while the interface is down. + */ + if ((changed & NETIF_F_RXHASH) && netif_running(dev)) + features ^= NETIF_F_RXHASH; + + return features; +} + +static int vxge_set_features(struct net_device *dev, u32 features) +{ + struct vxgedev *vdev = netdev_priv(dev); + u32 changed = dev->features ^ features; + + if (!(changed & NETIF_F_RXHASH)) + return 0; + + /* !netif_running() ensured by vxge_fix_features() */ + + vdev->devh->config.rth_en = !!(features & NETIF_F_RXHASH); + if (vxge_reset_all_vpaths(vdev) != VXGE_HW_OK) { + dev->features = features ^ NETIF_F_RXHASH; + vdev->devh->config.rth_en = !!(dev->features & NETIF_F_RXHASH); + return -EIO; + } + + return 0; +} + /** * vxge_open * @dev: pointer to the device structure. @@ -3112,8 +3136,7 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) return net_stats; } -static enum vxge_hw_status vxge_timestamp_config(struct vxgedev *vdev, - int enable) +static enum vxge_hw_status vxge_timestamp_config(struct __vxge_hw_device *devh) { enum vxge_hw_status status; u64 val64; @@ -3123,27 +3146,24 @@ static enum vxge_hw_status vxge_timestamp_config(struct vxgedev *vdev, * required for the driver to load (due to a hardware bug), * there is no need to do anything special here. */ - if (enable) - val64 = VXGE_HW_XMAC_TIMESTAMP_EN | - VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) | - VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0); - else - val64 = 0; + val64 = VXGE_HW_XMAC_TIMESTAMP_EN | + VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) | + VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0); - status = vxge_hw_mgmt_reg_write(vdev->devh, + status = vxge_hw_mgmt_reg_write(devh, vxge_hw_mgmt_reg_type_mrpcim, 0, offsetof(struct vxge_hw_mrpcim_reg, xmac_timestamp), val64); - vxge_hw_device_flush_io(vdev->devh); + vxge_hw_device_flush_io(devh); + devh->config.hwts_en = VXGE_HW_HWTS_ENABLE; return status; } static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) { struct hwtstamp_config config; - enum vxge_hw_status status; int i; if (copy_from_user(&config, data, sizeof(config))) @@ -3164,10 +3184,6 @@ static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) switch (config.rx_filter) { case HWTSTAMP_FILTER_NONE: - status = vxge_timestamp_config(vdev, 0); - if (status != VXGE_HW_OK) - return -EFAULT; - vdev->rx_hwts = 0; config.rx_filter = HWTSTAMP_FILTER_NONE; break; @@ -3186,8 +3202,7 @@ static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - status = vxge_timestamp_config(vdev, 1); - if (status != VXGE_HW_OK) + if (vdev->devh->config.hwts_en != VXGE_HW_HWTS_ENABLE) return -EFAULT; vdev->rx_hwts = 1; @@ -3378,6 +3393,8 @@ static const struct net_device_ops vxge_netdev_ops = { .ndo_do_ioctl = vxge_ioctl, .ndo_set_mac_address = vxge_set_mac_addr, .ndo_change_mtu = vxge_change_mtu, + .ndo_fix_features = vxge_fix_features, + .ndo_set_features = vxge_set_features, .ndo_vlan_rx_register = vxge_vlan_rx_register, .ndo_vlan_rx_kill_vid = vxge_vlan_rx_kill_vid, .ndo_vlan_rx_add_vid = vxge_vlan_rx_add_vid, @@ -3424,14 +3441,21 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, vdev->devh = hldev; vdev->pdev = hldev->pdev; memcpy(&vdev->config, config, sizeof(struct vxge_config)); - vdev->rx_csum = 1; /* Enable Rx CSUM by default. */ vdev->rx_hwts = 0; vdev->titan1 = (vdev->pdev->revision == VXGE_HW_TITAN1_PCI_REVISION); SET_NETDEV_DEV(ndev, &vdev->pdev->dev); - ndev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER; + ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_HW_VLAN_TX; + if (vdev->config.rth_steering != NO_STEERING) + ndev->hw_features |= NETIF_F_RXHASH; + + 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; @@ -3443,11 +3467,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, vxge_initialize_ethtool_ops(ndev); - if (vdev->config.rth_steering != NO_STEERING) { - ndev->features |= NETIF_F_RXHASH; - hldev->config.rth_en = VXGE_HW_RTH_ENABLE; - } - /* Allocate memory for vpath */ vdev->vpaths = kzalloc((sizeof(struct vxge_vpath)) * no_of_vpath, GFP_KERNEL); @@ -3459,9 +3478,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, goto _out1; } - ndev->features |= NETIF_F_SG; - - ndev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; vxge_debug_init(vxge_hw_device_trace_level_get(hldev), "%s : checksuming enabled", __func__); @@ -3471,11 +3487,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, "%s : using High DMA", __func__); } - ndev->features |= NETIF_F_TSO | NETIF_F_TSO6; - - if (vdev->config.gro_enable) - ndev->features |= NETIF_F_GRO; - ret = register_netdev(ndev); if (ret) { vxge_debug_init(vxge_hw_device_trace_level_get(hldev), @@ -4005,15 +4016,6 @@ static void __devinit vxge_print_parm(struct vxgedev *vdev, u64 vpath_mask) vdev->config.tx_steering_type = 0; } - if (vdev->config.gro_enable) { - vxge_debug_init(VXGE_ERR, - "%s: Generic receive offload enabled", - vdev->ndev->name); - } else - vxge_debug_init(VXGE_TRACE, - "%s: Generic receive offload disabled", - vdev->ndev->name); - if (vdev->config.addr_learn_en) vxge_debug_init(VXGE_TRACE, "%s: MAC Address learning enabled", vdev->ndev->name); @@ -4575,12 +4577,29 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) goto _exit4; } + /* Always enable HWTS. This will always cause the FCS to be invalid, + * due to the fact that HWTS is using the FCS as the location of the + * timestamp. The HW FCS checking will still correctly determine if + * there is a valid checksum, and the FCS is being removed by the driver + * anyway. So no fucntionality is being lost. Since it is always + * enabled, we now simply use the ioctl call to set whether or not the + * driver should be paying attention to the HWTS. + */ + if (is_privileged == VXGE_HW_OK) { + status = vxge_timestamp_config(hldev); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, "%s: HWTS enable failed", + VXGE_DRIVER_NAME); + ret = -EFAULT; + goto _exit4; + } + } + vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL); /* set private device info */ pci_set_drvdata(pdev, hldev); - ll_config->gro_enable = VXGE_GRO_ALWAYS_AGGREGATE; ll_config->fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS; ll_config->addr_learn_en = addr_learn_en; ll_config->rth_algorithm = RTH_ALG_JENKINS; diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 40474f0da576..ed120aba443d 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -168,9 +168,6 @@ struct vxge_config { #define NEW_NAPI_WEIGHT 64 int napi_weight; -#define VXGE_GRO_DONOT_AGGREGATE 0 -#define VXGE_GRO_ALWAYS_AGGREGATE 1 - int gro_enable; int intr_type; #define INTA 0 #define MSI 1 @@ -290,13 +287,11 @@ struct vxge_ring { unsigned long interrupt_count; unsigned long jiffies; - /* copy of the flag indicating whether rx_csum is to be used */ - u32 rx_csum:1, - rx_hwts:1; + /* copy of the flag indicating whether rx_hwts is to be used */ + u32 rx_hwts:1; int pkts_processed; int budget; - int gro_enable; struct napi_struct napi; struct napi_struct *napi_p; @@ -369,9 +364,8 @@ struct vxgedev { */ u16 all_multi_flg; - /* A flag indicating whether rx_csum is to be used or not. */ - u32 rx_csum:1, - rx_hwts:1, + /* A flag indicating whether rx_hwts is to be used or not. */ + u32 rx_hwts:1, titan1:1; struct vxge_msix_entry *vxge_entries; diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 6c2fc0b72af5..4a518a3b131c 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -240,7 +240,7 @@ struct vxge_hw_tim_intr_config { u32 btimer_val; #define VXGE_HW_MIN_TIM_BTIMER_VAL 0 #define VXGE_HW_MAX_TIM_BTIMER_VAL 67108864 -#define VXGE_HW_USE_FLASH_DEFAULT 0xffffffff +#define VXGE_HW_USE_FLASH_DEFAULT (~0) u32 timer_ac_en; #define VXGE_HW_TIM_TIMER_AC_ENABLE 1 diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h index 581e21525e85..b9efa28bab3e 100644 --- a/drivers/net/vxge/vxge-version.h +++ b/drivers/net/vxge/vxge-version.h @@ -16,8 +16,8 @@ #define VXGE_VERSION_MAJOR "2" #define VXGE_VERSION_MINOR "5" -#define VXGE_VERSION_FIX "2" -#define VXGE_VERSION_BUILD "22259" +#define VXGE_VERSION_FIX "3" +#define VXGE_VERSION_BUILD "22640" #define VXGE_VERSION_FOR "k" #define VXGE_FW_VER(maj, min, bld) (((maj) << 16) + ((min) << 8) + (bld)) diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 1481a446fefb..21b104db5a90 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -341,10 +341,6 @@ static int dlci_add(struct dlci_add *dlci) } } - err = dev_alloc_name(master, master->name); - if (err < 0) - goto err2; - *(short *)(master->dev_addr) = dlci->dlci; dlp = netdev_priv(master); diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 0edb535bb2b5..fc433f28c047 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -1070,7 +1070,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) hdlc_device *hdlc = dev_to_hdlc(frad); pvc_device *pvc; struct net_device *dev; - int result, used; + int used; if ((pvc = add_pvc(frad, dlci)) == NULL) { printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n", @@ -1106,13 +1106,6 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) dev->tx_queue_len = 0; dev->ml_priv = pvc; - result = dev_alloc_name(dev, dev->name); - if (result < 0) { - free_netdev(dev); - delete_unused_pvcs(hdlc); - return result; - } - if (register_netdevice(dev) != 0) { free_netdev(dev); delete_unused_pvcs(hdlc); diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 7f5bb913c8b9..eec463f99c09 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -338,10 +338,6 @@ static int lapbeth_new_device(struct net_device *dev) dev_hold(dev); lapbeth->ethdev = dev; - rc = dev_alloc_name(ndev, ndev->name); - if (rc < 0) - goto fail; - rc = -EIO; if (register_netdevice(ndev)) goto fail; diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7aeb113cbb90..f354bd4e121e 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -284,5 +284,6 @@ source "drivers/net/wireless/rtlwifi/Kconfig" source "drivers/net/wireless/wl1251/Kconfig" source "drivers/net/wireless/wl12xx/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" +source "drivers/net/wireless/mwifiex/Kconfig" endif # WLAN diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index ddd3fb6ba1d3..7bba6a82b875 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -56,3 +56,5 @@ obj-$(CONFIG_WL12XX) += wl12xx/ obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ obj-$(CONFIG_IWM) += iwmc3200wifi/ + +obj-$(CONFIG_MWIFIEX) += mwifiex/ diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 92c216263ee9..d1b23067619f 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -24,7 +24,6 @@ config ATH_DEBUG source "drivers/net/wireless/ath/ath5k/Kconfig" source "drivers/net/wireless/ath/ath9k/Kconfig" -source "drivers/net/wireless/ath/ar9170/Kconfig" source "drivers/net/wireless/ath/carl9170/Kconfig" endif diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 6d711ec97ec2..0e8f528c81c0 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -1,6 +1,5 @@ obj-$(CONFIG_ATH5K) += ath5k/ obj-$(CONFIG_ATH9K_HW) += ath9k/ -obj-$(CONFIG_AR9170_USB) += ar9170/ obj-$(CONFIG_CARL9170) += carl9170/ obj-$(CONFIG_ATH_COMMON) += ath.o diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig deleted file mode 100644 index 7b9672b0d090..000000000000 --- a/drivers/net/wireless/ath/ar9170/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config AR9170_USB - tristate "Atheros AR9170 802.11n USB support (OBSOLETE)" - depends on USB && MAC80211 - select FW_LOADER - help - This driver is going to get replaced by carl9170. - - This is a driver for the Atheros "otus" 802.11n USB devices. - - These devices require additional firmware (2 files). - For now, these files can be downloaded from here: - - http://wireless.kernel.org/en/users/Drivers/ar9170 - - If you choose to build a module, it'll be called ar9170usb. - -config AR9170_LEDS - bool - depends on AR9170_USB && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = AR9170_USB) - default y diff --git a/drivers/net/wireless/ath/ar9170/Makefile b/drivers/net/wireless/ath/ar9170/Makefile deleted file mode 100644 index 8d91c7ee3215..000000000000 --- a/drivers/net/wireless/ath/ar9170/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ar9170usb-objs := usb.o main.o cmd.o mac.o phy.o led.o - -obj-$(CONFIG_AR9170_USB) += ar9170usb.o diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h deleted file mode 100644 index 371e4ce49528..000000000000 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Driver specific definitions - * - * Copyright 2008, Johannes Berg - * - * 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; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 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 __AR9170_H -#define __AR9170_H - -#include -#include -#include -#include -#ifdef CONFIG_AR9170_LEDS -#include -#endif /* CONFIG_AR9170_LEDS */ -#include "eeprom.h" -#include "hw.h" - -#include "../regd.h" - -#define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1) - -enum ar9170_bw { - AR9170_BW_20, - AR9170_BW_40_BELOW, - AR9170_BW_40_ABOVE, - - __AR9170_NUM_BW, -}; - -static inline enum ar9170_bw nl80211_to_ar9170(enum nl80211_channel_type type) -{ - switch (type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: - return AR9170_BW_20; - case NL80211_CHAN_HT40MINUS: - return AR9170_BW_40_BELOW; - case NL80211_CHAN_HT40PLUS: - return AR9170_BW_40_ABOVE; - default: - BUG(); - } -} - -enum ar9170_rf_init_mode { - AR9170_RFI_NONE, - AR9170_RFI_WARM, - AR9170_RFI_COLD, -}; - -#define AR9170_MAX_RX_BUFFER_SIZE 8192 - -#ifdef CONFIG_AR9170_LEDS -struct ar9170; - -struct ar9170_led { - struct ar9170 *ar; - struct led_classdev l; - char name[32]; - unsigned int toggled; - bool last_state; - bool registered; -}; - -#endif /* CONFIG_AR9170_LEDS */ - -enum ar9170_device_state { - AR9170_UNKNOWN_STATE, - AR9170_STOPPED, - AR9170_IDLE, - AR9170_STARTED, -}; - -struct ar9170_rxstream_mpdu_merge { - struct ar9170_rx_head plcp; - bool has_plcp; -}; - -struct ar9170_tx_queue_stats { - unsigned int len; - unsigned int limit; - unsigned int count; -}; - -#define AR9170_QUEUE_TIMEOUT 64 -#define AR9170_TX_TIMEOUT 8 -#define AR9170_JANITOR_DELAY 128 -#define AR9170_TX_INVALID_RATE 0xffffffff - -#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH -#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10) - -struct ar9170 { - struct ieee80211_hw *hw; - struct ath_common common; - struct mutex mutex; - enum ar9170_device_state state; - bool registered; - unsigned long bad_hw_nagger; - - int (*open)(struct ar9170 *); - void (*stop)(struct ar9170 *); - int (*tx)(struct ar9170 *, struct sk_buff *); - int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 , - void *, u32 , void *); - void (*callback_cmd)(struct ar9170 *, u32 , void *); - int (*flush)(struct ar9170 *); - - /* interface mode settings */ - struct ieee80211_vif *vif; - - /* beaconing */ - struct sk_buff *beacon; - struct work_struct beacon_work; - bool enable_beacon; - - /* cryptographic engine */ - u64 usedkeys; - bool rx_software_decryption; - bool disable_offload; - - /* filter settings */ - u64 cur_mc_hash; - u32 cur_filter; - unsigned int filter_state; - bool sniffer_enabled; - - /* PHY */ - struct ieee80211_channel *channel; - int noise[4]; - - /* power calibration data */ - u8 power_5G_leg[4]; - u8 power_2G_cck[4]; - u8 power_2G_ofdm[4]; - u8 power_5G_ht20[8]; - u8 power_5G_ht40[8]; - u8 power_2G_ht20[8]; - u8 power_2G_ht40[8]; - - u8 phy_heavy_clip; - -#ifdef CONFIG_AR9170_LEDS - struct delayed_work led_work; - struct ar9170_led leds[AR9170_NUM_LEDS]; -#endif /* CONFIG_AR9170_LEDS */ - - /* qos queue settings */ - spinlock_t tx_stats_lock; - struct ar9170_tx_queue_stats tx_stats[5]; - struct ieee80211_tx_queue_params edcf[5]; - - spinlock_t cmdlock; - __le32 cmdbuf[PAYLOAD_MAX + 1]; - - /* MAC statistics */ - struct ieee80211_low_level_stats stats; - - /* EEPROM */ - struct ar9170_eeprom eeprom; - - /* tx queues - as seen by hw - */ - struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; - struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; - struct delayed_work tx_janitor; - - /* rxstream mpdu merge */ - struct ar9170_rxstream_mpdu_merge rx_mpdu; - struct sk_buff *rx_failover; - int rx_failover_missing; - - /* (cached) HW A-MPDU settings */ - u8 global_ampdu_density; - u8 global_ampdu_factor; -}; - -struct ar9170_tx_info { - unsigned long timeout; -}; - -#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) -#define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE) - -/* exported interface */ -void *ar9170_alloc(size_t priv_size); -int ar9170_register(struct ar9170 *ar, struct device *pdev); -void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); -void ar9170_unregister(struct ar9170 *ar); -void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb); -void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); -int ar9170_nag_limiter(struct ar9170 *ar); - -/* MAC */ -void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -int ar9170_init_mac(struct ar9170 *ar); -int ar9170_set_qos(struct ar9170 *ar); -int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast); -int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter); -int ar9170_set_operating_mode(struct ar9170 *ar); -int ar9170_set_beacon_timers(struct ar9170 *ar); -int ar9170_set_dyn_sifs_ack(struct ar9170 *ar); -int ar9170_set_slot_time(struct ar9170 *ar); -int ar9170_set_basic_rates(struct ar9170 *ar); -int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); -int ar9170_update_beacon(struct ar9170 *ar); -void ar9170_new_beacon(struct work_struct *work); -int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, - u8 keyidx, u8 *keydata, int keylen); -int ar9170_disable_key(struct ar9170 *ar, u8 id); - -/* LEDs */ -#ifdef CONFIG_AR9170_LEDS -int ar9170_register_leds(struct ar9170 *ar); -void ar9170_unregister_leds(struct ar9170 *ar); -#endif /* CONFIG_AR9170_LEDS */ -int ar9170_init_leds(struct ar9170 *ar); -int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state); - -/* PHY / RF */ -int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band); -int ar9170_init_rf(struct ar9170 *ar); -int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, - enum ar9170_rf_init_mode rfi, enum ar9170_bw bw); - -#endif /* __AR9170_H */ diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c deleted file mode 100644 index 6452c5055a63..000000000000 --- a/drivers/net/wireless/ath/ar9170/cmd.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Basic HW register/memory/command access functions - * - * Copyright 2008, Johannes Berg - * - * 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; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 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 "ar9170.h" -#include "cmd.h" - -int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len) -{ - int err; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return 0; - - err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL); - if (err) - wiphy_debug(ar->hw->wiphy, "writing memory failed\n"); - return err; -} - -int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val) -{ - const __le32 buf[2] = { - cpu_to_le32(reg), - cpu_to_le32(val), - }; - int err; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return 0; - - err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf), - (u8 *) buf, 0, NULL); - if (err) - wiphy_debug(ar->hw->wiphy, "writing reg %#x (val %#x) failed\n", - reg, val); - return err; -} - -int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out) -{ - int i, err; - __le32 *offs, *res; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return 0; - - /* abuse "out" for the register offsets, must be same length */ - offs = (__le32 *)out; - for (i = 0; i < nregs; i++) - offs[i] = cpu_to_le32(regs[i]); - - /* also use the same buffer for the input */ - res = (__le32 *)out; - - err = ar->exec_cmd(ar, AR9170_CMD_RREG, - 4 * nregs, (u8 *)offs, - 4 * nregs, (u8 *)res); - if (err) - return err; - - /* convert result to cpu endian */ - for (i = 0; i < nregs; i++) - out[i] = le32_to_cpu(res[i]); - - return 0; -} - -int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val) -{ - return ar9170_read_mreg(ar, 1, ®, val); -} - -int ar9170_echo_test(struct ar9170 *ar, u32 v) -{ - __le32 echobuf = cpu_to_le32(v); - __le32 echores; - int err; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return -ENODEV; - - err = ar->exec_cmd(ar, AR9170_CMD_ECHO, - 4, (u8 *)&echobuf, - 4, (u8 *)&echores); - if (err) - return err; - - if (echobuf != echores) - return -EINVAL; - - return 0; -} diff --git a/drivers/net/wireless/ath/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h deleted file mode 100644 index ec8134b4b949..000000000000 --- a/drivers/net/wireless/ath/ar9170/cmd.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Basic HW register/memory/command access functions - * - * Copyright 2008, Johannes Berg - * - * 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; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 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 __CMD_H -#define __CMD_H - -#include "ar9170.h" - -/* basic HW access */ -int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len); -int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val); -int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val); -int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out); -int ar9170_echo_test(struct ar9170 *ar, u32 v); - -/* - * Macros to facilitate writing multiple registers in a single - * write-combining USB command. Note that when the first group - * fails the whole thing will fail without any others attempted, - * but you won't know which write in the group failed. - */ -#define ar9170_regwrite_begin(ar) \ -do { \ - int __nreg = 0, __err = 0; \ - struct ar9170 *__ar = ar; - -#define ar9170_regwrite(r, v) do { \ - __ar->cmdbuf[2 * __nreg + 1] = cpu_to_le32(r); \ - __ar->cmdbuf[2 * __nreg + 2] = cpu_to_le32(v); \ - __nreg++; \ - if ((__nreg >= PAYLOAD_MAX/2)) { \ - if (IS_ACCEPTING_CMD(__ar)) \ - __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ - 8 * __nreg, \ - (u8 *) &__ar->cmdbuf[1], \ - 0, NULL); \ - __nreg = 0; \ - if (__err) \ - goto __regwrite_out; \ - } \ -} while (0) - -#define ar9170_regwrite_finish() \ -__regwrite_out : \ - if (__nreg) { \ - if (IS_ACCEPTING_CMD(__ar)) \ - __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ - 8 * __nreg, \ - (u8 *) &__ar->cmdbuf[1], \ - 0, NULL); \ - __nreg = 0; \ - } - -#define ar9170_regwrite_result() \ - __err; \ -} while (0); - -#endif /* __CMD_H */ diff --git a/drivers/net/wireless/ath/ar9170/eeprom.h b/drivers/net/wireless/ath/ar9170/eeprom.h deleted file mode 100644 index 6c4663883423..000000000000 --- a/drivers/net/wireless/ath/ar9170/eeprom.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Atheros AR9170 driver - * - * EEPROM layout - * - * Copyright 2008, Johannes Berg - * - * 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; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 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 __AR9170_EEPROM_H -#define __AR9170_EEPROM_H - -#define AR5416_MAX_CHAINS 2 -#define AR5416_MODAL_SPURS 5 - -struct ar9170_eeprom_modal { - __le32 antCtrlChain[AR5416_MAX_CHAINS]; - __le32 antCtrlCommon; - s8 antennaGainCh[AR5416_MAX_CHAINS]; - u8 switchSettling; - u8 txRxAttenCh[AR5416_MAX_CHAINS]; - u8 rxTxMarginCh[AR5416_MAX_CHAINS]; - s8 adcDesiredSize; - s8 pgaDesiredSize; - u8 xlnaGainCh[AR5416_MAX_CHAINS]; - u8 txEndToXpaOff; - u8 txEndToRxOn; - u8 txFrameToXpaOn; - u8 thresh62; - s8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; - u8 xpdGain; - u8 xpd; - s8 iqCalICh[AR5416_MAX_CHAINS]; - s8 iqCalQCh[AR5416_MAX_CHAINS]; - u8 pdGainOverlap; - u8 ob; - u8 db; - u8 xpaBiasLvl; - u8 pwrDecreaseFor2Chain; - u8 pwrDecreaseFor3Chain; - u8 txFrameToDataStart; - u8 txFrameToPaOn; - u8 ht40PowerIncForPdadc; - u8 bswAtten[AR5416_MAX_CHAINS]; - u8 bswMargin[AR5416_MAX_CHAINS]; - u8 swSettleHt40; - u8 reserved[22]; - struct spur_channel { - __le16 spurChan; - u8 spurRangeLow; - u8 spurRangeHigh; - } __packed spur_channels[AR5416_MODAL_SPURS]; -} __packed; - -#define AR5416_NUM_PD_GAINS 4 -#define AR5416_PD_GAIN_ICEPTS 5 - -struct ar9170_calibration_data_per_freq { - u8 pwr_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; - u8 vpd_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; -} __packed; - -#define AR5416_NUM_5G_CAL_PIERS 8 -#define AR5416_NUM_2G_CAL_PIERS 4 - -#define AR5416_NUM_5G_TARGET_PWRS 8 -#define AR5416_NUM_2G_CCK_TARGET_PWRS 3 -#define AR5416_NUM_2G_OFDM_TARGET_PWRS 4 -#define AR5416_MAX_NUM_TGT_PWRS 8 - -struct ar9170_calibration_target_power_legacy { - u8 freq; - u8 power[4]; -} __packed; - -struct ar9170_calibration_target_power_ht { - u8 freq; - u8 power[8]; -} __packed; - -#define AR5416_NUM_CTLS 24 - -struct ar9170_calctl_edges { - u8 channel; -#define AR9170_CALCTL_EDGE_FLAGS 0xC0 - u8 power_flags; -} __packed; - -#define AR5416_NUM_BAND_EDGES 8 - -struct ar9170_calctl_data { - struct ar9170_calctl_edges - control_edges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; -} __packed; - - -struct ar9170_eeprom { - __le16 length; - __le16 checksum; - __le16 version; - u8 operating_flags; -#define AR9170_OPFLAG_5GHZ 1 -#define AR9170_OPFLAG_2GHZ 2 - u8 misc; - __le16 reg_domain[2]; - u8 mac_address[6]; - u8 rx_mask; - u8 tx_mask; - __le16 rf_silent; - __le16 bluetooth_options; - __le16 device_capabilities; - __le32 build_number; - u8 deviceType; - u8 reserved[33]; - - u8 customer_data[64]; - - struct ar9170_eeprom_modal - modal_header[2]; - - u8 cal_freq_pier_5G[AR5416_NUM_5G_CAL_PIERS]; - u8 cal_freq_pier_2G[AR5416_NUM_2G_CAL_PIERS]; - - struct ar9170_calibration_data_per_freq - cal_pier_data_5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS], - cal_pier_data_2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; - - /* power calibration data */ - struct ar9170_calibration_target_power_legacy - cal_tgt_pwr_5G[AR5416_NUM_5G_TARGET_PWRS]; - struct ar9170_calibration_target_power_ht - cal_tgt_pwr_5G_ht20[AR5416_NUM_5G_TARGET_PWRS], - cal_tgt_pwr_5G_ht40[AR5416_NUM_5G_TARGET_PWRS]; - - struct ar9170_calibration_target_power_legacy - cal_tgt_pwr_2G_cck[AR5416_NUM_2G_CCK_TARGET_PWRS], - cal_tgt_pwr_2G_ofdm[AR5416_NUM_2G_OFDM_TARGET_PWRS]; - struct ar9170_calibration_target_power_ht - cal_tgt_pwr_2G_ht20[AR5416_NUM_2G_OFDM_TARGET_PWRS], - cal_tgt_pwr_2G_ht40[AR5416_NUM_2G_OFDM_TARGET_PWRS]; - - /* conformance testing limits */ - u8 ctl_index[AR5416_NUM_CTLS]; - struct ar9170_calctl_data - ctl_data[AR5416_NUM_CTLS]; - - u8 pad; - __le16 subsystem_id; -} __packed; - -#endif /* __AR9170_EEPROM_H */ diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h deleted file mode 100644 index 06f1f3c951a4..000000000000 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Hardware-specific definitions - * - * Copyright 2008, Johannes Berg - * - * 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; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 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 __AR9170_HW_H -#define __AR9170_HW_H - -#define AR9170_MAX_CMD_LEN 64 - -enum ar9170_cmd { - AR9170_CMD_RREG = 0x00, - AR9170_CMD_WREG = 0x01, - AR9170_CMD_RMEM = 0x02, - AR9170_CMD_WMEM = 0x03, - AR9170_CMD_BITAND = 0x04, - AR9170_CMD_BITOR = 0x05, - AR9170_CMD_EKEY = 0x28, - AR9170_CMD_DKEY = 0x29, - AR9170_CMD_FREQUENCY = 0x30, - AR9170_CMD_RF_INIT = 0x31, - AR9170_CMD_SYNTH = 0x32, - AR9170_CMD_FREQ_START = 0x33, - AR9170_CMD_ECHO = 0x80, - AR9170_CMD_TALLY = 0x81, - AR9170_CMD_TALLY_APD = 0x82, - AR9170_CMD_CONFIG = 0x83, - AR9170_CMD_RESET = 0x90, - AR9170_CMD_DKRESET = 0x91, - AR9170_CMD_DKTX_STATUS = 0x92, - AR9170_CMD_FDC = 0xA0, - AR9170_CMD_WREEPROM = 0xB0, - AR9170_CMD_WFLASH = 0xB0, - AR9170_CMD_FLASH_ERASE = 0xB1, - AR9170_CMD_FLASH_PROG = 0xB2, - AR9170_CMD_FLASH_CHKSUM = 0xB3, - AR9170_CMD_FLASH_READ = 0xB4, - AR9170_CMD_FW_DL_INIT = 0xB5, - AR9170_CMD_MEM_WREEPROM = 0xBB, -}; - -/* endpoints */ -#define AR9170_EP_TX 1 -#define AR9170_EP_RX 2 -#define AR9170_EP_IRQ 3 -#define AR9170_EP_CMD 4 - -#define AR9170_EEPROM_START 0x1600 - -#define AR9170_GPIO_REG_BASE 0x1d0100 -#define AR9170_GPIO_REG_PORT_TYPE AR9170_GPIO_REG_BASE -#define AR9170_GPIO_REG_DATA (AR9170_GPIO_REG_BASE + 4) -#define AR9170_NUM_LEDS 2 - - -#define AR9170_USB_REG_BASE 0x1e1000 -#define AR9170_USB_REG_DMA_CTL (AR9170_USB_REG_BASE + 0x108) -#define AR9170_DMA_CTL_ENABLE_TO_DEVICE 0x1 -#define AR9170_DMA_CTL_ENABLE_FROM_DEVICE 0x2 -#define AR9170_DMA_CTL_HIGH_SPEED 0x4 -#define AR9170_DMA_CTL_PACKET_MODE 0x8 - -#define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110) -#define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114) - - - -#define AR9170_MAC_REG_BASE 0x1c3000 - -#define AR9170_MAC_REG_TSF_L (AR9170_MAC_REG_BASE + 0x514) -#define AR9170_MAC_REG_TSF_H (AR9170_MAC_REG_BASE + 0x518) - -#define AR9170_MAC_REG_ATIM_WINDOW (AR9170_MAC_REG_BASE + 0x51C) -#define AR9170_MAC_REG_BCN_PERIOD (AR9170_MAC_REG_BASE + 0x520) -#define AR9170_MAC_REG_PRETBTT (AR9170_MAC_REG_BASE + 0x524) - -#define AR9170_MAC_REG_MAC_ADDR_L (AR9170_MAC_REG_BASE + 0x610) -#define AR9170_MAC_REG_MAC_ADDR_H (AR9170_MAC_REG_BASE + 0x614) -#define AR9170_MAC_REG_BSSID_L (AR9170_MAC_REG_BASE + 0x618) -#define AR9170_MAC_REG_BSSID_H (AR9170_MAC_REG_BASE + 0x61c) - -#define AR9170_MAC_REG_GROUP_HASH_TBL_L (AR9170_MAC_REG_BASE + 0x624) -#define AR9170_MAC_REG_GROUP_HASH_TBL_H (AR9170_MAC_REG_BASE + 0x628) - -#define AR9170_MAC_REG_RX_TIMEOUT (AR9170_MAC_REG_BASE + 0x62C) - -#define AR9170_MAC_REG_BASIC_RATE (AR9170_MAC_REG_BASE + 0x630) -#define AR9170_MAC_REG_MANDATORY_RATE (AR9170_MAC_REG_BASE + 0x634) -#define AR9170_MAC_REG_RTS_CTS_RATE (AR9170_MAC_REG_BASE + 0x638) -#define AR9170_MAC_REG_BACKOFF_PROTECT (AR9170_MAC_REG_BASE + 0x63c) -#define AR9170_MAC_REG_RX_THRESHOLD (AR9170_MAC_REG_BASE + 0x640) -#define AR9170_MAC_REG_RX_PE_DELAY (AR9170_MAC_REG_BASE + 0x64C) - -#define AR9170_MAC_REG_DYNAMIC_SIFS_ACK (AR9170_MAC_REG_BASE + 0x658) -#define AR9170_MAC_REG_SNIFFER (AR9170_MAC_REG_BASE + 0x674) -#define AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC BIT(0) -#define AR9170_MAC_REG_SNIFFER_DEFAULTS 0x02000000 -#define AR9170_MAC_REG_ENCRYPTION (AR9170_MAC_REG_BASE + 0x678) -#define AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE BIT(3) -#define AR9170_MAC_REG_ENCRYPTION_DEFAULTS 0x70 - -#define AR9170_MAC_REG_MISC_680 (AR9170_MAC_REG_BASE + 0x680) -#define AR9170_MAC_REG_TX_UNDERRUN (AR9170_MAC_REG_BASE + 0x688) - -#define AR9170_MAC_REG_FRAMETYPE_FILTER (AR9170_MAC_REG_BASE + 0x68c) -#define AR9170_MAC_REG_FTF_ASSOC_REQ BIT(0) -#define AR9170_MAC_REG_FTF_ASSOC_RESP BIT(1) -#define AR9170_MAC_REG_FTF_REASSOC_REQ BIT(2) -#define AR9170_MAC_REG_FTF_REASSOC_RESP BIT(3) -#define AR9170_MAC_REG_FTF_PRB_REQ BIT(4) -#define AR9170_MAC_REG_FTF_PRB_RESP BIT(5) -#define AR9170_MAC_REG_FTF_BIT6 BIT(6) -#define AR9170_MAC_REG_FTF_BIT7 BIT(7) -#define AR9170_MAC_REG_FTF_BEACON BIT(8) -#define AR9170_MAC_REG_FTF_ATIM BIT(9) -#define AR9170_MAC_REG_FTF_DEASSOC BIT(10) -#define AR9170_MAC_REG_FTF_AUTH BIT(11) -#define AR9170_MAC_REG_FTF_DEAUTH BIT(12) -#define AR9170_MAC_REG_FTF_BIT13 BIT(13) -#define AR9170_MAC_REG_FTF_BIT14 BIT(14) -#define AR9170_MAC_REG_FTF_BIT15 BIT(15) -#define AR9170_MAC_REG_FTF_BAR BIT(24) -#define AR9170_MAC_REG_FTF_BA BIT(25) -#define AR9170_MAC_REG_FTF_PSPOLL BIT(26) -#define AR9170_MAC_REG_FTF_RTS BIT(27) -#define AR9170_MAC_REG_FTF_CTS BIT(28) -#define AR9170_MAC_REG_FTF_ACK BIT(29) -#define AR9170_MAC_REG_FTF_CFE BIT(30) -#define AR9170_MAC_REG_FTF_CFE_ACK BIT(31) -#define AR9170_MAC_REG_FTF_DEFAULTS 0x0700ffff -#define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff - -#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0) -#define AR9170_MAC_REG_RX_CRC32 (AR9170_MAC_REG_BASE + 0x6A4) -#define AR9170_MAC_REG_RX_CRC16 (AR9170_MAC_REG_BASE + 0x6A8) -#define AR9170_MAC_REG_RX_ERR_DECRYPTION_UNI (AR9170_MAC_REG_BASE + 0x6AC) -#define AR9170_MAC_REG_RX_OVERRUN (AR9170_MAC_REG_BASE + 0x6B0) -#define AR9170_MAC_REG_RX_ERR_DECRYPTION_MUL (AR9170_MAC_REG_BASE + 0x6BC) -#define AR9170_MAC_REG_TX_RETRY (AR9170_MAC_REG_BASE + 0x6CC) -#define AR9170_MAC_REG_TX_TOTAL (AR9170_MAC_REG_BASE + 0x6F4) - - -#define AR9170_MAC_REG_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0x690) -#define AR9170_MAC_REG_EIFS_AND_SIFS (AR9170_MAC_REG_BASE + 0x698) - -#define AR9170_MAC_REG_SLOT_TIME (AR9170_MAC_REG_BASE + 0x6F0) - -#define AR9170_MAC_REG_POWERMANAGEMENT (AR9170_MAC_REG_BASE + 0x700) -#define AR9170_MAC_REG_POWERMGT_IBSS 0xe0 -#define AR9170_MAC_REG_POWERMGT_AP 0xa1 -#define AR9170_MAC_REG_POWERMGT_STA 0x2 -#define AR9170_MAC_REG_POWERMGT_AP_WDS 0x3 -#define AR9170_MAC_REG_POWERMGT_DEFAULTS (0xf << 24) - -#define AR9170_MAC_REG_ROLL_CALL_TBL_L (AR9170_MAC_REG_BASE + 0x704) -#define AR9170_MAC_REG_ROLL_CALL_TBL_H (AR9170_MAC_REG_BASE + 0x708) - -#define AR9170_MAC_REG_AC0_CW (AR9170_MAC_REG_BASE + 0xB00) -#define AR9170_MAC_REG_AC1_CW (AR9170_MAC_REG_BASE + 0xB04) -#define AR9170_MAC_REG_AC2_CW (AR9170_MAC_REG_BASE + 0xB08) -#define AR9170_MAC_REG_AC3_CW (AR9170_MAC_REG_BASE + 0xB0C) -#define AR9170_MAC_REG_AC4_CW (AR9170_MAC_REG_BASE + 0xB10) -#define AR9170_MAC_REG_AC1_AC0_AIFS (AR9170_MAC_REG_BASE + 0xB14) -#define AR9170_MAC_REG_AC3_AC2_AIFS (AR9170_MAC_REG_BASE + 0xB18) - -#define AR9170_MAC_REG_RETRY_MAX (AR9170_MAC_REG_BASE + 0xB28) - -#define AR9170_MAC_REG_FCS_SELECT (AR9170_MAC_REG_BASE + 0xBB0) -#define AR9170_MAC_FCS_SWFCS 0x1 -#define AR9170_MAC_FCS_FIFO_PROT 0x4 - - -#define AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND (AR9170_MAC_REG_BASE + 0xB30) - -#define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) -#define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) - -#define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xB9C) -#define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xBA0) - -#define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) -#define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) - -#define AR9170_MAC_REG_TXRX_MPI (AR9170_MAC_REG_BASE + 0xD7C) -#define AR9170_MAC_TXRX_MPI_TX_MPI_MASK 0x0000000f -#define AR9170_MAC_TXRX_MPI_TX_TO_MASK 0x0000fff0 -#define AR9170_MAC_TXRX_MPI_RX_MPI_MASK 0x000f0000 -#define AR9170_MAC_TXRX_MPI_RX_TO_MASK 0xfff00000 - -#define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xD84) -#define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xD88) -#define AR9170_MAC_REG_BCN_PLCP (AR9170_MAC_REG_BASE + 0xD90) -#define AR9170_MAC_REG_BCN_CTRL (AR9170_MAC_REG_BASE + 0xD94) -#define AR9170_MAC_REG_BCN_HT1 (AR9170_MAC_REG_BASE + 0xDA0) -#define AR9170_MAC_REG_BCN_HT2 (AR9170_MAC_REG_BASE + 0xDA4) - - -#define AR9170_PWR_REG_BASE 0x1D4000 - -#define AR9170_PWR_REG_CLOCK_SEL (AR9170_PWR_REG_BASE + 0x008) -#define AR9170_PWR_CLK_AHB_40MHZ 0 -#define AR9170_PWR_CLK_AHB_20_22MHZ 1 -#define AR9170_PWR_CLK_AHB_40_44MHZ 2 -#define AR9170_PWR_CLK_AHB_80_88MHZ 3 -#define AR9170_PWR_CLK_DAC_160_INV_DLY 0x70 - - -/* put beacon here in memory */ -#define AR9170_BEACON_BUFFER_ADDRESS 0x117900 - - -struct ar9170_tx_control { - __le16 length; - __le16 mac_control; - __le32 phy_control; - u8 frame_data[0]; -} __packed; - -/* these are either-or */ -#define AR9170_TX_MAC_PROT_RTS 0x0001 -#define AR9170_TX_MAC_PROT_CTS 0x0002 - -#define AR9170_TX_MAC_NO_ACK 0x0004 -/* if unset, MAC will only do SIFS space before frame */ -#define AR9170_TX_MAC_BACKOFF 0x0008 -#define AR9170_TX_MAC_BURST 0x0010 -#define AR9170_TX_MAC_AGGR 0x0020 - -/* encryption is a two-bit field */ -#define AR9170_TX_MAC_ENCR_NONE 0x0000 -#define AR9170_TX_MAC_ENCR_RC4 0x0040 -#define AR9170_TX_MAC_ENCR_CENC 0x0080 -#define AR9170_TX_MAC_ENCR_AES 0x00c0 - -#define AR9170_TX_MAC_MMIC 0x0100 -#define AR9170_TX_MAC_HW_DURATION 0x0200 -#define AR9170_TX_MAC_QOS_SHIFT 10 -#define AR9170_TX_MAC_QOS_MASK (3 << AR9170_TX_MAC_QOS_SHIFT) -#define AR9170_TX_MAC_AGGR_QOS_BIT1 0x0400 -#define AR9170_TX_MAC_AGGR_QOS_BIT2 0x0800 -#define AR9170_TX_MAC_DISABLE_TXOP 0x1000 -#define AR9170_TX_MAC_TXOP_RIFS 0x2000 -#define AR9170_TX_MAC_IMM_AMPDU 0x4000 -#define AR9170_TX_MAC_RATE_PROBE 0x8000 - -/* either-or */ -#define AR9170_TX_PHY_MOD_MASK 0x00000003 -#define AR9170_TX_PHY_MOD_CCK 0x00000000 -#define AR9170_TX_PHY_MOD_OFDM 0x00000001 -#define AR9170_TX_PHY_MOD_HT 0x00000002 - -/* depends on modulation */ -#define AR9170_TX_PHY_SHORT_PREAMBLE 0x00000004 -#define AR9170_TX_PHY_GREENFIELD 0x00000004 - -#define AR9170_TX_PHY_BW_SHIFT 3 -#define AR9170_TX_PHY_BW_MASK (3 << AR9170_TX_PHY_BW_SHIFT) -#define AR9170_TX_PHY_BW_20MHZ 0 -#define AR9170_TX_PHY_BW_40MHZ 2 -#define AR9170_TX_PHY_BW_40MHZ_DUP 3 - -#define AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT 6 -#define AR9170_TX_PHY_TX_HEAVY_CLIP_MASK (7 << AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT) - -#define AR9170_TX_PHY_TX_PWR_SHIFT 9 -#define AR9170_TX_PHY_TX_PWR_MASK (0x3f << AR9170_TX_PHY_TX_PWR_SHIFT) - -/* not part of the hw-spec */ -#define AR9170_TX_PHY_QOS_SHIFT 25 -#define AR9170_TX_PHY_QOS_MASK (3 << AR9170_TX_PHY_QOS_SHIFT) - -#define AR9170_TX_PHY_TXCHAIN_SHIFT 15 -#define AR9170_TX_PHY_TXCHAIN_MASK (7 << AR9170_TX_PHY_TXCHAIN_SHIFT) -#define AR9170_TX_PHY_TXCHAIN_1 1 -/* use for cck, ofdm 6/9/12/18/24 and HT if capable */ -#define AR9170_TX_PHY_TXCHAIN_2 5 - -#define AR9170_TX_PHY_MCS_SHIFT 18 -#define AR9170_TX_PHY_MCS_MASK (0x7f << AR9170_TX_PHY_MCS_SHIFT) - -#define AR9170_TX_PHY_SHORT_GI 0x80000000 - -#define AR5416_MAX_RATE_POWER 63 - -struct ar9170_rx_head { - u8 plcp[12]; -} __packed; - -struct ar9170_rx_phystatus { - union { - struct { - u8 rssi_ant0, rssi_ant1, rssi_ant2, - rssi_ant0x, rssi_ant1x, rssi_ant2x, - rssi_combined; - } __packed; - u8 rssi[7]; - } __packed; - - u8 evm_stream0[6], evm_stream1[6]; - u8 phy_err; -} __packed; - -struct ar9170_rx_macstatus { - u8 SAidx, DAidx; - u8 error; - u8 status; -} __packed; - -#define AR9170_ENC_ALG_NONE 0x0 -#define AR9170_ENC_ALG_WEP64 0x1 -#define AR9170_ENC_ALG_TKIP 0x2 -#define AR9170_ENC_ALG_AESCCMP 0x4 -#define AR9170_ENC_ALG_WEP128 0x5 -#define AR9170_ENC_ALG_WEP256 0x6 -#define AR9170_ENC_ALG_CENC 0x7 - -#define AR9170_RX_ENC_SOFTWARE 0x8 - -static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t) -{ - return (t->SAidx & 0xc0) >> 4 | - (t->DAidx & 0xc0) >> 6; -} - -#define AR9170_RX_STATUS_MODULATION_MASK 0x03 -#define AR9170_RX_STATUS_MODULATION_CCK 0x00 -#define AR9170_RX_STATUS_MODULATION_OFDM 0x01 -#define AR9170_RX_STATUS_MODULATION_HT 0x02 -#define AR9170_RX_STATUS_MODULATION_DUPOFDM 0x03 - -/* depends on modulation */ -#define AR9170_RX_STATUS_SHORT_PREAMBLE 0x08 -#define AR9170_RX_STATUS_GREENFIELD 0x08 - -#define AR9170_RX_STATUS_MPDU_MASK 0x30 -#define AR9170_RX_STATUS_MPDU_SINGLE 0x00 -#define AR9170_RX_STATUS_MPDU_FIRST 0x20 -#define AR9170_RX_STATUS_MPDU_MIDDLE 0x30 -#define AR9170_RX_STATUS_MPDU_LAST 0x10 - -#define AR9170_RX_ERROR_RXTO 0x01 -#define AR9170_RX_ERROR_OVERRUN 0x02 -#define AR9170_RX_ERROR_DECRYPT 0x04 -#define AR9170_RX_ERROR_FCS 0x08 -#define AR9170_RX_ERROR_WRONG_RA 0x10 -#define AR9170_RX_ERROR_PLCP 0x20 -#define AR9170_RX_ERROR_MMIC 0x40 -#define AR9170_RX_ERROR_FATAL 0x80 - -struct ar9170_cmd_tx_status { - u8 dst[ETH_ALEN]; - __le32 rate; - __le16 status; -} __packed; - -#define AR9170_TX_STATUS_COMPLETE 0x00 -#define AR9170_TX_STATUS_RETRY 0x01 -#define AR9170_TX_STATUS_FAILED 0x02 - -struct ar9170_cmd_ba_failed_count { - __le16 failed; - __le16 rate; -} __packed; - -struct ar9170_cmd_response { - u8 flag; - u8 type; - __le16 padding; - - union { - struct ar9170_cmd_tx_status tx_status; - struct ar9170_cmd_ba_failed_count ba_fail_cnt; - u8 data[0]; - }; -} __packed; - -/* QoS */ - -/* mac80211 queue to HW/FW map */ -static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 }; - -/* HW/FW queue to mac80211 map */ -static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 }; - -enum ar9170_txq { - AR9170_TXQ_BE, - AR9170_TXQ_BK, - AR9170_TXQ_VI, - AR9170_TXQ_VO, - - __AR9170_NUM_TXQ, -}; - -#define AR9170_TXQ_DEPTH 32 -#define AR9170_TX_MAX_PENDING 128 -#define AR9170_RX_STREAM_MAX_SIZE 65535 - -#endif /* __AR9170_HW_H */ diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c deleted file mode 100644 index 832d90087f8a..000000000000 --- a/drivers/net/wireless/ath/ar9170/led.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Atheros AR9170 driver - * - * LED handling - * - * Copyright 2008, Johannes Berg - * - * 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; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 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 "ar9170.h" -#include "cmd.h" - -int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state) -{ - return ar9170_write_reg(ar, AR9170_GPIO_REG_DATA, led_state); -} - -int ar9170_init_leds(struct ar9170 *ar) -{ - int err; - - /* disable LEDs */ - /* GPIO [0/1 mode: output, 2/3: input] */ - err = ar9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3); - if (err) - goto out; - - /* GPIO 0/1 value: off */ - err = ar9170_set_leds_state(ar, 0); - -out: - return err; -} - -#ifdef CONFIG_AR9170_LEDS -static void ar9170_update_leds(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, led_work.work); - int i, tmp, blink_delay = 1000; - u32 led_val = 0; - bool rerun = false; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return ; - - mutex_lock(&ar->mutex); - for (i = 0; i < AR9170_NUM_LEDS; i++) - if (ar->leds[i].registered && ar->leds[i].toggled) { - led_val |= 1 << i; - - tmp = 70 + 200 / (ar->leds[i].toggled); - if (tmp < blink_delay) - blink_delay = tmp; - - if (ar->leds[i].toggled > 1) - ar->leds[i].toggled = 0; - - rerun = true; - } - - ar9170_set_leds_state(ar, led_val); - mutex_unlock(&ar->mutex); - - if (!rerun) - return; - - ieee80211_queue_delayed_work(ar->hw, - &ar->led_work, - msecs_to_jiffies(blink_delay)); -} - -static void ar9170_led_brightness_set(struct led_classdev *led, - enum led_brightness brightness) -{ - struct ar9170_led *arl = container_of(led, struct ar9170_led, l); - struct ar9170 *ar = arl->ar; - - if (unlikely(!arl->registered)) - return ; - - if (arl->last_state != !!brightness) { - arl->toggled++; - arl->last_state = !!brightness; - } - - if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled)) - ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10); -} - -static int ar9170_register_led(struct ar9170 *ar, int i, char *name, - char *trigger) -{ - int err; - - snprintf(ar->leds[i].name, sizeof(ar->leds[i].name), - "ar9170-%s::%s", wiphy_name(ar->hw->wiphy), name); - - ar->leds[i].ar = ar; - ar->leds[i].l.name = ar->leds[i].name; - ar->leds[i].l.brightness_set = ar9170_led_brightness_set; - ar->leds[i].l.brightness = 0; - ar->leds[i].l.default_trigger = trigger; - - err = led_classdev_register(wiphy_dev(ar->hw->wiphy), - &ar->leds[i].l); - if (err) - wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n", - ar->leds[i].name, err); - else - ar->leds[i].registered = true; - - return err; -} - -void ar9170_unregister_leds(struct ar9170 *ar) -{ - int i; - - for (i = 0; i < AR9170_NUM_LEDS; i++) - if (ar->leds[i].registered) { - led_classdev_unregister(&ar->leds[i].l); - ar->leds[i].registered = false; - ar->leds[i].toggled = 0; - } - - cancel_delayed_work_sync(&ar->led_work); -} - -int ar9170_register_leds(struct ar9170 *ar) -{ - int err; - - INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds); - - err = ar9170_register_led(ar, 0, "tx", - ieee80211_get_tx_led_name(ar->hw)); - if (err) - goto fail; - - err = ar9170_register_led(ar, 1, "assoc", - ieee80211_get_assoc_led_name(ar->hw)); - if (err) - goto fail; - - return 0; - -fail: - ar9170_unregister_leds(ar); - return err; -} - -#endif /* CONFIG_AR9170_LEDS */ diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c deleted file mode 100644 index 857e86104295..000000000000 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Atheros AR9170 driver - * - * MAC programming - * - * Copyright 2008, Johannes Berg - * - * 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; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 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 - -#include "ar9170.h" -#include "cmd.h" - -int ar9170_set_dyn_sifs_ack(struct ar9170 *ar) -{ - u32 val; - - if (conf_is_ht40(&ar->hw->conf)) - val = 0x010a; - else { - if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) - val = 0x105; - else - val = 0x104; - } - - return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val); -} - -int ar9170_set_slot_time(struct ar9170 *ar) -{ - u32 slottime = 20; - - if (!ar->vif) - return 0; - - if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) || - ar->vif->bss_conf.use_short_slot) - slottime = 9; - - return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10); -} - -int ar9170_set_basic_rates(struct ar9170 *ar) -{ - u8 cck, ofdm; - - if (!ar->vif) - return 0; - - ofdm = ar->vif->bss_conf.basic_rates >> 4; - - /* FIXME: is still necessary? */ - if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) - cck = 0; - else - cck = ar->vif->bss_conf.basic_rates & 0xf; - - return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE, - ofdm << 8 | cck); -} - -int ar9170_set_qos(struct ar9170 *ar) -{ - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min | - (ar->edcf[0].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min | - (ar->edcf[1].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min | - (ar->edcf[2].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min | - (ar->edcf[3].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min | - (ar->edcf[4].cw_max << 16)); - - ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_AIFS, - ((ar->edcf[0].aifs * 9 + 10)) | - ((ar->edcf[1].aifs * 9 + 10) << 12) | - ((ar->edcf[2].aifs * 9 + 10) << 24)); - ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_AIFS, - ((ar->edcf[2].aifs * 9 + 10) >> 8) | - ((ar->edcf[3].aifs * 9 + 10) << 4) | - ((ar->edcf[4].aifs * 9 + 10) << 16)); - - ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP, - ar->edcf[0].txop | ar->edcf[1].txop << 16); - ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP, - ar->edcf[2].txop | ar->edcf[3].txop << 16); - - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity) -{ - u32 val; - - /* don't allow AMPDU density > 8us */ - if (mpdudensity > 6) - return -EINVAL; - - /* Watch out! Otus uses slightly different density values. */ - val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0); - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_init_mac(struct ar9170 *ar) -{ - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40); - - ar9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0); - - /* enable MMIC */ - ar9170_regwrite(AR9170_MAC_REG_SNIFFER, - AR9170_MAC_REG_SNIFFER_DEFAULTS); - - ar9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80); - - ar9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70); - ar9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000); - ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10); - - /* CF-END mode */ - ar9170_regwrite(0x1c3b2c, 0x19000000); - - /* NAV protects ACK only (in TXOP) */ - ar9170_regwrite(0x1c3b38, 0x201); - - /* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */ - /* OTUS set AM to 0x1 */ - ar9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170); - - ar9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105); - - /* AGG test code*/ - /* Aggregation MAX number and timeout */ - ar9170_regwrite(0x1c3b9c, 0x10000a); - - ar9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER, - AR9170_MAC_REG_FTF_DEFAULTS); - - /* Enable deaggregator, response in sniffer mode */ - ar9170_regwrite(0x1c3c40, 0x1 | 1<<30); - - /* rate sets */ - ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f); - ar9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f); - ar9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x10b01bb); - - /* MIMO response control */ - ar9170_regwrite(0x1c3694, 0x4003C1E);/* bit 26~28 otus-AM */ - - /* switch MAC to OTUS interface */ - ar9170_regwrite(0x1c3600, 0x3); - - ar9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff); - - /* set PHY register read timeout (??) */ - ar9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008); - - /* Disable Rx TimeOut, workaround for BB. */ - ar9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0); - - /* Set CPU clock frequency to 88/80MHz */ - ar9170_regwrite(AR9170_PWR_REG_CLOCK_SEL, - AR9170_PWR_CLK_AHB_80_88MHZ | - AR9170_PWR_CLK_DAC_160_INV_DLY); - - /* Set WLAN DMA interrupt mode: generate int per packet */ - ar9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011); - - ar9170_regwrite(AR9170_MAC_REG_FCS_SELECT, - AR9170_MAC_FCS_FIFO_PROT); - - /* Disables the CF_END frame, undocumented register */ - ar9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND, - 0x141E0F48); - - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac) -{ - static const u8 zero[ETH_ALEN] = { 0 }; - - if (!mac) - mac = zero; - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(reg, get_unaligned_le32(mac)); - ar9170_regwrite(reg + 4, get_unaligned_le16(mac + 4)); - - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hash) -{ - int err; - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash); - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - return err; - - ar->cur_mc_hash = mc_hash; - return 0; -} - -int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter) -{ - int err; - - err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, filter); - if (err) - return err; - - ar->cur_filter = filter; - return 0; -} - -static int ar9170_set_promiscouous(struct ar9170 *ar) -{ - u32 encr_mode, sniffer; - int err; - - err = ar9170_read_reg(ar, AR9170_MAC_REG_SNIFFER, &sniffer); - if (err) - return err; - - err = ar9170_read_reg(ar, AR9170_MAC_REG_ENCRYPTION, &encr_mode); - if (err) - return err; - - if (ar->sniffer_enabled) { - sniffer |= AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; - - /* - * Rx decryption works in place. - * - * If we don't disable it, the hardware will render all - * encrypted frames which are encrypted with an unknown - * key useless. - */ - - encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; - ar->sniffer_enabled = true; - } else { - sniffer &= ~AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; - - if (ar->rx_software_decryption) - encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; - else - encr_mode &= ~AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; - } - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_ENCRYPTION, encr_mode); - ar9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_set_operating_mode(struct ar9170 *ar) -{ - struct ath_common *common = &ar->common; - u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS; - u8 *mac_addr, *bssid; - int err; - - if (ar->vif) { - mac_addr = common->macaddr; - bssid = common->curbssid; - - switch (ar->vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_ADHOC: - pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS; - break; - case NL80211_IFTYPE_AP: - pm_mode |= AR9170_MAC_REG_POWERMGT_AP; - break; - case NL80211_IFTYPE_WDS: - pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS; - break; - case NL80211_IFTYPE_MONITOR: - ar->sniffer_enabled = true; - ar->rx_software_decryption = true; - break; - default: - pm_mode |= AR9170_MAC_REG_POWERMGT_STA; - break; - } - } else { - mac_addr = NULL; - bssid = NULL; - } - - err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr); - if (err) - return err; - - err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, bssid); - if (err) - return err; - - err = ar9170_set_promiscouous(ar); - if (err) - return err; - - /* set AMPDU density to 8us. */ - err = ar9170_set_ampdu_density(ar, 6); - if (err) - return err; - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_set_hwretry_limit(struct ar9170 *ar, unsigned int max_retry) -{ - u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111); - - return ar9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, tmp); -} - -int ar9170_set_beacon_timers(struct ar9170 *ar) -{ - u32 v = 0; - u32 pretbtt = 0; - - if (ar->vif) { - v |= ar->vif->bss_conf.beacon_int; - - if (ar->enable_beacon) { - switch (ar->vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_ADHOC: - v |= BIT(25); - break; - case NL80211_IFTYPE_AP: - v |= BIT(24); - pretbtt = (ar->vif->bss_conf.beacon_int - 6) << - 16; - break; - default: - break; - } - } - - v |= ar->vif->bss_conf.dtim_period << 16; - } - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt); - ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v); - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -int ar9170_update_beacon(struct ar9170 *ar) -{ - struct sk_buff *skb; - __le32 *data, *old = NULL; - u32 word; - int i; - - skb = ieee80211_beacon_get(ar->hw, ar->vif); - if (!skb) - return -ENOMEM; - - data = (__le32 *)skb->data; - if (ar->beacon) - old = (__le32 *)ar->beacon->data; - - ar9170_regwrite_begin(ar); - for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { - /* - * XXX: This accesses beyond skb data for up - * to the last 3 bytes!! - */ - - if (old && (data[i] == old[i])) - continue; - - word = le32_to_cpu(data[i]); - ar9170_regwrite(AR9170_BEACON_BUFFER_ADDRESS + 4 * i, word); - } - - /* XXX: use skb->cb info */ - if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) - ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << (3 + 16)) + 0x0400); - else - ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << 16) + 0x001b); - - ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); - ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); - ar9170_regwrite(AR9170_MAC_REG_BCN_CTRL, 1); - - ar9170_regwrite_finish(); - - dev_kfree_skb(ar->beacon); - ar->beacon = skb; - - return ar9170_regwrite_result(); -} - -void ar9170_new_beacon(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, - beacon_work); - struct sk_buff *skb; - - if (unlikely(!IS_STARTED(ar))) - return ; - - mutex_lock(&ar->mutex); - - if (!ar->vif) - goto out; - - ar9170_update_beacon(ar); - - rcu_read_lock(); - while ((skb = ieee80211_get_buffered_bc(ar->hw, ar->vif))) - ar9170_op_tx(ar->hw, skb); - - rcu_read_unlock(); - - out: - mutex_unlock(&ar->mutex); -} - -int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, - u8 keyidx, u8 *keydata, int keylen) -{ - __le32 vals[7]; - static const u8 bcast[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - u8 dummy; - - mac = mac ? : bcast; - - vals[0] = cpu_to_le32((keyidx << 16) + id); - vals[1] = cpu_to_le32(mac[1] << 24 | mac[0] << 16 | ktype); - vals[2] = cpu_to_le32(mac[5] << 24 | mac[4] << 16 | - mac[3] << 8 | mac[2]); - memset(&vals[3], 0, 16); - if (keydata) - memcpy(&vals[3], keydata, keylen); - - return ar->exec_cmd(ar, AR9170_CMD_EKEY, - sizeof(vals), (u8 *)vals, - 1, &dummy); -} - -int ar9170_disable_key(struct ar9170 *ar, u8 id) -{ - __le32 val = cpu_to_le32(id); - u8 dummy; - - return ar->exec_cmd(ar, AR9170_CMD_EKEY, - sizeof(val), (u8 *)&val, - 1, &dummy); -} diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c deleted file mode 100644 index ccc2edaaeda0..000000000000 --- a/drivers/net/wireless/ath/ar9170/main.c +++ /dev/null @@ -1,2190 +0,0 @@ -/* - * Atheros AR9170 driver - * - * mac80211 interaction code - * - * Copyright 2008, Johannes Berg - * Copyright 2009, Christian Lamparter - * - * 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; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 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 -#include -#include -#include -#include -#include "ar9170.h" -#include "hw.h" -#include "cmd.h" - -static int modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); -MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); - -#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate) | (_txpidx) << 4, \ -} - -static struct ieee80211_rate __ar9170_ratetable[] = { - RATE(10, 0, 0, 0), - RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(60, 0xb, 0, 0), - RATE(90, 0xf, 0, 0), - RATE(120, 0xa, 0, 0), - RATE(180, 0xe, 0, 0), - RATE(240, 0x9, 0, 0), - RATE(360, 0xd, 1, 0), - RATE(480, 0x8, 2, 0), - RATE(540, 0xc, 3, 0), -}; -#undef RATE - -#define ar9170_g_ratetable (__ar9170_ratetable + 0) -#define ar9170_g_ratetable_size 12 -#define ar9170_a_ratetable (__ar9170_ratetable + 4) -#define ar9170_a_ratetable_size 8 - -/* - * NB: The hw_value is used as an index into the ar9170_phy_freq_params - * array in phy.c so that we don't have to do frequency lookups! - */ -#define CHAN(_freq, _idx) { \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 18, /* XXX */ \ -} - -static struct ieee80211_channel ar9170_2ghz_chantable[] = { - CHAN(2412, 0), - CHAN(2417, 1), - CHAN(2422, 2), - CHAN(2427, 3), - CHAN(2432, 4), - CHAN(2437, 5), - CHAN(2442, 6), - CHAN(2447, 7), - CHAN(2452, 8), - CHAN(2457, 9), - CHAN(2462, 10), - CHAN(2467, 11), - CHAN(2472, 12), - CHAN(2484, 13), -}; - -static struct ieee80211_channel ar9170_5ghz_chantable[] = { - CHAN(4920, 14), - CHAN(4940, 15), - CHAN(4960, 16), - CHAN(4980, 17), - CHAN(5040, 18), - CHAN(5060, 19), - CHAN(5080, 20), - CHAN(5180, 21), - CHAN(5200, 22), - CHAN(5220, 23), - CHAN(5240, 24), - CHAN(5260, 25), - CHAN(5280, 26), - CHAN(5300, 27), - CHAN(5320, 28), - CHAN(5500, 29), - CHAN(5520, 30), - CHAN(5540, 31), - CHAN(5560, 32), - CHAN(5580, 33), - CHAN(5600, 34), - CHAN(5620, 35), - CHAN(5640, 36), - CHAN(5660, 37), - CHAN(5680, 38), - CHAN(5700, 39), - CHAN(5745, 40), - CHAN(5765, 41), - CHAN(5785, 42), - CHAN(5805, 43), - CHAN(5825, 44), - CHAN(5170, 45), - CHAN(5190, 46), - CHAN(5210, 47), - CHAN(5230, 48), -}; -#undef CHAN - -#define AR9170_HT_CAP \ -{ \ - .ht_supported = true, \ - .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ - IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ - IEEE80211_HT_CAP_SGI_40 | \ - IEEE80211_HT_CAP_GRN_FLD | \ - IEEE80211_HT_CAP_DSSSCCK40 | \ - IEEE80211_HT_CAP_SM_PS, \ - .ampdu_factor = 3, \ - .ampdu_density = 6, \ - .mcs = { \ - .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \ - .rx_highest = cpu_to_le16(300), \ - .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ - }, \ -} - -static struct ieee80211_supported_band ar9170_band_2GHz = { - .channels = ar9170_2ghz_chantable, - .n_channels = ARRAY_SIZE(ar9170_2ghz_chantable), - .bitrates = ar9170_g_ratetable, - .n_bitrates = ar9170_g_ratetable_size, - .ht_cap = AR9170_HT_CAP, -}; - -static struct ieee80211_supported_band ar9170_band_5GHz = { - .channels = ar9170_5ghz_chantable, - .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable), - .bitrates = ar9170_a_ratetable, - .n_bitrates = ar9170_a_ratetable_size, - .ht_cap = AR9170_HT_CAP, -}; - -static void ar9170_tx(struct ar9170 *ar); - -static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr) -{ - return le16_to_cpu(hdr->seq_ctrl) >> 4; -} - -static inline u16 ar9170_get_seq(struct sk_buff *skb) -{ - struct ar9170_tx_control *txc = (void *) skb->data; - return ar9170_get_seq_h((void *) txc->frame_data); -} - -#ifdef AR9170_QUEUE_DEBUG -static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); - struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; - struct ieee80211_hdr *hdr = (void *) txc->frame_data; - - wiphy_debug(ar->hw->wiphy, - "=> FRAME [skb:%p, q:%d, DA:[%pM] s:%d " - "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", - skb, skb_get_queue_mapping(skb), - ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr), - le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), - jiffies_to_msecs(arinfo->timeout - jiffies)); -} - -static void __ar9170_dump_txqueue(struct ar9170 *ar, - struct sk_buff_head *queue) -{ - struct sk_buff *skb; - int i = 0; - - printk(KERN_DEBUG "---[ cut here ]---\n"); - wiphy_debug(ar->hw->wiphy, "%d entries in queue.\n", - skb_queue_len(queue)); - - skb_queue_walk(queue, skb) { - printk(KERN_DEBUG "index:%d =>\n", i++); - ar9170_print_txheader(ar, skb); - } - if (i != skb_queue_len(queue)) - printk(KERN_DEBUG "WARNING: queue frame counter " - "mismatch %d != %d\n", skb_queue_len(queue), i); - printk(KERN_DEBUG "---[ end ]---\n"); -} -#endif /* AR9170_QUEUE_DEBUG */ - -#ifdef AR9170_QUEUE_DEBUG -static void ar9170_dump_txqueue(struct ar9170 *ar, - struct sk_buff_head *queue) -{ - unsigned long flags; - - spin_lock_irqsave(&queue->lock, flags); - __ar9170_dump_txqueue(ar, queue); - spin_unlock_irqrestore(&queue->lock, flags); -} -#endif /* AR9170_QUEUE_DEBUG */ - -#ifdef AR9170_QUEUE_STOP_DEBUG -static void __ar9170_dump_txstats(struct ar9170 *ar) -{ - int i; - - wiphy_debug(ar->hw->wiphy, "QoS queue stats\n"); - - for (i = 0; i < __AR9170_NUM_TXQ; i++) - wiphy_debug(ar->hw->wiphy, - "queue:%d limit:%d len:%d waitack:%d stopped:%d\n", - i, ar->tx_stats[i].limit, ar->tx_stats[i].len, - skb_queue_len(&ar->tx_status[i]), - ieee80211_queue_stopped(ar->hw, i)); -} -#endif /* AR9170_QUEUE_STOP_DEBUG */ - -/* caller must guarantee exclusive access for _bin_ queue. */ -static void ar9170_recycle_expired(struct ar9170 *ar, - struct sk_buff_head *queue, - struct sk_buff_head *bin) -{ - struct sk_buff *skb, *old = NULL; - unsigned long flags; - - spin_lock_irqsave(&queue->lock, flags); - while ((skb = skb_peek(queue))) { - struct ieee80211_tx_info *txinfo; - struct ar9170_tx_info *arinfo; - - txinfo = IEEE80211_SKB_CB(skb); - arinfo = (void *) txinfo->rate_driver_data; - - if (time_is_before_jiffies(arinfo->timeout)) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "[%ld > %ld] frame expired => recycle\n", - jiffies, arinfo->timeout); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - __skb_unlink(skb, queue); - __skb_queue_tail(bin, skb); - } else { - break; - } - - if (unlikely(old == skb)) { - /* bail out - queue is shot. */ - - WARN_ON(1); - break; - } - old = skb; - } - spin_unlock_irqrestore(&queue->lock, flags); -} - -static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, - u16 tx_status) -{ - struct ieee80211_tx_info *txinfo; - unsigned int retries = 0; - - txinfo = IEEE80211_SKB_CB(skb); - ieee80211_tx_info_clear_status(txinfo); - - switch (tx_status) { - case AR9170_TX_STATUS_RETRY: - retries = 2; - case AR9170_TX_STATUS_COMPLETE: - txinfo->flags |= IEEE80211_TX_STAT_ACK; - break; - - case AR9170_TX_STATUS_FAILED: - retries = ar->hw->conf.long_frame_max_tx_count; - break; - - default: - wiphy_err(ar->hw->wiphy, - "invalid tx_status response (%x)\n", tx_status); - break; - } - - txinfo->status.rates[0].count = retries + 1; - skb_pull(skb, sizeof(struct ar9170_tx_control)); - ieee80211_tx_status_irqsafe(ar->hw, skb); -} - -void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data; - unsigned int queue = skb_get_queue_mapping(skb); - unsigned long flags; - - spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - - if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) { -#ifdef AR9170_QUEUE_STOP_DEBUG - wiphy_debug(ar->hw->wiphy, "wake queue %d\n", queue); - __ar9170_dump_txstats(ar); -#endif /* AR9170_QUEUE_STOP_DEBUG */ - ieee80211_wake_queue(ar->hw, queue); - } - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - - if (info->flags & IEEE80211_TX_CTL_NO_ACK) { - ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); - } else { - arinfo->timeout = jiffies + - msecs_to_jiffies(AR9170_TX_TIMEOUT); - - skb_queue_tail(&ar->tx_status[queue], skb); - } - - if (!ar->tx_stats[queue].len && - !skb_queue_empty(&ar->tx_pending[queue])) { - ar9170_tx(ar); - } -} - -static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, - const u8 *mac, - struct sk_buff_head *queue, - const u32 rate) -{ - unsigned long flags; - struct sk_buff *skb; - - /* - * Unfortunately, the firmware does not tell to which (queued) frame - * this transmission status report belongs to. - * - * So we have to make risky guesses - with the scarce information - * the firmware provided (-> destination MAC, and phy_control) - - * and hope that we picked the right one... - */ - - spin_lock_irqsave(&queue->lock, flags); - skb_queue_walk(queue, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *) txc->frame_data; - u32 r; - - if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "skip frame => DA %pM != %pM\n", - mac, ieee80211_get_DA(hdr)); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - continue; - } - - r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >> - AR9170_TX_PHY_MCS_SHIFT; - - if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "skip frame => rate %d != %d\n", rate, r); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - continue; - } - - __skb_unlink(skb, queue); - spin_unlock_irqrestore(&queue->lock, flags); - return skb; - } - -#ifdef AR9170_QUEUE_DEBUG - wiphy_err(ar->hw->wiphy, - "ESS:[%pM] does not have any outstanding frames in queue.\n", - mac); - __ar9170_dump_txqueue(ar, queue); -#endif /* AR9170_QUEUE_DEBUG */ - spin_unlock_irqrestore(&queue->lock, flags); - - return NULL; -} - -/* - * This worker tries to keeps an maintain tx_status queues. - * So we can guarantee that incoming tx_status reports are - * actually for a pending frame. - */ - -static void ar9170_tx_janitor(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, - tx_janitor.work); - struct sk_buff_head waste; - unsigned int i; - bool resched = false; - - if (unlikely(!IS_STARTED(ar))) - return ; - - skb_queue_head_init(&waste); - - for (i = 0; i < __AR9170_NUM_TXQ; i++) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, "garbage collector scans queue:%d\n", - i); - ar9170_dump_txqueue(ar, &ar->tx_pending[i]); - ar9170_dump_txqueue(ar, &ar->tx_status[i]); -#endif /* AR9170_QUEUE_DEBUG */ - - ar9170_recycle_expired(ar, &ar->tx_status[i], &waste); - ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste); - skb_queue_purge(&waste); - - if (!skb_queue_empty(&ar->tx_status[i]) || - !skb_queue_empty(&ar->tx_pending[i])) - resched = true; - } - - if (!resched) - return; - - ieee80211_queue_delayed_work(ar->hw, - &ar->tx_janitor, - msecs_to_jiffies(AR9170_JANITOR_DELAY)); -} - -void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) -{ - struct ar9170_cmd_response *cmd = (void *) buf; - - if ((cmd->type & 0xc0) != 0xc0) { - ar->callback_cmd(ar, len, buf); - return; - } - - /* hardware event handlers */ - switch (cmd->type) { - case 0xc1: { - /* - * TX status notification: - * bytes: 0c c1 XX YY M1 M2 M3 M4 M5 M6 R4 R3 R2 R1 S2 S1 - * - * XX always 81 - * YY always 00 - * M1-M6 is the MAC address - * R1-R4 is the transmit rate - * S1-S2 is the transmit status - */ - - struct sk_buff *skb; - u32 phy = le32_to_cpu(cmd->tx_status.rate); - u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >> - AR9170_TX_PHY_QOS_SHIFT; -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "recv tx_status for %pm, p:%08x, q:%d\n", - cmd->tx_status.dst, phy, q); -#endif /* AR9170_QUEUE_DEBUG */ - - skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst, - &ar->tx_status[q], - AR9170_TX_INVALID_RATE); - if (unlikely(!skb)) - return ; - - ar9170_tx_status(ar, skb, le16_to_cpu(cmd->tx_status.status)); - break; - } - - case 0xc0: - /* - * pre-TBTT event - */ - if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP) - ieee80211_queue_work(ar->hw, &ar->beacon_work); - break; - - case 0xc2: - /* - * (IBSS) beacon send notification - * bytes: 04 c2 XX YY B4 B3 B2 B1 - * - * XX always 80 - * YY always 00 - * B1-B4 "should" be the number of send out beacons. - */ - break; - - case 0xc3: - /* End of Atim Window */ - break; - - case 0xc4: - /* BlockACK bitmap */ - break; - - case 0xc5: - /* BlockACK events */ - break; - - case 0xc6: - /* Watchdog Interrupt */ - break; - - case 0xc9: - /* retransmission issue / SIFS/EIFS collision ?! */ - break; - - /* firmware debug */ - case 0xca: - printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, - (char *)buf + 4); - break; - case 0xcb: - len -= 4; - - switch (len) { - case 1: - printk(KERN_DEBUG "ar9170 FW: u8: %#.2x\n", - *((char *)buf + 4)); - break; - case 2: - printk(KERN_DEBUG "ar9170 FW: u8: %#.4x\n", - le16_to_cpup((__le16 *)((char *)buf + 4))); - break; - case 4: - printk(KERN_DEBUG "ar9170 FW: u8: %#.8x\n", - le32_to_cpup((__le32 *)((char *)buf + 4))); - break; - case 8: - printk(KERN_DEBUG "ar9170 FW: u8: %#.16lx\n", - (unsigned long)le64_to_cpup( - (__le64 *)((char *)buf + 4))); - break; - } - break; - case 0xcc: - print_hex_dump_bytes("ar9170 FW:", DUMP_PREFIX_NONE, - (char *)buf + 4, len - 4); - break; - - default: - pr_info("received unhandled event %x\n", cmd->type); - print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); - break; - } -} - -static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar) -{ - memset(&ar->rx_mpdu.plcp, 0, sizeof(struct ar9170_rx_head)); - ar->rx_mpdu.has_plcp = false; -} - -int ar9170_nag_limiter(struct ar9170 *ar) -{ - bool print_message; - - /* - * we expect all sorts of errors in promiscuous mode. - * don't bother with it, it's OK! - */ - if (ar->sniffer_enabled) - return false; - - /* - * only go for frequent errors! The hardware tends to - * do some stupid thing once in a while under load, in - * noisy environments or just for fun! - */ - if (time_before(jiffies, ar->bad_hw_nagger) && net_ratelimit()) - print_message = true; - else - print_message = false; - - /* reset threshold for "once in a while" */ - ar->bad_hw_nagger = jiffies + HZ / 4; - return print_message; -} - -static int ar9170_rx_mac_status(struct ar9170 *ar, - struct ar9170_rx_head *head, - struct ar9170_rx_macstatus *mac, - struct ieee80211_rx_status *status) -{ - u8 error, decrypt; - - BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); - BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4); - - error = mac->error; - if (error & AR9170_RX_ERROR_MMIC) { - status->flag |= RX_FLAG_MMIC_ERROR; - error &= ~AR9170_RX_ERROR_MMIC; - } - - if (error & AR9170_RX_ERROR_PLCP) { - status->flag |= RX_FLAG_FAILED_PLCP_CRC; - error &= ~AR9170_RX_ERROR_PLCP; - - if (!(ar->filter_state & FIF_PLCPFAIL)) - return -EINVAL; - } - - if (error & AR9170_RX_ERROR_FCS) { - status->flag |= RX_FLAG_FAILED_FCS_CRC; - error &= ~AR9170_RX_ERROR_FCS; - - if (!(ar->filter_state & FIF_FCSFAIL)) - return -EINVAL; - } - - decrypt = ar9170_get_decrypt_type(mac); - if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && - decrypt != AR9170_ENC_ALG_NONE) - status->flag |= RX_FLAG_DECRYPTED; - - /* ignore wrong RA errors */ - error &= ~AR9170_RX_ERROR_WRONG_RA; - - if (error & AR9170_RX_ERROR_DECRYPT) { - error &= ~AR9170_RX_ERROR_DECRYPT; - /* - * Rx decryption is done in place, - * the original data is lost anyway. - */ - - return -EINVAL; - } - - /* drop any other error frames */ - if (unlikely(error)) { - /* TODO: update netdevice's RX dropped/errors statistics */ - - if (ar9170_nag_limiter(ar)) - wiphy_debug(ar->hw->wiphy, - "received frame with suspicious error code (%#x).\n", - error); - - return -EINVAL; - } - - status->band = ar->channel->band; - status->freq = ar->channel->center_freq; - - switch (mac->status & AR9170_RX_STATUS_MODULATION_MASK) { - case AR9170_RX_STATUS_MODULATION_CCK: - if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE) - status->flag |= RX_FLAG_SHORTPRE; - switch (head->plcp[0]) { - case 0x0a: - status->rate_idx = 0; - break; - case 0x14: - status->rate_idx = 1; - break; - case 0x37: - status->rate_idx = 2; - break; - case 0x6e: - status->rate_idx = 3; - break; - default: - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "invalid plcp cck rate (%x).\n", - head->plcp[0]); - return -EINVAL; - } - break; - - case AR9170_RX_STATUS_MODULATION_DUPOFDM: - case AR9170_RX_STATUS_MODULATION_OFDM: - switch (head->plcp[0] & 0xf) { - case 0xb: - status->rate_idx = 0; - break; - case 0xf: - status->rate_idx = 1; - break; - case 0xa: - status->rate_idx = 2; - break; - case 0xe: - status->rate_idx = 3; - break; - case 0x9: - status->rate_idx = 4; - break; - case 0xd: - status->rate_idx = 5; - break; - case 0x8: - status->rate_idx = 6; - break; - case 0xc: - status->rate_idx = 7; - break; - default: - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "invalid plcp ofdm rate (%x).\n", - head->plcp[0]); - return -EINVAL; - } - if (status->band == IEEE80211_BAND_2GHZ) - status->rate_idx += 4; - break; - - case AR9170_RX_STATUS_MODULATION_HT: - if (head->plcp[3] & 0x80) - status->flag |= RX_FLAG_40MHZ; - if (head->plcp[6] & 0x80) - status->flag |= RX_FLAG_SHORT_GI; - - status->rate_idx = clamp(0, 75, head->plcp[6] & 0x7f); - status->flag |= RX_FLAG_HT; - break; - - default: - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, "invalid modulation\n"); - return -EINVAL; - } - - return 0; -} - -static void ar9170_rx_phy_status(struct ar9170 *ar, - struct ar9170_rx_phystatus *phy, - struct ieee80211_rx_status *status) -{ - int i; - - BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20); - - for (i = 0; i < 3; i++) - if (phy->rssi[i] != 0x80) - status->antenna |= BIT(i); - - /* post-process RSSI */ - for (i = 0; i < 7; i++) - if (phy->rssi[i] & 0x80) - phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f; - - /* TODO: we could do something with phy_errors */ - status->signal = ar->noise[0] + phy->rssi_combined; -} - -static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len) -{ - struct sk_buff *skb; - int reserved = 0; - struct ieee80211_hdr *hdr = (void *) buf; - - if (ieee80211_is_data_qos(hdr->frame_control)) { - u8 *qc = ieee80211_get_qos_ctl(hdr); - reserved += NET_IP_ALIGN; - - if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) - reserved += NET_IP_ALIGN; - } - - if (ieee80211_has_a4(hdr->frame_control)) - reserved += NET_IP_ALIGN; - - reserved = 32 + (reserved & NET_IP_ALIGN); - - skb = dev_alloc_skb(len + reserved); - if (likely(skb)) { - skb_reserve(skb, reserved); - memcpy(skb_put(skb, len), buf, len); - } - - return skb; -} - -/* - * If the frame alignment is right (or the kernel has - * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there - * is only a single MPDU in the USB frame, then we could - * submit to mac80211 the SKB directly. However, since - * there may be multiple packets in one SKB in stream - * mode, and we need to observe the proper ordering, - * this is non-trivial. - */ - -static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) -{ - struct ar9170_rx_head *head; - struct ar9170_rx_macstatus *mac; - struct ar9170_rx_phystatus *phy = NULL; - struct ieee80211_rx_status status; - struct sk_buff *skb; - int mpdu_len; - - if (unlikely(!IS_STARTED(ar) || len < (sizeof(*mac)))) - return ; - - /* Received MPDU */ - mpdu_len = len - sizeof(*mac); - - mac = (void *)(buf + mpdu_len); - if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) { - /* this frame is too damaged and can't be used - drop it */ - - return ; - } - - switch (mac->status & AR9170_RX_STATUS_MPDU_MASK) { - case AR9170_RX_STATUS_MPDU_FIRST: - /* first mpdu packet has the plcp header */ - if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { - head = (void *) buf; - memcpy(&ar->rx_mpdu.plcp, (void *) buf, - sizeof(struct ar9170_rx_head)); - - mpdu_len -= sizeof(struct ar9170_rx_head); - buf += sizeof(struct ar9170_rx_head); - ar->rx_mpdu.has_plcp = true; - } else { - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "plcp info is clipped.\n"); - return ; - } - break; - - case AR9170_RX_STATUS_MPDU_LAST: - /* last mpdu has a extra tail with phy status information */ - - if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { - mpdu_len -= sizeof(struct ar9170_rx_phystatus); - phy = (void *)(buf + mpdu_len); - } else { - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "frame tail is clipped.\n"); - return ; - } - - case AR9170_RX_STATUS_MPDU_MIDDLE: - /* middle mpdus are just data */ - if (unlikely(!ar->rx_mpdu.has_plcp)) { - if (!ar9170_nag_limiter(ar)) - return ; - - wiphy_err(ar->hw->wiphy, - "rx stream did not start with a first_mpdu frame tag.\n"); - - return ; - } - - head = &ar->rx_mpdu.plcp; - break; - - case AR9170_RX_STATUS_MPDU_SINGLE: - /* single mpdu - has plcp (head) and phy status (tail) */ - head = (void *) buf; - - mpdu_len -= sizeof(struct ar9170_rx_head); - mpdu_len -= sizeof(struct ar9170_rx_phystatus); - - buf += sizeof(struct ar9170_rx_head); - phy = (void *)(buf + mpdu_len); - break; - - default: - BUG_ON(1); - break; - } - - if (unlikely(mpdu_len < FCS_LEN)) - return ; - - memset(&status, 0, sizeof(status)); - if (unlikely(ar9170_rx_mac_status(ar, head, mac, &status))) - return ; - - if (phy) - ar9170_rx_phy_status(ar, phy, &status); - - skb = ar9170_rx_copy_data(buf, mpdu_len); - if (likely(skb)) { - memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); - ieee80211_rx_irqsafe(ar->hw, skb); - } -} - -void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) -{ - unsigned int i, tlen, resplen, wlen = 0, clen = 0; - u8 *tbuf, *respbuf; - - tbuf = skb->data; - tlen = skb->len; - - while (tlen >= 4) { - clen = tbuf[1] << 8 | tbuf[0]; - wlen = ALIGN(clen, 4); - - /* check if this is stream has a valid tag.*/ - if (tbuf[2] != 0 || tbuf[3] != 0x4e) { - /* - * TODO: handle the highly unlikely event that the - * corrupted stream has the TAG at the right position. - */ - - /* check if the frame can be repaired. */ - if (!ar->rx_failover_missing) { - /* this is no "short read". */ - if (ar9170_nag_limiter(ar)) { - wiphy_err(ar->hw->wiphy, - "missing tag!\n"); - goto err_telluser; - } else - goto err_silent; - } - - if (ar->rx_failover_missing > tlen) { - if (ar9170_nag_limiter(ar)) { - wiphy_err(ar->hw->wiphy, - "possible multi stream corruption!\n"); - goto err_telluser; - } else - goto err_silent; - } - - memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); - ar->rx_failover_missing -= tlen; - - if (ar->rx_failover_missing <= 0) { - /* - * nested ar9170_rx call! - * termination is guaranteed, even when the - * combined frame also have a element with - * a bad tag. - */ - - ar->rx_failover_missing = 0; - ar9170_rx(ar, ar->rx_failover); - - skb_reset_tail_pointer(ar->rx_failover); - skb_trim(ar->rx_failover, 0); - } - - return ; - } - - /* check if stream is clipped */ - if (wlen > tlen - 4) { - if (ar->rx_failover_missing) { - /* TODO: handle double stream corruption. */ - if (ar9170_nag_limiter(ar)) { - wiphy_err(ar->hw->wiphy, - "double rx stream corruption!\n"); - goto err_telluser; - } else - goto err_silent; - } - - /* - * save incomplete data set. - * the firmware will resend the missing bits when - * the rx - descriptor comes round again. - */ - - memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); - ar->rx_failover_missing = clen - tlen; - return ; - } - resplen = clen; - respbuf = tbuf + 4; - tbuf += wlen + 4; - tlen -= wlen + 4; - - i = 0; - - /* weird thing, but this is the same in the original driver */ - while (resplen > 2 && i < 12 && - respbuf[0] == 0xff && respbuf[1] == 0xff) { - i += 2; - resplen -= 2; - respbuf += 2; - } - - if (resplen < 4) - continue; - - /* found the 6 * 0xffff marker? */ - if (i == 12) - ar9170_handle_command_response(ar, respbuf, resplen); - else - ar9170_handle_mpdu(ar, respbuf, clen); - } - - if (tlen) { - if (net_ratelimit()) - wiphy_err(ar->hw->wiphy, - "%d bytes of unprocessed data left in rx stream!\n", - tlen); - - goto err_telluser; - } - - return ; - -err_telluser: - wiphy_err(ar->hw->wiphy, - "damaged RX stream data [want:%d, data:%d, rx:%d, pending:%d ]\n", - clen, wlen, tlen, ar->rx_failover_missing); - - if (ar->rx_failover_missing) - print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET, - ar->rx_failover->data, - ar->rx_failover->len); - - print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET, - skb->data, skb->len); - - wiphy_err(ar->hw->wiphy, - "If you see this message frequently, please check your hardware and cables.\n"); - -err_silent: - if (ar->rx_failover_missing) { - skb_reset_tail_pointer(ar->rx_failover); - skb_trim(ar->rx_failover, 0); - ar->rx_failover_missing = 0; - } -} - -#define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \ -do { \ - queue.aifs = ai_fs; \ - queue.cw_min = cwmin; \ - queue.cw_max = cwmax; \ - queue.txop = _txop; \ -} while (0) - -static int ar9170_op_start(struct ieee80211_hw *hw) -{ - struct ar9170 *ar = hw->priv; - int err, i; - - mutex_lock(&ar->mutex); - - /* reinitialize queues statistics */ - memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); - for (i = 0; i < __AR9170_NUM_TXQ; i++) - ar->tx_stats[i].limit = AR9170_TXQ_DEPTH; - - /* reset QoS defaults */ - AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/ - AR9170_FILL_QUEUE(ar->edcf[1], 7, 15, 1023, 0); /* BACKGROUND */ - AR9170_FILL_QUEUE(ar->edcf[2], 2, 7, 15, 94); /* VIDEO */ - AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ - AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ - - /* set sane AMPDU defaults */ - ar->global_ampdu_density = 6; - ar->global_ampdu_factor = 3; - - ar->bad_hw_nagger = jiffies; - - err = ar->open(ar); - if (err) - goto out; - - err = ar9170_init_mac(ar); - if (err) - goto out; - - err = ar9170_set_qos(ar); - if (err) - goto out; - - err = ar9170_init_phy(ar, IEEE80211_BAND_2GHZ); - if (err) - goto out; - - err = ar9170_init_rf(ar); - if (err) - goto out; - - /* start DMA */ - err = ar9170_write_reg(ar, 0x1c3d30, 0x100); - if (err) - goto out; - - ar->state = AR9170_STARTED; - -out: - mutex_unlock(&ar->mutex); - return err; -} - -static void ar9170_op_stop(struct ieee80211_hw *hw) -{ - struct ar9170 *ar = hw->priv; - unsigned int i; - - if (IS_STARTED(ar)) - ar->state = AR9170_IDLE; - - cancel_delayed_work_sync(&ar->tx_janitor); -#ifdef CONFIG_AR9170_LEDS - cancel_delayed_work_sync(&ar->led_work); -#endif - cancel_work_sync(&ar->beacon_work); - - mutex_lock(&ar->mutex); - - if (IS_ACCEPTING_CMD(ar)) { - ar9170_set_leds_state(ar, 0); - - /* stop DMA */ - ar9170_write_reg(ar, 0x1c3d30, 0); - ar->stop(ar); - } - - for (i = 0; i < __AR9170_NUM_TXQ; i++) { - skb_queue_purge(&ar->tx_pending[i]); - skb_queue_purge(&ar->tx_status[i]); - } - - mutex_unlock(&ar->mutex); -} - -static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - struct ar9170_tx_control *txc; - struct ieee80211_tx_info *info; - struct ieee80211_tx_rate *txrate; - struct ar9170_tx_info *arinfo; - unsigned int queue = skb_get_queue_mapping(skb); - u16 keytype = 0; - u16 len, icv = 0; - - BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); - - hdr = (void *)skb->data; - info = IEEE80211_SKB_CB(skb); - len = skb->len; - - txc = (void *)skb_push(skb, sizeof(*txc)); - - if (info->control.hw_key) { - icv = info->control.hw_key->icv_len; - - switch (info->control.hw_key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - case WLAN_CIPHER_SUITE_TKIP: - keytype = AR9170_TX_MAC_ENCR_RC4; - break; - case WLAN_CIPHER_SUITE_CCMP: - keytype = AR9170_TX_MAC_ENCR_AES; - break; - default: - WARN_ON(1); - goto err_out; - } - } - - /* Length */ - txc->length = cpu_to_le16(len + icv + 4); - - txc->mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION | - AR9170_TX_MAC_BACKOFF); - txc->mac_control |= cpu_to_le16(ar9170_qos_hwmap[queue] << - AR9170_TX_MAC_QOS_SHIFT); - txc->mac_control |= cpu_to_le16(keytype); - txc->phy_control = cpu_to_le32(0); - - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); - - txrate = &info->control.rates[0]; - if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); - else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); - - arinfo = (void *)info->rate_driver_data; - arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_QUEUE_TIMEOUT); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (is_valid_ether_addr(ieee80211_get_DA(hdr)))) { - /* - * WARNING: - * Putting the QoS queue bits into an unexplored territory is - * certainly not elegant. - * - * In my defense: This idea provides a reasonable way to - * smuggle valuable information to the tx_status callback. - * Also, the idea behind this bit-abuse came straight from - * the original driver code. - */ - - txc->phy_control |= - cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); - - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); - } - - return 0; - -err_out: - skb_pull(skb, sizeof(*txc)); - return -EINVAL; -} - -static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ar9170_tx_control *txc; - struct ieee80211_tx_info *info; - struct ieee80211_rate *rate = NULL; - struct ieee80211_tx_rate *txrate; - u32 power, chains; - - txc = (void *) skb->data; - info = IEEE80211_SKB_CB(skb); - txrate = &info->control.rates[0]; - - if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); - - if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE); - - if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ); - /* this works because 40 MHz is 2 and dup is 3 */ - if (txrate->flags & IEEE80211_TX_RC_DUP_DATA) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ_DUP); - - if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI); - - if (txrate->flags & IEEE80211_TX_RC_MCS) { - u32 r = txrate->idx; - u8 *txpower; - - /* heavy clip control */ - txc->phy_control |= cpu_to_le32((r & 0x7) << 7); - - r <<= AR9170_TX_PHY_MCS_SHIFT; - BUG_ON(r & ~AR9170_TX_PHY_MCS_MASK); - - txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); - - if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { - if (info->band == IEEE80211_BAND_5GHZ) - txpower = ar->power_5G_ht40; - else - txpower = ar->power_2G_ht40; - } else { - if (info->band == IEEE80211_BAND_5GHZ) - txpower = ar->power_5G_ht20; - else - txpower = ar->power_2G_ht20; - } - - power = txpower[(txrate->idx) & 7]; - } else { - u8 *txpower; - u32 mod; - u32 phyrate; - u8 idx = txrate->idx; - - if (info->band != IEEE80211_BAND_2GHZ) { - idx += 4; - txpower = ar->power_5G_leg; - mod = AR9170_TX_PHY_MOD_OFDM; - } else { - if (idx < 4) { - txpower = ar->power_2G_cck; - mod = AR9170_TX_PHY_MOD_CCK; - } else { - mod = AR9170_TX_PHY_MOD_OFDM; - txpower = ar->power_2G_ofdm; - } - } - - rate = &__ar9170_ratetable[idx]; - - phyrate = rate->hw_value & 0xF; - power = txpower[(rate->hw_value & 0x30) >> 4]; - phyrate <<= AR9170_TX_PHY_MCS_SHIFT; - - txc->phy_control |= cpu_to_le32(mod); - txc->phy_control |= cpu_to_le32(phyrate); - } - - power <<= AR9170_TX_PHY_TX_PWR_SHIFT; - power &= AR9170_TX_PHY_TX_PWR_MASK; - txc->phy_control |= cpu_to_le32(power); - - /* set TX chains */ - if (ar->eeprom.tx_mask == 1) { - chains = AR9170_TX_PHY_TXCHAIN_1; - } else { - chains = AR9170_TX_PHY_TXCHAIN_2; - - /* >= 36M legacy OFDM - use only one chain */ - if (rate && rate->bitrate >= 360) - chains = AR9170_TX_PHY_TXCHAIN_1; - } - txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); -} - -static void ar9170_tx(struct ar9170 *ar) -{ - struct sk_buff *skb; - unsigned long flags; - struct ieee80211_tx_info *info; - struct ar9170_tx_info *arinfo; - unsigned int i, frames, frames_failed, remaining_space; - int err; - bool schedule_garbagecollector = false; - - BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); - - if (unlikely(!IS_STARTED(ar))) - return ; - - remaining_space = AR9170_TX_MAX_PENDING; - - for (i = 0; i < __AR9170_NUM_TXQ; i++) { - spin_lock_irqsave(&ar->tx_stats_lock, flags); - frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, - skb_queue_len(&ar->tx_pending[i])); - - if (remaining_space < frames) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "tx quota reached queue:%d, " - "remaining slots:%d, needed:%d\n", - i, remaining_space, frames); -#endif /* AR9170_QUEUE_DEBUG */ - frames = remaining_space; - } - - ar->tx_stats[i].len += frames; - ar->tx_stats[i].count += frames; - if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, "queue %d full\n", i); - wiphy_debug(ar->hw->wiphy, "stuck frames: ===>\n"); - ar9170_dump_txqueue(ar, &ar->tx_pending[i]); - ar9170_dump_txqueue(ar, &ar->tx_status[i]); -#endif /* AR9170_QUEUE_DEBUG */ - -#ifdef AR9170_QUEUE_STOP_DEBUG - wiphy_debug(ar->hw->wiphy, "stop queue %d\n", i); - __ar9170_dump_txstats(ar); -#endif /* AR9170_QUEUE_STOP_DEBUG */ - ieee80211_stop_queue(ar->hw, i); - } - - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - - if (!frames) - continue; - - frames_failed = 0; - while (frames) { - skb = skb_dequeue(&ar->tx_pending[i]); - if (unlikely(!skb)) { - frames_failed += frames; - frames = 0; - break; - } - - info = IEEE80211_SKB_CB(skb); - arinfo = (void *) info->rate_driver_data; - - /* TODO: cancel stuck frames */ - arinfo->timeout = jiffies + - msecs_to_jiffies(AR9170_TX_TIMEOUT); - -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, "send frame q:%d =>\n", i); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - - err = ar->tx(ar, skb); - if (unlikely(err)) { - frames_failed++; - dev_kfree_skb_any(skb); - } else { - remaining_space--; - schedule_garbagecollector = true; - } - - frames--; - } - -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "ar9170_tx report for queue %d\n", i); - - wiphy_debug(ar->hw->wiphy, - "unprocessed pending frames left:\n"); - ar9170_dump_txqueue(ar, &ar->tx_pending[i]); -#endif /* AR9170_QUEUE_DEBUG */ - - if (unlikely(frames_failed)) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "frames failed %d =>\n", frames_failed); -#endif /* AR9170_QUEUE_DEBUG */ - - spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[i].len -= frames_failed; - ar->tx_stats[i].count -= frames_failed; -#ifdef AR9170_QUEUE_STOP_DEBUG - wiphy_debug(ar->hw->wiphy, "wake queue %d\n", i); - __ar9170_dump_txstats(ar); -#endif /* AR9170_QUEUE_STOP_DEBUG */ - ieee80211_wake_queue(ar->hw, i); - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - } - } - - if (!schedule_garbagecollector) - return; - - ieee80211_queue_delayed_work(ar->hw, - &ar->tx_janitor, - msecs_to_jiffies(AR9170_JANITOR_DELAY)); -} - -void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct ar9170 *ar = hw->priv; - struct ieee80211_tx_info *info; - unsigned int queue; - - if (unlikely(!IS_STARTED(ar))) - goto err_free; - - if (unlikely(ar9170_tx_prepare(ar, skb))) - goto err_free; - - queue = skb_get_queue_mapping(skb); - info = IEEE80211_SKB_CB(skb); - ar9170_tx_prepare_phy(ar, skb); - skb_queue_tail(&ar->tx_pending[queue], skb); - - ar9170_tx(ar); - return; - -err_free: - dev_kfree_skb_any(skb); -} - -static int ar9170_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct ar9170 *ar = hw->priv; - struct ath_common *common = &ar->common; - int err = 0; - - mutex_lock(&ar->mutex); - - if (ar->vif) { - err = -EBUSY; - goto unlock; - } - - ar->vif = vif; - memcpy(common->macaddr, vif->addr, ETH_ALEN); - - if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { - ar->rx_software_decryption = true; - ar->disable_offload = true; - } - - ar->cur_filter = 0; - err = ar9170_update_frame_filter(ar, AR9170_MAC_REG_FTF_DEFAULTS); - if (err) - goto unlock; - - err = ar9170_set_operating_mode(ar); - -unlock: - mutex_unlock(&ar->mutex); - return err; -} - -static void ar9170_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct ar9170 *ar = hw->priv; - - mutex_lock(&ar->mutex); - ar->vif = NULL; - ar9170_update_frame_filter(ar, 0); - ar9170_set_beacon_timers(ar); - dev_kfree_skb(ar->beacon); - ar->beacon = NULL; - ar->sniffer_enabled = false; - ar->rx_software_decryption = false; - ar9170_set_operating_mode(ar); - mutex_unlock(&ar->mutex); -} - -static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) -{ - struct ar9170 *ar = hw->priv; - int err = 0; - - mutex_lock(&ar->mutex); - - if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_PS) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { - /* - * is it long_frame_max_tx_count or short_frame_max_tx_count? - */ - - err = ar9170_set_hwretry_limit(ar, - ar->hw->conf.long_frame_max_tx_count); - if (err) - goto out; - } - - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - - /* adjust slot time for 5 GHz */ - err = ar9170_set_slot_time(ar); - if (err) - goto out; - - err = ar9170_set_dyn_sifs_ack(ar); - if (err) - goto out; - - err = ar9170_set_channel(ar, hw->conf.channel, - AR9170_RFI_NONE, - nl80211_to_ar9170(hw->conf.channel_type)); - if (err) - goto out; - } - -out: - mutex_unlock(&ar->mutex); - return err; -} - -static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, - struct netdev_hw_addr_list *mc_list) -{ - u64 mchash; - struct netdev_hw_addr *ha; - - /* always get broadcast frames */ - mchash = 1ULL << (0xff >> 2); - - netdev_hw_addr_list_for_each(ha, mc_list) - mchash |= 1ULL << (ha->addr[5] >> 2); - - return mchash; -} - -static void ar9170_op_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *new_flags, - u64 multicast) -{ - struct ar9170 *ar = hw->priv; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return ; - - mutex_lock(&ar->mutex); - - /* mask supported flags */ - *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | - FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL; - ar->filter_state = *new_flags; - /* - * We can support more by setting the sniffer bit and - * then checking the error flags, later. - */ - - if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) - multicast = ~0ULL; - - if (multicast != ar->cur_mc_hash) - ar9170_update_multicast(ar, multicast); - - if (changed_flags & FIF_CONTROL) { - u32 filter = AR9170_MAC_REG_FTF_PSPOLL | - AR9170_MAC_REG_FTF_RTS | - AR9170_MAC_REG_FTF_CTS | - AR9170_MAC_REG_FTF_ACK | - AR9170_MAC_REG_FTF_CFE | - AR9170_MAC_REG_FTF_CFE_ACK; - - if (*new_flags & FIF_CONTROL) - filter |= ar->cur_filter; - else - filter &= (~ar->cur_filter); - - ar9170_update_frame_filter(ar, filter); - } - - if (changed_flags & FIF_PROMISC_IN_BSS) { - ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; - ar9170_set_operating_mode(ar); - } - - mutex_unlock(&ar->mutex); -} - - -static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - struct ar9170 *ar = hw->priv; - struct ath_common *common = &ar->common; - int err = 0; - - mutex_lock(&ar->mutex); - - if (changed & BSS_CHANGED_BSSID) { - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - err = ar9170_set_operating_mode(ar); - if (err) - goto out; - } - - if (changed & BSS_CHANGED_BEACON_ENABLED) - ar->enable_beacon = bss_conf->enable_beacon; - - if (changed & BSS_CHANGED_BEACON) { - err = ar9170_update_beacon(ar); - if (err) - goto out; - } - - if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON | - BSS_CHANGED_BEACON_INT)) { - err = ar9170_set_beacon_timers(ar); - if (err) - goto out; - } - - if (changed & BSS_CHANGED_ASSOC) { -#ifndef CONFIG_AR9170_LEDS - /* enable assoc LED. */ - err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); -#endif /* CONFIG_AR9170_LEDS */ - } - - if (changed & BSS_CHANGED_HT) { - /* TODO */ - err = 0; - } - - if (changed & BSS_CHANGED_ERP_SLOT) { - err = ar9170_set_slot_time(ar); - if (err) - goto out; - } - - if (changed & BSS_CHANGED_BASIC_RATES) { - err = ar9170_set_basic_rates(ar); - if (err) - goto out; - } - -out: - mutex_unlock(&ar->mutex); -} - -static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw) -{ - struct ar9170 *ar = hw->priv; - int err; - u64 tsf; -#define NR 3 - static const u32 addr[NR] = { AR9170_MAC_REG_TSF_H, - AR9170_MAC_REG_TSF_L, - AR9170_MAC_REG_TSF_H }; - u32 val[NR]; - int loops = 0; - - mutex_lock(&ar->mutex); - - while (loops++ < 10) { - err = ar9170_read_mreg(ar, NR, addr, val); - if (err || val[0] == val[2]) - break; - } - - mutex_unlock(&ar->mutex); - - if (WARN_ON(err)) - return 0; - tsf = val[0]; - tsf = (tsf << 32) | val[1]; - return tsf; -#undef NR -} - -static int ar9170_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 ar9170 *ar = hw->priv; - int err = 0, i; - u8 ktype; - - if ((!ar->vif) || (ar->disable_offload)) - return -EOPNOTSUPP; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - ktype = AR9170_ENC_ALG_WEP64; - break; - case WLAN_CIPHER_SUITE_WEP104: - ktype = AR9170_ENC_ALG_WEP128; - break; - case WLAN_CIPHER_SUITE_TKIP: - ktype = AR9170_ENC_ALG_TKIP; - break; - case WLAN_CIPHER_SUITE_CCMP: - ktype = AR9170_ENC_ALG_AESCCMP; - break; - default: - return -EOPNOTSUPP; - } - - mutex_lock(&ar->mutex); - if (cmd == SET_KEY) { - if (unlikely(!IS_STARTED(ar))) { - err = -EOPNOTSUPP; - goto out; - } - - /* group keys need all-zeroes address */ - if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) - sta = NULL; - - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { - for (i = 0; i < 64; i++) - if (!(ar->usedkeys & BIT(i))) - break; - if (i == 64) { - ar->rx_software_decryption = true; - ar9170_set_operating_mode(ar); - err = -ENOSPC; - goto out; - } - } else { - i = 64 + key->keyidx; - } - - key->hw_key_idx = i; - - err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, ktype, 0, - key->key, min_t(u8, 16, key->keylen)); - if (err) - goto out; - - if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { - err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, - ktype, 1, key->key + 16, 16); - if (err) - goto out; - - /* - * hardware is not capable generating the MMIC - * for fragmented frames! - */ - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - } - - if (i < 64) - ar->usedkeys |= BIT(i); - - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - } else { - if (unlikely(!IS_STARTED(ar))) { - /* The device is gone... together with the key ;-) */ - err = 0; - goto out; - } - - err = ar9170_disable_key(ar, key->hw_key_idx); - if (err) - goto out; - - if (key->hw_key_idx < 64) { - ar->usedkeys &= ~BIT(key->hw_key_idx); - } else { - err = ar9170_upload_key(ar, key->hw_key_idx, NULL, - AR9170_ENC_ALG_NONE, 0, - NULL, 0); - if (err) - goto out; - - if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { - err = ar9170_upload_key(ar, key->hw_key_idx, - NULL, - AR9170_ENC_ALG_NONE, 1, - NULL, 0); - if (err) - goto out; - } - - } - } - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_L, ar->usedkeys); - ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_H, ar->usedkeys >> 32); - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - -out: - mutex_unlock(&ar->mutex); - - return err; -} - -static int ar9170_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) -{ - struct ar9170 *ar = hw->priv; - u32 val; - int err; - - mutex_lock(&ar->mutex); - err = ar9170_read_reg(ar, AR9170_MAC_REG_TX_RETRY, &val); - ar->stats.dot11ACKFailureCount += val; - - memcpy(stats, &ar->stats, sizeof(*stats)); - mutex_unlock(&ar->mutex); - - return 0; -} - -static int ar9170_get_survey(struct ieee80211_hw *hw, int idx, - struct survey_info *survey) -{ - struct ar9170 *ar = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - - if (idx != 0) - return -ENOENT; - - /* TODO: update noise value, e.g. call ar9170_set_channel */ - - survey->channel = conf->channel; - survey->filled = SURVEY_INFO_NOISE_DBM; - survey->noise = ar->noise[0]; - - return 0; -} - -static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *param) -{ - struct ar9170 *ar = hw->priv; - int ret; - - mutex_lock(&ar->mutex); - if (queue < __AR9170_NUM_TXQ) { - memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], - param, sizeof(*param)); - - ret = ar9170_set_qos(ar); - } else { - ret = -EINVAL; - } - - mutex_unlock(&ar->mutex); - return ret; -} - -static int ar9170_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) -{ - switch (action) { - case IEEE80211_AMPDU_RX_START: - case IEEE80211_AMPDU_RX_STOP: - /* Handled by firmware */ - break; - - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static const struct ieee80211_ops ar9170_ops = { - .start = ar9170_op_start, - .stop = ar9170_op_stop, - .tx = ar9170_op_tx, - .add_interface = ar9170_op_add_interface, - .remove_interface = ar9170_op_remove_interface, - .config = ar9170_op_config, - .prepare_multicast = ar9170_op_prepare_multicast, - .configure_filter = ar9170_op_configure_filter, - .conf_tx = ar9170_conf_tx, - .bss_info_changed = ar9170_op_bss_info_changed, - .get_tsf = ar9170_op_get_tsf, - .set_key = ar9170_set_key, - .get_stats = ar9170_get_stats, - .get_survey = ar9170_get_survey, - .ampdu_action = ar9170_ampdu_action, -}; - -void *ar9170_alloc(size_t priv_size) -{ - struct ieee80211_hw *hw; - struct ar9170 *ar; - struct sk_buff *skb; - int i; - - /* - * this buffer is used for rx stream reconstruction. - * Under heavy load this device (or the transport layer?) - * tends to split the streams into separate rx descriptors. - */ - - skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL); - if (!skb) - goto err_nomem; - - hw = ieee80211_alloc_hw(priv_size, &ar9170_ops); - if (!hw) - goto err_nomem; - - ar = hw->priv; - ar->hw = hw; - ar->rx_failover = skb; - - mutex_init(&ar->mutex); - spin_lock_init(&ar->cmdlock); - spin_lock_init(&ar->tx_stats_lock); - for (i = 0; i < __AR9170_NUM_TXQ; i++) { - skb_queue_head_init(&ar->tx_status[i]); - skb_queue_head_init(&ar->tx_pending[i]); - } - ar9170_rx_reset_rx_mpdu(ar); - INIT_WORK(&ar->beacon_work, ar9170_new_beacon); - INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); - - /* all hw supports 2.4 GHz, so set channel to 1 by default */ - ar->channel = &ar9170_2ghz_chantable[0]; - - /* first part of wiphy init */ - ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_WDS) | - BIT(NL80211_IFTYPE_ADHOC); - ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM; - - ar->hw->queues = __AR9170_NUM_TXQ; - ar->hw->extra_tx_headroom = 8; - - ar->hw->max_rates = 1; - ar->hw->max_rate_tries = 3; - - for (i = 0; i < ARRAY_SIZE(ar->noise); i++) - ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ - - return ar; - -err_nomem: - kfree_skb(skb); - return ERR_PTR(-ENOMEM); -} - -static int ar9170_read_eeprom(struct ar9170 *ar) -{ -#define RW 8 /* number of words to read at once */ -#define RB (sizeof(u32) * RW) - struct ath_regulatory *regulatory = &ar->common.regulatory; - u8 *eeprom = (void *)&ar->eeprom; - u8 *addr = ar->eeprom.mac_address; - __le32 offsets[RW]; - unsigned int rx_streams, tx_streams, tx_params = 0; - int i, j, err, bands = 0; - - BUILD_BUG_ON(sizeof(ar->eeprom) & 3); - - BUILD_BUG_ON(RB > AR9170_MAX_CMD_LEN - 4); -#ifndef __CHECKER__ - /* don't want to handle trailing remains */ - BUILD_BUG_ON(sizeof(ar->eeprom) % RB); -#endif - - for (i = 0; i < sizeof(ar->eeprom)/RB; i++) { - for (j = 0; j < RW; j++) - offsets[j] = cpu_to_le32(AR9170_EEPROM_START + - RB * i + 4 * j); - - err = ar->exec_cmd(ar, AR9170_CMD_RREG, - RB, (u8 *) &offsets, - RB, eeprom + RB * i); - if (err) - return err; - } - -#undef RW -#undef RB - - if (ar->eeprom.length == cpu_to_le16(0xFFFF)) - return -ENODATA; - - if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) { - ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar9170_band_2GHz; - bands++; - } - if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) { - ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz; - bands++; - } - - rx_streams = hweight8(ar->eeprom.rx_mask); - tx_streams = hweight8(ar->eeprom.tx_mask); - - if (rx_streams != tx_streams) - tx_params = IEEE80211_HT_MCS_TX_RX_DIFF; - - if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS) - tx_params = (tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; - - ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params; - ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params; - - /* - * I measured this, a bandswitch takes roughly - * 135 ms and a frequency switch about 80. - * - * FIXME: measure these values again once EEPROM settings - * are used, that will influence them! - */ - if (bands == 2) - ar->hw->channel_change_time = 135 * 1000; - else - ar->hw->channel_change_time = 80 * 1000; - - regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); - regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); - - /* second part of wiphy init */ - SET_IEEE80211_PERM_ADDR(ar->hw, addr); - - return bands ? 0 : -EINVAL; -} - -static int ar9170_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ar9170 *ar = hw->priv; - - return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory); -} - -int ar9170_register(struct ar9170 *ar, struct device *pdev) -{ - struct ath_regulatory *regulatory = &ar->common.regulatory; - int err; - - /* try to read EEPROM, init MAC addr */ - err = ar9170_read_eeprom(ar); - if (err) - goto err_out; - - err = ath_regd_init(regulatory, ar->hw->wiphy, - ar9170_reg_notifier); - if (err) - goto err_out; - - err = ieee80211_register_hw(ar->hw); - if (err) - goto err_out; - - if (!ath_is_world_regd(regulatory)) - regulatory_hint(ar->hw->wiphy, regulatory->alpha2); - - err = ar9170_init_leds(ar); - if (err) - goto err_unreg; - -#ifdef CONFIG_AR9170_LEDS - err = ar9170_register_leds(ar); - if (err) - goto err_unreg; -#endif /* CONFIG_AR9170_LEDS */ - - dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", - wiphy_name(ar->hw->wiphy)); - - ar->registered = true; - return 0; - -err_unreg: - ieee80211_unregister_hw(ar->hw); - -err_out: - return err; -} - -void ar9170_unregister(struct ar9170 *ar) -{ - if (ar->registered) { -#ifdef CONFIG_AR9170_LEDS - ar9170_unregister_leds(ar); -#endif /* CONFIG_AR9170_LEDS */ - - ieee80211_unregister_hw(ar->hw); - } - - kfree_skb(ar->rx_failover); - mutex_destroy(&ar->mutex); -} diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c deleted file mode 100644 index aa8d06ba1ee4..000000000000 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ /dev/null @@ -1,1719 +0,0 @@ -/* - * Atheros AR9170 driver - * - * PHY and RF code - * - * Copyright 2008, Johannes Berg - * - * 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; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 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 -#include "ar9170.h" -#include "cmd.h" - -static int ar9170_init_power_cal(struct ar9170 *ar) -{ - ar9170_regwrite_begin(ar); - - ar9170_regwrite(0x1bc000 + 0x993c, 0x7f); - ar9170_regwrite(0x1bc000 + 0x9934, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0x9938, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa234, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa238, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa38c, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa390, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa3cc, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa3d0, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa3d4, 0x3f3f3f3f); - - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -struct ar9170_phy_init { - u32 reg, _5ghz_20, _5ghz_40, _2ghz_40, _2ghz_20; -}; - -static struct ar9170_phy_init ar5416_phy_init[] = { - { 0x1c5800, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c5804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, }, - { 0x1c5808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c580c, 0xad848e19, 0xad848e19, 0xad848e19, 0xad848e19, }, - { 0x1c5810, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0x7d14e000, }, - { 0x1c5814, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, }, - { 0x1c5818, 0x00000090, 0x00000090, 0x00000090, 0x00000090, }, - { 0x1c581c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, }, - { 0x1c5824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, - { 0x1c5828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, }, - { 0x1c582c, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, - { 0x1c5830, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, - { 0x1c5838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c583c, 0x00200400, 0x00200400, 0x00200400, 0x00200400, }, - { 0x1c5840, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e, }, - { 0x1c5844, 0x1372161e, 0x13721c1e, 0x13721c24, 0x137216a4, }, - { 0x1c5848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, }, - { 0x1c584c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, }, - { 0x1c5850, 0x6c48b4e4, 0x6c48b4e4, 0x6c48b0e4, 0x6c48b0e4, }, - { 0x1c5854, 0x00000859, 0x00000859, 0x00000859, 0x00000859, }, - { 0x1c5858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, }, - { 0x1c585c, 0x31395c5e, 0x31395c5e, 0x31395c5e, 0x31395c5e, }, - { 0x1c5860, 0x0004dd10, 0x0004dd10, 0x0004dd20, 0x0004dd20, }, - { 0x1c5868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, }, - { 0x1c586c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, }, - { 0x1c5900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5908, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c590c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, }, - { 0x1c5918, 0x00000118, 0x00000230, 0x00000268, 0x00000134, }, - { 0x1c591c, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff, }, - { 0x1c5920, 0x0510081c, 0x0510081c, 0x0510001c, 0x0510001c, }, - { 0x1c5924, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0xd0058a15, }, - { 0x1c5928, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c592c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, - { 0x1c5934, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c5938, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c593c, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, }, - { 0x1c5944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, }, - { 0x1c5948, 0x9280b212, 0x9280b212, 0x9280b212, 0x9280b212, }, - { 0x1c594c, 0x00020028, 0x00020028, 0x00020028, 0x00020028, }, - { 0x1c5954, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0x5d50e188, }, - { 0x1c5958, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, }, - { 0x1c5960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, - { 0x1c5964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, }, - { 0x1c5970, 0x190fb515, 0x190fb515, 0x190fb515, 0x190fb515, }, - { 0x1c5974, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5978, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c597c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5980, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5984, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5988, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c598c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5990, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5994, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5998, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c599c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59a4, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c59a8, 0x001fff00, 0x001fff00, 0x001fff00, 0x001fff00, }, - { 0x1c59ac, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0x006f00c4, }, - { 0x1c59b0, 0x03051000, 0x03051000, 0x03051000, 0x03051000, }, - { 0x1c59b4, 0x00000820, 0x00000820, 0x00000820, 0x00000820, }, - { 0x1c59c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, }, - { 0x1c59c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, }, - { 0x1c59c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, }, - { 0x1c59cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, }, - { 0x1c59d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, }, - { 0x1c59d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59e0, 0x00000200, 0x00000200, 0x00000200, 0x00000200, }, - { 0x1c59e4, 0x64646464, 0x64646464, 0x64646464, 0x64646464, }, - { 0x1c59e8, 0x3c787878, 0x3c787878, 0x3c787878, 0x3c787878, }, - { 0x1c59ec, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, }, - { 0x1c59f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59fc, 0x00001042, 0x00001042, 0x00001042, 0x00001042, }, - { 0x1c5a00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5a04, 0x00000040, 0x00000040, 0x00000040, 0x00000040, }, - { 0x1c5a08, 0x00000080, 0x00000080, 0x00000080, 0x00000080, }, - { 0x1c5a0c, 0x000001a1, 0x000001a1, 0x00000141, 0x00000141, }, - { 0x1c5a10, 0x000001e1, 0x000001e1, 0x00000181, 0x00000181, }, - { 0x1c5a14, 0x00000021, 0x00000021, 0x000001c1, 0x000001c1, }, - { 0x1c5a18, 0x00000061, 0x00000061, 0x00000001, 0x00000001, }, - { 0x1c5a1c, 0x00000168, 0x00000168, 0x00000041, 0x00000041, }, - { 0x1c5a20, 0x000001a8, 0x000001a8, 0x000001a8, 0x000001a8, }, - { 0x1c5a24, 0x000001e8, 0x000001e8, 0x000001e8, 0x000001e8, }, - { 0x1c5a28, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, - { 0x1c5a2c, 0x00000068, 0x00000068, 0x00000068, 0x00000068, }, - { 0x1c5a30, 0x00000189, 0x00000189, 0x000000a8, 0x000000a8, }, - { 0x1c5a34, 0x000001c9, 0x000001c9, 0x00000169, 0x00000169, }, - { 0x1c5a38, 0x00000009, 0x00000009, 0x000001a9, 0x000001a9, }, - { 0x1c5a3c, 0x00000049, 0x00000049, 0x000001e9, 0x000001e9, }, - { 0x1c5a40, 0x00000089, 0x00000089, 0x00000029, 0x00000029, }, - { 0x1c5a44, 0x00000170, 0x00000170, 0x00000069, 0x00000069, }, - { 0x1c5a48, 0x000001b0, 0x000001b0, 0x00000190, 0x00000190, }, - { 0x1c5a4c, 0x000001f0, 0x000001f0, 0x000001d0, 0x000001d0, }, - { 0x1c5a50, 0x00000030, 0x00000030, 0x00000010, 0x00000010, }, - { 0x1c5a54, 0x00000070, 0x00000070, 0x00000050, 0x00000050, }, - { 0x1c5a58, 0x00000191, 0x00000191, 0x00000090, 0x00000090, }, - { 0x1c5a5c, 0x000001d1, 0x000001d1, 0x00000151, 0x00000151, }, - { 0x1c5a60, 0x00000011, 0x00000011, 0x00000191, 0x00000191, }, - { 0x1c5a64, 0x00000051, 0x00000051, 0x000001d1, 0x000001d1, }, - { 0x1c5a68, 0x00000091, 0x00000091, 0x00000011, 0x00000011, }, - { 0x1c5a6c, 0x000001b8, 0x000001b8, 0x00000051, 0x00000051, }, - { 0x1c5a70, 0x000001f8, 0x000001f8, 0x00000198, 0x00000198, }, - { 0x1c5a74, 0x00000038, 0x00000038, 0x000001d8, 0x000001d8, }, - { 0x1c5a78, 0x00000078, 0x00000078, 0x00000018, 0x00000018, }, - { 0x1c5a7c, 0x00000199, 0x00000199, 0x00000058, 0x00000058, }, - { 0x1c5a80, 0x000001d9, 0x000001d9, 0x00000098, 0x00000098, }, - { 0x1c5a84, 0x00000019, 0x00000019, 0x00000159, 0x00000159, }, - { 0x1c5a88, 0x00000059, 0x00000059, 0x00000199, 0x00000199, }, - { 0x1c5a8c, 0x00000099, 0x00000099, 0x000001d9, 0x000001d9, }, - { 0x1c5a90, 0x000000d9, 0x000000d9, 0x00000019, 0x00000019, }, - { 0x1c5a94, 0x000000f9, 0x000000f9, 0x00000059, 0x00000059, }, - { 0x1c5a98, 0x000000f9, 0x000000f9, 0x00000099, 0x00000099, }, - { 0x1c5a9c, 0x000000f9, 0x000000f9, 0x000000d9, 0x000000d9, }, - { 0x1c5aa0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aa4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aa8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aac, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ab0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ab4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ab8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5abc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ac0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ac4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ac8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5acc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ad0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ad4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ad8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5adc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ae0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ae4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ae8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aec, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5af0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5af4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5af8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5afc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5b00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5b04, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c5b08, 0x00000002, 0x00000002, 0x00000002, 0x00000002, }, - { 0x1c5b0c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, }, - { 0x1c5b10, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, - { 0x1c5b14, 0x00000005, 0x00000005, 0x00000005, 0x00000005, }, - { 0x1c5b18, 0x00000008, 0x00000008, 0x00000008, 0x00000008, }, - { 0x1c5b1c, 0x00000009, 0x00000009, 0x00000009, 0x00000009, }, - { 0x1c5b20, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, }, - { 0x1c5b24, 0x0000000b, 0x0000000b, 0x0000000b, 0x0000000b, }, - { 0x1c5b28, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, }, - { 0x1c5b2c, 0x0000000d, 0x0000000d, 0x0000000d, 0x0000000d, }, - { 0x1c5b30, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, - { 0x1c5b34, 0x00000011, 0x00000011, 0x00000011, 0x00000011, }, - { 0x1c5b38, 0x00000012, 0x00000012, 0x00000012, 0x00000012, }, - { 0x1c5b3c, 0x00000013, 0x00000013, 0x00000013, 0x00000013, }, - { 0x1c5b40, 0x00000014, 0x00000014, 0x00000014, 0x00000014, }, - { 0x1c5b44, 0x00000015, 0x00000015, 0x00000015, 0x00000015, }, - { 0x1c5b48, 0x00000018, 0x00000018, 0x00000018, 0x00000018, }, - { 0x1c5b4c, 0x00000019, 0x00000019, 0x00000019, 0x00000019, }, - { 0x1c5b50, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, - { 0x1c5b54, 0x0000001b, 0x0000001b, 0x0000001b, 0x0000001b, }, - { 0x1c5b58, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, }, - { 0x1c5b5c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, }, - { 0x1c5b60, 0x00000020, 0x00000020, 0x00000020, 0x00000020, }, - { 0x1c5b64, 0x00000021, 0x00000021, 0x00000021, 0x00000021, }, - { 0x1c5b68, 0x00000022, 0x00000022, 0x00000022, 0x00000022, }, - { 0x1c5b6c, 0x00000023, 0x00000023, 0x00000023, 0x00000023, }, - { 0x1c5b70, 0x00000024, 0x00000024, 0x00000024, 0x00000024, }, - { 0x1c5b74, 0x00000025, 0x00000025, 0x00000025, 0x00000025, }, - { 0x1c5b78, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, - { 0x1c5b7c, 0x00000029, 0x00000029, 0x00000029, 0x00000029, }, - { 0x1c5b80, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a, }, - { 0x1c5b84, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, }, - { 0x1c5b88, 0x0000002c, 0x0000002c, 0x0000002c, 0x0000002c, }, - { 0x1c5b8c, 0x0000002d, 0x0000002d, 0x0000002d, 0x0000002d, }, - { 0x1c5b90, 0x00000030, 0x00000030, 0x00000030, 0x00000030, }, - { 0x1c5b94, 0x00000031, 0x00000031, 0x00000031, 0x00000031, }, - { 0x1c5b98, 0x00000032, 0x00000032, 0x00000032, 0x00000032, }, - { 0x1c5b9c, 0x00000033, 0x00000033, 0x00000033, 0x00000033, }, - { 0x1c5ba0, 0x00000034, 0x00000034, 0x00000034, 0x00000034, }, - { 0x1c5ba4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5ba8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bac, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bb0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bb4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bb8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bbc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bc0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bc4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bc8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bcc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bd0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bd4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bd8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bdc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5be0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5be4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5be8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bec, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bf0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bf4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bf8, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, - { 0x1c5bfc, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, - { 0x1c5c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c14, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c1c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c20, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c28, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c2c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c30, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c34, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c38, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cf0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cf4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cf8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cfc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6200, 0x00000008, 0x00000008, 0x0000000e, 0x0000000e, }, - { 0x1c6204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, }, - { 0x1c6208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, }, - { 0x1c620c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, - { 0x1c6210, 0x40806333, 0x40806333, 0x40806333, 0x40806333, }, - { 0x1c6214, 0x00106c10, 0x00106c10, 0x00106c10, 0x00106c10, }, - { 0x1c6218, 0x009c4060, 0x009c4060, 0x009c4060, 0x009c4060, }, - { 0x1c621c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, }, - { 0x1c6220, 0x018830c6, 0x018830c6, 0x018830c6, 0x018830c6, }, - { 0x1c6224, 0x00000400, 0x00000400, 0x00000400, 0x00000400, }, - { 0x1c6228, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, }, - { 0x1c622c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6230, 0x00000108, 0x00000210, 0x00000210, 0x00000108, }, - { 0x1c6234, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c6238, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c623c, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, }, - { 0x1c6240, 0x38490a20, 0x38490a20, 0x38490a20, 0x38490a20, }, - { 0x1c6244, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0x00007bb6, }, - { 0x1c6248, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, }, - { 0x1c624c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c6250, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, - { 0x1c6254, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6258, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, }, - { 0x1c625c, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, }, - { 0x1c6260, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, }, - { 0x1c6264, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, }, - { 0x1c6268, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c626c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, - { 0x1c6274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, }, - { 0x1c6278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, - { 0x1c627c, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, }, - { 0x1c6300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, }, - { 0x1c6304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, }, - { 0x1c6308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, }, - { 0x1c630c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, }, - { 0x1c6310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, }, - { 0x1c6314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, }, - { 0x1c6318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, }, - { 0x1c631c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, }, - { 0x1c6320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, }, - { 0x1c6324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, }, - { 0x1c6328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, }, - { 0x1c632c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6338, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c633c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6340, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6344, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6348, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, - { 0x1c634c, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, - { 0x1c6350, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, - { 0x1c6354, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, }, - { 0x1c6358, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, }, - { 0x1c6388, 0x08000000, 0x08000000, 0x08000000, 0x08000000, }, - { 0x1c638c, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c6390, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c6394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, - { 0x1c6398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, }, - { 0x1c639c, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c63a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63a4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63a8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63ac, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63b0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63b4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63bc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63c4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63c8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63cc, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c63d0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c63d4, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c63d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, - { 0x1c63e0, 0x000000c0, 0x000000c0, 0x000000c0, 0x000000c0, }, - { 0x1c6848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, - { 0x1c6920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, - { 0x1c6960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, - { 0x1c720c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, - { 0x1c726c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, - { 0x1c7848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, - { 0x1c7920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, - { 0x1c7960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, - { 0x1c820c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, - { 0x1c826c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, -/* { 0x1c8864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, }, */ - { 0x1c8864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, }, - { 0x1c895c, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, }, - { 0x1c8968, 0x000003ce, 0x000003ce, 0x000003ce, 0x000003ce, }, - { 0x1c89bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, }, - { 0x1c9270, 0x00820820, 0x00820820, 0x00820820, 0x00820820, }, - { 0x1c935c, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, }, - { 0x1c9360, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, }, - { 0x1c9364, 0x17601685, 0x17601685, 0x17601685, 0x17601685, }, - { 0x1c9368, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, }, - { 0x1c936c, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, }, - { 0x1c9370, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, }, - { 0x1c9374, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, }, - { 0x1c9378, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, }, - { 0x1c937c, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, }, - { 0x1c9380, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, }, - { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } -}; - -/* - * look up a certain register in ar5416_phy_init[] and return the init. value - * for the band and bandwidth given. Return 0 if register address not found. - */ -static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz) -{ - unsigned int i; - for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { - if (ar5416_phy_init[i].reg != reg) - continue; - - if (is_2ghz) { - if (is_40mhz) - return ar5416_phy_init[i]._2ghz_40; - else - return ar5416_phy_init[i]._2ghz_20; - } else { - if (is_40mhz) - return ar5416_phy_init[i]._5ghz_40; - else - return ar5416_phy_init[i]._5ghz_20; - } - } - return 0; -} - -/* - * initialize some phy regs from eeprom values in modal_header[] - * acc. to band and bandwidth - */ -static int ar9170_init_phy_from_eeprom(struct ar9170 *ar, - bool is_2ghz, bool is_40mhz) -{ - static const u8 xpd2pd[16] = { - 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2, - 0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2 - }; - u32 defval, newval; - /* pointer to the modal_header acc. to band */ - struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz]; - - ar9170_regwrite_begin(ar); - - /* ant common control (index 0) */ - newval = le32_to_cpu(m->antCtrlCommon); - ar9170_regwrite(0x1c5964, newval); - - /* ant control chain 0 (index 1) */ - newval = le32_to_cpu(m->antCtrlChain[0]); - ar9170_regwrite(0x1c5960, newval); - - /* ant control chain 2 (index 2) */ - newval = le32_to_cpu(m->antCtrlChain[1]); - ar9170_regwrite(0x1c7960, newval); - - /* SwSettle (index 3) */ - if (!is_40mhz) { - defval = ar9170_get_default_phy_reg_val(0x1c5844, - is_2ghz, is_40mhz); - newval = (defval & ~0x3f80) | - ((m->switchSettling & 0x7f) << 7); - ar9170_regwrite(0x1c5844, newval); - } - - /* adcDesired, pdaDesired (index 4) */ - defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz); - newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) | - ((u8)m->adcDesiredSize); - ar9170_regwrite(0x1c5850, newval); - - /* TxEndToXpaOff, TxFrameToXpaOn (index 5) */ - defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz); - newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) | - (m->txFrameToXpaOn << 8) | m->txFrameToXpaOn; - ar9170_regwrite(0x1c5834, newval); - - /* TxEndToRxOn (index 6) */ - defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz); - newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16); - ar9170_regwrite(0x1c5828, newval); - - /* thresh62 (index 7) */ - defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz); - newval = (defval & ~0x7f000) | (m->thresh62 << 12); - ar9170_regwrite(0x1c8864, newval); - - /* tx/rx attenuation chain 0 (index 8) */ - defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz); - newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12); - ar9170_regwrite(0x1c5848, newval); - - /* tx/rx attenuation chain 2 (index 9) */ - defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz); - newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12); - ar9170_regwrite(0x1c7848, newval); - - /* tx/rx margin chain 0 (index 10) */ - defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz); - newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18); - /* bsw margin chain 0 for 5GHz only */ - if (!is_2ghz) - newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10); - ar9170_regwrite(0x1c620c, newval); - - /* tx/rx margin chain 2 (index 11) */ - defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz); - newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18); - ar9170_regwrite(0x1c820c, newval); - - /* iqCall, iqCallq chain 0 (index 12) */ - defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz); - newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) | - ((u8)m->iqCalQCh[0] & 0x1f); - ar9170_regwrite(0x1c5920, newval); - - /* iqCall, iqCallq chain 2 (index 13) */ - defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz); - newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) | - ((u8)m->iqCalQCh[1] & 0x1f); - ar9170_regwrite(0x1c7920, newval); - - /* xpd gain mask (index 14) */ - defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz); - newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16); - ar9170_regwrite(0x1c6258, newval); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) -{ - int i, err; - u32 val; - bool is_2ghz = band == IEEE80211_BAND_2GHZ; - bool is_40mhz = conf_is_ht40(&ar->hw->conf); - - ar9170_regwrite_begin(ar); - - for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { - if (is_40mhz) { - if (is_2ghz) - val = ar5416_phy_init[i]._2ghz_40; - else - val = ar5416_phy_init[i]._5ghz_40; - } else { - if (is_2ghz) - val = ar5416_phy_init[i]._2ghz_20; - else - val = ar5416_phy_init[i]._5ghz_20; - } - - ar9170_regwrite(ar5416_phy_init[i].reg, val); - } - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - return err; - - err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); - if (err) - return err; - - err = ar9170_init_power_cal(ar); - if (err) - return err; - - /* XXX: remove magic! */ - if (is_2ghz) - err = ar9170_write_reg(ar, 0x1d4014, 0x5163); - else - err = ar9170_write_reg(ar, 0x1d4014, 0x5143); - - return err; -} - -struct ar9170_rf_init { - u32 reg, _5ghz, _2ghz; -}; - -static struct ar9170_rf_init ar9170_rf_init[] = { - /* bank 0 */ - { 0x1c58b0, 0x1e5795e5, 0x1e5795e5}, - { 0x1c58e0, 0x02008020, 0x02008020}, - /* bank 1 */ - { 0x1c58b0, 0x02108421, 0x02108421}, - { 0x1c58ec, 0x00000008, 0x00000008}, - /* bank 2 */ - { 0x1c58b0, 0x0e73ff17, 0x0e73ff17}, - { 0x1c58e0, 0x00000420, 0x00000420}, - /* bank 3 */ - { 0x1c58f0, 0x01400018, 0x01c00018}, - /* bank 4 */ - { 0x1c58b0, 0x000001a1, 0x000001a1}, - { 0x1c58e8, 0x00000001, 0x00000001}, - /* bank 5 */ - { 0x1c58b0, 0x00000013, 0x00000013}, - { 0x1c58e4, 0x00000002, 0x00000002}, - /* bank 6 */ - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00004000, 0x00004000}, - { 0x1c58b0, 0x00006c00, 0x00006c00}, - { 0x1c58b0, 0x00002c00, 0x00002c00}, - { 0x1c58b0, 0x00004800, 0x00004800}, - { 0x1c58b0, 0x00004000, 0x00004000}, - { 0x1c58b0, 0x00006000, 0x00006000}, - { 0x1c58b0, 0x00001000, 0x00001000}, - { 0x1c58b0, 0x00004000, 0x00004000}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00087c00, 0x00087c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00005400, 0x00005400}, - { 0x1c58b0, 0x00000c00, 0x00000c00}, - { 0x1c58b0, 0x00001800, 0x00001800}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00006c00, 0x00006c00}, - { 0x1c58b0, 0x00006c00, 0x00006c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00002c00, 0x00002c00}, - { 0x1c58b0, 0x00003c00, 0x00003c00}, - { 0x1c58b0, 0x00003800, 0x00003800}, - { 0x1c58b0, 0x00001c00, 0x00001c00}, - { 0x1c58b0, 0x00000800, 0x00000800}, - { 0x1c58b0, 0x00000408, 0x00000408}, - { 0x1c58b0, 0x00004c15, 0x00004c15}, - { 0x1c58b0, 0x00004188, 0x00004188}, - { 0x1c58b0, 0x0000201e, 0x0000201e}, - { 0x1c58b0, 0x00010408, 0x00010408}, - { 0x1c58b0, 0x00000801, 0x00000801}, - { 0x1c58b0, 0x00000c08, 0x00000c08}, - { 0x1c58b0, 0x0000181e, 0x0000181e}, - { 0x1c58b0, 0x00001016, 0x00001016}, - { 0x1c58b0, 0x00002800, 0x00002800}, - { 0x1c58b0, 0x00004010, 0x00004010}, - { 0x1c58b0, 0x0000081c, 0x0000081c}, - { 0x1c58b0, 0x00000115, 0x00000115}, - { 0x1c58b0, 0x00000015, 0x00000015}, - { 0x1c58b0, 0x00000066, 0x00000066}, - { 0x1c58b0, 0x0000001c, 0x0000001c}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000004, 0x00000004}, - { 0x1c58b0, 0x00000015, 0x00000015}, - { 0x1c58b0, 0x0000001f, 0x0000001f}, - { 0x1c58e0, 0x00000000, 0x00000400}, - /* bank 7 */ - { 0x1c58b0, 0x000000a0, 0x000000a0}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000040, 0x00000040}, - { 0x1c58f0, 0x0000001c, 0x0000001c}, -}; - -static int ar9170_init_rf_banks_0_7(struct ar9170 *ar, bool band5ghz) -{ - int err, i; - - ar9170_regwrite_begin(ar); - - for (i = 0; i < ARRAY_SIZE(ar9170_rf_init); i++) - ar9170_regwrite(ar9170_rf_init[i].reg, - band5ghz ? ar9170_rf_init[i]._5ghz - : ar9170_rf_init[i]._2ghz); - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - wiphy_err(ar->hw->wiphy, "rf init failed\n"); - return err; -} - -static int ar9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz, - u32 freq, enum ar9170_bw bw) -{ - int err; - u32 d0, d1, td0, td1, fd0, fd1; - u8 chansel; - u8 refsel0 = 1, refsel1 = 0; - u8 lf_synth = 0; - - switch (bw) { - case AR9170_BW_40_ABOVE: - freq += 10; - break; - case AR9170_BW_40_BELOW: - freq -= 10; - break; - case AR9170_BW_20: - break; - case __AR9170_NUM_BW: - BUG(); - } - - if (band5ghz) { - if (freq % 10) { - chansel = (freq - 4800) / 5; - } else { - chansel = ((freq - 4800) / 10) * 2; - refsel0 = 0; - refsel1 = 1; - } - chansel = byte_rev_table[chansel]; - } else { - if (freq == 2484) { - chansel = 10 + (freq - 2274) / 5; - lf_synth = 1; - } else - chansel = 16 + (freq - 2272) / 5; - chansel *= 4; - chansel = byte_rev_table[chansel]; - } - - d1 = chansel; - d0 = 0x21 | - refsel0 << 3 | - refsel1 << 2 | - lf_synth << 1; - td0 = d0 & 0x1f; - td1 = d1 & 0x1f; - fd0 = td1 << 5 | td0; - - td0 = (d0 >> 5) & 0x7; - td1 = (d1 >> 5) & 0x7; - fd1 = td1 << 5 | td0; - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(0x1c58b0, fd0); - ar9170_regwrite(0x1c58e8, fd1); - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - return err; - - msleep(10); - - return 0; -} - -struct ar9170_phy_freq_params { - u8 coeff_exp; - u16 coeff_man; - u8 coeff_exp_shgi; - u16 coeff_man_shgi; -}; - -struct ar9170_phy_freq_entry { - u16 freq; - struct ar9170_phy_freq_params params[__AR9170_NUM_BW]; -}; - -/* NB: must be in sync with channel tables in main! */ -static const struct ar9170_phy_freq_entry ar9170_phy_freq_params[] = { -/* - * freq, - * 20MHz, - * 40MHz (below), - * 40Mhz (above), - */ - { 2412, { - { 3, 21737, 3, 19563, }, - { 3, 21827, 3, 19644, }, - { 3, 21647, 3, 19482, }, - } }, - { 2417, { - { 3, 21692, 3, 19523, }, - { 3, 21782, 3, 19604, }, - { 3, 21602, 3, 19442, }, - } }, - { 2422, { - { 3, 21647, 3, 19482, }, - { 3, 21737, 3, 19563, }, - { 3, 21558, 3, 19402, }, - } }, - { 2427, { - { 3, 21602, 3, 19442, }, - { 3, 21692, 3, 19523, }, - { 3, 21514, 3, 19362, }, - } }, - { 2432, { - { 3, 21558, 3, 19402, }, - { 3, 21647, 3, 19482, }, - { 3, 21470, 3, 19323, }, - } }, - { 2437, { - { 3, 21514, 3, 19362, }, - { 3, 21602, 3, 19442, }, - { 3, 21426, 3, 19283, }, - } }, - { 2442, { - { 3, 21470, 3, 19323, }, - { 3, 21558, 3, 19402, }, - { 3, 21382, 3, 19244, }, - } }, - { 2447, { - { 3, 21426, 3, 19283, }, - { 3, 21514, 3, 19362, }, - { 3, 21339, 3, 19205, }, - } }, - { 2452, { - { 3, 21382, 3, 19244, }, - { 3, 21470, 3, 19323, }, - { 3, 21295, 3, 19166, }, - } }, - { 2457, { - { 3, 21339, 3, 19205, }, - { 3, 21426, 3, 19283, }, - { 3, 21252, 3, 19127, }, - } }, - { 2462, { - { 3, 21295, 3, 19166, }, - { 3, 21382, 3, 19244, }, - { 3, 21209, 3, 19088, }, - } }, - { 2467, { - { 3, 21252, 3, 19127, }, - { 3, 21339, 3, 19205, }, - { 3, 21166, 3, 19050, }, - } }, - { 2472, { - { 3, 21209, 3, 19088, }, - { 3, 21295, 3, 19166, }, - { 3, 21124, 3, 19011, }, - } }, - { 2484, { - { 3, 21107, 3, 18996, }, - { 3, 21192, 3, 19073, }, - { 3, 21022, 3, 18920, }, - } }, - { 4920, { - { 4, 21313, 4, 19181, }, - { 4, 21356, 4, 19220, }, - { 4, 21269, 4, 19142, }, - } }, - { 4940, { - { 4, 21226, 4, 19104, }, - { 4, 21269, 4, 19142, }, - { 4, 21183, 4, 19065, }, - } }, - { 4960, { - { 4, 21141, 4, 19027, }, - { 4, 21183, 4, 19065, }, - { 4, 21098, 4, 18988, }, - } }, - { 4980, { - { 4, 21056, 4, 18950, }, - { 4, 21098, 4, 18988, }, - { 4, 21014, 4, 18912, }, - } }, - { 5040, { - { 4, 20805, 4, 18725, }, - { 4, 20846, 4, 18762, }, - { 4, 20764, 4, 18687, }, - } }, - { 5060, { - { 4, 20723, 4, 18651, }, - { 4, 20764, 4, 18687, }, - { 4, 20682, 4, 18614, }, - } }, - { 5080, { - { 4, 20641, 4, 18577, }, - { 4, 20682, 4, 18614, }, - { 4, 20601, 4, 18541, }, - } }, - { 5180, { - { 4, 20243, 4, 18219, }, - { 4, 20282, 4, 18254, }, - { 4, 20204, 4, 18183, }, - } }, - { 5200, { - { 4, 20165, 4, 18148, }, - { 4, 20204, 4, 18183, }, - { 4, 20126, 4, 18114, }, - } }, - { 5220, { - { 4, 20088, 4, 18079, }, - { 4, 20126, 4, 18114, }, - { 4, 20049, 4, 18044, }, - } }, - { 5240, { - { 4, 20011, 4, 18010, }, - { 4, 20049, 4, 18044, }, - { 4, 19973, 4, 17976, }, - } }, - { 5260, { - { 4, 19935, 4, 17941, }, - { 4, 19973, 4, 17976, }, - { 4, 19897, 4, 17907, }, - } }, - { 5280, { - { 4, 19859, 4, 17873, }, - { 4, 19897, 4, 17907, }, - { 4, 19822, 4, 17840, }, - } }, - { 5300, { - { 4, 19784, 4, 17806, }, - { 4, 19822, 4, 17840, }, - { 4, 19747, 4, 17772, }, - } }, - { 5320, { - { 4, 19710, 4, 17739, }, - { 4, 19747, 4, 17772, }, - { 4, 19673, 4, 17706, }, - } }, - { 5500, { - { 4, 19065, 4, 17159, }, - { 4, 19100, 4, 17190, }, - { 4, 19030, 4, 17127, }, - } }, - { 5520, { - { 4, 18996, 4, 17096, }, - { 4, 19030, 4, 17127, }, - { 4, 18962, 4, 17065, }, - } }, - { 5540, { - { 4, 18927, 4, 17035, }, - { 4, 18962, 4, 17065, }, - { 4, 18893, 4, 17004, }, - } }, - { 5560, { - { 4, 18859, 4, 16973, }, - { 4, 18893, 4, 17004, }, - { 4, 18825, 4, 16943, }, - } }, - { 5580, { - { 4, 18792, 4, 16913, }, - { 4, 18825, 4, 16943, }, - { 4, 18758, 4, 16882, }, - } }, - { 5600, { - { 4, 18725, 4, 16852, }, - { 4, 18758, 4, 16882, }, - { 4, 18691, 4, 16822, }, - } }, - { 5620, { - { 4, 18658, 4, 16792, }, - { 4, 18691, 4, 16822, }, - { 4, 18625, 4, 16762, }, - } }, - { 5640, { - { 4, 18592, 4, 16733, }, - { 4, 18625, 4, 16762, }, - { 4, 18559, 4, 16703, }, - } }, - { 5660, { - { 4, 18526, 4, 16673, }, - { 4, 18559, 4, 16703, }, - { 4, 18493, 4, 16644, }, - } }, - { 5680, { - { 4, 18461, 4, 16615, }, - { 4, 18493, 4, 16644, }, - { 4, 18428, 4, 16586, }, - } }, - { 5700, { - { 4, 18396, 4, 16556, }, - { 4, 18428, 4, 16586, }, - { 4, 18364, 4, 16527, }, - } }, - { 5745, { - { 4, 18252, 4, 16427, }, - { 4, 18284, 4, 16455, }, - { 4, 18220, 4, 16398, }, - } }, - { 5765, { - { 4, 18189, 5, 32740, }, - { 4, 18220, 4, 16398, }, - { 4, 18157, 5, 32683, }, - } }, - { 5785, { - { 4, 18126, 5, 32626, }, - { 4, 18157, 5, 32683, }, - { 4, 18094, 5, 32570, }, - } }, - { 5805, { - { 4, 18063, 5, 32514, }, - { 4, 18094, 5, 32570, }, - { 4, 18032, 5, 32458, }, - } }, - { 5825, { - { 4, 18001, 5, 32402, }, - { 4, 18032, 5, 32458, }, - { 4, 17970, 5, 32347, }, - } }, - { 5170, { - { 4, 20282, 4, 18254, }, - { 4, 20321, 4, 18289, }, - { 4, 20243, 4, 18219, }, - } }, - { 5190, { - { 4, 20204, 4, 18183, }, - { 4, 20243, 4, 18219, }, - { 4, 20165, 4, 18148, }, - } }, - { 5210, { - { 4, 20126, 4, 18114, }, - { 4, 20165, 4, 18148, }, - { 4, 20088, 4, 18079, }, - } }, - { 5230, { - { 4, 20049, 4, 18044, }, - { 4, 20088, 4, 18079, }, - { 4, 20011, 4, 18010, }, - } }, -}; - -static const struct ar9170_phy_freq_params * -ar9170_get_hw_dyn_params(struct ieee80211_channel *channel, - enum ar9170_bw bw) -{ - unsigned int chanidx = 0; - u16 freq = 2412; - - if (channel) { - chanidx = channel->hw_value; - freq = channel->center_freq; - } - - BUG_ON(chanidx >= ARRAY_SIZE(ar9170_phy_freq_params)); - - BUILD_BUG_ON(__AR9170_NUM_BW != 3); - - WARN_ON(ar9170_phy_freq_params[chanidx].freq != freq); - - return &ar9170_phy_freq_params[chanidx].params[bw]; -} - - -int ar9170_init_rf(struct ar9170 *ar) -{ - const struct ar9170_phy_freq_params *freqpar; - __le32 cmd[7]; - int err; - - err = ar9170_init_rf_banks_0_7(ar, false); - if (err) - return err; - - err = ar9170_init_rf_bank4_pwr(ar, false, 2412, AR9170_BW_20); - if (err) - return err; - - freqpar = ar9170_get_hw_dyn_params(NULL, AR9170_BW_20); - - cmd[0] = cpu_to_le32(2412 * 1000); - cmd[1] = cpu_to_le32(0); - cmd[2] = cpu_to_le32(1); - cmd[3] = cpu_to_le32(freqpar->coeff_exp); - cmd[4] = cpu_to_le32(freqpar->coeff_man); - cmd[5] = cpu_to_le32(freqpar->coeff_exp_shgi); - cmd[6] = cpu_to_le32(freqpar->coeff_man_shgi); - - /* RF_INIT echoes the command back to us */ - err = ar->exec_cmd(ar, AR9170_CMD_RF_INIT, - sizeof(cmd), (u8 *)cmd, - sizeof(cmd), (u8 *)cmd); - if (err) - return err; - - msleep(1000); - - return ar9170_echo_test(ar, 0xaabbccdd); -} - -static int ar9170_find_freq_idx(int nfreqs, u8 *freqs, u8 f) -{ - int idx = nfreqs - 2; - - while (idx >= 0) { - if (f >= freqs[idx]) - return idx; - idx--; - } - - return 0; -} - -static s32 ar9170_interpolate_s32(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) -{ - /* nothing to interpolate, it's horizontal */ - if (y2 == y1) - return y1; - - /* check if we hit one of the edges */ - if (x == x1) - return y1; - if (x == x2) - return y2; - - /* x1 == x2 is bad, hopefully == x */ - if (x2 == x1) - return y1; - - return y1 + (((y2 - y1) * (x - x1)) / (x2 - x1)); -} - -static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2) -{ -#define SHIFT 8 - s32 y; - - y = ar9170_interpolate_s32(x << SHIFT, - x1 << SHIFT, y1 << SHIFT, - x2 << SHIFT, y2 << SHIFT); - - /* - * XXX: unwrap this expression - * Isn't it just DIV_ROUND_UP(y, 1<> SHIFT) + ((y & (1<<(SHIFT-1))) >> (SHIFT - 1)); -#undef SHIFT -} - -static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array) -{ - int i; - - for (i = 0; i < 3; i++) - if (x <= x_array[i + 1]) - break; - - return ar9170_interpolate_u8(x, - x_array[i], - y_array[i], - x_array[i + 1], - y_array[i + 1]); -} - -static int ar9170_set_freq_cal_data(struct ar9170 *ar, - struct ieee80211_channel *channel) -{ - u8 *cal_freq_pier; - u8 vpds[2][AR5416_PD_GAIN_ICEPTS]; - u8 pwrs[2][AR5416_PD_GAIN_ICEPTS]; - int chain, idx, i; - u32 phy_data = 0; - u8 f, tmp; - - switch (channel->band) { - case IEEE80211_BAND_2GHZ: - f = channel->center_freq - 2300; - cal_freq_pier = ar->eeprom.cal_freq_pier_2G; - i = AR5416_NUM_2G_CAL_PIERS - 1; - break; - - case IEEE80211_BAND_5GHZ: - f = (channel->center_freq - 4800) / 5; - cal_freq_pier = ar->eeprom.cal_freq_pier_5G; - i = AR5416_NUM_5G_CAL_PIERS - 1; - break; - - default: - return -EINVAL; - break; - } - - for (; i >= 0; i--) { - if (cal_freq_pier[i] != 0xff) - break; - } - if (i < 0) - return -EINVAL; - - idx = ar9170_find_freq_idx(i, cal_freq_pier, f); - - ar9170_regwrite_begin(ar); - - for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) { - for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) { - struct ar9170_calibration_data_per_freq *cal_pier_data; - int j; - - switch (channel->band) { - case IEEE80211_BAND_2GHZ: - cal_pier_data = &ar->eeprom. - cal_pier_data_2G[chain][idx]; - break; - - case IEEE80211_BAND_5GHZ: - cal_pier_data = &ar->eeprom. - cal_pier_data_5G[chain][idx]; - break; - - default: - return -EINVAL; - } - - for (j = 0; j < 2; j++) { - vpds[j][i] = ar9170_interpolate_u8(f, - cal_freq_pier[idx], - cal_pier_data->vpd_pdg[j][i], - cal_freq_pier[idx + 1], - cal_pier_data[1].vpd_pdg[j][i]); - - pwrs[j][i] = ar9170_interpolate_u8(f, - cal_freq_pier[idx], - cal_pier_data->pwr_pdg[j][i], - cal_freq_pier[idx + 1], - cal_pier_data[1].pwr_pdg[j][i]) / 2; - } - } - - for (i = 0; i < 76; i++) { - if (i < 25) { - tmp = ar9170_interpolate_val(i, &pwrs[0][0], - &vpds[0][0]); - } else { - tmp = ar9170_interpolate_val(i - 12, - &pwrs[1][0], - &vpds[1][0]); - } - - phy_data |= tmp << ((i & 3) << 3); - if ((i & 3) == 3) { - ar9170_regwrite(0x1c6280 + chain * 0x1000 + - (i & ~3), phy_data); - phy_data = 0; - } - } - - for (i = 19; i < 32; i++) - ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2), - 0x0); - } - - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -static u8 ar9170_get_max_edge_power(struct ar9170 *ar, - struct ar9170_calctl_edges edges[], - u32 freq) -{ - int i; - u8 rc = AR5416_MAX_RATE_POWER; - u8 f; - if (freq < 3000) - f = freq - 2300; - else - f = (freq - 4800) / 5; - - for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { - if (edges[i].channel == 0xff) - break; - if (f == edges[i].channel) { - /* exact freq match */ - rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS; - break; - } - if (i > 0 && f < edges[i].channel) { - if (f > edges[i - 1].channel && - edges[i - 1].power_flags & - AR9170_CALCTL_EDGE_FLAGS) { - /* lower channel has the inband flag set */ - rc = edges[i - 1].power_flags & - ~AR9170_CALCTL_EDGE_FLAGS; - } - break; - } - } - - if (i == AR5416_NUM_BAND_EDGES) { - if (f > edges[i - 1].channel && - edges[i - 1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { - /* lower channel has the inband flag set */ - rc = edges[i - 1].power_flags & - ~AR9170_CALCTL_EDGE_FLAGS; - } - } - return rc; -} - -static u8 ar9170_get_heavy_clip(struct ar9170 *ar, - struct ar9170_calctl_edges edges[], - u32 freq, enum ar9170_bw bw) -{ - u8 f; - int i; - u8 rc = 0; - - if (freq < 3000) - f = freq - 2300; - else - f = (freq - 4800) / 5; - - if (bw == AR9170_BW_40_BELOW || bw == AR9170_BW_40_ABOVE) - rc |= 0xf0; - - for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { - if (edges[i].channel == 0xff) - break; - if (f == edges[i].channel) { - if (!(edges[i].power_flags & AR9170_CALCTL_EDGE_FLAGS)) - rc |= 0x0f; - break; - } - } - - return rc; -} - -/* - * calculate the conformance test limits and the heavy clip parameter - * and apply them to ar->power* (derived from otus hal/hpmain.c, line 3706) - */ -static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) -{ - u8 ctl_grp; /* CTL group */ - u8 ctl_idx; /* CTL index */ - int i, j; - struct ctl_modes { - u8 ctl_mode; - u8 max_power; - u8 *pwr_cal_data; - int pwr_cal_len; - } *modes; - - /* - * order is relevant in the mode_list_*: we fall back to the - * lower indices if any mode is missed in the EEPROM. - */ - struct ctl_modes mode_list_2ghz[] = { - { CTL_11B, 0, ar->power_2G_cck, 4 }, - { CTL_11G, 0, ar->power_2G_ofdm, 4 }, - { CTL_2GHT20, 0, ar->power_2G_ht20, 8 }, - { CTL_2GHT40, 0, ar->power_2G_ht40, 8 }, - }; - struct ctl_modes mode_list_5ghz[] = { - { CTL_11A, 0, ar->power_5G_leg, 4 }, - { CTL_5GHT20, 0, ar->power_5G_ht20, 8 }, - { CTL_5GHT40, 0, ar->power_5G_ht40, 8 }, - }; - int nr_modes; - -#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) - - ar->phy_heavy_clip = 0; - - /* - * TODO: investigate the differences between OTUS' - * hpreg.c::zfHpGetRegulatoryDomain() and - * ath/regd.c::ath_regd_get_band_ctl() - - * e.g. for FCC3_WORLD the OTUS procedure - * always returns CTL_FCC, while the one in ath/ delivers - * CTL_ETSI for 2GHz and CTL_FCC for 5GHz. - */ - ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory, - ar->hw->conf.channel->band); - - /* ctl group not found - either invalid band (NO_CTL) or ww roaming */ - if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL) - ctl_grp = CTL_FCC; - - if (ctl_grp != CTL_FCC) - /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */ - return; - - if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) { - modes = mode_list_2ghz; - nr_modes = ARRAY_SIZE(mode_list_2ghz); - } else { - modes = mode_list_5ghz; - nr_modes = ARRAY_SIZE(mode_list_5ghz); - } - - for (i = 0; i < nr_modes; i++) { - u8 c = ctl_grp | modes[i].ctl_mode; - for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++) - if (c == ar->eeprom.ctl_index[ctl_idx]) - break; - if (ctl_idx < AR5416_NUM_CTLS) { - int f_off = 0; - - /* determine heav clip parameter from - the 11G edges array */ - if (modes[i].ctl_mode == CTL_11G) { - ar->phy_heavy_clip = - ar9170_get_heavy_clip(ar, - EDGES(ctl_idx, 1), - freq, bw); - } - - /* adjust freq for 40MHz */ - if (modes[i].ctl_mode == CTL_2GHT40 || - modes[i].ctl_mode == CTL_5GHT40) { - if (bw == AR9170_BW_40_BELOW) - f_off = -10; - else - f_off = 10; - } - - modes[i].max_power = - ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1), - freq+f_off); - - /* - * TODO: check if the regulatory max. power is - * controlled by cfg80211 for DFS - * (hpmain applies it to max_power itself for DFS freq) - */ - - } else { - /* - * Workaround in otus driver, hpmain.c, line 3906: - * if no data for 5GHT20 are found, take the - * legacy 5G value. - * We extend this here to fallback from any other *HT or - * 11G, too. - */ - int k = i; - - modes[i].max_power = AR5416_MAX_RATE_POWER; - while (k-- > 0) { - if (modes[k].max_power != - AR5416_MAX_RATE_POWER) { - modes[i].max_power = modes[k].max_power; - break; - } - } - } - - /* apply max power to pwr_cal_data (ar->power_*) */ - for (j = 0; j < modes[i].pwr_cal_len; j++) { - modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j], - modes[i].max_power); - } - } - - if (ar->phy_heavy_clip & 0xf0) { - ar->power_2G_ht40[0]--; - ar->power_2G_ht40[1]--; - ar->power_2G_ht40[2]--; - } - if (ar->phy_heavy_clip & 0xf) { - ar->power_2G_ht20[0]++; - ar->power_2G_ht20[1]++; - ar->power_2G_ht20[2]++; - } - - -#undef EDGES -} - -static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) -{ - struct ar9170_calibration_target_power_legacy *ctpl; - struct ar9170_calibration_target_power_ht *ctph; - u8 *ctpres; - int ntargets; - int idx, i, n; - u8 ackpower, ackchains, f; - u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS]; - - if (freq < 3000) - f = freq - 2300; - else - f = (freq - 4800)/5; - - /* - * cycle through the various modes - * - * legacy modes first: 5G, 2G CCK, 2G OFDM - */ - for (i = 0; i < 3; i++) { - switch (i) { - case 0: /* 5 GHz legacy */ - ctpl = &ar->eeprom.cal_tgt_pwr_5G[0]; - ntargets = AR5416_NUM_5G_TARGET_PWRS; - ctpres = ar->power_5G_leg; - break; - case 1: /* 2.4 GHz CCK */ - ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0]; - ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS; - ctpres = ar->power_2G_cck; - break; - case 2: /* 2.4 GHz OFDM */ - ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0]; - ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; - ctpres = ar->power_2G_ofdm; - break; - default: - BUG(); - } - - for (n = 0; n < ntargets; n++) { - if (ctpl[n].freq == 0xff) - break; - pwr_freqs[n] = ctpl[n].freq; - } - ntargets = n; - idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); - for (n = 0; n < 4; n++) - ctpres[n] = ar9170_interpolate_u8( - f, - ctpl[idx + 0].freq, - ctpl[idx + 0].power[n], - ctpl[idx + 1].freq, - ctpl[idx + 1].power[n]); - } - - /* - * HT modes now: 5G HT20, 5G HT40, 2G CCK, 2G OFDM, 2G HT20, 2G HT40 - */ - for (i = 0; i < 4; i++) { - switch (i) { - case 0: /* 5 GHz HT 20 */ - ctph = &ar->eeprom.cal_tgt_pwr_5G_ht20[0]; - ntargets = AR5416_NUM_5G_TARGET_PWRS; - ctpres = ar->power_5G_ht20; - break; - case 1: /* 5 GHz HT 40 */ - ctph = &ar->eeprom.cal_tgt_pwr_5G_ht40[0]; - ntargets = AR5416_NUM_5G_TARGET_PWRS; - ctpres = ar->power_5G_ht40; - break; - case 2: /* 2.4 GHz HT 20 */ - ctph = &ar->eeprom.cal_tgt_pwr_2G_ht20[0]; - ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; - ctpres = ar->power_2G_ht20; - break; - case 3: /* 2.4 GHz HT 40 */ - ctph = &ar->eeprom.cal_tgt_pwr_2G_ht40[0]; - ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; - ctpres = ar->power_2G_ht40; - break; - default: - BUG(); - } - - for (n = 0; n < ntargets; n++) { - if (ctph[n].freq == 0xff) - break; - pwr_freqs[n] = ctph[n].freq; - } - ntargets = n; - idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); - for (n = 0; n < 8; n++) - ctpres[n] = ar9170_interpolate_u8( - f, - ctph[idx + 0].freq, - ctph[idx + 0].power[n], - ctph[idx + 1].freq, - ctph[idx + 1].power[n]); - } - - - /* calc. conformance test limits and apply to ar->power*[] */ - ar9170_calc_ctl(ar, freq, bw); - - /* set ACK/CTS TX power */ - ar9170_regwrite_begin(ar); - - if (ar->eeprom.tx_mask != 1) - ackchains = AR9170_TX_PHY_TXCHAIN_2; - else - ackchains = AR9170_TX_PHY_TXCHAIN_1; - - if (freq < 3000) - ackpower = ar->power_2G_ofdm[0] & 0x3f; - else - ackpower = ar->power_5G_leg[0] & 0x3f; - - ar9170_regwrite(0x1c3694, ackpower << 20 | ackchains << 26); - ar9170_regwrite(0x1c3bb4, ackpower << 5 | ackchains << 11 | - ackpower << 21 | ackchains << 27); - - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -static int ar9170_calc_noise_dbm(u32 raw_noise) -{ - if (raw_noise & 0x100) - return ~((raw_noise & 0x0ff) >> 1); - else - return (raw_noise & 0xff) >> 1; -} - -int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, - enum ar9170_rf_init_mode rfi, enum ar9170_bw bw) -{ - const struct ar9170_phy_freq_params *freqpar; - u32 cmd, tmp, offs; - __le32 vals[8]; - int i, err; - bool bandswitch; - - /* clear BB heavy clip enable */ - err = ar9170_write_reg(ar, 0x1c59e0, 0x200); - if (err) - return err; - - /* may be NULL at first setup */ - if (ar->channel) - bandswitch = ar->channel->band != channel->band; - else - bandswitch = true; - - /* HW workaround */ - if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] && - channel->center_freq <= 2417) - bandswitch = true; - - err = ar->exec_cmd(ar, AR9170_CMD_FREQ_START, 0, NULL, 0, NULL); - if (err) - return err; - - if (rfi != AR9170_RFI_NONE || bandswitch) { - u32 val = 0x400; - - if (rfi == AR9170_RFI_COLD) - val = 0x800; - - /* warm/cold reset BB/ADDA */ - err = ar9170_write_reg(ar, 0x1d4004, val); - if (err) - return err; - - err = ar9170_write_reg(ar, 0x1d4004, 0x0); - if (err) - return err; - - err = ar9170_init_phy(ar, channel->band); - if (err) - return err; - - err = ar9170_init_rf_banks_0_7(ar, - channel->band == IEEE80211_BAND_5GHZ); - if (err) - return err; - - cmd = AR9170_CMD_RF_INIT; - } else { - cmd = AR9170_CMD_FREQUENCY; - } - - err = ar9170_init_rf_bank4_pwr(ar, - channel->band == IEEE80211_BAND_5GHZ, - channel->center_freq, bw); - if (err) - return err; - - switch (bw) { - case AR9170_BW_20: - tmp = 0x240; - offs = 0; - break; - case AR9170_BW_40_BELOW: - tmp = 0x2c4; - offs = 3; - break; - case AR9170_BW_40_ABOVE: - tmp = 0x2d4; - offs = 1; - break; - default: - BUG(); - return -ENOSYS; - } - - if (ar->eeprom.tx_mask != 1) - tmp |= 0x100; - - err = ar9170_write_reg(ar, 0x1c5804, tmp); - if (err) - return err; - - err = ar9170_set_freq_cal_data(ar, channel); - if (err) - return err; - - err = ar9170_set_power_cal(ar, channel->center_freq, bw); - if (err) - return err; - - freqpar = ar9170_get_hw_dyn_params(channel, bw); - - vals[0] = cpu_to_le32(channel->center_freq * 1000); - vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf)); - vals[2] = cpu_to_le32(offs << 2 | 1); - vals[3] = cpu_to_le32(freqpar->coeff_exp); - vals[4] = cpu_to_le32(freqpar->coeff_man); - vals[5] = cpu_to_le32(freqpar->coeff_exp_shgi); - vals[6] = cpu_to_le32(freqpar->coeff_man_shgi); - vals[7] = cpu_to_le32(1000); - - err = ar->exec_cmd(ar, cmd, sizeof(vals), (u8 *)vals, - sizeof(vals), (u8 *)vals); - if (err) - return err; - - if (ar->phy_heavy_clip) { - err = ar9170_write_reg(ar, 0x1c59e0, - 0x200 | ar->phy_heavy_clip); - if (err) { - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "failed to set heavy clip\n"); - } - } - - for (i = 0; i < 2; i++) { - ar->noise[i] = ar9170_calc_noise_dbm( - (le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff); - - ar->noise[i + 2] = ar9170_calc_noise_dbm( - (le32_to_cpu(vals[5 + i]) >> 23) & 0x1ff); - } - - ar->channel = channel; - return 0; -} diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c deleted file mode 100644 index d3be6f9816b5..000000000000 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ /dev/null @@ -1,1008 +0,0 @@ -/* - * Atheros AR9170 driver - * - * USB - frontend - * - * Copyright 2008, Johannes Berg - * Copyright 2009, Christian Lamparter - * - * 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; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 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 -#include -#include -#include -#include -#include -#include -#include "ar9170.h" -#include "cmd.h" -#include "hw.h" -#include "usb.h" - -MODULE_AUTHOR("Johannes Berg "); -MODULE_AUTHOR("Christian Lamparter "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); -MODULE_FIRMWARE("ar9170.fw"); - -enum ar9170_requirements { - AR9170_REQ_FW1_ONLY = 1, -}; - -static struct usb_device_id ar9170_usb_ids[] = { - /* Atheros 9170 */ - { USB_DEVICE(0x0cf3, 0x9170) }, - /* Atheros TG121N */ - { USB_DEVICE(0x0cf3, 0x1001) }, - /* TP-Link TL-WN821N v2 */ - { USB_DEVICE(0x0cf3, 0x1002) }, - /* 3Com Dual Band 802.11n USB Adapter */ - { USB_DEVICE(0x0cf3, 0x1010) }, - /* H3C Dual Band 802.11n USB Adapter */ - { USB_DEVICE(0x0cf3, 0x1011) }, - /* Cace Airpcap NX */ - { USB_DEVICE(0xcace, 0x0300) }, - /* D-Link DWA 160 A1 */ - { USB_DEVICE(0x07d1, 0x3c10) }, - /* D-Link DWA 160 A2 */ - { USB_DEVICE(0x07d1, 0x3a09) }, - /* Netgear WNA1000 */ - { USB_DEVICE(0x0846, 0x9040) }, - /* Netgear WNDA3100 */ - { USB_DEVICE(0x0846, 0x9010) }, - /* Netgear WN111 v2 */ - { USB_DEVICE(0x0846, 0x9001) }, - /* Zydas ZD1221 */ - { USB_DEVICE(0x0ace, 0x1221) }, - /* Proxim ORiNOCO 802.11n USB */ - { USB_DEVICE(0x1435, 0x0804) }, - /* WNC Generic 11n USB Dongle */ - { USB_DEVICE(0x1435, 0x0326) }, - /* ZyXEL NWD271N */ - { USB_DEVICE(0x0586, 0x3417) }, - /* Z-Com UB81 BG */ - { USB_DEVICE(0x0cde, 0x0023) }, - /* Z-Com UB82 ABG */ - { USB_DEVICE(0x0cde, 0x0026) }, - /* Sphairon Homelink 1202 */ - { USB_DEVICE(0x0cde, 0x0027) }, - /* Arcadyan WN7512 */ - { USB_DEVICE(0x083a, 0xf522) }, - /* Planex GWUS300 */ - { USB_DEVICE(0x2019, 0x5304) }, - /* IO-Data WNGDNUS2 */ - { USB_DEVICE(0x04bb, 0x093f) }, - /* AVM FRITZ!WLAN USB Stick N */ - { USB_DEVICE(0x057C, 0x8401) }, - /* NEC WL300NU-G */ - { USB_DEVICE(0x0409, 0x0249) }, - /* AVM FRITZ!WLAN USB Stick N 2.4 */ - { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY }, - /* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */ - { USB_DEVICE(0x1668, 0x1200) }, - - /* terminate */ - {} -}; -MODULE_DEVICE_TABLE(usb, ar9170_usb_ids); - -static void ar9170_usb_submit_urb(struct ar9170_usb *aru) -{ - struct urb *urb; - unsigned long flags; - int err; - - if (unlikely(!IS_STARTED(&aru->common))) - return ; - - spin_lock_irqsave(&aru->tx_urb_lock, flags); - if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) { - spin_unlock_irqrestore(&aru->tx_urb_lock, flags); - return ; - } - atomic_inc(&aru->tx_submitted_urbs); - - urb = usb_get_from_anchor(&aru->tx_pending); - if (!urb) { - atomic_dec(&aru->tx_submitted_urbs); - spin_unlock_irqrestore(&aru->tx_urb_lock, flags); - - return ; - } - spin_unlock_irqrestore(&aru->tx_urb_lock, flags); - - aru->tx_pending_urbs--; - usb_anchor_urb(urb, &aru->tx_submitted); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) { - if (ar9170_nag_limiter(&aru->common)) - dev_err(&aru->udev->dev, "submit_urb failed (%d).\n", - err); - - usb_unanchor_urb(urb); - atomic_dec(&aru->tx_submitted_urbs); - ar9170_tx_callback(&aru->common, urb->context); - } - - usb_free_urb(urb); -} - -static void ar9170_usb_tx_urb_complete_frame(struct urb *urb) -{ - struct sk_buff *skb = urb->context; - struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); - - if (unlikely(!aru)) { - dev_kfree_skb_irq(skb); - return ; - } - - atomic_dec(&aru->tx_submitted_urbs); - - ar9170_tx_callback(&aru->common, skb); - - ar9170_usb_submit_urb(aru); -} - -static void ar9170_usb_tx_urb_complete(struct urb *urb) -{ -} - -static void ar9170_usb_irq_completed(struct urb *urb) -{ - struct ar9170_usb *aru = urb->context; - - switch (urb->status) { - /* everything is fine */ - case 0: - break; - - /* disconnect */ - case -ENOENT: - case -ECONNRESET: - case -ENODEV: - case -ESHUTDOWN: - goto free; - - default: - goto resubmit; - } - - ar9170_handle_command_response(&aru->common, urb->transfer_buffer, - urb->actual_length); - -resubmit: - usb_anchor_urb(urb, &aru->rx_submitted); - if (usb_submit_urb(urb, GFP_ATOMIC)) { - usb_unanchor_urb(urb); - goto free; - } - - return; - -free: - usb_free_coherent(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma); -} - -static void ar9170_usb_rx_completed(struct urb *urb) -{ - struct sk_buff *skb = urb->context; - struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); - int err; - - if (!aru) - goto free; - - switch (urb->status) { - /* everything is fine */ - case 0: - break; - - /* disconnect */ - case -ENOENT: - case -ECONNRESET: - case -ENODEV: - case -ESHUTDOWN: - goto free; - - default: - goto resubmit; - } - - skb_put(skb, urb->actual_length); - ar9170_rx(&aru->common, skb); - -resubmit: - skb_reset_tail_pointer(skb); - skb_trim(skb, 0); - - usb_anchor_urb(urb, &aru->rx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) { - usb_unanchor_urb(urb); - goto free; - } - - return ; - -free: - dev_kfree_skb_irq(skb); -} - -static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, - struct urb *urb, gfp_t gfp) -{ - struct sk_buff *skb; - - skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE + 32, gfp); - if (!skb) - return -ENOMEM; - - /* reserve some space for mac80211's radiotap */ - skb_reserve(skb, 32); - - usb_fill_bulk_urb(urb, aru->udev, - usb_rcvbulkpipe(aru->udev, AR9170_EP_RX), - skb->data, min(skb_tailroom(skb), - AR9170_MAX_RX_BUFFER_SIZE), - ar9170_usb_rx_completed, skb); - - return 0; -} - -static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru) -{ - struct urb *urb = NULL; - void *ibuf; - int err = -ENOMEM; - - /* initialize interrupt endpoint */ - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - goto out; - - ibuf = usb_alloc_coherent(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma); - if (!ibuf) - goto out; - - usb_fill_int_urb(urb, aru->udev, - usb_rcvintpipe(aru->udev, AR9170_EP_IRQ), ibuf, - 64, ar9170_usb_irq_completed, aru, 1); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - usb_anchor_urb(urb, &aru->rx_submitted); - err = usb_submit_urb(urb, GFP_KERNEL); - if (err) { - usb_unanchor_urb(urb); - usb_free_coherent(aru->udev, 64, urb->transfer_buffer, - urb->transfer_dma); - } - -out: - usb_free_urb(urb); - return err; -} - -static int ar9170_usb_alloc_rx_bulk_urbs(struct ar9170_usb *aru) -{ - struct urb *urb; - int i; - int err = -EINVAL; - - for (i = 0; i < AR9170_NUM_RX_URBS; i++) { - err = -ENOMEM; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - goto err_out; - - err = ar9170_usb_prep_rx_urb(aru, urb, GFP_KERNEL); - if (err) { - usb_free_urb(urb); - goto err_out; - } - - usb_anchor_urb(urb, &aru->rx_submitted); - err = usb_submit_urb(urb, GFP_KERNEL); - if (err) { - usb_unanchor_urb(urb); - dev_kfree_skb_any((void *) urb->transfer_buffer); - usb_free_urb(urb); - goto err_out; - } - usb_free_urb(urb); - } - - /* the device now waiting for a firmware. */ - aru->common.state = AR9170_IDLE; - return 0; - -err_out: - - usb_kill_anchored_urbs(&aru->rx_submitted); - return err; -} - -static int ar9170_usb_flush(struct ar9170 *ar) -{ - struct ar9170_usb *aru = (void *) ar; - struct urb *urb; - int ret, err = 0; - - if (IS_STARTED(ar)) - aru->common.state = AR9170_IDLE; - - usb_wait_anchor_empty_timeout(&aru->tx_pending, - msecs_to_jiffies(800)); - while ((urb = usb_get_from_anchor(&aru->tx_pending))) { - ar9170_tx_callback(&aru->common, (void *) urb->context); - usb_free_urb(urb); - } - - /* lets wait a while until the tx - queues are dried out */ - ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, - msecs_to_jiffies(100)); - if (ret == 0) - err = -ETIMEDOUT; - - usb_kill_anchored_urbs(&aru->tx_submitted); - - if (IS_ACCEPTING_CMD(ar)) - aru->common.state = AR9170_STARTED; - - return err; -} - -static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) -{ - int err; - - aru->common.state = AR9170_UNKNOWN_STATE; - - err = ar9170_usb_flush(&aru->common); - if (err) - dev_err(&aru->udev->dev, "stuck tx urbs!\n"); - - usb_poison_anchored_urbs(&aru->tx_submitted); - usb_poison_anchored_urbs(&aru->rx_submitted); -} - -static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, - unsigned int plen, void *payload, - unsigned int outlen, void *out) -{ - struct ar9170_usb *aru = (void *) ar; - struct urb *urb = NULL; - unsigned long flags; - int err = -ENOMEM; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return -EPERM; - - if (WARN_ON(plen > AR9170_MAX_CMD_LEN - 4)) - return -EINVAL; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (unlikely(!urb)) - goto err_free; - - ar->cmdbuf[0] = cpu_to_le32(plen); - ar->cmdbuf[0] |= cpu_to_le32(cmd << 8); - /* writing multiple regs fills this buffer already */ - if (plen && payload != (u8 *)(&ar->cmdbuf[1])) - memcpy(&ar->cmdbuf[1], payload, plen); - - spin_lock_irqsave(&aru->common.cmdlock, flags); - aru->readbuf = (u8 *)out; - aru->readlen = outlen; - spin_unlock_irqrestore(&aru->common.cmdlock, flags); - - usb_fill_int_urb(urb, aru->udev, - usb_sndintpipe(aru->udev, AR9170_EP_CMD), - aru->common.cmdbuf, plen + 4, - ar9170_usb_tx_urb_complete, NULL, 1); - - usb_anchor_urb(urb, &aru->tx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) { - usb_unanchor_urb(urb); - usb_free_urb(urb); - goto err_unbuf; - } - usb_free_urb(urb); - - err = wait_for_completion_timeout(&aru->cmd_wait, HZ); - if (err == 0) { - err = -ETIMEDOUT; - goto err_unbuf; - } - - if (aru->readlen != outlen) { - err = -EMSGSIZE; - goto err_unbuf; - } - - return 0; - -err_unbuf: - /* Maybe the device was removed in the second we were waiting? */ - if (IS_STARTED(ar)) { - dev_err(&aru->udev->dev, "no command feedback " - "received (%d).\n", err); - - /* provide some maybe useful debug information */ - print_hex_dump_bytes("ar9170 cmd: ", DUMP_PREFIX_NONE, - aru->common.cmdbuf, plen + 4); - dump_stack(); - } - - /* invalidate to avoid completing the next prematurely */ - spin_lock_irqsave(&aru->common.cmdlock, flags); - aru->readbuf = NULL; - aru->readlen = 0; - spin_unlock_irqrestore(&aru->common.cmdlock, flags); - -err_free: - - return err; -} - -static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ar9170_usb *aru = (struct ar9170_usb *) ar; - struct urb *urb; - - if (unlikely(!IS_STARTED(ar))) { - /* Seriously, what were you drink... err... thinking!? */ - return -EPERM; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (unlikely(!urb)) - return -ENOMEM; - - usb_fill_bulk_urb(urb, aru->udev, - usb_sndbulkpipe(aru->udev, AR9170_EP_TX), - skb->data, skb->len, - ar9170_usb_tx_urb_complete_frame, skb); - urb->transfer_flags |= URB_ZERO_PACKET; - - usb_anchor_urb(urb, &aru->tx_pending); - aru->tx_pending_urbs++; - - usb_free_urb(urb); - - ar9170_usb_submit_urb(aru); - return 0; -} - -static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) -{ - struct ar9170_usb *aru = (void *) ar; - unsigned long flags; - u32 in, out; - - if (unlikely(!buffer)) - return ; - - in = le32_to_cpup((__le32 *)buffer); - out = le32_to_cpu(ar->cmdbuf[0]); - - /* mask off length byte */ - out &= ~0xFF; - - if (aru->readlen >= 0) { - /* add expected length */ - out |= aru->readlen; - } else { - /* add obtained length */ - out |= in & 0xFF; - } - - /* - * Some commands (e.g: AR9170_CMD_FREQUENCY) have a variable response - * length and we cannot predict the correct length in advance. - * So we only check if we provided enough space for the data. - */ - if (unlikely(out < in)) { - dev_warn(&aru->udev->dev, "received invalid command response " - "got %d bytes, instead of %d bytes " - "and the resp length is %d bytes\n", - in, out, len); - print_hex_dump_bytes("ar9170 invalid resp: ", - DUMP_PREFIX_OFFSET, buffer, len); - /* - * Do not complete, then the command times out, - * and we get a stack trace from there. - */ - return ; - } - - spin_lock_irqsave(&aru->common.cmdlock, flags); - if (aru->readbuf && len > 0) { - memcpy(aru->readbuf, buffer + 4, len - 4); - aru->readbuf = NULL; - } - complete(&aru->cmd_wait); - spin_unlock_irqrestore(&aru->common.cmdlock, flags); -} - -static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data, - size_t len, u32 addr, bool complete) -{ - int transfer, err; - u8 *buf = kmalloc(4096, GFP_KERNEL); - - if (!buf) - return -ENOMEM; - - while (len) { - transfer = min_t(int, len, 4096); - memcpy(buf, data, transfer); - - err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), - 0x30 /* FW DL */, 0x40 | USB_DIR_OUT, - addr >> 8, 0, buf, transfer, 1000); - - if (err < 0) { - kfree(buf); - return err; - } - - len -= transfer; - data += transfer; - addr += transfer; - } - kfree(buf); - - if (complete) { - err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), - 0x31 /* FW DL COMPLETE */, - 0x40 | USB_DIR_OUT, 0, 0, NULL, 0, 5000); - } - - return 0; -} - -static int ar9170_usb_reset(struct ar9170_usb *aru) -{ - int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING); - - if (lock) { - ret = usb_lock_device_for_reset(aru->udev, aru->intf); - if (ret < 0) { - dev_err(&aru->udev->dev, "unable to lock device " - "for reset (%d).\n", ret); - return ret; - } - } - - ret = usb_reset_device(aru->udev); - if (lock) - usb_unlock_device(aru->udev); - - /* let it rest - for a second - */ - msleep(1000); - - return ret; -} - -static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) -{ - int err; - - if (!aru->init_values) - goto upload_fw_start; - - /* First, upload initial values to device RAM */ - err = ar9170_usb_upload(aru, aru->init_values->data, - aru->init_values->size, 0x102800, false); - if (err) { - dev_err(&aru->udev->dev, "firmware part 1 " - "upload failed (%d).\n", err); - return err; - } - -upload_fw_start: - - /* Then, upload the firmware itself and start it */ - return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, - 0x200000, true); -} - -static int ar9170_usb_init_transport(struct ar9170_usb *aru) -{ - struct ar9170 *ar = (void *) &aru->common; - int err; - - ar9170_regwrite_begin(ar); - - /* Set USB Rx stream mode MAX packet number to 2 */ - ar9170_regwrite(AR9170_USB_REG_MAX_AGG_UPLOAD, 0x4); - - /* Set USB Rx stream mode timeout to 10us */ - ar9170_regwrite(AR9170_USB_REG_UPLOAD_TIME_CTL, 0x80); - - ar9170_regwrite_finish(); - - err = ar9170_regwrite_result(); - if (err) - dev_err(&aru->udev->dev, "USB setup failed (%d).\n", err); - - return err; -} - -static void ar9170_usb_stop(struct ar9170 *ar) -{ - struct ar9170_usb *aru = (void *) ar; - int ret; - - if (IS_ACCEPTING_CMD(ar)) - aru->common.state = AR9170_STOPPED; - - ret = ar9170_usb_flush(ar); - if (ret) - dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); - - usb_poison_anchored_urbs(&aru->tx_submitted); - - /* - * Note: - * So far we freed all tx urbs, but we won't dare to touch any rx urbs. - * Else we would end up with a unresponsive device... - */ -} - -static int ar9170_usb_open(struct ar9170 *ar) -{ - struct ar9170_usb *aru = (void *) ar; - int err; - - usb_unpoison_anchored_urbs(&aru->tx_submitted); - err = ar9170_usb_init_transport(aru); - if (err) { - usb_poison_anchored_urbs(&aru->tx_submitted); - return err; - } - - aru->common.state = AR9170_IDLE; - return 0; -} - -static int ar9170_usb_init_device(struct ar9170_usb *aru) -{ - int err; - - err = ar9170_usb_alloc_rx_irq_urb(aru); - if (err) - goto err_out; - - err = ar9170_usb_alloc_rx_bulk_urbs(aru); - if (err) - goto err_unrx; - - err = ar9170_usb_upload_firmware(aru); - if (err) { - err = ar9170_echo_test(&aru->common, 0x60d43110); - if (err) { - /* force user invention, by disabling the device */ - err = usb_driver_set_configuration(aru->udev, -1); - dev_err(&aru->udev->dev, "device is in a bad state. " - "please reconnect it!\n"); - goto err_unrx; - } - } - - return 0; - -err_unrx: - ar9170_usb_cancel_urbs(aru); - -err_out: - return err; -} - -static void ar9170_usb_firmware_failed(struct ar9170_usb *aru) -{ - struct device *parent = aru->udev->dev.parent; - struct usb_device *udev; - - /* - * Store a copy of the usb_device pointer locally. - * This is because device_release_driver initiates - * ar9170_usb_disconnect, which in turn frees our - * driver context (aru). - */ - udev = aru->udev; - - complete(&aru->firmware_loading_complete); - - /* unbind anything failed */ - if (parent) - device_lock(parent); - - device_release_driver(&udev->dev); - if (parent) - device_unlock(parent); - - usb_put_dev(udev); -} - -static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) -{ - struct ar9170_usb *aru = context; - int err; - - aru->firmware = fw; - - if (!fw) { - dev_err(&aru->udev->dev, "firmware file not found.\n"); - goto err_freefw; - } - - err = ar9170_usb_init_device(aru); - if (err) - goto err_freefw; - - err = ar9170_usb_open(&aru->common); - if (err) - goto err_unrx; - - err = ar9170_register(&aru->common, &aru->udev->dev); - - ar9170_usb_stop(&aru->common); - if (err) - goto err_unrx; - - complete(&aru->firmware_loading_complete); - usb_put_dev(aru->udev); - return; - - err_unrx: - ar9170_usb_cancel_urbs(aru); - - err_freefw: - ar9170_usb_firmware_failed(aru); -} - -static void ar9170_usb_firmware_inits(const struct firmware *fw, - void *context) -{ - struct ar9170_usb *aru = context; - int err; - - if (!fw) { - dev_err(&aru->udev->dev, "file with init values not found.\n"); - ar9170_usb_firmware_failed(aru); - return; - } - - aru->init_values = fw; - - /* ok so we have the init values -- get code for two-stage */ - - err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw", - &aru->udev->dev, GFP_KERNEL, aru, - ar9170_usb_firmware_finish); - if (err) - ar9170_usb_firmware_failed(aru); -} - -static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context) -{ - struct ar9170_usb *aru = context; - int err; - - if (fw) { - ar9170_usb_firmware_finish(fw, context); - return; - } - - if (aru->req_one_stage_fw) { - dev_err(&aru->udev->dev, "ar9170.fw firmware file " - "not found and is required for this device\n"); - ar9170_usb_firmware_failed(aru); - return; - } - - dev_err(&aru->udev->dev, "ar9170.fw firmware file " - "not found, trying old firmware...\n"); - - err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw", - &aru->udev->dev, GFP_KERNEL, aru, - ar9170_usb_firmware_inits); - if (err) - ar9170_usb_firmware_failed(aru); -} - -static bool ar9170_requires_one_stage(const struct usb_device_id *id) -{ - if (!id->driver_info) - return false; - if (id->driver_info == AR9170_REQ_FW1_ONLY) - return true; - return false; -} - -static int ar9170_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct ar9170_usb *aru; - struct ar9170 *ar; - struct usb_device *udev; - int err; - - aru = ar9170_alloc(sizeof(*aru)); - if (IS_ERR(aru)) { - err = PTR_ERR(aru); - goto out; - } - - udev = interface_to_usbdev(intf); - usb_get_dev(udev); - aru->udev = udev; - aru->intf = intf; - ar = &aru->common; - - aru->req_one_stage_fw = ar9170_requires_one_stage(id); - - usb_set_intfdata(intf, aru); - SET_IEEE80211_DEV(ar->hw, &intf->dev); - - init_usb_anchor(&aru->rx_submitted); - init_usb_anchor(&aru->tx_pending); - init_usb_anchor(&aru->tx_submitted); - init_completion(&aru->cmd_wait); - init_completion(&aru->firmware_loading_complete); - spin_lock_init(&aru->tx_urb_lock); - - aru->tx_pending_urbs = 0; - atomic_set(&aru->tx_submitted_urbs, 0); - - aru->common.stop = ar9170_usb_stop; - aru->common.flush = ar9170_usb_flush; - aru->common.open = ar9170_usb_open; - aru->common.tx = ar9170_usb_tx; - aru->common.exec_cmd = ar9170_usb_exec_cmd; - aru->common.callback_cmd = ar9170_usb_callback_cmd; - -#ifdef CONFIG_PM - udev->reset_resume = 1; -#endif /* CONFIG_PM */ - err = ar9170_usb_reset(aru); - if (err) - goto err_freehw; - - usb_get_dev(aru->udev); - return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw", - &aru->udev->dev, GFP_KERNEL, aru, - ar9170_usb_firmware_step2); -err_freehw: - usb_set_intfdata(intf, NULL); - usb_put_dev(udev); - ieee80211_free_hw(ar->hw); -out: - return err; -} - -static void ar9170_usb_disconnect(struct usb_interface *intf) -{ - struct ar9170_usb *aru = usb_get_intfdata(intf); - - if (!aru) - return; - - aru->common.state = AR9170_IDLE; - - wait_for_completion(&aru->firmware_loading_complete); - - ar9170_unregister(&aru->common); - ar9170_usb_cancel_urbs(aru); - - usb_put_dev(aru->udev); - usb_set_intfdata(intf, NULL); - ieee80211_free_hw(aru->common.hw); - - release_firmware(aru->init_values); - release_firmware(aru->firmware); -} - -#ifdef CONFIG_PM -static int ar9170_suspend(struct usb_interface *intf, - pm_message_t message) -{ - struct ar9170_usb *aru = usb_get_intfdata(intf); - - if (!aru) - return -ENODEV; - - aru->common.state = AR9170_IDLE; - ar9170_usb_cancel_urbs(aru); - - return 0; -} - -static int ar9170_resume(struct usb_interface *intf) -{ - struct ar9170_usb *aru = usb_get_intfdata(intf); - int err; - - if (!aru) - return -ENODEV; - - usb_unpoison_anchored_urbs(&aru->rx_submitted); - usb_unpoison_anchored_urbs(&aru->tx_submitted); - - err = ar9170_usb_init_device(aru); - if (err) - goto err_unrx; - - err = ar9170_usb_open(&aru->common); - if (err) - goto err_unrx; - - return 0; - -err_unrx: - aru->common.state = AR9170_IDLE; - ar9170_usb_cancel_urbs(aru); - - return err; -} -#endif /* CONFIG_PM */ - -static struct usb_driver ar9170_driver = { - .name = "ar9170usb", - .probe = ar9170_usb_probe, - .disconnect = ar9170_usb_disconnect, - .id_table = ar9170_usb_ids, - .soft_unbind = 1, -#ifdef CONFIG_PM - .suspend = ar9170_suspend, - .resume = ar9170_resume, - .reset_resume = ar9170_resume, -#endif /* CONFIG_PM */ -}; - -static int __init ar9170_init(void) -{ - return usb_register(&ar9170_driver); -} - -static void __exit ar9170_exit(void) -{ - usb_deregister(&ar9170_driver); -} - -module_init(ar9170_init); -module_exit(ar9170_exit); diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h deleted file mode 100644 index 919b06046eb3..000000000000 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Atheros AR9170 USB driver - * - * Driver specific definitions - * - * Copyright 2008, Johannes Berg - * Copyright 2009, Christian Lamparter - * - * 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; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 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 __USB_H -#define __USB_H - -#include -#include -#include -#include -#include -#include -#include -#include "eeprom.h" -#include "hw.h" -#include "ar9170.h" - -#define AR9170_NUM_RX_URBS 16 -#define AR9170_NUM_TX_URBS 8 - -struct firmware; - -struct ar9170_usb { - struct ar9170 common; - struct usb_device *udev; - struct usb_interface *intf; - - struct usb_anchor rx_submitted; - struct usb_anchor tx_pending; - struct usb_anchor tx_submitted; - - bool req_one_stage_fw; - - spinlock_t tx_urb_lock; - atomic_t tx_submitted_urbs; - unsigned int tx_pending_urbs; - - struct completion cmd_wait; - struct completion firmware_loading_complete; - int readlen; - u8 *readbuf; - - const struct firmware *init_values; - const struct firmware *firmware; -}; - -#endif /* __USB_H */ diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index a6c6a466000f..7cf4317a2a84 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -119,17 +119,11 @@ struct ath_ops { void (*write)(void *, u32 val, u32 reg_offset); void (*enable_write_buffer)(void *); void (*write_flush) (void *); + u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr); }; struct ath_common; - -struct ath_bus_ops { - enum ath_bus_type ath_bus_type; - void (*read_cachesize)(struct ath_common *common, int *csz); - bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); - void (*bt_coex_prep)(struct ath_common *common); - void (*extn_synch_en)(struct ath_common *common); -}; +struct ath_bus_ops; struct ath_common { void *ah; diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index 82324e98efef..ea9982781559 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -18,6 +18,7 @@ #include #include +#include #include #include "ath5k.h" #include "debug.h" @@ -62,10 +63,27 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah) return 0; } +static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) +{ + struct ath5k_softc *sc = ah->ah_sc; + struct platform_device *pdev = to_platform_device(sc->dev); + struct ar231x_board_config *bcfg = pdev->dev.platform_data; + u8 *cfg_mac; + + if (to_platform_device(sc->dev)->id == 0) + cfg_mac = bcfg->config->wlan0_mac; + else + cfg_mac = bcfg->config->wlan1_mac; + + memcpy(mac, cfg_mac, ETH_ALEN); + return 0; +} + static const struct ath_bus_ops ath_ahb_bus_ops = { .ath_bus_type = ATH_AHB, .read_cachesize = ath5k_ahb_read_cachesize, .eeprom_read = ath5k_ahb_eeprom_read, + .eeprom_read_mac = ath5k_ahb_eeprom_read_mac, }; /*Initialization*/ @@ -142,6 +160,16 @@ static int ath_ahb_probe(struct platform_device *pdev) else reg |= AR5K_AR5312_ENABLE_WLAN1; __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE); + + /* + * On a dual-band AR5312, the multiband radio is only + * used as pass-through. Disable 2 GHz support in the + * driver for it + */ + if (to_platform_device(sc->dev)->id == 0 && + (bcfg->config->flags & (BD_WLAN0|BD_WLAN1)) == + (BD_WLAN1|BD_WLAN0)) + __set_bit(ATH_STAT_2G_DISABLED, sc->status); } ret = ath5k_init_softc(sc, &ath_ahb_bus_ops); diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 8a06dbd39629..bb50700436fe 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -224,8 +224,7 @@ /* SIFS */ #define AR5K_INIT_SIFS_TURBO 6 -/* XXX: 8 from initvals 10 from standard */ -#define AR5K_INIT_SIFS_DEFAULT_BG 8 +#define AR5K_INIT_SIFS_DEFAULT_BG 10 #define AR5K_INIT_SIFS_DEFAULT_A 16 #define AR5K_INIT_SIFS_HALF_RATE 32 #define AR5K_INIT_SIFS_QUARTER_RATE 64 @@ -453,12 +452,10 @@ struct ath5k_tx_status { u16 ts_seqnum; u16 ts_tstamp; u8 ts_status; - u8 ts_rate[4]; - u8 ts_retry[4]; u8 ts_final_idx; + u8 ts_final_retry; s8 ts_rssi; u8 ts_shortretry; - u8 ts_longretry; u8 ts_virtcol; u8 ts_antenna; }; @@ -875,6 +872,19 @@ enum ath5k_int { AR5K_INT_QTRIG = 0x40000000, /* Non common */ AR5K_INT_GLOBAL = 0x80000000, + AR5K_INT_TX_ALL = AR5K_INT_TXOK + | AR5K_INT_TXDESC + | AR5K_INT_TXERR + | AR5K_INT_TXEOL + | AR5K_INT_TXURN, + + AR5K_INT_RX_ALL = AR5K_INT_RXOK + | AR5K_INT_RXDESC + | AR5K_INT_RXERR + | AR5K_INT_RXNOFRM + | AR5K_INT_RXEOL + | AR5K_INT_RXORN, + AR5K_INT_COMMON = AR5K_INT_RXOK | AR5K_INT_RXDESC | AR5K_INT_RXERR @@ -1058,6 +1068,7 @@ struct ath5k_hw { u8 ah_coverage_class; bool ah_ack_bitrate_high; u8 ah_bwmode; + bool ah_short_slot; /* Antenna Control */ u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; @@ -1144,6 +1155,13 @@ struct ath5k_hw { struct ath5k_rx_status *); }; +struct ath_bus_ops { + enum ath_bus_type ath_bus_type; + void (*read_cachesize)(struct ath_common *common, int *csz); + bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); + int (*eeprom_read_mac)(struct ath5k_hw *ah, u8 *mac); +}; + /* * Prototypes */ @@ -1227,13 +1245,12 @@ int ath5k_hw_dma_stop(struct ath5k_hw *ah); /* EEPROM access functions */ int ath5k_eeprom_init(struct ath5k_hw *ah); void ath5k_eeprom_detach(struct ath5k_hw *ah); -int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); /* Protocol Control Unit Functions */ /* Helpers */ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, - int len, struct ieee80211_rate *rate); + 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); extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index bc8240560488..1588401de3c4 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -313,12 +313,17 @@ int ath5k_hw_init(struct ath5k_softc *sc) goto err; } + if (test_bit(ATH_STAT_2G_DISABLED, sc->status)) { + __clear_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode); + __clear_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode); + } + /* Crypto settings */ common->keymax = (sc->ah->ah_version == AR5K_AR5210 ? AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211); if (srev >= AR5K_SREV_AR5212_V4 && - (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 && + (ee->ee_version < AR5K_EEPROM_VERSION_5_0 || !AR5K_EEPROM_AES_DIS(ee->ee_misc5))) common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 349a5963931b..22047628ccfa 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1443,6 +1443,21 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs) return true; } +static void +ath5k_set_current_imask(struct ath5k_softc *sc) +{ + enum ath5k_int imask = sc->imask; + unsigned long flags; + + spin_lock_irqsave(&sc->irqlock, flags); + if (sc->rx_pending) + imask &= ~AR5K_INT_RX_ALL; + if (sc->tx_pending) + imask &= ~AR5K_INT_TX_ALL; + ath5k_hw_set_imr(sc->ah, imask); + spin_unlock_irqrestore(&sc->irqlock, flags); +} + static void ath5k_tasklet_rx(unsigned long data) { @@ -1506,6 +1521,8 @@ ath5k_tasklet_rx(unsigned long data) } while (ath5k_rxbuf_setup(sc, bf) == 0); unlock: spin_unlock(&sc->rxbuflock); + sc->rx_pending = false; + ath5k_set_current_imask(sc); } @@ -1573,28 +1590,28 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, struct ath5k_txq *txq, struct ath5k_tx_status *ts) { struct ieee80211_tx_info *info; + u8 tries[3]; int i; sc->stats.tx_all_count++; sc->stats.tx_bytes_count += skb->len; info = IEEE80211_SKB_CB(skb); + tries[0] = info->status.rates[0].count; + tries[1] = info->status.rates[1].count; + tries[2] = info->status.rates[2].count; + ieee80211_tx_info_clear_status(info); - for (i = 0; i < 4; i++) { + + for (i = 0; i < ts->ts_final_idx; i++) { struct ieee80211_tx_rate *r = &info->status.rates[i]; - if (ts->ts_rate[i]) { - r->idx = ath5k_hw_to_driver_rix(sc, ts->ts_rate[i]); - r->count = ts->ts_retry[i]; - } else { - r->idx = -1; - r->count = 0; - } + r->count = tries[i]; } - /* count the successful attempt as well */ - info->status.rates[ts->ts_final_idx].count++; + info->status.rates[ts->ts_final_idx].count = ts->ts_final_retry; + info->status.rates[ts->ts_final_idx + 1].idx = -1; if (unlikely(ts->ts_status)) { sc->stats.ack_fail++; @@ -1609,6 +1626,9 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, } else { info->flags |= IEEE80211_TX_STAT_ACK; info->status.ack_signal = ts->ts_rssi; + + /* count the successful attempt as well */ + info->status.rates[ts->ts_final_idx].count++; } /* @@ -1690,6 +1710,9 @@ ath5k_tasklet_tx(unsigned long data) for (i=0; i < AR5K_NUM_TX_QUEUES; i++) if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i))) ath5k_tx_processq(sc, &sc->txqs[i]); + + sc->tx_pending = false; + ath5k_set_current_imask(sc); } @@ -2119,6 +2142,20 @@ ath5k_intr_calibration_poll(struct ath5k_hw *ah) * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ } +static void +ath5k_schedule_rx(struct ath5k_softc *sc) +{ + sc->rx_pending = true; + tasklet_schedule(&sc->rxtq); +} + +static void +ath5k_schedule_tx(struct ath5k_softc *sc) +{ + sc->tx_pending = true; + tasklet_schedule(&sc->txtq); +} + irqreturn_t ath5k_intr(int irq, void *dev_id) { @@ -2161,7 +2198,7 @@ ath5k_intr(int irq, void *dev_id) ieee80211_queue_work(sc->hw, &sc->reset_work); } else - tasklet_schedule(&sc->rxtq); + ath5k_schedule_rx(sc); } else { if (status & AR5K_INT_SWBA) { tasklet_hi_schedule(&sc->beacontq); @@ -2179,10 +2216,10 @@ ath5k_intr(int irq, void *dev_id) ath5k_hw_update_tx_triglevel(ah, true); } if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) - tasklet_schedule(&sc->rxtq); + ath5k_schedule_rx(sc); if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC | AR5K_INT_TXERR | AR5K_INT_TXEOL)) - tasklet_schedule(&sc->txtq); + ath5k_schedule_tx(sc); if (status & AR5K_INT_BMISS) { /* TODO */ } @@ -2201,6 +2238,9 @@ ath5k_intr(int irq, void *dev_id) } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); + if (sc->rx_pending || sc->tx_pending) + ath5k_set_current_imask(sc); + if (unlikely(!counter)) ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); @@ -2354,7 +2394,7 @@ ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops) spin_lock_init(&sc->rxbuflock); spin_lock_init(&sc->txbuflock); spin_lock_init(&sc->block); - + spin_lock_init(&sc->irqlock); /* Setup interrupt handler */ ret = request_irq(sc->irq, ath5k_intr, IRQF_SHARED, "ath", sc); @@ -2572,6 +2612,8 @@ ath5k_init_hw(struct ath5k_softc *sc) static void stop_tasklets(struct ath5k_softc *sc) { + sc->rx_pending = false; + sc->tx_pending = false; tasklet_kill(&sc->rxtq); tasklet_kill(&sc->txtq); tasklet_kill(&sc->calib); @@ -2838,7 +2880,7 @@ ath5k_init(struct ieee80211_hw *hw) INIT_WORK(&sc->reset_work, ath5k_reset_work); INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work); - ret = ath5k_eeprom_read_mac(ah, mac); + ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac); if (ret) { ATH5K_ERR(sc, "unable to read address from EEPROM\n"); goto err_queues; @@ -2898,7 +2940,6 @@ ath5k_deinit_softc(struct ath5k_softc *sc) * XXX: ??? detach ath5k_hw ??? * Other than that, it's straightforward... */ - ath5k_debug_finish_device(sc); ieee80211_unregister_hw(hw); ath5k_desc_free(sc); ath5k_txq_release(sc); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 978f1f4ac2f3..b294f3305011 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -193,12 +193,13 @@ struct ath5k_softc { dma_addr_t desc_daddr; /* DMA (physical) address */ size_t desc_len; /* size of TX/RX descriptors */ - DECLARE_BITMAP(status, 5); + DECLARE_BITMAP(status, 6); #define ATH_STAT_INVALID 0 /* disable hardware accesses */ #define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ #define ATH_STAT_PROMISC 2 #define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ #define ATH_STAT_STARTED 4 /* opened & irqs enabled */ +#define ATH_STAT_2G_DISABLED 5 /* multiband radio without 2G */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ struct ieee80211_channel *curchan; /* current h/w channel */ @@ -207,6 +208,10 @@ struct ath5k_softc { enum ath5k_int imask; /* interrupt mask copy */ + spinlock_t irqlock; + bool rx_pending; /* rx tasklet pending */ + bool tx_pending; /* tx tasklet pending */ + u8 lladdr[ETH_ALEN]; u8 bssidmask[ETH_ALEN]; diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index f77e8a703c5c..7dd88e1c3ff8 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c @@ -94,6 +94,9 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) } } + if ((ah->ah_radio_5ghz_revision & 0xf0) == AR5K_SREV_RAD_2112) + __clear_bit(AR5K_MODE_11A, caps->cap_mode); + /* Set number of supported TX queues */ if (ah->ah_version == AR5K_AR5210) caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU; diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 0230f30e9e9a..0bf7313b8a17 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -888,65 +888,38 @@ static const struct file_operations fops_queue = { void ath5k_debug_init_device(struct ath5k_softc *sc) { + struct dentry *phydir; + sc->debug.level = ath5k_debug; - sc->debug.debugfs_phydir = debugfs_create_dir("ath5k", - sc->hw->wiphy->debugfsdir); + phydir = debugfs_create_dir("ath5k", sc->hw->wiphy->debugfsdir); + if (!phydir) + return; - sc->debug.debugfs_debug = debugfs_create_file("debug", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_debug); + debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, sc, + &fops_debug); - sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_registers); + debugfs_create_file("registers", S_IRUSR, phydir, sc, &fops_registers); - sc->debug.debugfs_beacon = debugfs_create_file("beacon", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_beacon); + debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, sc, + &fops_beacon); - sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, - sc->debug.debugfs_phydir, sc, &fops_reset); + debugfs_create_file("reset", S_IWUSR, phydir, sc, &fops_reset); - sc->debug.debugfs_antenna = debugfs_create_file("antenna", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_antenna); + debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, sc, + &fops_antenna); - sc->debug.debugfs_misc = debugfs_create_file("misc", - S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_misc); + debugfs_create_file("misc", S_IRUSR, phydir, sc, &fops_misc); - sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, - &fops_frameerrors); + debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, sc, + &fops_frameerrors); - sc->debug.debugfs_ani = debugfs_create_file("ani", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, - &fops_ani); + debugfs_create_file("ani", S_IWUSR | S_IRUSR, phydir, sc, &fops_ani); - sc->debug.debugfs_queue = debugfs_create_file("queue", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, - &fops_queue); + debugfs_create_file("queue", S_IWUSR | S_IRUSR, phydir, sc, + &fops_queue); } -void -ath5k_debug_finish_device(struct ath5k_softc *sc) -{ - debugfs_remove(sc->debug.debugfs_debug); - debugfs_remove(sc->debug.debugfs_registers); - debugfs_remove(sc->debug.debugfs_beacon); - debugfs_remove(sc->debug.debugfs_reset); - debugfs_remove(sc->debug.debugfs_antenna); - debugfs_remove(sc->debug.debugfs_misc); - debugfs_remove(sc->debug.debugfs_frameerrors); - debugfs_remove(sc->debug.debugfs_ani); - debugfs_remove(sc->debug.debugfs_queue); - debugfs_remove(sc->debug.debugfs_phydir); -} - - /* functions used in other places */ void diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index b0355aef68d3..193dd2d4ea3c 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -68,17 +68,6 @@ struct ath5k_buf; struct ath5k_dbg_info { unsigned int level; /* debug level */ - /* debugfs entries */ - struct dentry *debugfs_phydir; - struct dentry *debugfs_debug; - struct dentry *debugfs_registers; - struct dentry *debugfs_beacon; - struct dentry *debugfs_reset; - struct dentry *debugfs_antenna; - struct dentry *debugfs_misc; - struct dentry *debugfs_frameerrors; - struct dentry *debugfs_ani; - struct dentry *debugfs_queue; }; /** @@ -140,9 +129,6 @@ enum ath5k_debug_level { void ath5k_debug_init_device(struct ath5k_softc *sc); -void -ath5k_debug_finish_device(struct ath5k_softc *sc); - void ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah); @@ -166,9 +152,6 @@ ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) static inline void ath5k_debug_init_device(struct ath5k_softc *sc) {} -static inline void -ath5k_debug_finish_device(struct ath5k_softc *sc) {} - static inline void ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {} diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index a8fcc94269f7..62172d585723 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -185,6 +185,12 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; + /* + * Use local variables for these to reduce load/store access on + * uncached memory + */ + u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0; + tx_ctl = &desc->ud.ds_tx5212.tx_ctl; /* @@ -208,8 +214,9 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if (tx_power > AR5K_TUNE_MAX_TXPOWER) tx_power = AR5K_TUNE_MAX_TXPOWER; - /* Clear descriptor */ - memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); + /* Clear descriptor status area */ + memset(&desc->ud.ds_tx5212.tx_stat, 0, + sizeof(desc->ud.ds_tx5212.tx_stat)); /* Setup control descriptor */ @@ -221,7 +228,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; - tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; + txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ @@ -232,21 +239,17 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; - tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; + txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; - tx_ctl->tx_control_0 |= - AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | - AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); - tx_ctl->tx_control_1 |= AR5K_REG_SM(type, - AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); - tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); - tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; + txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | + AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); + txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); + txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); + txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ - tx_ctl->tx_control_##_c |= \ - AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ + txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ } _TX_FLAGS(0, CLRDMASK); @@ -262,8 +265,8 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, * WEP crap */ if (key_index != AR5K_TXKEYIX_INVALID) { - tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; - tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, + txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; + txctl1 |= AR5K_REG_SM(key_index, AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX); } @@ -274,12 +277,16 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if ((flags & AR5K_TXDESC_RTSENA) && (flags & AR5K_TXDESC_CTSENA)) return -EINVAL; - tx_ctl->tx_control_2 |= rtscts_duration & - AR5K_4W_TX_DESC_CTL2_RTS_DURATION; - tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, + txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION; + txctl3 |= AR5K_REG_SM(rtscts_rate, AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); } + tx_ctl->tx_control_0 = txctl0; + tx_ctl->tx_control_1 = txctl1; + tx_ctl->tx_control_2 = txctl2; + tx_ctl->tx_control_3 = txctl3; + return 0; } @@ -364,7 +371,7 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_final_retry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); /*TODO: ts->ts_virtcol + test*/ ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, @@ -373,9 +380,6 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); ts->ts_antenna = 1; ts->ts_status = 0; - ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0, - AR5K_2W_TX_DESC_CTL0_XMIT_RATE); - ts->ts_retry[0] = ts->ts_longretry; ts->ts_final_idx = 0; if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { @@ -401,81 +405,48 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, { 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); + /* No frame has been send or error */ - if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE))) + if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE))) return -EINPROGRESS; + txstat0 = ACCESS_ONCE(tx_status->tx_status_0); + /* * Get descriptor status */ - ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_tstamp = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); - ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_shortretry = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_final_retry = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); - ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, + ts->ts_seqnum = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_SEQ_NUM); - ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, + ts->ts_rssi = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); - ts->ts_antenna = (tx_status->tx_status_1 & + ts->ts_antenna = (txstat1 & AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1; ts->ts_status = 0; - ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1, + ts->ts_final_idx = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212); - /* The longretry counter has the number of un-acked retries - * for the final rate. To get the total number of retries - * we have to add the retry counters for the other rates - * as well - */ - ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; - switch (ts->ts_final_idx) { - case 3: - ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); - - ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); - ts->ts_longretry += ts->ts_retry[2]; - /* fall through */ - case 2: - ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); - - ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); - ts->ts_longretry += ts->ts_retry[1]; - /* fall through */ - case 1: - ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); - - ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); - ts->ts_longretry += ts->ts_retry[0]; - /* fall through */ - case 0: - ts->ts_rate[0] = tx_ctl->tx_control_3 & - AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; - break; - } - /* TX error */ - if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { - if (tx_status->tx_status_0 & - AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) + if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { + if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) ts->ts_status |= AR5K_TXERR_XRETRY; - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) + if (txstat0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) ts->ts_status |= AR5K_TXERR_FIFO; - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) + if (txstat0 & AR5K_DESC_TX_STATUS0_FILTERED) ts->ts_status |= AR5K_TXERR_FILT; } @@ -609,37 +580,37 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, struct ath5k_rx_status *rs) { struct ath5k_hw_rx_status *rx_status; + u32 rxstat0, rxstat1; rx_status = &desc->ud.ds_rx.rx_stat; + rxstat1 = ACCESS_ONCE(rx_status->rx_status_1); /* No frame received / not ready */ - if (unlikely(!(rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_DONE))) + if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE))) return -EINPROGRESS; memset(rs, 0, sizeof(struct ath5k_rx_status)); + rxstat0 = ACCESS_ONCE(rx_status->rx_status_0); /* * Frame receive status */ - rs->rs_datalen = rx_status->rx_status_0 & - AR5K_5212_RX_DESC_STATUS0_DATA_LEN; - rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, + rs->rs_datalen = rxstat0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN; + rs->rs_rssi = AR5K_REG_MS(rxstat0, AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); - rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, + rs->rs_rate = AR5K_REG_MS(rxstat0, AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); - rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0, + rs->rs_antenna = AR5K_REG_MS(rxstat0, AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA); - rs->rs_more = !!(rx_status->rx_status_0 & - AR5K_5212_RX_DESC_STATUS0_MORE); - rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, + rs->rs_more = !!(rxstat0 & AR5K_5212_RX_DESC_STATUS0_MORE); + rs->rs_tstamp = AR5K_REG_MS(rxstat1, AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); /* * Key table status */ - if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) - rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) + rs->rs_keyix = AR5K_REG_MS(rxstat1, AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); else rs->rs_keyix = AR5K_RXKEYIX_INVALID; @@ -647,27 +618,22 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, /* * Receive/descriptor errors */ - if (!(rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) + if (!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) rs->rs_status |= AR5K_RXERR_CRC; - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { rs->rs_status |= AR5K_RXERR_PHY; - rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, + rs->rs_phyerr = AR5K_REG_MS(rxstat1, AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE); if (!ah->ah_capabilities.cap_has_phyerr_counters) ath5k_ani_phy_error_report(ah, rs->rs_phyerr); } - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) rs->rs_status |= AR5K_RXERR_DECRYPT; - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) rs->rs_status |= AR5K_RXERR_MIC; } return 0; diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index efb672cb31e4..1fef84f87c78 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -660,6 +660,53 @@ ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100; } +static int +ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *chinfo; + u8 pier, pdg; + + switch (mode) { + case AR5K_EEPROM_MODE_11A: + if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) + return 0; + chinfo = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) + return 0; + chinfo = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + chinfo = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } + + for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { + if (!chinfo[pier].pd_curves) + continue; + + for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { + struct ath5k_pdgain_info *pd = + &chinfo[pier].pd_curves[pdg]; + + if (pd != NULL) { + kfree(pd->pd_step); + kfree(pd->pd_pwr); + } + } + + kfree(chinfo[pier].pd_curves); + } + + return 0; +} + /* Convert RF5111 specific data to generic raw data * used by interpolation code */ static int @@ -684,7 +731,7 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, GFP_KERNEL); if (!chinfo[pier].pd_curves) - return -ENOMEM; + goto err_out; /* Only one curve for RF5111 * find out which one and place @@ -708,12 +755,12 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, sizeof(u8), GFP_KERNEL); if (!pd->pd_step) - return -ENOMEM; + goto err_out; pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, sizeof(s16), GFP_KERNEL); if (!pd->pd_pwr) - return -ENOMEM; + goto err_out; /* Fill raw dataset * (convert power to 0.25dB units @@ -734,6 +781,10 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, } return 0; + +err_out: + ath5k_eeprom_free_pcal_info(ah, mode); + return -ENOMEM; } /* Parse EEPROM data */ @@ -867,7 +918,7 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, GFP_KERNEL); if (!chinfo[pier].pd_curves) - return -ENOMEM; + goto err_out; /* Fill pd_curves */ for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { @@ -886,14 +937,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, sizeof(u8), GFP_KERNEL); if (!pd->pd_step) - return -ENOMEM; + goto err_out; pd->pd_pwr = kcalloc(pd->pd_points, sizeof(s16), GFP_KERNEL); if (!pd->pd_pwr) - return -ENOMEM; - + goto err_out; /* Fill raw dataset * (all power levels are in 0.25dB units) */ @@ -925,13 +975,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, sizeof(u8), GFP_KERNEL); if (!pd->pd_step) - return -ENOMEM; + goto err_out; pd->pd_pwr = kcalloc(pd->pd_points, sizeof(s16), GFP_KERNEL); if (!pd->pd_pwr) - return -ENOMEM; + goto err_out; /* Fill raw dataset * (all power levels are in 0.25dB units) */ @@ -954,6 +1004,10 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, } return 0; + +err_out: + ath5k_eeprom_free_pcal_info(ah, mode); + return -ENOMEM; } /* Parse EEPROM data */ @@ -1156,7 +1210,7 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, GFP_KERNEL); if (!chinfo[pier].pd_curves) - return -ENOMEM; + goto err_out; /* Fill pd_curves */ for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { @@ -1177,13 +1231,13 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, sizeof(u8), GFP_KERNEL); if (!pd->pd_step) - return -ENOMEM; + goto err_out; pd->pd_pwr = kcalloc(pd->pd_points, sizeof(s16), GFP_KERNEL); if (!pd->pd_pwr) - return -ENOMEM; + goto err_out; /* Fill raw dataset * convert all pwr levels to @@ -1213,6 +1267,10 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, } return 0; + +err_out: + ath5k_eeprom_free_pcal_info(ah, mode); + return -ENOMEM; } /* Parse EEPROM data */ @@ -1534,53 +1592,6 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) return 0; } -static int -ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info *chinfo; - u8 pier, pdg; - - switch (mode) { - case AR5K_EEPROM_MODE_11A: - if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) - return 0; - chinfo = ee->ee_pwr_cal_a; - break; - case AR5K_EEPROM_MODE_11B: - if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) - return 0; - chinfo = ee->ee_pwr_cal_b; - break; - case AR5K_EEPROM_MODE_11G: - if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) - return 0; - chinfo = ee->ee_pwr_cal_g; - break; - default: - return -EINVAL; - } - - for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { - if (!chinfo[pier].pd_curves) - continue; - - for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { - struct ath5k_pdgain_info *pd = - &chinfo[pier].pd_curves[pdg]; - - if (pd != NULL) { - kfree(pd->pd_step); - kfree(pd->pd_pwr); - } - } - - kfree(chinfo[pier].pd_curves); - } - - return 0; -} - /* Read conformance test limits used for regulatory control */ static int ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) @@ -1721,35 +1732,6 @@ ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah) return ret; } -/* - * Read the MAC address from eeprom - */ -int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) -{ - u8 mac_d[ETH_ALEN] = {}; - u32 total, offset; - u16 data; - int octet; - - AR5K_EEPROM_READ(0x20, data); - - for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { - AR5K_EEPROM_READ(offset, data); - - total += data; - mac_d[octet + 1] = data & 0xff; - mac_d[octet] = data >> 8; - octet += 2; - } - - if (!total || total == 3 * 0xffff) - return -EINVAL; - - memcpy(mac, mac_d, ETH_ALEN); - - return 0; -} - /***********************\ * Init/Detach functions * diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 9be29b728b1c..807bd6440169 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -282,6 +282,15 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changes & BSS_CHANGED_BEACON_INT) sc->bintval = bss_conf->beacon_int; + if (changes & BSS_CHANGED_ERP_SLOT) { + int slot_time; + + ah->ah_short_slot = bss_conf->use_short_slot; + slot_time = ath5k_hw_get_default_slottime(ah) + + 3 * ah->ah_coverage_class; + ath5k_hw_set_ifs_intervals(ah, slot_time); + } + if (changes & BSS_CHANGED_ASSOC) { avf->assoc = bss_conf->assoc; if (bss_conf->assoc) diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index 3c44689a700b..296c316a8341 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "../ath.h" #include "ath5k.h" #include "debug.h" @@ -108,11 +109,42 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah) return 0; } +/* + * Read the MAC address from eeprom or platform_data + */ +static int ath5k_pci_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) +{ + u8 mac_d[ETH_ALEN] = {}; + u32 total, offset; + u16 data; + int octet; + + AR5K_EEPROM_READ(0x20, data); + + for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { + AR5K_EEPROM_READ(offset, data); + + total += data; + mac_d[octet + 1] = data & 0xff; + mac_d[octet] = data >> 8; + octet += 2; + } + + if (!total || total == 3 * 0xffff) + return -EINVAL; + + memcpy(mac, mac_d, ETH_ALEN); + + return 0; +} + + /* Common ath_bus_opts structure */ static const struct ath_bus_ops ath_pci_bus_ops = { .ath_bus_type = ATH_PCI, .read_cachesize = ath5k_pci_read_cachesize, .eeprom_read = ath5k_pci_eeprom_read, + .eeprom_read_mac = ath5k_pci_eeprom_read_mac, }; /********************\ diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index d9b3f828455a..712a9ac4000e 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -75,7 +75,7 @@ static const unsigned int ack_rates_high[] = * bwmodes. */ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, - int len, struct ieee80211_rate *rate) + int len, struct ieee80211_rate *rate, bool shortpre) { struct ath5k_softc *sc = ah->ah_sc; int sifs, preamble, plcp_bits, sym_time; @@ -84,9 +84,15 @@ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, /* Fallback */ if (!ah->ah_bwmode) { - dur = ieee80211_generic_frame_duration(sc->hw, - NULL, len, rate); - return le16_to_cpu(dur); + __le16 raw_dur = ieee80211_generic_frame_duration(sc->hw, + NULL, len, rate); + + /* subtract difference between long and short preamble */ + dur = le16_to_cpu(raw_dur); + if (shortpre) + dur -= 96; + + return dur; } bitrate = rate->bitrate; @@ -145,9 +151,9 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE; break; case AR5K_BWMODE_DEFAULT: - slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; default: - if (channel->hw_value & CHANNEL_CCK) + slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; + if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot) slot_time = AR5K_INIT_SLOT_TIME_B; break; } @@ -263,27 +269,14 @@ static inline void 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); + tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); ath5k_hw_reg_write(ah, tx_time, reg); if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) continue; - /* - * We're not distinguishing short preamble here, - * This is true, all we'll get is a longer value here - * which is not necessarilly bad. We could use - * export ieee80211_frame_duration() but that needs to be - * fixed first to be properly used by mac802111 drivers: - * - * - remove erp stuff and let the routine figure ofdm - * erp rates - * - remove passing argument ieee80211_local as - * drivers don't have access to it - * - move drivers using ieee80211_generic_frame_duration() - * to this - */ + tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true); ath5k_hw_reg_write(ah, tx_time, reg + (AR5K_SET_SHORT_PREAMBLE << 2)); } diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 3343fb9e4940..b18c5021aac3 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -519,7 +519,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) return -EINVAL; sifs = ath5k_hw_get_default_sifs(ah); - sifs_clock = ath5k_hw_htoclock(ah, sifs); + sifs_clock = ath5k_hw_htoclock(ah, sifs - 2); /* EIFS * Txtime of ack at lowest rate + SIFS + DIFS @@ -550,7 +550,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) else rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0]; - ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate); + ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); /* ack_tx_time includes an SIFS already */ eifs = ack_tx_time + sifs + 2 * slot_time; diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 84206898f77d..3510de2cf622 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -158,6 +158,11 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah) txlat = AR5K_REG_MS(usec_reg, AR5K_USEC_TX_LATENCY_5211); rxlat = AR5K_REG_MS(usec_reg, AR5K_USEC_RX_LATENCY_5211); + /* + * Set default Tx frame to Tx data start delay + */ + txf2txs = AR5K_INIT_TXF2TXD_START_DEFAULT; + /* * 5210 initvals don't include usec settings * so we need to use magic values here for diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index ad57a6d23110..d9ff8413ab9a 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -5,7 +5,7 @@ config ATH9K_COMMON config ATH9K tristate "Atheros 802.11n wireless cards support" - depends on PCI && MAC80211 + depends on MAC80211 select ATH9K_HW select MAC80211_LEDS select LEDS_CLASS @@ -23,6 +23,25 @@ config ATH9K If you choose to build a module, it'll be called ath9k. +config ATH9K_PCI + bool "Atheros ath9k PCI/PCIe bus support" + depends on ATH9K && PCI + default PCI + ---help--- + This option enables the PCI bus support in ath9k. + + Say Y, if you have a compatible PCI/PCIe wireless card. + +config ATH9K_AHB + bool "Atheros ath9k AHB bus support" + depends on ATH9K + default n + ---help--- + This option enables the AHB bus support in ath9k. + + Say Y, if you have a SoC with a compatible built-in + wireless MAC. Say N if unsure. + config ATH9K_DEBUGFS bool "Atheros ath9k debugging" depends on ATH9K && DEBUG_FS diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 4d66ca8042eb..05a6fade7b1c 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -6,8 +6,8 @@ ath9k-y += beacon.o \ xmit.o \ ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o -ath9k-$(CONFIG_PCI) += pci.o -ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o +ath9k-$(CONFIG_ATH9K_PCI) += pci.o +ath9k-$(CONFIG_ATH9K_AHB) += ahb.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o obj-$(CONFIG_ATH9K) += ath9k.o @@ -48,4 +48,6 @@ ath9k_htc-y += htc_hst.o \ htc_drv_init.o \ htc_drv_gpio.o +ath9k_htc-$(CONFIG_ATH9K_HTC_DEBUGFS) += htc_drv_debug.o + obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 9cb0efa9b4c0..61956392f2da 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -21,6 +21,18 @@ #include #include "ath9k.h" +static const struct platform_device_id ath9k_platform_id_table[] = { + { + .name = "ath9k", + .driver_data = AR5416_AR9100_DEVID, + }, + { + .name = "ar934x_wmac", + .driver_data = AR9300_DEVID_AR9340, + }, + {}, +}; + /* return bus cachesize in 4B word units */ static void ath_ahb_read_cachesize(struct ath_common *common, int *csz) { @@ -57,6 +69,7 @@ static int ath_ahb_probe(struct platform_device *pdev) struct ath_softc *sc; struct ieee80211_hw *hw; struct resource *res; + const struct platform_device_id *id = platform_get_device_id(pdev); int irq; int ret = 0; struct ath_hw *ah; @@ -116,7 +129,7 @@ static int ath_ahb_probe(struct platform_device *pdev) goto err_free_hw; } - ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops); + ret = ath9k_init_device(id->driver_data, sc, 0x0, &ath_ahb_bus_ops); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto err_irq; @@ -165,8 +178,11 @@ static struct platform_driver ath_ahb_driver = { .name = "ath9k", .owner = THIS_MODULE, }, + .id_table = ath9k_platform_id_table, }; +MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table); + int ath_ahb_init(void) { return platform_driver_register(&ath_ahb_driver); diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 2e31c775351f..5a1f4f511bc1 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -899,12 +899,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah) * check here default level should not modify INI setting. */ if (use_new_ani(ah)) { - const struct ani_ofdm_level_entry *entry_ofdm; - const struct ani_cck_level_entry *entry_cck; - - entry_ofdm = &ofdm_level_table[ATH9K_ANI_OFDM_DEF_LEVEL]; - entry_cck = &cck_level_table[ATH9K_ANI_CCK_DEF_LEVEL]; - ah->aniperiod = ATH9K_ANI_PERIOD_NEW; ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW; } else { diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 106c0b06cf55..4bf9dab4f2b3 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -44,6 +44,34 @@ static const int m1ThreshExt_off = 127; static const int m2ThreshExt_off = 127; +static void ar5008_rf_bank_setup(u32 *bank, struct ar5416IniArray *array, + int col) +{ + int i; + + for (i = 0; i < array->ia_rows; i++) + bank[i] = INI_RA(array, i, col); +} + + +#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) \ + ar5008_write_rf_array(ah, iniarray, regData, &(regWr)) + +static void ar5008_write_rf_array(struct ath_hw *ah, struct ar5416IniArray *array, + u32 *data, unsigned int *writecnt) +{ + int r; + + ENABLE_REGWRITE_BUFFER(ah); + + for (r = 0; r < array->ia_rows; r++) { + REG_WRITE(ah, INI_RA(array, r, 0), data[r]); + DO_DELAY(*writecnt); + } + + REGWRITE_BUFFER_FLUSH(ah); +} + /** * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters * @rfbuf: @@ -530,16 +558,16 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah, eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); /* Setup Bank 0 Write */ - RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); + ar5008_rf_bank_setup(ah->analogBank0Data, &ah->iniBank0, 1); /* Setup Bank 1 Write */ - RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); + ar5008_rf_bank_setup(ah->analogBank1Data, &ah->iniBank1, 1); /* Setup Bank 2 Write */ - RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); + ar5008_rf_bank_setup(ah->analogBank2Data, &ah->iniBank2, 1); /* Setup Bank 6 Write */ - RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, + ar5008_rf_bank_setup(ah->analogBank3Data, &ah->iniBank3, modesIndex); { int i; @@ -569,7 +597,7 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah, } /* Setup Bank 7 Setup */ - RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); + ar5008_rf_bank_setup(ah->analogBank7Data, &ah->iniBank7, 1); /* Write Analog registers */ REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, @@ -729,6 +757,7 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + struct ath_common *common = ath9k_hw_common(ah); int i, regWrites = 0; struct ieee80211_channel *channel = chan->chan; u32 modesIndex, freqIndex; @@ -805,7 +834,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, REG_WRITE(ah, reg, val); if (reg >= 0x7800 && reg < 0x78a0 - && ah->config.analog_shiftreg) { + && ah->config.analog_shiftreg + && (common->bus_ops->ath_bus_type != ATH_USB)) { udelay(100); } @@ -835,7 +865,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, REG_WRITE(ah, reg, val); if (reg >= 0x7800 && reg < 0x78a0 - && ah->config.analog_shiftreg) { + && ah->config.analog_shiftreg + && (common->bus_ops->ath_bus_type != ATH_USB)) { udelay(100); } diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 76388c6d6692..cb611b287b35 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -26,6 +26,27 @@ enum ar9002_cal_types { IQ_MISMATCH_CAL = BIT(2), }; +static bool ar9002_hw_is_cal_supported(struct ath_hw *ah, + struct ath9k_channel *chan, + enum ar9002_cal_types cal_type) +{ + bool supported = false; + switch (ah->supp_cals & cal_type) { + case IQ_MISMATCH_CAL: + /* Run IQ Mismatch for non-CCK only */ + if (!IS_CHAN_B(chan)) + supported = true; + break; + case ADC_GAIN_CAL: + case ADC_DC_CAL: + /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ + if (!IS_CHAN_B(chan) && + !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) + supported = true; + break; + } + return supported; +} static void ar9002_hw_setup_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal) @@ -858,26 +879,32 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { ah->supp_cals = IQ_MISMATCH_CAL; - if (AR_SREV_9160_10_OR_LATER(ah) && - !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) { + if (AR_SREV_9160_10_OR_LATER(ah)) ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL; + if (AR_SREV_9287(ah)) + ah->supp_cals &= ~ADC_GAIN_CAL; + if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) { INIT_CAL(&ah->adcgain_caldata); INSERT_CAL(ah, &ah->adcgain_caldata); ath_dbg(common, ATH_DBG_CALIBRATE, - "enabling ADC Gain Calibration.\n"); + "enabling ADC Gain Calibration.\n"); + } + if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) { INIT_CAL(&ah->adcdc_caldata); INSERT_CAL(ah, &ah->adcdc_caldata); ath_dbg(common, ATH_DBG_CALIBRATE, - "enabling ADC DC Calibration.\n"); + "enabling ADC DC Calibration.\n"); } - INIT_CAL(&ah->iq_caldata); - INSERT_CAL(ah, &ah->iq_caldata); - ath_dbg(common, ATH_DBG_CALIBRATE, - "enabling IQ Calibration.\n"); + if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) { + INIT_CAL(&ah->iq_caldata); + INSERT_CAL(ah, &ah->iq_caldata); + ath_dbg(common, ATH_DBG_CALIBRATE, + "enabling IQ Calibration.\n"); + } ah->cal_list_curr = ah->cal_list; diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 399ab3bb299b..7a332f16b79a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -290,7 +290,6 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds, | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | SM(txPower, AR_XmitPower) | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) - | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); @@ -311,6 +310,16 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds, } } +static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if (val) + ads->ds_ctl0 |= AR_ClrDestMask; + else + ads->ds_ctl0 &= ~AR_ClrDestMask; +} + static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, void *lastds, u32 durUpdateEn, u32 rtsctsRate, @@ -406,26 +415,6 @@ static void ar9002_hw_clr11n_aggr(struct ath_hw *ah, void *ds) ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); } -static void ar9002_hw_set11n_burstduration(struct ath_hw *ah, void *ds, - u32 burstDuration) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl2 &= ~AR_BurstDur; - ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); -} - -static void ar9002_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, - u32 vmf) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if (vmf) - ads->ds_ctl0 |= AR_VirtMoreFrag; - else - ads->ds_ctl0 &= ~AR_VirtMoreFrag; -} - void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags) { @@ -458,6 +447,5 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah) ops->set11n_aggr_middle = ar9002_hw_set11n_aggr_middle; ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; ops->clr11n_aggr = ar9002_hw_clr11n_aggr; - ops->set11n_burstduration = ar9002_hw_set11n_burstduration; - ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag; + ops->set_clrdmask = ar9002_hw_set_clrdmask; } diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 7d68d61e406b..a57e963cf0dc 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -517,23 +517,7 @@ static void ar9002_hw_set_nf_limits(struct ath_hw *ah) } } -void ar9002_hw_attach_phy_ops(struct ath_hw *ah) -{ - struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); - - priv_ops->set_rf_regs = NULL; - priv_ops->rf_alloc_ext_banks = NULL; - priv_ops->rf_free_ext_banks = NULL; - priv_ops->rf_set_freq = ar9002_hw_set_channel; - priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate; - priv_ops->olc_init = ar9002_olc_init; - priv_ops->compute_pll_control = ar9002_hw_compute_pll_control; - priv_ops->do_getnf = ar9002_hw_do_getnf; - - ar9002_hw_set_nf_limits(ah); -} - -void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah, +static void ar9002_hw_antdiv_comb_conf_get(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf) { u32 regval; @@ -545,10 +529,11 @@ void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah, AR_PHY_9285_ANT_DIV_ALT_LNACONF_S; antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >> AR_PHY_9285_FAST_DIV_BIAS_S; + antconf->lna1_lna2_delta = -3; + antconf->div_group = 0; } -EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_get); -void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, +static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf) { u32 regval; @@ -566,4 +551,23 @@ void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval); } -EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_set); + +void ar9002_hw_attach_phy_ops(struct ath_hw *ah) +{ + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + struct ath_hw_ops *ops = ath9k_hw_ops(ah); + + priv_ops->set_rf_regs = NULL; + priv_ops->rf_alloc_ext_banks = NULL; + priv_ops->rf_free_ext_banks = NULL; + priv_ops->rf_set_freq = ar9002_hw_set_channel; + priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate; + priv_ops->olc_init = ar9002_olc_init; + priv_ops->compute_pll_control = ar9002_hw_compute_pll_control; + priv_ops->do_getnf = ar9002_hw_do_getnf; + + ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get; + ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set; + + ar9002_hw_set_nf_limits(ah); +} diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h index 37663dbbcf57..47780ef1c892 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h @@ -483,7 +483,11 @@ #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000 #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19 +#define AR_PHY_TX_PWRCTRL8 0xa278 + #define AR_PHY_TX_PWRCTRL9 0xa27C + +#define AR_PHY_TX_PWRCTRL10 0xa394 #define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 #define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 #define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000 @@ -495,6 +499,8 @@ #define AR_PHY_CH0_TX_PWRCTRL11 0xa398 #define AR_PHY_CH1_TX_PWRCTRL11 0xb398 +#define AR_PHY_CH0_TX_PWRCTRL12 0xa3dc +#define AR_PHY_CH0_TX_PWRCTRL13 0xa3e0 #define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00 #define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10 diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 9ecca93392e8..f915a3dbfcad 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -34,10 +34,10 @@ static const u32 ar9300_2p2_radio_postamble[][5] = { static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800}, - {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000}, - {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, @@ -119,14 +119,14 @@ static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = { {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800}, - {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000}, - {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000c2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800}, - {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000}, - {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000}, - {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, {0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, @@ -835,10 +835,10 @@ static const u32 ar9300_2p2_baseband_core[][2] = { static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, - {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, - {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, @@ -920,14 +920,14 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, - {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, - {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, - {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, - {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, @@ -941,10 +941,10 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, - {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, - {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, @@ -1026,14 +1026,14 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, - {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, - {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000c2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, - {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, - {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, @@ -1307,10 +1307,10 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = { static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, - {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, - {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, @@ -1329,21 +1329,21 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = { {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, @@ -1361,45 +1361,45 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = { {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, - {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, - {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, - {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83}, - {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84}, - {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3}, - {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5}, - {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9}, - {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb}, - {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, - {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, - {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, - {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, - {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, - {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, - {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, - {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, - {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000}, + {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501}, + {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 4a4cd88429c0..f276cb922b4d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -18,13 +18,13 @@ #include "hw-ops.h" #include "ar9003_phy.h" -#define MPASS 3 #define MAX_MEASUREMENT 8 -#define MAX_DIFFERENCE 10 +#define MAX_MAG_DELTA 11 +#define MAX_PHS_DELTA 10 struct coeff { - int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS]; - int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS]; + int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; + int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; int iqc_coeff[2]; }; @@ -185,17 +185,19 @@ static void ar9003_hw_iqcal_collect(struct ath_hw *ah) /* Accumulate IQ cal measures for active chains */ for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ah->totalPowerMeasI[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ah->totalPowerMeasQ[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ah->totalIqCorrMeas[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, - "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", - ah->cal_samples, i, ah->totalPowerMeasI[i], - ah->totalPowerMeasQ[i], - ah->totalIqCorrMeas[i]); + if (ah->txchainmask & BIT(i)) { + ah->totalPowerMeasI[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ah->totalPowerMeasQ[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ah->totalIqCorrMeas[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", + ah->cal_samples, i, ah->totalPowerMeasI[i], + ah->totalPowerMeasQ[i], + ah->totalIqCorrMeas[i]); + } } } @@ -608,36 +610,48 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, return true; } -static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg) +static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, + int max_delta) { - int diff[MPASS]; + int mp_max = -64, max_idx = 0; + int mp_min = 63, min_idx = 0; + int mp_avg = 0, i, outlier_idx = 0; - diff[0] = abs(mp_coeff[0] - mp_coeff[1]); - diff[1] = abs(mp_coeff[1] - mp_coeff[2]); - diff[2] = abs(mp_coeff[2] - mp_coeff[0]); + /* find min/max mismatch across all calibrated gains */ + for (i = 0; i < nmeasurement; i++) { + mp_avg += mp_coeff[i]; + if (mp_coeff[i] > mp_max) { + mp_max = mp_coeff[i]; + max_idx = i; + } else if (mp_coeff[i] < mp_min) { + mp_min = mp_coeff[i]; + min_idx = i; + } + } - if (diff[0] > MAX_DIFFERENCE && - diff[1] > MAX_DIFFERENCE && - diff[2] > MAX_DIFFERENCE) - return false; + /* find average (exclude max abs value) */ + for (i = 0; i < nmeasurement; i++) { + if ((abs(mp_coeff[i]) < abs(mp_max)) || + (abs(mp_coeff[i]) < abs(mp_min))) + mp_avg += mp_coeff[i]; + } + mp_avg /= (nmeasurement - 1); - if (diff[0] <= diff[1] && diff[0] <= diff[2]) - *mp_avg = (mp_coeff[0] + mp_coeff[1]) / 2; - else if (diff[1] <= diff[2]) - *mp_avg = (mp_coeff[1] + mp_coeff[2]) / 2; - else - *mp_avg = (mp_coeff[2] + mp_coeff[0]) / 2; - - return true; + /* detect outlier */ + if (abs(mp_max - mp_min) > max_delta) { + if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg)) + outlier_idx = max_idx; + else + outlier_idx = min_idx; + } + mp_coeff[outlier_idx] = mp_avg; } static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, u8 num_chains, struct coeff *coeff) { - struct ath_common *common = ath9k_hw_common(ah); int i, im, nmeasurement; - int magnitude, phase; u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff)); @@ -657,37 +671,28 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, /* Load the average of 2 passes */ for (i = 0; i < num_chains; i++) { - if (AR_SREV_9485(ah)) - nmeasurement = REG_READ_FIELD(ah, - AR_PHY_TX_IQCAL_STATUS_B0_9485, - AR_PHY_CALIBRATED_GAINS_0); - else - nmeasurement = REG_READ_FIELD(ah, - AR_PHY_TX_IQCAL_STATUS_B0, - AR_PHY_CALIBRATED_GAINS_0); + nmeasurement = REG_READ_FIELD(ah, + AR_PHY_TX_IQCAL_STATUS_B0, + AR_PHY_CALIBRATED_GAINS_0); if (nmeasurement > MAX_MEASUREMENT) nmeasurement = MAX_MEASUREMENT; + /* detect outlier only if nmeasurement > 1 */ + if (nmeasurement > 1) { + /* Detect magnitude outlier */ + ar9003_hw_detect_outlier(coeff->mag_coeff[i], + nmeasurement, MAX_MAG_DELTA); + + /* Detect phase outlier */ + ar9003_hw_detect_outlier(coeff->phs_coeff[i], + nmeasurement, MAX_PHS_DELTA); + } + for (im = 0; im < nmeasurement; im++) { - /* - * Determine which 2 passes are closest and compute avg - * magnitude - */ - if (!ar9003_hw_compute_closest_pass_and_avg(coeff->mag_coeff[i][im], - &magnitude)) - goto disable_txiqcal; - /* - * Determine which 2 passes are closest and compute avg - * phase - */ - if (!ar9003_hw_compute_closest_pass_and_avg(coeff->phs_coeff[i][im], - &phase)) - goto disable_txiqcal; - - coeff->iqc_coeff[0] = (magnitude & 0x7f) | - ((phase & 0x7f) << 7); + coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) | + ((coeff->phs_coeff[i][im] & 0x7f) << 7); if ((im % 2) == 0) REG_RMW_FIELD(ah, tx_corr_coeff[im][i], @@ -707,141 +712,37 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, return; -disable_txiqcal: - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, - AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x0); - REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, - AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x0); - - ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n"); } -static void ar9003_hw_tx_iq_cal(struct ath_hw *ah) +static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - static const u32 txiqcal_status[AR9300_MAX_CHAINS] = { - AR_PHY_TX_IQCAL_STATUS_B0, - AR_PHY_TX_IQCAL_STATUS_B1, - AR_PHY_TX_IQCAL_STATUS_B2, - }; - static const u32 chan_info_tab[] = { - AR_PHY_CHAN_INFO_TAB_0, - AR_PHY_CHAN_INFO_TAB_1, - AR_PHY_CHAN_INFO_TAB_2, - }; - struct coeff coeff; - s32 iq_res[6]; - s32 i, j, ip, im, nmeasurement; - u8 nchains = get_streams(common->tx_chainmask); - - for (ip = 0; ip < MPASS; ip++) { - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, - AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, - DELPT); - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, - AR_PHY_TX_IQCAL_START_DO_CAL, - AR_PHY_TX_IQCAL_START_DO_CAL); - - if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, - AR_PHY_TX_IQCAL_START_DO_CAL, - 0, AH_WAIT_TIMEOUT)) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Tx IQ Cal not complete.\n"); - goto TX_IQ_CAL_FAILED; - } - - nmeasurement = REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0, - AR_PHY_CALIBRATED_GAINS_0); - if (nmeasurement > MAX_MEASUREMENT) - nmeasurement = MAX_MEASUREMENT; - - for (i = 0; i < nchains; i++) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Doing Tx IQ Cal for chain %d.\n", i); - for (im = 0; im < nmeasurement; im++) { - if (REG_READ(ah, txiqcal_status[i]) & - AR_PHY_TX_IQCAL_STATUS_FAILED) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Tx IQ Cal failed for chain %d.\n", i); - goto TX_IQ_CAL_FAILED; - } - - for (j = 0; j < 3; j++) { - u8 idx = 2 * j, - offset = 4 * (3 * im + j); - - REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, - AR_PHY_CHAN_INFO_TAB_S2_READ, - 0); - - /* 32 bits */ - iq_res[idx] = REG_READ(ah, - chan_info_tab[i] + - offset); - - REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, - AR_PHY_CHAN_INFO_TAB_S2_READ, - 1); - - /* 16 bits */ - iq_res[idx+1] = 0xffff & REG_READ(ah, - chan_info_tab[i] + - offset); - - ath_dbg(common, ATH_DBG_CALIBRATE, - "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n", - idx, iq_res[idx], idx+1, iq_res[idx+1]); - } - - if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, - coeff.iqc_coeff)) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Failed in calculation of IQ correction.\n"); - goto TX_IQ_CAL_FAILED; - } - coeff.mag_coeff[i][im][ip] = - coeff.iqc_coeff[0] & 0x7f; - coeff.phs_coeff[i][im][ip] = - (coeff.iqc_coeff[0] >> 7) & 0x7f; - - if (coeff.mag_coeff[i][im][ip] > 63) - coeff.mag_coeff[i][im][ip] -= 128; - if (coeff.phs_coeff[i][im][ip] > 63) - coeff.phs_coeff[i][im][ip] -= 128; - - } - } - } - - ar9003_hw_tx_iqcal_load_avg_2_passes(ah, nchains, &coeff); - - return; - -TX_IQ_CAL_FAILED: - ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n"); -} - -static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) -{ u8 tx_gain_forced; - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1_9485, - AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT); tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE); if (tx_gain_forced) REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE, 0); - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START_9485, - AR_PHY_TX_IQCAL_START_DO_CAL_9485, 1); + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, + AR_PHY_TX_IQCAL_START_DO_CAL, 1); + + if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, + AR_PHY_TX_IQCAL_START_DO_CAL, 0, + AH_WAIT_TIMEOUT)) { + ath_dbg(common, ATH_DBG_CALIBRATE, + "Tx IQ Cal is not completed.\n"); + return false; + } + return true; } static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); const u32 txiqcal_status[AR9300_MAX_CHAINS] = { - AR_PHY_TX_IQCAL_STATUS_B0_9485, + AR_PHY_TX_IQCAL_STATUS_B0, AR_PHY_TX_IQCAL_STATUS_B1, AR_PHY_TX_IQCAL_STATUS_B2, }; @@ -853,7 +754,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) struct coeff coeff; s32 iq_res[6]; u8 num_chains = 0; - int i, ip, im, j; + int i, im, j; int nmeasurement; for (i = 0; i < AR9300_MAX_CHAINS; i++) { @@ -861,71 +762,69 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) num_chains++; } - for (ip = 0; ip < MPASS; ip++) { - for (i = 0; i < num_chains; i++) { - nmeasurement = REG_READ_FIELD(ah, - AR_PHY_TX_IQCAL_STATUS_B0_9485, - AR_PHY_CALIBRATED_GAINS_0); - if (nmeasurement > MAX_MEASUREMENT) - nmeasurement = MAX_MEASUREMENT; + for (i = 0; i < num_chains; i++) { + nmeasurement = REG_READ_FIELD(ah, + AR_PHY_TX_IQCAL_STATUS_B0, + AR_PHY_CALIBRATED_GAINS_0); + if (nmeasurement > MAX_MEASUREMENT) + nmeasurement = MAX_MEASUREMENT; - for (im = 0; im < nmeasurement; im++) { + for (im = 0; im < nmeasurement; im++) { + ath_dbg(common, ATH_DBG_CALIBRATE, + "Doing Tx IQ Cal for chain %d.\n", i); + + if (REG_READ(ah, txiqcal_status[i]) & + AR_PHY_TX_IQCAL_STATUS_FAILED) { ath_dbg(common, ATH_DBG_CALIBRATE, - "Doing Tx IQ Cal for chain %d.\n", i); - - if (REG_READ(ah, txiqcal_status[i]) & - AR_PHY_TX_IQCAL_STATUS_FAILED) { - ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed for chain %d.\n", i); - goto tx_iqcal_fail; - } + goto tx_iqcal_fail; + } - for (j = 0; j < 3; j++) { - u32 idx = 2 * j, offset = 4 * (3 * im + j); + for (j = 0; j < 3; j++) { + u32 idx = 2 * j, offset = 4 * (3 * im + j); - REG_RMW_FIELD(ah, + REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, AR_PHY_CHAN_INFO_TAB_S2_READ, 0); - /* 32 bits */ - iq_res[idx] = REG_READ(ah, - chan_info_tab[i] + - offset); + /* 32 bits */ + iq_res[idx] = REG_READ(ah, + chan_info_tab[i] + + offset); - REG_RMW_FIELD(ah, + REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, AR_PHY_CHAN_INFO_TAB_S2_READ, 1); - /* 16 bits */ - iq_res[idx + 1] = 0xffff & REG_READ(ah, - chan_info_tab[i] + offset); + /* 16 bits */ + iq_res[idx + 1] = 0xffff & REG_READ(ah, + chan_info_tab[i] + offset); - ath_dbg(common, ATH_DBG_CALIBRATE, - "IQ RES[%d]=0x%x" - "IQ_RES[%d]=0x%x\n", - idx, iq_res[idx], idx + 1, - iq_res[idx + 1]); - } - - if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, - coeff.iqc_coeff)) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Failed in calculation of IQ correction.\n"); - goto tx_iqcal_fail; - } - - coeff.mag_coeff[i][im][ip] = - coeff.iqc_coeff[0] & 0x7f; - coeff.phs_coeff[i][im][ip] = - (coeff.iqc_coeff[0] >> 7) & 0x7f; - - if (coeff.mag_coeff[i][im][ip] > 63) - coeff.mag_coeff[i][im][ip] -= 128; - if (coeff.phs_coeff[i][im][ip] > 63) - coeff.phs_coeff[i][im][ip] -= 128; + ath_dbg(common, ATH_DBG_CALIBRATE, + "IQ RES[%d]=0x%x" + "IQ_RES[%d]=0x%x\n", + idx, iq_res[idx], idx + 1, + iq_res[idx + 1]); } + + if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, + coeff.iqc_coeff)) { + ath_dbg(common, ATH_DBG_CALIBRATE, + "Failed in calculation of \ + IQ correction.\n"); + goto tx_iqcal_fail; + } + + coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f; + coeff.phs_coeff[i][im] = + (coeff.iqc_coeff[0] >> 7) & 0x7f; + + if (coeff.mag_coeff[i][im] > 63) + coeff.mag_coeff[i][im] -= 128; + if (coeff.phs_coeff[i][im] > 63) + coeff.phs_coeff[i][im] -= 128; } } ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff); @@ -940,31 +839,37 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_capabilities *pCap = &ah->caps; int val; + bool txiqcal_done = false; val = REG_READ(ah, AR_ENT_OTP); ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val); - if (AR_SREV_9485(ah)) - ar9003_hw_set_chain_masks(ah, 0x1, 0x1); - else if (val & AR_ENT_OTP_CHAIN2_DISABLE) + /* Configure rx/tx chains before running AGC/TxiQ cals */ + if (val & AR_ENT_OTP_CHAIN2_DISABLE) ar9003_hw_set_chain_masks(ah, 0x3, 0x3); else - /* - * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain - * mode before running AGC/TxIQ cals - */ - ar9003_hw_set_chain_masks(ah, 0x7, 0x7); + ar9003_hw_set_chain_masks(ah, pCap->rx_chainmask, + pCap->tx_chainmask); /* Do Tx IQ Calibration */ - if (AR_SREV_9485(ah)) - ar9003_hw_tx_iq_cal_run(ah); - else - ar9003_hw_tx_iq_cal(ah); + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, + AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, + DELPT); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); - udelay(5); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + /* + * For AR9485 or later chips, TxIQ cal runs as part of + * AGC calibration + */ + if (AR_SREV_9485_OR_LATER(ah)) + txiqcal_done = true; + else { + 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); + } /* Calibrate the AGC */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, @@ -979,7 +884,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, return false; } - if (AR_SREV_9485(ah)) + if (txiqcal_done) ar9003_hw_tx_iq_cal_post_proc(ah); /* Revert chainmasks to their original values before NF cal */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 6eadf975ae48..1e220354e4be 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -652,7 +652,7 @@ static const struct ar9300_eeprom ar9300_x113 = { .regDmn = { LE16(0), LE16(0x1f) }, .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */ .opCapFlags = { - .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A, + .opFlags = AR5416_OPFLAGS_11A, .eepMisc = 0, }, .rfSilent = 0, @@ -922,7 +922,7 @@ static const struct ar9300_eeprom ar9300_x113 = { .db_stage2 = {3, 3, 3}, /* 3 chain */ .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */ .db_stage4 = {3, 3, 3}, /* don't exist for 2G */ - .xpaBiasLvl = 0, + .xpaBiasLvl = 0xf, .txFrameToDataStart = 0x0e, .txFrameToPaOn = 0x0e, .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */ @@ -3217,7 +3217,6 @@ static int ar9300_compress_decision(struct ath_hw *ah, u8 *word, int length, int mdata_size) { struct ath_common *common = ath9k_hw_common(ah); - u8 *dptr; const struct ar9300_eeprom *eep = NULL; switch (code) { @@ -3235,7 +3234,6 @@ static int ar9300_compress_decision(struct ath_hw *ah, break; case _CompressBlock: if (reference == 0) { - dptr = mptr; } else { eep = ar9003_eeprom_struct_find_by_id(reference); if (eep == NULL) { @@ -3444,13 +3442,15 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) { int bias = ar9003_hw_xpa_bias_level_get(ah, is2ghz); - if (AR_SREV_9485(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); else { REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); - REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPABIASLVL_MSB, - bias >> 2); - REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPASHORT2GND, 1); + REG_RMW_FIELD(ah, AR_CH0_THERM, + AR_CH0_THERM_XPABIASLVL_MSB, + bias >> 2); + REG_RMW_FIELD(ah, AR_CH0_THERM, + AR_CH0_THERM_XPASHORT2GND, 1); } } @@ -3497,34 +3497,77 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) { + int chain; + u32 regval; + u32 ant_div_ctl1; + static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = { + AR_PHY_SWITCH_CHAIN_0, + AR_PHY_SWITCH_CHAIN_1, + AR_PHY_SWITCH_CHAIN_2, + }; + u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz); + REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_ALL, value); value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz); REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); - value = ar9003_hw_ant_ctrl_chain_get(ah, 0, is2ghz); - REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value); - - if (!AR_SREV_9485(ah)) { - value = ar9003_hw_ant_ctrl_chain_get(ah, 1, is2ghz); - REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL, - value); - - value = ar9003_hw_ant_ctrl_chain_get(ah, 2, is2ghz); - REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL, - value); + for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { + if ((ah->rxchainmask & BIT(chain)) || + (ah->txchainmask & BIT(chain))) { + value = ar9003_hw_ant_ctrl_chain_get(ah, chain, + is2ghz); + REG_RMW_FIELD(ah, switch_chain_reg[chain], + AR_SWITCH_TABLE_ALL, value); + } } if (AR_SREV_9485(ah)) { value = ath9k_hw_ar9300_get_eeprom(ah, EEP_ANT_DIV_CTL1); - REG_RMW_FIELD(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_CTRL_ALL, - value); - REG_RMW_FIELD(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE, - value >> 6); - REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE, - value >> 7); + /* + * main_lnaconf, alt_lnaconf, main_tb, alt_tb + * are the fields present + */ + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + regval &= (~AR_ANT_DIV_CTRL_ALL); + regval |= (value & 0x3f) << AR_ANT_DIV_CTRL_ALL_S; + /* enable_lnadiv */ + regval &= (~AR_PHY_9485_ANT_DIV_LNADIV); + regval |= ((value >> 6) & 0x1) << + AR_PHY_9485_ANT_DIV_LNADIV_S; + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); + + /*enable fast_div */ + regval = REG_READ(ah, AR_PHY_CCK_DETECT); + regval &= (~AR_FAST_DIV_ENABLE); + regval |= ((value >> 7) & 0x1) << + AR_FAST_DIV_ENABLE_S; + REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); + ant_div_ctl1 = + ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); + /* check whether antenna diversity is enabled */ + if ((ant_div_ctl1 >> 0x6) == 0x3) { + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + /* + * clear bits 25-30 main_lnaconf, alt_lnaconf, + * main_tb, alt_tb + */ + regval &= (~(AR_PHY_9485_ANT_DIV_MAIN_LNACONF | + AR_PHY_9485_ANT_DIV_ALT_LNACONF | + AR_PHY_9485_ANT_DIV_ALT_GAINTB | + AR_PHY_9485_ANT_DIV_MAIN_GAINTB)); + /* by default use LNA1 for the main antenna */ + regval |= (AR_PHY_9485_ANT_DIV_LNA1 << + AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S); + regval |= (AR_PHY_9485_ANT_DIV_LNA2 << + AR_PHY_9485_ANT_DIV_ALT_LNACONF_S); + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); + } + + } + } static void ar9003_hw_drive_strength_apply(struct ath_hw *ah) @@ -3634,13 +3677,16 @@ static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan) /* Test value. if 0 then attenuation is unused. Don't load anything. */ for (i = 0; i < 3; i++) { - value = ar9003_hw_atten_chain_get(ah, i, chan); - REG_RMW_FIELD(ah, ext_atten_reg[i], - AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); + if (ah->txchainmask & BIT(i)) { + value = ar9003_hw_atten_chain_get(ah, i, chan); + REG_RMW_FIELD(ah, ext_atten_reg[i], + AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); - value = ar9003_hw_atten_chain_get_margin(ah, i, chan); - REG_RMW_FIELD(ah, ext_atten_reg[i], - AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value); + value = ar9003_hw_atten_chain_get_margin(ah, i, chan); + REG_RMW_FIELD(ah, ext_atten_reg[i], + AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, + value); + } } } @@ -3749,8 +3795,9 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan)); ar9003_hw_drive_strength_apply(ah); ar9003_hw_atten_apply(ah, chan); - ar9003_hw_internal_regulator_apply(ah); - if (AR_SREV_9485(ah)) + if (!AR_SREV_9340(ah)) + ar9003_hw_internal_regulator_apply(ah); + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) ar9003_hw_apply_tuning_caps(ah); } @@ -3994,6 +4041,16 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0) ); + /* Write the power for duplicated frames - HT40 */ + + /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */ + REG_WRITE(ah, 0xa3e0, + POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0) + ); + /* Write the HT20 power per rate set */ /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 7f5de6e4448b..a55eddbb2589 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -18,6 +18,7 @@ #include "ar9003_mac.h" #include "ar9003_2p2_initvals.h" #include "ar9485_initvals.h" +#include "ar9340_initvals.h" /* General hardware code for the AR9003 hadware family */ @@ -28,7 +29,63 @@ */ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) { - if (AR_SREV_9485_11(ah)) { + if (AR_SREV_9340(ah)) { + /* mac */ + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + ar9340_1p0_mac_core, + ARRAY_SIZE(ar9340_1p0_mac_core), 2); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + ar9340_1p0_mac_postamble, + ARRAY_SIZE(ar9340_1p0_mac_postamble), 5); + + /* bb */ + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + ar9340_1p0_baseband_core, + ARRAY_SIZE(ar9340_1p0_baseband_core), 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + ar9340_1p0_baseband_postamble, + ARRAY_SIZE(ar9340_1p0_baseband_postamble), 5); + + /* radio */ + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + ar9340_1p0_radio_core, + ARRAY_SIZE(ar9340_1p0_radio_core), 2); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + ar9340_1p0_radio_postamble, + ARRAY_SIZE(ar9340_1p0_radio_postamble), 5); + + /* soc */ + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + ar9340_1p0_soc_preamble, + ARRAY_SIZE(ar9340_1p0_soc_preamble), 2); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + ar9340_1p0_soc_postamble, + ARRAY_SIZE(ar9340_1p0_soc_postamble), 5); + + /* rx/tx gain */ + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9340Common_wo_xlna_rx_gain_table_1p0, + ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0), + 5); + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_high_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0), + 5); + + INIT_INI_ARRAY(&ah->iniModesAdditional, + ar9340Modes_fast_clock_1p0, + ARRAY_SIZE(ar9340Modes_fast_clock_1p0), + 3); + + INIT_INI_ARRAY(&ah->iniModesAdditional_40M, + ar9340_1p0_radio_core_40M, + ARRAY_SIZE(ar9340_1p0_radio_core_40M), + 2); + } else if (AR_SREV_9485_11(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], @@ -66,8 +123,8 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) /* rx/tx gain */ INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485_common_rx_gain_1_1, - ARRAY_SIZE(ar9485_common_rx_gain_1_1), 2); + ar9485Common_wo_xlna_rx_gain_1_1, + ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485_modes_lowest_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), @@ -88,66 +145,6 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9485_1_1_pcie_phy_clkreq_disable_L1, ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), 2); - } else if (AR_SREV_9485(ah)) { - /* mac */ - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], - ar9485_1_0_mac_core, - ARRAY_SIZE(ar9485_1_0_mac_core), 2); - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar9485_1_0_mac_postamble, - ARRAY_SIZE(ar9485_1_0_mac_postamble), 5); - - /* bb */ - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_0, - ARRAY_SIZE(ar9485_1_0), 2); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar9485_1_0_baseband_core, - ARRAY_SIZE(ar9485_1_0_baseband_core), 2); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar9485_1_0_baseband_postamble, - ARRAY_SIZE(ar9485_1_0_baseband_postamble), 5); - - /* radio */ - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar9485_1_0_radio_core, - ARRAY_SIZE(ar9485_1_0_radio_core), 2); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], - ar9485_1_0_radio_postamble, - ARRAY_SIZE(ar9485_1_0_radio_postamble), 2); - - /* soc */ - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar9485_1_0_soc_preamble, - ARRAY_SIZE(ar9485_1_0_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0); - - /* rx/tx gain */ - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_rx_gain_1_0, - ARRAY_SIZE(ar9485Common_rx_gain_1_0), 2); - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_lowest_ob_db_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0), - 5); - - /* Load PCIE SERDES settings from INI */ - - /* Awake Setting */ - - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1, - ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1), - 2); - - /* Sleep Setting */ - - INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1, - ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1), - 2); } else { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); @@ -223,16 +220,16 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) switch (ar9003_hw_get_tx_gain_idx(ah)) { case 0: default: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485_modes_lowest_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), 5); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_lowest_ob_db_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0), - 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_lowest_ob_db_tx_gain_table_2p2, @@ -240,16 +237,16 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) 5); break; case 1: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_high_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1), 5); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_high_ob_db_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_0), - 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_high_ob_db_tx_gain_table_2p2, @@ -257,16 +254,16 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) 5); break; case 2: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_low_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1), 5); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_low_ob_db_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_0), - 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_low_ob_db_tx_gain_table_2p2, @@ -274,16 +271,16 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) 5); break; case 3: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_high_power_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1), 5); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_high_power_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_0), - 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_high_power_tx_gain_table_2p2, @@ -298,15 +295,15 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) switch (ar9003_hw_get_rx_gain_idx(ah)) { case 0: default: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485_common_rx_gain_1_1, - ARRAY_SIZE(ar9485_common_rx_gain_1_1), + ar9340Common_rx_gain_table_1p0, + ARRAY_SIZE(ar9340Common_rx_gain_table_1p0), 2); - else if (AR_SREV_9485(ah)) + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_rx_gain_1_0, - ARRAY_SIZE(ar9485Common_rx_gain_1_0), + ar9485Common_wo_xlna_rx_gain_1_1, + ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); else INIT_INI_ARRAY(&ah->iniModesRxGain, @@ -315,16 +312,16 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) 2); break; case 1: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9340Common_wo_xlna_rx_gain_table_1p0, + ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0), + 2); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9485Common_wo_xlna_rx_gain_1_1, ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_wo_xlna_rx_gain_1_0, - ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_0), - 2); else INIT_INI_ARRAY(&ah->iniModesRxGain, ar9300Common_wo_xlna_rx_gain_table_2p2, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 038a0cbfc6e7..be6adec33ddb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -329,7 +329,6 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds, | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | SM(txpower, AR_XmitPower) | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) - | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0); @@ -350,6 +349,16 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds, ads->ctl22 = 0; } +static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) +{ + struct ar9003_txc *ads = (struct ar9003_txc *) ds; + + if (val) + ads->ctl11 |= AR_ClrDestMask; + else + ads->ctl11 &= ~AR_ClrDestMask; +} + static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, void *lastds, u32 durUpdateEn, u32 rtsctsRate, @@ -475,27 +484,6 @@ static void ar9003_hw_clr11n_aggr(struct ath_hw *ah, void *ds) ads->ctl12 &= (~AR_IsAggr & ~AR_MoreAggr); } -static void ar9003_hw_set11n_burstduration(struct ath_hw *ah, void *ds, - u32 burstDuration) -{ - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - - ads->ctl13 &= ~AR_BurstDur; - ads->ctl13 |= SM(burstDuration, AR_BurstDur); - -} - -static void ar9003_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, - u32 vmf) -{ - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - - if (vmf) - ads->ctl11 |= AR_VirtMoreFrag; - else - ads->ctl11 &= ~AR_VirtMoreFrag; -} - void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains) { struct ar9003_txc *ads = ds; @@ -520,8 +508,7 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw) ops->set11n_aggr_middle = ar9003_hw_set11n_aggr_middle; ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; ops->clr11n_aggr = ar9003_hw_clr11n_aggr; - ops->set11n_burstduration = ar9003_hw_set11n_burstduration; - ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag; + ops->set_clrdmask = ar9003_hw_set_clrdmask; } void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index eb250d6b8038..25f3c2fdf2bc 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -75,16 +75,42 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) freq = centers.synth_center; if (freq < 4800) { /* 2 GHz, fractional mode */ - if (AR_SREV_9485(ah)) - channelSel = CHANSEL_2G_9485(freq); - else + if (AR_SREV_9485(ah)) { + u32 chan_frac; + + /* + * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0 + * ndiv = ((chan_mhz * 4) / 3) / freq_ref; + * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 + */ + channelSel = (freq * 4) / 120; + chan_frac = (((freq * 4) % 120) * 0x20000) / 120; + channelSel = (channelSel << 17) | chan_frac; + } else if (AR_SREV_9340(ah)) { + if (ah->is_clk_25mhz) { + u32 chan_frac; + + channelSel = (freq * 2) / 75; + chan_frac = (((freq * 2) % 75) * 0x20000) / 75; + channelSel = (channelSel << 17) | chan_frac; + } else + channelSel = CHANSEL_2G(freq) >> 1; + } else channelSel = CHANSEL_2G(freq); /* Set to 2G mode */ bMode = 1; } else { - channelSel = CHANSEL_5G(freq); - /* Doubler is ON, so, divide channelSel by 2. */ - channelSel >>= 1; + if (AR_SREV_9340(ah) && ah->is_clk_25mhz) { + u32 chan_frac; + + channelSel = (freq * 2) / 75; + chan_frac = ((freq % 75) * 0x20000) / 75; + channelSel = (channelSel << 17) | chan_frac; + } else { + channelSel = CHANSEL_5G(freq); + /* Doubler is ON, so, divide channelSel by 2. */ + channelSel >>= 1; + } /* Set to 5G mode */ bMode = 0; } @@ -142,7 +168,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, * is out-of-band and can be ignored. */ - if (AR_SREV_9485(ah)) { + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) { spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah, IS_CHAN_2GHZ(chan)); if (spur_fbin_ptr[0] == 0) /* No spur */ @@ -167,7 +193,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, for (i = 0; i < max_spur_cnts; i++) { negative = 0; - if (AR_SREV_9485(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i], IS_CHAN_2GHZ(chan)) - synth_freq; else @@ -401,7 +427,7 @@ static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah, ar9003_hw_spur_ofdm_clear(ah); - for (i = 0; spurChansPtr[i] && i < 5; i++) { + for (i = 0; i < AR_EEPROM_MODAL_SPURS && spurChansPtr[i]; i++) { freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq; if (abs(freq_offset) < range) { ar9003_hw_spur_ofdm_work(ah, chan, freq_offset); @@ -590,29 +616,25 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); unsigned int regWrites = 0, i; struct ieee80211_channel *channel = chan->chan; - u32 modesIndex, freqIndex; + u32 modesIndex; switch (chan->chanmode) { case CHANNEL_A: case CHANNEL_A_HT20: modesIndex = 1; - freqIndex = 1; break; case CHANNEL_A_HT40PLUS: case CHANNEL_A_HT40MINUS: modesIndex = 2; - freqIndex = 1; break; case CHANNEL_G: case CHANNEL_G_HT20: case CHANNEL_B: modesIndex = 4; - freqIndex = 2; break; case CHANNEL_G_HT40PLUS: case CHANNEL_G_HT40MINUS: modesIndex = 3; - freqIndex = 2; break; default: @@ -637,6 +659,9 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites); + if (AR_SREV_9340(ah) && !ah->is_clk_25mhz) + REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites); + ar9003_hw_override_ini(ah); ar9003_hw_set_channel_regs(ah, chan); ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); @@ -1159,9 +1184,52 @@ static void ar9003_hw_set_radar_conf(struct ath_hw *ah) conf->radar_inband = 8; } +static void ar9003_hw_antdiv_comb_conf_get(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf) +{ + u32 regval; + + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + antconf->main_lna_conf = (regval & AR_PHY_9485_ANT_DIV_MAIN_LNACONF) >> + AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S; + antconf->alt_lna_conf = (regval & AR_PHY_9485_ANT_DIV_ALT_LNACONF) >> + AR_PHY_9485_ANT_DIV_ALT_LNACONF_S; + antconf->fast_div_bias = (regval & AR_PHY_9485_ANT_FAST_DIV_BIAS) >> + AR_PHY_9485_ANT_FAST_DIV_BIAS_S; + antconf->lna1_lna2_delta = -9; + antconf->div_group = 2; +} + +static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf) +{ + u32 regval; + + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + regval &= ~(AR_PHY_9485_ANT_DIV_MAIN_LNACONF | + AR_PHY_9485_ANT_DIV_ALT_LNACONF | + AR_PHY_9485_ANT_FAST_DIV_BIAS | + AR_PHY_9485_ANT_DIV_MAIN_GAINTB | + AR_PHY_9485_ANT_DIV_ALT_GAINTB); + regval |= ((antconf->main_lna_conf << + AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S) + & AR_PHY_9485_ANT_DIV_MAIN_LNACONF); + regval |= ((antconf->alt_lna_conf << AR_PHY_9485_ANT_DIV_ALT_LNACONF_S) + & AR_PHY_9485_ANT_DIV_ALT_LNACONF); + regval |= ((antconf->fast_div_bias << AR_PHY_9485_ANT_FAST_DIV_BIAS_S) + & AR_PHY_9485_ANT_FAST_DIV_BIAS); + regval |= ((antconf->main_gaintb << AR_PHY_9485_ANT_DIV_MAIN_GAINTB_S) + & AR_PHY_9485_ANT_DIV_MAIN_GAINTB); + regval |= ((antconf->alt_gaintb << AR_PHY_9485_ANT_DIV_ALT_GAINTB_S) + & AR_PHY_9485_ANT_DIV_ALT_GAINTB); + + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); +} + void ar9003_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + struct ath_hw_ops *ops = ath9k_hw_ops(ah); static const u32 ar9300_cca_regs[6] = { AR_PHY_CCA_0, AR_PHY_CCA_1, @@ -1188,6 +1256,9 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs; priv_ops->set_radar_params = ar9003_hw_set_radar_params; + ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; + ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; + ar9003_hw_set_nf_limits(ah); ar9003_hw_set_radar_conf(ah); memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs)); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 8bdda2cf9dd7..c7505b48e5c0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -261,12 +261,34 @@ #define AR_PHY_EXT_CCA0 (AR_AGC_BASE + 0x20) #define AR_PHY_RESTART (AR_AGC_BASE + 0x24) +/* + * Antenna Diversity settings + */ #define AR_PHY_MC_GAIN_CTRL (AR_AGC_BASE + 0x28) #define AR_ANT_DIV_CTRL_ALL 0x7e000000 #define AR_ANT_DIV_CTRL_ALL_S 25 #define AR_ANT_DIV_ENABLE 0x1000000 #define AR_ANT_DIV_ENABLE_S 24 + +#define AR_PHY_9485_ANT_FAST_DIV_BIAS 0x00007e00 +#define AR_PHY_9485_ANT_FAST_DIV_BIAS_S 9 +#define AR_PHY_9485_ANT_DIV_LNADIV 0x01000000 +#define AR_PHY_9485_ANT_DIV_LNADIV_S 24 +#define AR_PHY_9485_ANT_DIV_ALT_LNACONF 0x06000000 +#define AR_PHY_9485_ANT_DIV_ALT_LNACONF_S 25 +#define AR_PHY_9485_ANT_DIV_MAIN_LNACONF 0x18000000 +#define AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S 27 +#define AR_PHY_9485_ANT_DIV_ALT_GAINTB 0x20000000 +#define AR_PHY_9485_ANT_DIV_ALT_GAINTB_S 29 +#define AR_PHY_9485_ANT_DIV_MAIN_GAINTB 0x40000000 +#define AR_PHY_9485_ANT_DIV_MAIN_GAINTB_S 30 + +#define AR_PHY_9485_ANT_DIV_LNA1_MINUS_LNA2 0x0 +#define AR_PHY_9485_ANT_DIV_LNA2 0x1 +#define AR_PHY_9485_ANT_DIV_LNA1 0x2 +#define AR_PHY_9485_ANT_DIV_LNA1_PLUS_LNA2 0x3 + #define AR_PHY_EXTCHN_PWRTHR1 (AR_AGC_BASE + 0x2c) #define AR_PHY_EXT_CHN_WIN (AR_AGC_BASE + 0x30) #define AR_PHY_20_40_DET_THR (AR_AGC_BASE + 0x34) @@ -548,15 +570,12 @@ #define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300) -#define AR_PHY_TX_IQCAL_START_9485 (AR_SM_BASE + 0x3c4) -#define AR_PHY_TX_IQCAL_START_DO_CAL_9485 0x80000000 -#define AR_PHY_TX_IQCAL_START_DO_CAL_9485_S 31 -#define AR_PHY_TX_IQCAL_CONTROL_1_9485 (AR_SM_BASE + 0x3c8) -#define AR_PHY_TX_IQCAL_STATUS_B0_9485 (AR_SM_BASE + 0x3f0) - -#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + 0x448) -#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + 0x440) -#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + 0x48c) +#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + AR_SREV_9485(ah) ? \ + 0x3c8 : 0x448) +#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + AR_SREV_9485(ah) ? \ + 0x3c4 : 0x440) +#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + AR_SREV_9485(ah) ? \ + 0x3f0 : 0x48c) #define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i) (AR_SM_BASE + \ (AR_SREV_9485(ah) ? \ 0x3d0 : 0x450) + ((_i) << 2)) @@ -588,7 +607,7 @@ #define AR_PHY_65NM_CH0_BIAS2 0x160c4 #define AR_PHY_65NM_CH0_BIAS4 0x160cc #define AR_PHY_65NM_CH0_RXTX4 0x1610c -#define AR_PHY_65NM_CH0_THERM (AR_SREV_9485(ah) ? 0x1628c : 0x16290) +#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : 0x1628c) #define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000 #define AR_PHY_65NM_CH0_THERM_LOCAL_S 31 @@ -758,10 +777,10 @@ #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 #define AR_PHY_CHANNEL_STATUS_RX_CLEAR 0x00000004 -#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000 -#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18 -#define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001 -#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0 +#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000 +#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18 +#define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001 +#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0 #define AR_PHY_TX_IQCAL_STATUS_FAILED 0x00000001 #define AR_PHY_CALIBRATED_GAINS_0 0x3e diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h new file mode 100644 index 000000000000..815a8af1beef --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -0,0 +1,1525 @@ +/* + * Copyright (c) 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 INITVALS_9340_H +#define INITVALS_9340_H + +static const u32 ar9340_1p0_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800}, + {0x0001610c, 0x08000000, 0x08000000, 0x00000000, 0x00000000}, + {0x00016140, 0x10804000, 0x10804000, 0x50804000, 0x50804000}, + {0x0001650c, 0x08000000, 0x08000000, 0x00000000, 0x00000000}, + {0x00016540, 0x10804000, 0x10804000, 0x50804000, 0x50804000}, +}; + +static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, + {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, +}; + +static const u32 ar9340Modes_fast_clock_1p0[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x00001030, 0x00000268, 0x000004d0}, + {0x00001070, 0x0000018c, 0x00000318}, + {0x000010b0, 0x00000fd0, 0x00001fa0}, + {0x00008014, 0x044c044c, 0x08980898}, + {0x0000801c, 0x148ec02b, 0x148ec057}, + {0x00008318, 0x000044c0, 0x00008980}, + {0x00009e00, 0x03721821, 0x03721821}, + {0x0000a230, 0x0000000b, 0x00000016}, + {0x0000a254, 0x00000898, 0x00001130}, +}; + +static const u32 ar9340_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016040, 0x7f80fff8}, + {0x00016044, 0x03b6d2db}, + {0x00016048, 0x24925266}, + {0x0001604c, 0x000f0278}, + {0x00016050, 0x6db6db6c}, + {0x00016054, 0x6db60000}, + {0x00016080, 0x00080000}, + {0x00016084, 0x0e48048c}, + {0x00016088, 0x14214514}, + {0x0001608c, 0x119f081c}, + {0x00016090, 0x24926490}, + {0x00016094, 0x00000000}, + {0x00016098, 0xd411eb84}, + {0x0001609c, 0x03e47f32}, + {0x000160a0, 0xc2108ffe}, + {0x000160a4, 0x812fc370}, + {0x000160a8, 0x423c8000}, + {0x000160ac, 0xa4646800}, + {0x000160b0, 0x00fe7f46}, + {0x000160b4, 0x92480000}, + {0x000160c0, 0x006db6db}, + {0x000160c4, 0x6db6db60}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x6de6db6c}, + {0x000160d0, 0xb6da4924}, + {0x00016100, 0x04cb0001}, + {0x00016104, 0xfff80000}, + {0x00016108, 0x00080010}, + {0x0001610c, 0x00000000}, + {0x00016140, 0x50804008}, + {0x00016144, 0x01884080}, + {0x00016148, 0x000080c0}, + {0x00016280, 0x01000015}, + {0x00016284, 0x05530000}, + {0x00016288, 0x00318000}, + {0x0001628c, 0x50000000}, + {0x00016290, 0x4080294f}, + {0x00016380, 0x00000000}, + {0x00016384, 0x00000000}, + {0x00016388, 0x00800700}, + {0x0001638c, 0x00800700}, + {0x00016390, 0x00800700}, + {0x00016394, 0x00000000}, + {0x00016398, 0x00000000}, + {0x0001639c, 0x00000000}, + {0x000163a0, 0x00000001}, + {0x000163a4, 0x00000001}, + {0x000163a8, 0x00000000}, + {0x000163ac, 0x00000000}, + {0x000163b0, 0x00000000}, + {0x000163b4, 0x00000000}, + {0x000163b8, 0x00000000}, + {0x000163bc, 0x00000000}, + {0x000163c0, 0x000000a0}, + {0x000163c4, 0x000c0000}, + {0x000163c8, 0x14021402}, + {0x000163cc, 0x00001402}, + {0x000163d0, 0x00000000}, + {0x000163d4, 0x00000000}, + {0x00016400, 0x36db6db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016440, 0x7f80fff8}, + {0x00016444, 0x03b6d2db}, + {0x00016448, 0x24927266}, + {0x0001644c, 0x000f0278}, + {0x00016450, 0x6db6db6c}, + {0x00016454, 0x6db60000}, + {0x00016500, 0x04cb0001}, + {0x00016504, 0xfff80000}, + {0x00016508, 0x00080010}, + {0x0001650c, 0x00000000}, + {0x00016540, 0x50804008}, + {0x00016544, 0x01884080}, + {0x00016548, 0x000080c0}, + {0x00016780, 0x00000000}, + {0x00016784, 0x00000000}, + {0x00016788, 0x00800700}, + {0x0001678c, 0x00800700}, + {0x00016790, 0x00800700}, + {0x00016794, 0x00000000}, + {0x00016798, 0x00000000}, + {0x0001679c, 0x00000000}, + {0x000167a0, 0x00000001}, + {0x000167a4, 0x00000001}, + {0x000167a8, 0x00000000}, + {0x000167ac, 0x00000000}, + {0x000167b0, 0x00000000}, + {0x000167b4, 0x00000000}, + {0x000167b8, 0x00000000}, + {0x000167bc, 0x00000000}, + {0x000167c0, 0x000000a0}, + {0x000167c4, 0x000c0000}, + {0x000167c8, 0x14021402}, + {0x000167cc, 0x00001402}, + {0x000167d0, 0x00000000}, + {0x000167d4, 0x00000000}, +}; + +static const u32 ar9340_1p0_radio_core_40M[][2] = { + {0x0001609c, 0x02566f3a}, + {0x000160ac, 0xa4647c00}, + {0x000160b0, 0x01885f5a}, +}; + +static const u32 ar9340_1p0_mac_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, + {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, + {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, + {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, + {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, +}; + +static const u32 ar9340_1p0_soc_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, +}; + +static const u32 ar9340_1p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044}, + {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e}, + {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, + {0x0000a288, 0x00000220, 0x00000220, 0x00000110, 0x00000110}, + {0x0000a28c, 0x00011111, 0x00011111, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x00180000, 0x00180000, 0x00180000, 0x00180000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, +}; + +static const u32 ar9340_1p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0xb280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x5f3ca3de}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14750600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x52440bbe}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x9883800a}, + {0x00009d10, 0x01834061}, + {0x00009d14, 0x00c0040b}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038230c}, + {0x00009e24, 0x990bb515}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e3c, 0xcf946222}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009e54, 0x00000000}, + {0x00009fc0, 0x803e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x01193b93}, + {0x0000a20c, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a22c, 0x01036a1e}, + {0x0000a234, 0x10000fff}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a2a0, 0x00000001}, + {0x0000a2c0, 0x00000001}, + {0x0000a2c8, 0x00000000}, + {0x0000a2cc, 0x18c43433}, + {0x0000a2d4, 0x00000000}, + {0x0000a2dc, 0x00000000}, + {0x0000a2e0, 0x00000000}, + {0x0000a2e4, 0x00000000}, + {0x0000a2e8, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, + {0x0000a3a4, 0x00000000}, + {0x0000a3a8, 0xaaaaaaaa}, + {0x0000a3ac, 0x3c466478}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000246}, + {0x0000a3f8, 0x0cdbd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce739ce}, + {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00000000}, + {0x0000a440, 0x00000000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x04000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a458, 0x00000000}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x00000000}, + {0x0000a610, 0x00000000}, + {0x0000a614, 0x00000000}, + {0x0000a618, 0x00000000}, + {0x0000a61c, 0x00000000}, + {0x0000a620, 0x00000000}, + {0x0000a624, 0x00000000}, + {0x0000a628, 0x00000000}, + {0x0000a62c, 0x00000000}, + {0x0000a630, 0x00000000}, + {0x0000a634, 0x00000000}, + {0x0000a638, 0x00000000}, + {0x0000a63c, 0x00000000}, + {0x0000a640, 0x00000000}, + {0x0000a644, 0x3fad9d74}, + {0x0000a648, 0x0048060a}, + {0x0000a64c, 0x00000637}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x09080504}, + {0x0000a678, 0x0d0c0b0a}, + {0x0000a67c, 0x13121110}, + {0x0000a680, 0x31301514}, + {0x0000a684, 0x35343332}, + {0x0000a688, 0x00000036}, + {0x0000a690, 0x00000838}, + {0x0000a7c0, 0x00000000}, + {0x0000a7c4, 0xfffffffc}, + {0x0000a7c8, 0x00000000}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000000}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2dc, 0x00000000}, + {0x0000b2e0, 0x00000000}, + {0x0000b2e4, 0x00000000}, + {0x0000b2e8, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, +}; + +static const u32 ar9340Modes_high_power_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, + {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, +}; + +static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x00016044, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016048, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266}, + {0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016448, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266}, +}; +static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x00016044, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db}, + {0x00016048, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266}, + {0x00016444, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db}, + {0x00016448, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266}, +}; + + +static const u32 ar9340Common_rx_gain_table_1p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x01910190}, + {0x0000a030, 0x01930192}, + {0x0000a034, 0x01950194}, + {0x0000a038, 0x038a0196}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x22222229}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x171d1d1d}, + {0x0000a094, 0x11111717}, + {0x0000a098, 0x00030311}, + {0x0000a09c, 0x00000000}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x32323232}, + {0x0000b084, 0x2f2f3232}, + {0x0000b088, 0x23282a2d}, + {0x0000b08c, 0x1c1e2123}, + {0x0000b090, 0x14171919}, + {0x0000b094, 0x0e0e1214}, + {0x0000b098, 0x03050707}, + {0x0000b09c, 0x00030303}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, + {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, +}; + +static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x15000402, 0x15000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x15800402, 0x15800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016048, 0x24927266, 0x24927266, 0x8e483266, 0x8e483266}, + {0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016448, 0x24927266, 0x24927266, 0x8e482266, 0x8e482266}, +}; + +static const u32 ar9340_1p0_mac_core[][2] = { + /* Addr allmodes */ + {0x00000008, 0x00000000}, + {0x00000030, 0x00020085}, + {0x00000034, 0x00000005}, + {0x00000040, 0x00000000}, + {0x00000044, 0x00000000}, + {0x00000048, 0x00000008}, + {0x0000004c, 0x00000010}, + {0x00000050, 0x00000000}, + {0x00001040, 0x002ffc0f}, + {0x00001044, 0x002ffc0f}, + {0x00001048, 0x002ffc0f}, + {0x0000104c, 0x002ffc0f}, + {0x00001050, 0x002ffc0f}, + {0x00001054, 0x002ffc0f}, + {0x00001058, 0x002ffc0f}, + {0x0000105c, 0x002ffc0f}, + {0x00001060, 0x002ffc0f}, + {0x00001064, 0x002ffc0f}, + {0x000010f0, 0x00000100}, + {0x00001270, 0x00000000}, + {0x000012b0, 0x00000000}, + {0x000012f0, 0x00000000}, + {0x0000143c, 0x00000000}, + {0x0000147c, 0x00000000}, + {0x00008000, 0x00000000}, + {0x00008004, 0x00000000}, + {0x00008008, 0x00000000}, + {0x0000800c, 0x00000000}, + {0x00008018, 0x00000000}, + {0x00008020, 0x00000000}, + {0x00008038, 0x00000000}, + {0x0000803c, 0x00000000}, + {0x00008040, 0x00000000}, + {0x00008044, 0x00000000}, + {0x00008048, 0x00000000}, + {0x0000804c, 0xffffffff}, + {0x00008054, 0x00000000}, + {0x00008058, 0x00000000}, + {0x0000805c, 0x000fc78f}, + {0x00008060, 0x0000000f}, + {0x00008064, 0x00000000}, + {0x00008070, 0x00000310}, + {0x00008074, 0x00000020}, + {0x00008078, 0x00000000}, + {0x0000809c, 0x0000000f}, + {0x000080a0, 0x00000000}, + {0x000080a4, 0x02ff0000}, + {0x000080a8, 0x0e070605}, + {0x000080ac, 0x0000000d}, + {0x000080b0, 0x00000000}, + {0x000080b4, 0x00000000}, + {0x000080b8, 0x00000000}, + {0x000080bc, 0x00000000}, + {0x000080c0, 0x2a800000}, + {0x000080c4, 0x06900168}, + {0x000080c8, 0x13881c20}, + {0x000080cc, 0x01f40000}, + {0x000080d0, 0x00252500}, + {0x000080d4, 0x00a00000}, + {0x000080d8, 0x00400000}, + {0x000080dc, 0x00000000}, + {0x000080e0, 0xffffffff}, + {0x000080e4, 0x0000ffff}, + {0x000080e8, 0x3f3f3f3f}, + {0x000080ec, 0x00000000}, + {0x000080f0, 0x00000000}, + {0x000080f4, 0x00000000}, + {0x000080fc, 0x00020000}, + {0x00008100, 0x00000000}, + {0x00008108, 0x00000052}, + {0x0000810c, 0x00000000}, + {0x00008110, 0x00000000}, + {0x00008114, 0x000007ff}, + {0x00008118, 0x000000aa}, + {0x0000811c, 0x00003210}, + {0x00008124, 0x00000000}, + {0x00008128, 0x00000000}, + {0x0000812c, 0x00000000}, + {0x00008130, 0x00000000}, + {0x00008134, 0x00000000}, + {0x00008138, 0x00000000}, + {0x0000813c, 0x0000ffff}, + {0x00008144, 0xffffffff}, + {0x00008168, 0x00000000}, + {0x0000816c, 0x00000000}, + {0x00008170, 0x18486200}, + {0x00008174, 0x33332210}, + {0x00008178, 0x00000000}, + {0x0000817c, 0x00020000}, + {0x000081c0, 0x00000000}, + {0x000081c4, 0x33332210}, + {0x000081c8, 0x00000000}, + {0x000081cc, 0x00000000}, + {0x000081d4, 0x00000000}, + {0x000081ec, 0x00000000}, + {0x000081f0, 0x00000000}, + {0x000081f4, 0x00000000}, + {0x000081f8, 0x00000000}, + {0x000081fc, 0x00000000}, + {0x00008240, 0x00100000}, + {0x00008244, 0x0010f424}, + {0x00008248, 0x00000800}, + {0x0000824c, 0x0001e848}, + {0x00008250, 0x00000000}, + {0x00008254, 0x00000000}, + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, + {0x00008264, 0x9d400010}, + {0x00008268, 0xffffffff}, + {0x0000826c, 0x0000ffff}, + {0x00008270, 0x00000000}, + {0x00008274, 0x40000000}, + {0x00008278, 0x003e4180}, + {0x0000827c, 0x00000004}, + {0x00008284, 0x0000002c}, + {0x00008288, 0x0000002c}, + {0x0000828c, 0x000000ff}, + {0x00008294, 0x00000000}, + {0x00008298, 0x00000000}, + {0x0000829c, 0x00000000}, + {0x00008300, 0x00000140}, + {0x00008314, 0x00000000}, + {0x0000831c, 0x0000010d}, + {0x00008328, 0x00000000}, + {0x0000832c, 0x00000007}, + {0x00008330, 0x00000302}, + {0x00008334, 0x00000700}, + {0x00008338, 0x00ff0000}, + {0x0000833c, 0x02400000}, + {0x00008340, 0x000107ff}, + {0x00008344, 0xaa48105b}, + {0x00008348, 0x008f0000}, + {0x0000835c, 0x00000000}, + {0x00008360, 0xffffffff}, + {0x00008364, 0xffffffff}, + {0x00008368, 0x00000000}, + {0x00008370, 0x00000000}, + {0x00008374, 0x000000ff}, + {0x00008378, 0x00000000}, + {0x0000837c, 0x00000000}, + {0x00008380, 0xffffffff}, + {0x00008384, 0xffffffff}, + {0x00008390, 0xffffffff}, + {0x00008394, 0xffffffff}, + {0x00008398, 0x00000000}, + {0x0000839c, 0x00000000}, + {0x000083a0, 0x00000000}, + {0x000083a4, 0x0000fa14}, + {0x000083a8, 0x000f0c00}, + {0x000083ac, 0x33332210}, + {0x000083b0, 0x33332210}, + {0x000083b4, 0x33332210}, + {0x000083b8, 0x33332210}, + {0x000083bc, 0x00000000}, + {0x000083c0, 0x00000000}, + {0x000083c4, 0x00000000}, + {0x000083c8, 0x00000000}, + {0x000083cc, 0x00000200}, + {0x000083d0, 0x000301ff}, +}; + +static const u32 ar9340Common_wo_xlna_rx_gain_table_1p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x03820190}, + {0x0000a030, 0x03840383}, + {0x0000a034, 0x03880385}, + {0x0000a038, 0x038a0389}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x29292929}, + {0x0000a084, 0x29292929}, + {0x0000a088, 0x29292929}, + {0x0000a08c, 0x29292929}, + {0x0000a090, 0x22292929}, + {0x0000a094, 0x1d1d2222}, + {0x0000a098, 0x0c111117}, + {0x0000a09c, 0x00030303}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x32323232}, + {0x0000b084, 0x2f2f3232}, + {0x0000b088, 0x23282a2d}, + {0x0000b08c, 0x1c1e2123}, + {0x0000b090, 0x14171919}, + {0x0000b094, 0x0e0e1214}, + {0x0000b098, 0x03050707}, + {0x0000b09c, 0x00030303}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar9340_1p0_soc_preamble[][2] = { + /* Addr allmodes */ + {0x000040a4, 0x00a0c1c9}, + {0x00007008, 0x00000000}, + {0x00007020, 0x00000000}, + {0x00007034, 0x00000002}, + {0x00007038, 0x000004c2}, +}; + +#endif diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index 71cc0a3a29fb..fbdde29f0ab8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -17,931 +17,6 @@ #ifndef INITVALS_9485_H #define INITVALS_9485_H -static const u32 ar9485Common_1_0[][2] = { - /* Addr allmodes */ - {0x00007010, 0x00000022}, - {0x00007020, 0x00000000}, - {0x00007034, 0x00000002}, - {0x00007038, 0x000004c2}, -}; - -static const u32 ar9485_1_0_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; - -static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10212e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9485Common_wo_xlna_rx_gain_1_0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x01800082}, - {0x0000a014, 0x01820181}, - {0x0000a018, 0x01840183}, - {0x0000a01c, 0x01880185}, - {0x0000a020, 0x018a0189}, - {0x0000a024, 0x02850284}, - {0x0000a028, 0x02890288}, - {0x0000a02c, 0x03850384}, - {0x0000a030, 0x03890388}, - {0x0000a034, 0x038b038a}, - {0x0000a038, 0x038d038c}, - {0x0000a03c, 0x03910390}, - {0x0000a040, 0x03930392}, - {0x0000a044, 0x03950394}, - {0x0000a048, 0x00000396}, - {0x0000a04c, 0x00000000}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x28282828}, - {0x0000a084, 0x28282828}, - {0x0000a088, 0x28282828}, - {0x0000a08c, 0x28282828}, - {0x0000a090, 0x28282828}, - {0x0000a094, 0x21212128}, - {0x0000a098, 0x171c1c1c}, - {0x0000a09c, 0x02020212}, - {0x0000a0a0, 0x00000202}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x111f1100}, - {0x0000a0c8, 0x111d111e}, - {0x0000a0cc, 0x111b111c}, - {0x0000a0d0, 0x22032204}, - {0x0000a0d4, 0x22012202}, - {0x0000a0d8, 0x221f2200}, - {0x0000a0dc, 0x221d221e}, - {0x0000a0e0, 0x33013302}, - {0x0000a0e4, 0x331f3300}, - {0x0000a0e8, 0x4402331e}, - {0x0000a0ec, 0x44004401}, - {0x0000a0f0, 0x441e441f}, - {0x0000a0f4, 0x55015502}, - {0x0000a0f8, 0x551f5500}, - {0x0000a0fc, 0x6602551e}, - {0x0000a100, 0x66006601}, - {0x0000a104, 0x661e661f}, - {0x0000a108, 0x7703661d}, - {0x0000a10c, 0x77017702}, - {0x0000a110, 0x00007700}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x111f1100}, - {0x0000a148, 0x111d111e}, - {0x0000a14c, 0x111b111c}, - {0x0000a150, 0x22032204}, - {0x0000a154, 0x22012202}, - {0x0000a158, 0x221f2200}, - {0x0000a15c, 0x221d221e}, - {0x0000a160, 0x33013302}, - {0x0000a164, 0x331f3300}, - {0x0000a168, 0x4402331e}, - {0x0000a16c, 0x44004401}, - {0x0000a170, 0x441e441f}, - {0x0000a174, 0x55015502}, - {0x0000a178, 0x551f5500}, - {0x0000a17c, 0x6602551e}, - {0x0000a180, 0x66006601}, - {0x0000a184, 0x661e661f}, - {0x0000a188, 0x7703661d}, - {0x0000a18c, 0x77017702}, - {0x0000a190, 0x00007700}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000296}, -}; - -static const u32 ar9485Modes_high_power_tx_gain_1_0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, -}; - -static const u32 ar9485_1_0[][2] = { - /* Addr allmodes */ - {0x0000a580, 0x00000000}, - {0x0000a584, 0x00000000}, - {0x0000a588, 0x00000000}, - {0x0000a58c, 0x00000000}, - {0x0000a590, 0x00000000}, - {0x0000a594, 0x00000000}, - {0x0000a598, 0x00000000}, - {0x0000a59c, 0x00000000}, - {0x0000a5a0, 0x00000000}, - {0x0000a5a4, 0x00000000}, - {0x0000a5a8, 0x00000000}, - {0x0000a5ac, 0x00000000}, - {0x0000a5b0, 0x00000000}, - {0x0000a5b4, 0x00000000}, - {0x0000a5b8, 0x00000000}, - {0x0000a5bc, 0x00000000}, -}; - -static const u32 ar9485_1_0_radio_core[][2] = { - /* Addr allmodes */ - {0x00016000, 0x36db6db6}, - {0x00016004, 0x6db6db40}, - {0x00016008, 0x73800000}, - {0x0001600c, 0x00000000}, - {0x00016040, 0x7f80fff8}, - {0x00016048, 0x6c92426e}, - {0x0001604c, 0x000f0278}, - {0x00016050, 0x6db6db6c}, - {0x00016054, 0x6db60000}, - {0x00016080, 0x00080000}, - {0x00016084, 0x0e48048c}, - {0x00016088, 0x14214514}, - {0x0001608c, 0x119f081e}, - {0x00016090, 0x24926490}, - {0x00016098, 0xd28b3330}, - {0x000160a0, 0xc2108ffe}, - {0x000160a4, 0x812fc370}, - {0x000160a8, 0x423c8000}, - {0x000160b4, 0x92480040}, - {0x000160c0, 0x006db6db}, - {0x000160c4, 0x0186db60}, - {0x000160c8, 0x6db6db6c}, - {0x000160cc, 0x6de6fbe0}, - {0x000160d0, 0xf7dfcf3c}, - {0x00016100, 0x04cb0001}, - {0x00016104, 0xfff80015}, - {0x00016108, 0x00080010}, - {0x00016144, 0x01884080}, - {0x00016148, 0x00008040}, - {0x00016180, 0x08453333}, - {0x00016184, 0x18e82f01}, - {0x00016188, 0x00000000}, - {0x0001618c, 0x00000000}, - {0x00016240, 0x08400000}, - {0x00016244, 0x1bf90f00}, - {0x00016248, 0x00000000}, - {0x0001624c, 0x00000000}, - {0x00016280, 0x01000015}, - {0x00016284, 0x00d30000}, - {0x00016288, 0x00318000}, - {0x0001628c, 0x50000000}, - {0x00016290, 0x4b96210f}, - {0x00016380, 0x00000000}, - {0x00016384, 0x00000000}, - {0x00016388, 0x00800700}, - {0x0001638c, 0x00800700}, - {0x00016390, 0x00800700}, - {0x00016394, 0x00000000}, - {0x00016398, 0x00000000}, - {0x0001639c, 0x00000000}, - {0x000163a0, 0x00000001}, - {0x000163a4, 0x00000001}, - {0x000163a8, 0x00000000}, - {0x000163ac, 0x00000000}, - {0x000163b0, 0x00000000}, - {0x000163b4, 0x00000000}, - {0x000163b8, 0x00000000}, - {0x000163bc, 0x00000000}, - {0x000163c0, 0x000000a0}, - {0x000163c4, 0x000c0000}, - {0x000163c8, 0x14021402}, - {0x000163cc, 0x00001402}, - {0x000163d0, 0x00000000}, - {0x000163d4, 0x00000000}, - {0x00016c40, 0x1319c178}, - {0x00016c44, 0x10000000}, -}; - -static const u32 ar9485Modes_lowest_ob_db_tx_gain_1_0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, -}; - -static const u32 ar9485_1_0_baseband_core[][2] = { - /* Addr allmodes */ - {0x00009800, 0xafe68e30}, - {0x00009804, 0xfd14e000}, - {0x00009808, 0x9c0a8f6b}, - {0x0000980c, 0x04800000}, - {0x00009814, 0x9280c00a}, - {0x00009818, 0x00000000}, - {0x0000981c, 0x00020028}, - {0x00009834, 0x5f3ca3de}, - {0x00009838, 0x0108ecff}, - {0x0000983c, 0x14750600}, - {0x00009880, 0x201fff00}, - {0x00009884, 0x00001042}, - {0x000098a4, 0x00200400}, - {0x000098b0, 0x52440bbe}, - {0x000098bc, 0x00000002}, - {0x000098d0, 0x004b6a8e}, - {0x000098d4, 0x00000820}, - {0x000098dc, 0x00000000}, - {0x000098f0, 0x00000000}, - {0x000098f4, 0x00000000}, - {0x00009c04, 0x00000000}, - {0x00009c08, 0x03200000}, - {0x00009c0c, 0x00000000}, - {0x00009c10, 0x00000000}, - {0x00009c14, 0x00046384}, - {0x00009c18, 0x05b6b440}, - {0x00009c1c, 0x00b6b440}, - {0x00009d00, 0xc080a333}, - {0x00009d04, 0x40206c10}, - {0x00009d08, 0x009c4060}, - {0x00009d0c, 0x1883800a}, - {0x00009d10, 0x01834061}, - {0x00009d14, 0x00c00400}, - {0x00009d18, 0x00000000}, - {0x00009d1c, 0x00000000}, - {0x00009e08, 0x0038233c}, - {0x00009e24, 0x990bb515}, - {0x00009e28, 0x0a6f0000}, - {0x00009e30, 0x06336f77}, - {0x00009e34, 0x6af6532f}, - {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, - {0x00009e4c, 0x00001004}, - {0x00009e50, 0x00ff03f1}, - {0x00009fc0, 0x80be4788}, - {0x00009fc4, 0x0001efb5}, - {0x00009fcc, 0x40000014}, - {0x0000a20c, 0x00000000}, - {0x0000a210, 0x00000000}, - {0x0000a220, 0x00000000}, - {0x0000a224, 0x00000000}, - {0x0000a228, 0x10002310}, - {0x0000a23c, 0x00000000}, - {0x0000a244, 0x0c000000}, - {0x0000a2a0, 0x00000001}, - {0x0000a2c0, 0x00000001}, - {0x0000a2c8, 0x00000000}, - {0x0000a2cc, 0x18c43433}, - {0x0000a2d4, 0x00000000}, - {0x0000a2dc, 0x00000000}, - {0x0000a2e0, 0x00000000}, - {0x0000a2e4, 0x00000000}, - {0x0000a2e8, 0x00000000}, - {0x0000a2ec, 0x00000000}, - {0x0000a2f0, 0x00000000}, - {0x0000a2f4, 0x00000000}, - {0x0000a2f8, 0x00000000}, - {0x0000a344, 0x00000000}, - {0x0000a34c, 0x00000000}, - {0x0000a350, 0x0000a000}, - {0x0000a364, 0x00000000}, - {0x0000a370, 0x00000000}, - {0x0000a390, 0x00000001}, - {0x0000a394, 0x00000444}, - {0x0000a398, 0x001f0e0f}, - {0x0000a39c, 0x0075393f}, - {0x0000a3a0, 0xb79f6427}, - {0x0000a3a4, 0x00000000}, - {0x0000a3a8, 0xaaaaaaaa}, - {0x0000a3ac, 0x3c466478}, - {0x0000a3c0, 0x20202020}, - {0x0000a3c4, 0x22222220}, - {0x0000a3c8, 0x20200020}, - {0x0000a3cc, 0x20202020}, - {0x0000a3d0, 0x20202020}, - {0x0000a3d4, 0x20202020}, - {0x0000a3d8, 0x20202020}, - {0x0000a3dc, 0x20202020}, - {0x0000a3e0, 0x20202020}, - {0x0000a3e4, 0x20202020}, - {0x0000a3e8, 0x20202020}, - {0x0000a3ec, 0x20202020}, - {0x0000a3f0, 0x00000000}, - {0x0000a3f4, 0x00000006}, - {0x0000a3f8, 0x0cdbd380}, - {0x0000a3fc, 0x000f0f01}, - {0x0000a400, 0x8fa91f01}, - {0x0000a404, 0x00000000}, - {0x0000a408, 0x0e79e5c6}, - {0x0000a40c, 0x00820820}, - {0x0000a414, 0x1ce739ce}, - {0x0000a418, 0x2d0011ce}, - {0x0000a41c, 0x1ce739ce}, - {0x0000a420, 0x000001ce}, - {0x0000a424, 0x1ce739ce}, - {0x0000a428, 0x000001ce}, - {0x0000a42c, 0x1ce739ce}, - {0x0000a430, 0x1ce739ce}, - {0x0000a434, 0x00000000}, - {0x0000a438, 0x00001801}, - {0x0000a43c, 0x00000000}, - {0x0000a440, 0x00000000}, - {0x0000a444, 0x00000000}, - {0x0000a448, 0x04000000}, - {0x0000a44c, 0x00000001}, - {0x0000a450, 0x00010000}, - {0x0000a458, 0x00000000}, - {0x0000a5c4, 0x3fad9d74}, - {0x0000a5c8, 0x0048060a}, - {0x0000a5cc, 0x00000637}, - {0x0000a760, 0x03020100}, - {0x0000a764, 0x09080504}, - {0x0000a768, 0x0d0c0b0a}, - {0x0000a76c, 0x13121110}, - {0x0000a770, 0x31301514}, - {0x0000a774, 0x35343332}, - {0x0000a778, 0x00000036}, - {0x0000a780, 0x00000838}, - {0x0000a7c0, 0x00000000}, - {0x0000a7c4, 0xfffffffc}, - {0x0000a7c8, 0x00000000}, - {0x0000a7cc, 0x00000000}, - {0x0000a7d0, 0x00000000}, - {0x0000a7d4, 0x00000004}, - {0x0000a7dc, 0x00000001}, -}; - -static const u32 ar9485Modes_high_ob_db_tx_gain_1_0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, -}; - -static const u32 ar9485Common_rx_gain_1_0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x01800082}, - {0x0000a014, 0x01820181}, - {0x0000a018, 0x01840183}, - {0x0000a01c, 0x01880185}, - {0x0000a020, 0x018a0189}, - {0x0000a024, 0x02850284}, - {0x0000a028, 0x02890288}, - {0x0000a02c, 0x03850384}, - {0x0000a030, 0x03890388}, - {0x0000a034, 0x038b038a}, - {0x0000a038, 0x038d038c}, - {0x0000a03c, 0x03910390}, - {0x0000a040, 0x03930392}, - {0x0000a044, 0x03950394}, - {0x0000a048, 0x00000396}, - {0x0000a04c, 0x00000000}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x28282828}, - {0x0000a084, 0x28282828}, - {0x0000a088, 0x28282828}, - {0x0000a08c, 0x28282828}, - {0x0000a090, 0x28282828}, - {0x0000a094, 0x21212128}, - {0x0000a098, 0x171c1c1c}, - {0x0000a09c, 0x02020212}, - {0x0000a0a0, 0x00000202}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x111f1100}, - {0x0000a0c8, 0x111d111e}, - {0x0000a0cc, 0x111b111c}, - {0x0000a0d0, 0x22032204}, - {0x0000a0d4, 0x22012202}, - {0x0000a0d8, 0x221f2200}, - {0x0000a0dc, 0x221d221e}, - {0x0000a0e0, 0x33013302}, - {0x0000a0e4, 0x331f3300}, - {0x0000a0e8, 0x4402331e}, - {0x0000a0ec, 0x44004401}, - {0x0000a0f0, 0x441e441f}, - {0x0000a0f4, 0x55015502}, - {0x0000a0f8, 0x551f5500}, - {0x0000a0fc, 0x6602551e}, - {0x0000a100, 0x66006601}, - {0x0000a104, 0x661e661f}, - {0x0000a108, 0x7703661d}, - {0x0000a10c, 0x77017702}, - {0x0000a110, 0x00007700}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x111f1100}, - {0x0000a148, 0x111d111e}, - {0x0000a14c, 0x111b111c}, - {0x0000a150, 0x22032204}, - {0x0000a154, 0x22012202}, - {0x0000a158, 0x221f2200}, - {0x0000a15c, 0x221d221e}, - {0x0000a160, 0x33013302}, - {0x0000a164, 0x331f3300}, - {0x0000a168, 0x4402331e}, - {0x0000a16c, 0x44004401}, - {0x0000a170, 0x441e441f}, - {0x0000a174, 0x55015502}, - {0x0000a178, 0x551f5500}, - {0x0000a17c, 0x6602551e}, - {0x0000a180, 0x66006601}, - {0x0000a184, 0x661e661f}, - {0x0000a188, 0x7703661d}, - {0x0000a18c, 0x77017702}, - {0x0000a190, 0x00007700}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000296}, -}; - -static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_enable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10252e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9485_1_0_pcie_phy_clkreq_enable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10253e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9485_1_0_soc_preamble[][2] = { - /* Addr allmodes */ - {0x00004090, 0x00aa10aa}, - {0x000040a4, 0x00a0c9c9}, - {0x00007048, 0x00000004}, -}; - -static const u32 ar9485_fast_clock_1_0_baseband_postamble[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x00009e00, 0x03721821, 0x03721821}, - {0x0000a230, 0x0000400b, 0x00004016}, - {0x0000a254, 0x00000898, 0x00001130}, -}; - -static const u32 ar9485_1_0_baseband_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, - {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, - {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, - {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, - {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, - {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, - {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, - {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, - {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, - {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e}, - {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, - {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, - {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, - {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, - {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, - {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, - {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0}, - {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, - {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, - {0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff}, - {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, - {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, - {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, - {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, - {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, - {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, - {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, - {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0}, - {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, - {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, - {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, - {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -}; - -static const u32 ar9485Modes_low_ob_db_tx_gain_1_0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, -}; - -static const u32 ar9485_1_0_pcie_phy_clkreq_disable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10213e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9485_1_0_radio_postamble[][2] = { - /* Addr allmodes */ - {0x0001609c, 0x0b283f31}, - {0x000160ac, 0x24611800}, - {0x000160b0, 0x03284f3e}, - {0x0001610c, 0x00170000}, - {0x00016140, 0x10804008}, -}; - -static const u32 ar9485_1_0_mac_core[][2] = { - /* Addr allmodes */ - {0x00000008, 0x00000000}, - {0x00000030, 0x00020085}, - {0x00000034, 0x00000005}, - {0x00000040, 0x00000000}, - {0x00000044, 0x00000000}, - {0x00000048, 0x00000008}, - {0x0000004c, 0x00000010}, - {0x00000050, 0x00000000}, - {0x00001040, 0x002ffc0f}, - {0x00001044, 0x002ffc0f}, - {0x00001048, 0x002ffc0f}, - {0x0000104c, 0x002ffc0f}, - {0x00001050, 0x002ffc0f}, - {0x00001054, 0x002ffc0f}, - {0x00001058, 0x002ffc0f}, - {0x0000105c, 0x002ffc0f}, - {0x00001060, 0x002ffc0f}, - {0x00001064, 0x002ffc0f}, - {0x000010f0, 0x00000100}, - {0x00001270, 0x00000000}, - {0x000012b0, 0x00000000}, - {0x000012f0, 0x00000000}, - {0x0000143c, 0x00000000}, - {0x0000147c, 0x00000000}, - {0x00008000, 0x00000000}, - {0x00008004, 0x00000000}, - {0x00008008, 0x00000000}, - {0x0000800c, 0x00000000}, - {0x00008018, 0x00000000}, - {0x00008020, 0x00000000}, - {0x00008038, 0x00000000}, - {0x0000803c, 0x00000000}, - {0x00008040, 0x00000000}, - {0x00008044, 0x00000000}, - {0x00008048, 0x00000000}, - {0x0000804c, 0xffffffff}, - {0x00008054, 0x00000000}, - {0x00008058, 0x00000000}, - {0x0000805c, 0x000fc78f}, - {0x00008060, 0x0000000f}, - {0x00008064, 0x00000000}, - {0x00008070, 0x00000310}, - {0x00008074, 0x00000020}, - {0x00008078, 0x00000000}, - {0x0000809c, 0x0000000f}, - {0x000080a0, 0x00000000}, - {0x000080a4, 0x02ff0000}, - {0x000080a8, 0x0e070605}, - {0x000080ac, 0x0000000d}, - {0x000080b0, 0x00000000}, - {0x000080b4, 0x00000000}, - {0x000080b8, 0x00000000}, - {0x000080bc, 0x00000000}, - {0x000080c0, 0x2a800000}, - {0x000080c4, 0x06900168}, - {0x000080c8, 0x13881c20}, - {0x000080cc, 0x01f40000}, - {0x000080d0, 0x00252500}, - {0x000080d4, 0x00a00000}, - {0x000080d8, 0x00400000}, - {0x000080dc, 0x00000000}, - {0x000080e0, 0xffffffff}, - {0x000080e4, 0x0000ffff}, - {0x000080e8, 0x3f3f3f3f}, - {0x000080ec, 0x00000000}, - {0x000080f0, 0x00000000}, - {0x000080f4, 0x00000000}, - {0x000080fc, 0x00020000}, - {0x00008100, 0x00000000}, - {0x00008108, 0x00000052}, - {0x0000810c, 0x00000000}, - {0x00008110, 0x00000000}, - {0x00008114, 0x000007ff}, - {0x00008118, 0x000000aa}, - {0x0000811c, 0x00003210}, - {0x00008124, 0x00000000}, - {0x00008128, 0x00000000}, - {0x0000812c, 0x00000000}, - {0x00008130, 0x00000000}, - {0x00008134, 0x00000000}, - {0x00008138, 0x00000000}, - {0x0000813c, 0x0000ffff}, - {0x00008144, 0xffffffff}, - {0x00008168, 0x00000000}, - {0x0000816c, 0x00000000}, - {0x00008170, 0x18486200}, - {0x00008174, 0x33332210}, - {0x00008178, 0x00000000}, - {0x0000817c, 0x00020000}, - {0x000081c0, 0x00000000}, - {0x000081c4, 0x33332210}, - {0x000081c8, 0x00000000}, - {0x000081cc, 0x00000000}, - {0x000081d4, 0x00000000}, - {0x000081ec, 0x00000000}, - {0x000081f0, 0x00000000}, - {0x000081f4, 0x00000000}, - {0x000081f8, 0x00000000}, - {0x000081fc, 0x00000000}, - {0x00008240, 0x00100000}, - {0x00008244, 0x0010f400}, - {0x00008248, 0x00000800}, - {0x0000824c, 0x0001e800}, - {0x00008250, 0x00000000}, - {0x00008254, 0x00000000}, - {0x00008258, 0x00000000}, - {0x0000825c, 0x40000000}, - {0x00008260, 0x00080922}, - {0x00008264, 0x9ca00010}, - {0x00008268, 0xffffffff}, - {0x0000826c, 0x0000ffff}, - {0x00008270, 0x00000000}, - {0x00008274, 0x40000000}, - {0x00008278, 0x003e4180}, - {0x0000827c, 0x00000004}, - {0x00008284, 0x0000002c}, - {0x00008288, 0x0000002c}, - {0x0000828c, 0x000000ff}, - {0x00008294, 0x00000000}, - {0x00008298, 0x00000000}, - {0x0000829c, 0x00000000}, - {0x00008300, 0x00000140}, - {0x00008314, 0x00000000}, - {0x0000831c, 0x0000010d}, - {0x00008328, 0x00000000}, - {0x0000832c, 0x00000007}, - {0x00008330, 0x00000302}, - {0x00008334, 0x00000700}, - {0x00008338, 0x00ff0000}, - {0x0000833c, 0x02400000}, - {0x00008340, 0x000107ff}, - {0x00008344, 0xa248105b}, - {0x00008348, 0x008f0000}, - {0x0000835c, 0x00000000}, - {0x00008360, 0xffffffff}, - {0x00008364, 0xffffffff}, - {0x00008368, 0x00000000}, - {0x00008370, 0x00000000}, - {0x00008374, 0x000000ff}, - {0x00008378, 0x00000000}, - {0x0000837c, 0x00000000}, - {0x00008380, 0xffffffff}, - {0x00008384, 0xffffffff}, - {0x00008390, 0xffffffff}, - {0x00008394, 0xffffffff}, - {0x00008398, 0x00000000}, - {0x0000839c, 0x00000000}, - {0x000083a0, 0x00000000}, - {0x000083a4, 0x0000fa14}, - {0x000083a8, 0x000f0c00}, - {0x000083ac, 0x33332210}, - {0x000083b0, 0x33332210}, - {0x000083b4, 0x33332210}, - {0x000083b8, 0x33332210}, - {0x000083bc, 0x00000000}, - {0x000083c0, 0x00000000}, - {0x000083c4, 0x00000000}, - {0x000083c8, 0x00000000}, - {0x000083cc, 0x00000200}, - {0x000083d0, 0x000301ff}, -}; - static const u32 ar9485_1_1_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, @@ -1321,7 +396,7 @@ static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = { {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, @@ -1394,7 +469,7 @@ static const u32 ar9485_modes_lowest_ob_db_tx_gain_1_1[][5] = { {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, @@ -1560,7 +635,7 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, @@ -1653,7 +728,7 @@ static const u32 ar9485_modes_green_ob_db_tx_gain_1_1[][5] = { {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, @@ -1752,7 +827,7 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = { {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 099bd4183ad0..03b37d7be1c3 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -62,7 +62,6 @@ struct ath_node; #define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<ds_link = 0; - /* - * Switch antenna every beacon. - * Should only switch every beacon period, not for every SWBA - * XXX assumes two antennae - */ - antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); sband = &sc->sbands[common->hw->conf.channel->band]; rate = sband->bitrates[rateidx].hw_value; @@ -278,7 +272,7 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) return -ENOMEM; tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - sc->beacon.bc_tstamp = le64_to_cpu(tstamp); + sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp); /* Calculate a TSF adjustment factor required for staggered beacons. */ if (avp->av_bslot > 0) { u64 tsfadjust; @@ -294,8 +288,8 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) * adjustment. Other slots are adjusted to get the timestamp * close to the TBTT for the BSS. */ - tsfadjust = intval * avp->av_bslot / ATH_BCBUF; - avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); + tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF; + avp->tsf_adjust = cpu_to_le64(tsfadjust); ath_dbg(common, ATH_DBG_BEACON, "stagger beacons, bslot %d intval %u tsfadjust %llu\n", @@ -326,9 +320,11 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) if (avp->av_bcbuf != NULL) { struct ath_buf *bf; + avp->is_bslot_active = false; if (avp->av_bslot != -1) { sc->beacon.bslot[avp->av_bslot] = NULL; sc->nbcnvifs--; + avp->av_bslot = -1; } bf = avp->av_bcbuf; @@ -369,12 +365,13 @@ void ath_beacon_tasklet(unsigned long data) if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { sc->beacon.bmisscnt++; - if (sc->beacon.bmisscnt < BSTUCK_THRESH) { + if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) { ath_dbg(common, ATH_DBG_BSTUCK, "missed %u consecutive beacons\n", sc->beacon.bmisscnt); ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); - ath9k_hw_bstuck_nfcal(ah); + if (sc->beacon.bmisscnt > 3) + ath9k_hw_bstuck_nfcal(ah); } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { ath_dbg(common, ATH_DBG_BSTUCK, "beacon is officially stuck\n"); @@ -385,13 +382,6 @@ void ath_beacon_tasklet(unsigned long data) return; } - if (sc->beacon.bmisscnt != 0) { - ath_dbg(common, ATH_DBG_BSTUCK, - "resume beacon xmit after %u misses\n", - sc->beacon.bmisscnt); - sc->beacon.bmisscnt = 0; - } - /* * Generate beacon frames. we are sending frames * staggered so calculate the slot for this frame based @@ -401,21 +391,14 @@ void ath_beacon_tasklet(unsigned long data) intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; tsf = ath9k_hw_gettsf64(ah); - tsftu = TSF_TO_TU(tsf>>32, tsf); - slot = ((tsftu % intval) * ATH_BCBUF) / intval; - /* - * Reverse the slot order to get slot 0 on the TBTT offset that does - * not require TSF adjustment and other slots adding - * slot/ATH_BCBUF * beacon_int to timestamp. For example, with - * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 .. - * and slot 0 is at correct offset to TBTT. - */ - slot = ATH_BCBUF - slot - 1; + tsf += TU_TO_USEC(ah->config.sw_beacon_response_time); + tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF); + slot = (tsftu % (intval * ATH_BCBUF)) / intval; vif = sc->beacon.bslot[slot]; ath_dbg(common, ATH_DBG_BEACON, "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", - slot, tsf, tsftu, intval, vif); + slot, tsf, tsftu / ATH_BCBUF, intval, vif); bfaddr = 0; if (vif) { @@ -424,6 +407,13 @@ void ath_beacon_tasklet(unsigned long data) bfaddr = bf->bf_daddr; bc = 1; } + + if (sc->beacon.bmisscnt != 0) { + ath_dbg(common, ATH_DBG_BSTUCK, + "resume beacon xmit after %u misses\n", + sc->beacon.bmisscnt); + sc->beacon.bmisscnt = 0; + } } /* @@ -463,13 +453,17 @@ static void ath9k_beacon_init(struct ath_softc *sc, u32 next_beacon, u32 beacon_period) { - if (beacon_period & ATH9K_BEACON_RESET_TSF) + if (sc->sc_flags & SC_OP_TSF_RESET) { ath9k_ps_wakeup(sc); + ath9k_hw_reset_tsf(sc->sc_ah); + } ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); - if (beacon_period & ATH9K_BEACON_RESET_TSF) + if (sc->sc_flags & SC_OP_TSF_RESET) { ath9k_ps_restore(sc); + sc->sc_flags &= ~SC_OP_TSF_RESET; + } } /* @@ -484,18 +478,14 @@ static void ath_beacon_config_ap(struct ath_softc *sc, u32 nexttbtt, intval; /* NB: the beacon interval is kept internally in TU's */ - intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); intval /= ATH_BCBUF; /* for staggered beacons */ nexttbtt = intval; - if (sc->sc_flags & SC_OP_TSF_RESET) - intval |= ATH9K_BEACON_RESET_TSF; - /* * In AP mode we enable the beacon timers and SWBA interrupts to * prepare beacon frames. */ - intval |= ATH9K_BEACON_ENA; ah->imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); @@ -505,11 +495,6 @@ static void ath_beacon_config_ap(struct ath_softc *sc, ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah, ah->imask); - - /* Clear the reset TSF flag, so that subsequent beacon updation - will not reset the HW TSF. */ - - sc->sc_flags &= ~SC_OP_TSF_RESET; } /* @@ -635,7 +620,13 @@ static void ath_beacon_config_sta(struct ath_softc *sc, ath9k_hw_disable_interrupts(ah); ath9k_hw_set_sta_beacon_timers(ah, &bs); ah->imask |= ATH9K_INT_BMISS; - ath9k_hw_set_interrupts(ah, ah->imask); + + /* + * If the beacon config is called beacause of TSFOOR, + * Interrupts will be enabled back at the end of ath9k_tasklet + */ + if (!(sc->ps_flags & PS_TSFOOR_SYNC)) + ath9k_hw_set_interrupts(ah, ah->imask); } static void ath_beacon_config_adhoc(struct ath_softc *sc, @@ -643,25 +634,20 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u64 tsf; - u32 tsftu, intval, nexttbtt; + u32 tsf, delta, intval, nexttbtt; - intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE); + intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); - - /* Pull nexttbtt forward to reflect the current TSF */ - - nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); - if (nexttbtt == 0) - nexttbtt = intval; - else if (intval) - nexttbtt = roundup(nexttbtt, intval); - - tsf = ath9k_hw_gettsf64(ah); - tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; - do { - nexttbtt += intval; - } while (nexttbtt < tsftu); + if (!sc->beacon.bc_tstamp) + nexttbtt = tsf + intval; + else { + if (tsf > sc->beacon.bc_tstamp) + delta = (tsf - sc->beacon.bc_tstamp); + else + delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp)); + nexttbtt = tsf + roundup(delta, intval); + } ath_dbg(common, ATH_DBG_BEACON, "IBSS nexttbtt %u intval %u (%u)\n", @@ -672,7 +658,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, * if we need to manually prepare beacon frames. Otherwise we use a * self-linked tx descriptor and let the hardware deal with things. */ - intval |= ATH9K_BEACON_ENA; ah->imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); @@ -682,25 +667,71 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, ath9k_hw_disable_interrupts(ah); ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(ah, ah->imask); + /* + * If the beacon config is called beacause of TSFOOR, + * Interrupts will be enabled back at the end of ath9k_tasklet + */ + if (!(sc->ps_flags & PS_TSFOOR_SYNC)) + ath9k_hw_set_interrupts(ah, ah->imask); +} + +static bool ath9k_allow_beacon_config(struct ath_softc *sc, + struct ieee80211_vif *vif) +{ + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_vif *avp = (void *)vif->drv_priv; + + /* + * Can not have different beacon interval on multiple + * AP interface case + */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && + (sc->nbcnvifs > 1) && + (vif->type == NL80211_IFTYPE_AP) && + (cur_conf->beacon_interval != bss_conf->beacon_int)) { + ath_dbg(common, ATH_DBG_CONFIG, + "Changing beacon interval of multiple \ + AP interfaces !\n"); + return false; + } + /* + * Can not configure station vif's beacon config + * while on AP opmode + */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && + (vif->type != NL80211_IFTYPE_AP)) { + ath_dbg(common, ATH_DBG_CONFIG, + "STA vif's beacon not allowed on AP mode\n"); + return false; + } + /* + * Do not allow beacon config if HW was already configured + * with another STA vif + */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && + (vif->type == NL80211_IFTYPE_STATION) && + (sc->sc_flags & SC_OP_BEACONS) && + !avp->primary_sta_vif) { + ath_dbg(common, ATH_DBG_CONFIG, + "Beacon already configured for a station interface\n"); + return false; + } + return true; } void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) { struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - enum nl80211_iftype iftype; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + + if (!ath9k_allow_beacon_config(sc, vif)) + return; /* Setup the beacon configuration parameters */ - if (vif) { - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - iftype = vif->type; - cur_conf->beacon_interval = bss_conf->beacon_int; - cur_conf->dtim_period = bss_conf->dtim_period; - } else { - iftype = sc->sc_ah->opmode; - } - + cur_conf->beacon_interval = bss_conf->beacon_int; + cur_conf->dtim_period = bss_conf->dtim_period; cur_conf->listen_interval = 1; cur_conf->dtim_count = 1; cur_conf->bmiss_timeout = @@ -723,9 +754,37 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) if (cur_conf->dtim_period == 0) cur_conf->dtim_period = 1; - switch (iftype) { + ath_set_beacon(sc); +} + +static bool ath_has_valid_bslot(struct ath_softc *sc) +{ + struct ath_vif *avp; + int slot; + bool found = false; + + for (slot = 0; slot < ATH_BCBUF; slot++) { + if (sc->beacon.bslot[slot]) { + avp = (void *)sc->beacon.bslot[slot]->drv_priv; + if (avp->is_bslot_active) { + found = true; + break; + } + } + } + return found; +} + + +void ath_set_beacon(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + + switch (sc->sc_ah->opmode) { case NL80211_IFTYPE_AP: - ath_beacon_config_ap(sc, cur_conf); + if (ath_has_valid_bslot(sc)) + ath_beacon_config_ap(sc, cur_conf); break; case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: @@ -746,26 +805,15 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) { struct ath_hw *ah = sc->sc_ah; - struct ath_vif *avp; - int slot; - bool found = false; + + if (!ath_has_valid_bslot(sc)) + return; ath9k_ps_wakeup(sc); if (status) { - for (slot = 0; slot < ATH_BCBUF; slot++) { - if (sc->beacon.bslot[slot]) { - avp = (void *)sc->beacon.bslot[slot]->drv_priv; - if (avp->is_bslot_active) { - found = true; - break; - } - } - } - if (found) { - /* Re-enable beaconing */ - ah->imask |= ATH9K_INT_SWBA; - ath9k_hw_set_interrupts(ah, ah->imask); - } + /* Re-enable beaconing */ + ah->imask |= ATH9K_INT_SWBA; + ath9k_hw_set_interrupts(ah, ah->imask); } else { /* Disable SWBA interrupt */ ah->imask &= ~ATH9K_INT_SWBA; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index d33bf204c995..23f15a7ca7f1 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -51,6 +51,10 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) .bt_hold_rx_clear = true, }; u32 i; + bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity; + + if (AR_SREV_9300_20_OR_LATER(ah)) + rxclear_polarity = !ath_bt_config.bt_rxclear_polarity; btcoex_hw->bt_coex_mode = (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) | @@ -59,7 +63,7 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | SM(ath_bt_config.bt_mode, AR_BT_MODE) | SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) | - SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | + SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) | SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | SM(qnum, AR_BT_QCU_THRESH); @@ -142,6 +146,7 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, } EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); + static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; @@ -152,9 +157,22 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) * enable coex 3-wire */ REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_hw->bt_coex_mode); - REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2); + + if (AR_SREV_9300_20_OR_LATER(ah)) { + REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, ah->bt_coex_wlan_weight[0]); + REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, ah->bt_coex_wlan_weight[1]); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, ah->bt_coex_bt_weight[0]); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, ah->bt_coex_bt_weight[1]); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, ah->bt_coex_bt_weight[2]); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, ah->bt_coex_bt_weight[3]); + + } else + REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); + + + if (AR_SREV_9271(ah)) { val = REG_READ(ah, 0x50040); val &= 0xFFFFFEFF; @@ -202,10 +220,86 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) { REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); - REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); REG_WRITE(ah, AR_BT_COEX_MODE2, 0); + + if (AR_SREV_9300_20_OR_LATER(ah)) { + REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, 0); + REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, 0); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, 0); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, 0); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, 0); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, 0); + } else + REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); + } ah->btcoex_hw.enabled = false; } EXPORT_SYMBOL(ath9k_hw_btcoex_disable); + +static void ar9003_btcoex_bt_stomp(struct ath_hw *ah, + enum ath_stomp_type stomp_type) +{ + ah->bt_coex_bt_weight[0] = AR9300_BT_WGHT; + ah->bt_coex_bt_weight[1] = AR9300_BT_WGHT; + ah->bt_coex_bt_weight[2] = AR9300_BT_WGHT; + ah->bt_coex_bt_weight[3] = AR9300_BT_WGHT; + + + switch (stomp_type) { + case ATH_BTCOEX_STOMP_ALL: + ah->bt_coex_wlan_weight[0] = AR9300_STOMP_ALL_WLAN_WGHT0; + ah->bt_coex_wlan_weight[1] = AR9300_STOMP_ALL_WLAN_WGHT1; + break; + case ATH_BTCOEX_STOMP_LOW: + ah->bt_coex_wlan_weight[0] = AR9300_STOMP_LOW_WLAN_WGHT0; + ah->bt_coex_wlan_weight[1] = AR9300_STOMP_LOW_WLAN_WGHT1; + break; + case ATH_BTCOEX_STOMP_NONE: + ah->bt_coex_wlan_weight[0] = AR9300_STOMP_NONE_WLAN_WGHT0; + ah->bt_coex_wlan_weight[1] = AR9300_STOMP_NONE_WLAN_WGHT1; + break; + + default: + ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Invalid Stomptype\n"); + break; + } + + ath9k_hw_btcoex_enable(ah); +} + +/* + * Configures appropriate weight based on stomp type. + */ +void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, + enum ath_stomp_type stomp_type) +{ + if (AR_SREV_9300_20_OR_LATER(ah)) { + ar9003_btcoex_bt_stomp(ah, stomp_type); + return; + } + + switch (stomp_type) { + case ATH_BTCOEX_STOMP_ALL: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_ALL_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_LOW: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_NONE: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_NONE_WLAN_WGHT); + break; + default: + ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Invalid Stomptype\n"); + break; + } + + ath9k_hw_btcoex_enable(ah); +} +EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp); diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 588dfd464dd1..a9efca83d676 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -19,9 +19,13 @@ #include "hw.h" -#define ATH_WLANACTIVE_GPIO 5 -#define ATH_BTACTIVE_GPIO 6 -#define ATH_BTPRIORITY_GPIO 7 +#define ATH_WLANACTIVE_GPIO_9280 5 +#define ATH_BTACTIVE_GPIO_9280 6 +#define ATH_BTPRIORITY_GPIO_9285 7 + +#define ATH_WLANACTIVE_GPIO_9300 5 +#define ATH_BTACTIVE_GPIO_9300 4 +#define ATH_BTPRIORITY_GPIO_9300 8 #define ATH_BTCOEX_DEF_BT_PERIOD 45 #define ATH_BTCOEX_DEF_DUTY_CYCLE 55 @@ -32,6 +36,14 @@ #define ATH_BT_CNT_THRESHOLD 3 #define ATH_BT_CNT_SCAN_THRESHOLD 15 +/* Defines the BT AR_BT_COEX_WGHT used */ +enum ath_stomp_type { + ATH_BTCOEX_NO_STOMP, + ATH_BTCOEX_STOMP_ALL, + ATH_BTCOEX_STOMP_LOW, + ATH_BTCOEX_STOMP_NONE +}; + enum ath_btcoex_scheme { ATH_BTCOEX_CFG_NONE, ATH_BTCOEX_CFG_2WIRE, @@ -57,5 +69,7 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, u32 wlan_weight); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); +void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, + enum ath_stomp_type stomp_type); #endif diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 8649581fa4dd..558b228a717f 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -69,15 +69,21 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, int16_t *nfarray) { struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &common->hw->conf; struct ath_nf_limits *limit; struct ath9k_nfcal_hist *h; bool high_nf_mid = false; + u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; int i; h = cal->nfCalHist; limit = ath9k_hw_get_nf_limits(ah, ah->curchan); for (i = 0; i < NUM_NF_READINGS; i++) { + if (!(chainmask & (1 << i)) || + ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))) + continue; + h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) @@ -225,6 +231,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) int32_t val; u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &common->hw->conf; s16 default_nf = ath9k_hw_get_default_nf(ah, chan); if (ah->caldata) @@ -234,6 +241,9 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) if (chainmask & (1 << i)) { s16 nfval; + if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)) + continue; + if (h) nfval = h[i].privNF; else @@ -293,6 +303,9 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) ENABLE_REGWRITE_BUFFER(ah); for (i = 0; i < NUM_NF_READINGS; i++) { if (chainmask & (1 << i)) { + if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)) + continue; + val = REG_READ(ah, ah->nf_regs[i]); val &= 0xFFFFFE00; val |= (((u32) (-50) << 1) & 0x1ff); @@ -396,14 +409,6 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, } } -s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) -{ - if (!ah->curchan || !ah->curchan->noisefloor) - return ath9k_hw_get_default_nf(ah, chan); - - return ah->curchan->noisefloor; -} -EXPORT_SYMBOL(ath9k_hw_getchan_noise); void ath9k_hw_bstuck_nfcal(struct ath_hw *ah) { diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index b8973eb8d858..4420780fa3b8 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -106,7 +106,6 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_hw_bstuck_nfcal(struct ath_hw *ah); -s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_hw_reset_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal); diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 615e68276e72..74535e6dfb82 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -116,7 +116,7 @@ void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, if (chan->band == IEEE80211_BAND_2GHZ) { ichan->chanmode = CHANNEL_G; - ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; + ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; } else { ichan->chanmode = CHANNEL_A; ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; @@ -158,37 +158,6 @@ int ath9k_cmn_count_streams(unsigned int chainmask, int max) } EXPORT_SYMBOL(ath9k_cmn_count_streams); -/* - * Configures appropriate weight based on stomp type. - */ -void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common, - enum ath_stomp_type stomp_type) -{ - struct ath_hw *ah = common->ah; - - switch (stomp_type) { - case ATH_BTCOEX_STOMP_ALL: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_ALL_WLAN_WGHT); - break; - case ATH_BTCOEX_STOMP_LOW: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); - break; - case ATH_BTCOEX_STOMP_NONE: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_NONE_WLAN_WGHT); - break; - default: - ath_dbg(common, ATH_DBG_BTCOEX, - "Invalid Stomptype\n"); - break; - } - - ath9k_hw_btcoex_enable(ah); -} -EXPORT_SYMBOL(ath9k_cmn_btcoex_bt_stomp); - void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, u16 new_txpow, u16 *txpower) { diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index b2f7b5f89097..5124f1420b3a 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -50,14 +50,6 @@ #define ATH_EP_RND(x, mul) \ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) -/* Defines the BT AR_BT_COEX_WGHT used */ -enum ath_stomp_type { - ATH_BTCOEX_NO_STOMP, - ATH_BTCOEX_STOMP_ALL, - ATH_BTCOEX_STOMP_LOW, - ATH_BTCOEX_STOMP_NONE -}; - int ath9k_cmn_padpos(__le16 frame_control); int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 8df5a92a20f1..bad1a87249b6 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -326,6 +326,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) sc->debug.stats.istats.dtimsync++; if (status & ATH9K_INT_DTIM) sc->debug.stats.istats.dtim++; + if (status & ATH9K_INT_TSFOOR) + sc->debug.stats.istats.tsfoor++; } static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, @@ -379,9 +381,12 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, "%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); @@ -845,7 +850,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, struct ath_softc *sc = file->private_data; char *buf; - unsigned int len = 0, size = 1152; + unsigned int len = 0, size = 1400; ssize_t retval = 0; buf = kzalloc(size, GFP_KERNEL); @@ -874,6 +879,34 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, "%18s : %10u\n", "DECRYPT BUSY ERR", sc->debug.stats.rxstats.decrypt_busy_err); + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-CTL0", + sc->debug.stats.rxstats.rs_rssi_ctl0); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-CTL1", + sc->debug.stats.rxstats.rs_rssi_ctl1); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-CTL2", + sc->debug.stats.rxstats.rs_rssi_ctl2); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-EXT0", + sc->debug.stats.rxstats.rs_rssi_ext0); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-EXT1", + sc->debug.stats.rxstats.rs_rssi_ext1); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-EXT2", + sc->debug.stats.rxstats.rs_rssi_ext2); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "Rx Antenna", + sc->debug.stats.rxstats.rs_antenna); + PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); @@ -948,6 +981,16 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) RX_PHY_ERR_INC(phyerr); } + sc->debug.stats.rxstats.rs_rssi_ctl0 = rs->rs_rssi_ctl0; + sc->debug.stats.rxstats.rs_rssi_ctl1 = rs->rs_rssi_ctl1; + sc->debug.stats.rxstats.rs_rssi_ctl2 = rs->rs_rssi_ctl2; + + sc->debug.stats.rxstats.rs_rssi_ext0 = rs->rs_rssi_ext0; + sc->debug.stats.rxstats.rs_rssi_ext1 = rs->rs_rssi_ext1; + sc->debug.stats.rxstats.rs_rssi_ext2 = rs->rs_rssi_ext2; + + sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna; + #undef RX_STAT_INC #undef RX_PHY_ERR_INC } @@ -1088,67 +1131,43 @@ int ath9k_init_debug(struct ath_hw *ah) return -ENOMEM; #ifdef CONFIG_ATH_DEBUG - if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_debug)) - goto err; + debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_debug); #endif + debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_dma); + debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_interrupt); + debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_wiphy); + debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_xmit); + debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_stations); + debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_misc); + debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_recv); + debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_rx_chainmask); + debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_tx_chainmask); + debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_regidx); + debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_regval); + debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, + &ah->config.cwm_ignore_extcca); + debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_regdump); - if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_dma)) - goto err; + debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); - if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_interrupt)) - goto err; - - if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_wiphy)) - goto err; - - if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_xmit)) - goto err; - - if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_stations)) - goto err; - - if (!debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_misc)) - goto err; - - if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_recv)) - goto err; - - if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_rx_chainmask)) - goto err; - - if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_tx_chainmask)) - goto err; - - if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_regidx)) - goto err; - - if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_regval)) - goto err; - - if (!debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca)) - goto err; - - if (!debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_regdump)) - goto err; + debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); sc->debug.regidx = 0; return 0; -err: - debugfs_remove_recursive(sc->debug.debugfs_phy); - sc->debug.debugfs_phy = NULL; - return -ENOMEM; } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 59338de0ce19..5488a324cc10 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -54,6 +54,9 @@ struct ath_buf; * @dtimsync: DTIM sync lossage * @dtim: RX Beacon with DTIM * @bb_watchdog: Baseband watchdog + * @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 */ struct ath_interrupt_stats { u32 total; @@ -78,6 +81,7 @@ struct ath_interrupt_stats { u32 dtimsync; u32 dtim; u32 bb_watchdog; + u32 tsfoor; }; /** @@ -157,6 +161,13 @@ struct ath_rx_stats { u32 post_delim_crc_err; u32 decrypt_busy_err; u32 phy_err_stats[ATH9K_PHYERR_MAX]; + int8_t rs_rssi_ctl0; + int8_t rs_rssi_ctl1; + int8_t rs_rssi_ctl2; + int8_t rs_rssi_ext0; + int8_t rs_rssi_ext1; + int8_t rs_rssi_ext2; + u8 rs_antenna; }; struct ath_stats { diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index bd82447f5b78..3e316133f114 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -436,7 +436,11 @@ struct modal_eep_4k_header { u8 db2_2:4, db2_3:4; u8 db2_4:4, reserved:4; #endif - u8 futureModal[4]; + u8 tx_diversity; + u8 flc_pwr_thresh; + u8 bb_scale_smrt_antenna; +#define EEP_4K_BB_DESIRED_SCALE_MASK 0x1f + u8 futureModal[1]; struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS]; } __packed; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index bc77a308c901..6f714dd72365 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -781,6 +781,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, { struct modal_eep_4k_header *pModal; struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + struct base_eep_header_4k *pBase = &eep->baseEepHeader; u8 txRxAttenLocal; u8 ob[5], db1[5], db2[5]; u8 ant_div_control1, ant_div_control2; @@ -1003,6 +1004,31 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); } + if (AR_SREV_9271(ah) || AR_SREV_9285(ah)) { + u8 bb_desired_scale = (pModal->bb_scale_smrt_antenna & + EEP_4K_BB_DESIRED_SCALE_MASK); + if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) { + u32 pwrctrl, mask, clr; + + mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25); + pwrctrl = mask * bb_desired_scale; + clr = mask * 0x1f; + REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr); + REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr); + REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr); + + mask = BIT(0)|BIT(5)|BIT(15); + pwrctrl = mask * bb_desired_scale; + clr = mask * 0x1f; + REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr); + + mask = BIT(0)|BIT(5); + pwrctrl = mask * bb_desired_scale; + clr = mask * 0x1f; + REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr); + REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr); + } + } } static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 8cd8333cc086..b87db4763098 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -319,10 +319,9 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, u16 numXpdGain, xpdMask; u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0}; u32 reg32, regOffset, regChainOffset, regval; - int16_t modalIdx, diff = 0; + int16_t diff = 0; struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; xpdMask = pEepData->modalHeader.xpdGain; if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= @@ -392,6 +391,8 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, numXpdGain); } + ENABLE_REGWRITE_BUFFER(ah); + if (i == 0) { if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { @@ -442,6 +443,7 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, regOffset += 4; } } + REGWRITE_BUFFER_FLUSH(ah); } } @@ -757,6 +759,8 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; } + ENABLE_REGWRITE_BUFFER(ah); + /* OFDM power per rate */ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, ATH9K_POW_SM(ratesArray[rate18mb], 24) @@ -840,6 +844,7 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } + REGWRITE_BUFFER_FLUSH(ah); } static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah, @@ -852,35 +857,12 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah, { struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; - u16 antWrites[AR9287_ANT_16S]; u32 regChainOffset, regval; u8 txRxAttenLocal; - int i, j, offset_num; + int i; pModal = &eep->modalHeader; - antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF); - antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF); - antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF); - antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF); - antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF); - antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF); - antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF); - antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF); - - offset_num = 8; - - for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3); - antWrites[j++] = 0; - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3); - antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); - } - REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); for (i = 0; i < AR9287_MAX_CHAINS; i++) { diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index fccd87df7300..c031854b569f 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -231,6 +231,10 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) integer = swab32(pModal->antCtrlChain[i]); pModal->antCtrlChain[i] = integer; } + for (i = 0; i < 3; i++) { + word = swab16(pModal->xpaBiasLvlFreq[i]); + pModal->xpaBiasLvlFreq[i] = word; + } for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { word = swab16(pModal->spurChans[i].spurChan); @@ -799,6 +803,8 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, pwr_table_offset, &diff); + ENABLE_REGWRITE_BUFFER(ah); + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { if (OLC_FOR_AR9280_20_LATER) { REG_WRITE(ah, @@ -847,6 +853,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, regOffset += 4; } + REGWRITE_BUFFER_FLUSH(ah); } } @@ -1205,6 +1212,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, } } + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, ATH9K_POW_SM(ratesArray[rate18mb], 24) | ATH9K_POW_SM(ratesArray[rate12mb], 16) @@ -1291,6 +1300,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_POWER_TX_SUB, ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + + REGWRITE_BUFFER_FLUSH(ah); } static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 0fb8f8ac275a..0349b3a1cc58 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -41,12 +41,16 @@ void ath_init_leds(struct ath_softc *sc) { int ret; - if (AR_SREV_9287(sc->sc_ah)) - sc->sc_ah->led_pin = ATH_LED_PIN_9287; - else if (AR_SREV_9485(sc->sc_ah)) - sc->sc_ah->led_pin = ATH_LED_PIN_9485; - else - sc->sc_ah->led_pin = ATH_LED_PIN_DEF; + if (sc->sc_ah->led_pin < 0) { + if (AR_SREV_9287(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9287; + else if (AR_SREV_9485(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9485; + else if (AR_SREV_9300(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9300; + else + sc->sc_ah->led_pin = ATH_LED_PIN_DEF; + } /* Configure gpio 1 for output */ ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, @@ -136,10 +140,10 @@ static void ath_detect_bt_priority(struct ath_softc *sc) static void ath9k_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, - u32 timer_next, + u32 trig_timeout, u32 timer_period) { - ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); + ath9k_hw_gen_timer_start(ah, timer, trig_timeout, timer_period); if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { ath9k_hw_disable_interrupts(ah); @@ -172,17 +176,17 @@ static void ath_btcoex_period_timer(unsigned long data) struct ath_softc *sc = (struct ath_softc *) data; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_common *common = ath9k_hw_common(ah); u32 timer_period; bool is_btscan; + ath9k_ps_wakeup(sc); ath_detect_bt_priority(sc); is_btscan = sc->sc_flags & SC_OP_BT_SCAN; spin_lock_bh(&btcoex->btcoex_lock); - ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL : + ath9k_hw_btcoex_bt_stomp(ah, is_btscan ? ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type); spin_unlock_bh(&btcoex->btcoex_lock); @@ -193,11 +197,12 @@ static void ath_btcoex_period_timer(unsigned long data) timer_period = is_btscan ? btcoex->btscan_no_stomp : btcoex->btcoex_no_stomp; - ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, 0, + ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period, timer_period * 10); btcoex->hw_timer_enabled = true; } + ath9k_ps_restore(sc); mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); } @@ -217,14 +222,16 @@ static void ath_btcoex_no_stomp_timer(void *arg) ath_dbg(common, ATH_DBG_BTCOEX, "no stomp timer running\n"); + ath9k_ps_wakeup(sc); spin_lock_bh(&btcoex->btcoex_lock); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) - ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE); + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) - ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW); + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); spin_unlock_bh(&btcoex->btcoex_lock); + ath9k_ps_restore(sc); } int ath_init_btcoex_timer(struct ath_softc *sc) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index f1b8af64569c..2e3a33a53406 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -17,11 +17,9 @@ #include "htc.h" /* identify firmware images */ -#define FIRMWARE_AR7010 "ar7010.fw" -#define FIRMWARE_AR7010_1_1 "ar7010_1_1.fw" -#define FIRMWARE_AR9271 "ar9271.fw" +#define FIRMWARE_AR7010_1_1 "htc_7010.fw" +#define FIRMWARE_AR9271 "htc_9271.fw" -MODULE_FIRMWARE(FIRMWARE_AR7010); MODULE_FIRMWARE(FIRMWARE_AR7010_1_1); MODULE_FIRMWARE(FIRMWARE_AR9271); @@ -80,7 +78,7 @@ static void hif_usb_regout_cb(struct urb *urb) if (cmd) { ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle, - cmd->skb, 1); + cmd->skb, true); kfree(cmd); } @@ -126,6 +124,90 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev, return ret; } +static void hif_usb_mgmt_cb(struct urb *urb) +{ + struct cmd_buf *cmd = (struct cmd_buf *)urb->context; + struct hif_device_usb *hif_dev = cmd->hif_dev; + bool txok = true; + + if (!cmd || !cmd->skb || !cmd->hif_dev) + return; + + switch (urb->status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ENODEV: + case -ESHUTDOWN: + txok = false; + + /* + * If the URBs are being flushed, no need to complete + * this packet. + */ + spin_lock(&hif_dev->tx.tx_lock); + if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) { + spin_unlock(&hif_dev->tx.tx_lock); + dev_kfree_skb_any(cmd->skb); + kfree(cmd); + return; + } + spin_unlock(&hif_dev->tx.tx_lock); + + break; + default: + txok = false; + break; + } + + skb_pull(cmd->skb, 4); + ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle, + cmd->skb, txok); + kfree(cmd); +} + +static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev, + struct sk_buff *skb) +{ + struct urb *urb; + struct cmd_buf *cmd; + int ret = 0; + __le16 *hdr; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (urb == NULL) + return -ENOMEM; + + cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); + if (cmd == NULL) { + usb_free_urb(urb); + return -ENOMEM; + } + + cmd->skb = skb; + cmd->hif_dev = hif_dev; + + hdr = (__le16 *) skb_push(skb, 4); + *hdr++ = cpu_to_le16(skb->len - 4); + *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG); + + usb_fill_bulk_urb(urb, hif_dev->udev, + usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE), + skb->data, skb->len, + hif_usb_mgmt_cb, cmd); + + usb_anchor_urb(urb, &hif_dev->mgmt_submitted); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + usb_unanchor_urb(urb); + kfree(cmd); + } + usb_free_urb(urb); + + return ret; +} + static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, struct sk_buff_head *list) { @@ -133,7 +215,22 @@ static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, while ((skb = __skb_dequeue(list)) != NULL) { dev_kfree_skb_any(skb); - TX_STAT_INC(skb_dropped); + } +} + +static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev, + struct sk_buff_head *queue, + bool txok) +{ + struct sk_buff *skb; + + while ((skb = __skb_dequeue(queue)) != NULL) { + ath9k_htc_txcompletion_cb(hif_dev->htc_handle, + skb, txok); + if (txok) + TX_STAT_INC(skb_success); + else + TX_STAT_INC(skb_failed); } } @@ -141,7 +238,7 @@ static void hif_usb_tx_cb(struct urb *urb) { struct tx_buf *tx_buf = (struct tx_buf *) urb->context; struct hif_device_usb *hif_dev; - struct sk_buff *skb; + bool txok = true; if (!tx_buf || !tx_buf->hif_dev) return; @@ -155,10 +252,7 @@ static void hif_usb_tx_cb(struct urb *urb) case -ECONNRESET: case -ENODEV: case -ESHUTDOWN: - /* - * The URB has been killed, free the SKBs. - */ - ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); + txok = false; /* * If the URBs are being flushed, no need to add this @@ -167,41 +261,19 @@ static void hif_usb_tx_cb(struct urb *urb) spin_lock(&hif_dev->tx.tx_lock); if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) { spin_unlock(&hif_dev->tx.tx_lock); + ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); return; } spin_unlock(&hif_dev->tx.tx_lock); - /* - * In the stop() case, this URB has to be added to - * the free list. - */ - goto add_free; + break; default: + txok = false; break; } - /* - * Check if TX has been stopped, this is needed because - * this CB could have been invoked just after the TX lock - * was released in hif_stop() and kill_urb() hasn't been - * called yet. - */ - spin_lock(&hif_dev->tx.tx_lock); - if (hif_dev->tx.flags & HIF_USB_TX_STOP) { - spin_unlock(&hif_dev->tx.tx_lock); - ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); - goto add_free; - } - spin_unlock(&hif_dev->tx.tx_lock); + ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, txok); - /* Complete the queued SKBs. */ - while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) { - ath9k_htc_txcompletion_cb(hif_dev->htc_handle, - skb, 1); - TX_STAT_INC(skb_completed); - } - -add_free: /* Re-initialize the SKB queue */ tx_buf->len = tx_buf->offset = 0; __skb_queue_head_init(&tx_buf->skb_queue); @@ -274,7 +346,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev) ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC); if (ret) { tx_buf->len = tx_buf->offset = 0; - ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); + ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, false); __skb_queue_head_init(&tx_buf->skb_queue); list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf); hif_dev->tx.tx_buf_cnt++; @@ -286,10 +358,11 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev) return ret; } -static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb, - struct ath9k_htc_tx_ctl *tx_ctl) +static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb) { + struct ath9k_htc_tx_ctl *tx_ctl; unsigned long flags; + int ret = 0; spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); @@ -304,26 +377,36 @@ static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb, return -ENOMEM; } - __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb); - hif_dev->tx.tx_skb_cnt++; + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); - /* Send normal frames immediately */ - if (!tx_ctl || (tx_ctl && (tx_ctl->type == ATH9K_HTC_NORMAL))) - __hif_usb_tx(hif_dev); + tx_ctl = HTC_SKB_CB(skb); + + /* Mgmt/Beacon frames don't use the TX buffer pool */ + if ((tx_ctl->type == ATH9K_HTC_MGMT) || + (tx_ctl->type == ATH9K_HTC_BEACON)) { + ret = hif_usb_send_mgmt(hif_dev, skb); + } + + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); + + if ((tx_ctl->type == ATH9K_HTC_NORMAL) || + (tx_ctl->type == ATH9K_HTC_AMPDU)) { + __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb); + hif_dev->tx.tx_skb_cnt++; + } /* Check if AMPDUs have to be sent immediately */ - if (tx_ctl && (tx_ctl->type == ATH9K_HTC_AMPDU) && - (hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) && + if ((hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) && (hif_dev->tx.tx_skb_cnt < 2)) { __hif_usb_tx(hif_dev); } spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); - return 0; + return ret; } -static void hif_usb_start(void *hif_handle, u8 pipe_id) +static void hif_usb_start(void *hif_handle) { struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; unsigned long flags; @@ -335,14 +418,14 @@ static void hif_usb_start(void *hif_handle, u8 pipe_id) spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); } -static void hif_usb_stop(void *hif_handle, u8 pipe_id) +static void hif_usb_stop(void *hif_handle) { struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; unsigned long flags; spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); - ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue); + ath9k_skb_queue_complete(hif_dev, &hif_dev->tx.tx_skb_queue, false); hif_dev->tx.tx_skb_cnt = 0; hif_dev->tx.flags |= HIF_USB_TX_STOP; spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); @@ -352,17 +435,18 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id) &hif_dev->tx.tx_pending, list) { usb_kill_urb(tx_buf->urb); } + + usb_kill_anchored_urbs(&hif_dev->mgmt_submitted); } -static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, - struct ath9k_htc_tx_ctl *tx_ctl) +static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb) { struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; int ret = 0; switch (pipe_id) { case USB_WLAN_TX_PIPE: - ret = hif_usb_send_tx(hif_dev, skb, tx_ctl); + ret = hif_usb_send_tx(hif_dev, skb); break; case USB_REG_OUT_PIPE: ret = hif_usb_send_regout(hif_dev, skb); @@ -377,6 +461,40 @@ static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, return ret; } +static inline bool check_index(struct sk_buff *skb, u8 idx) +{ + struct ath9k_htc_tx_ctl *tx_ctl; + + tx_ctl = HTC_SKB_CB(skb); + + if ((tx_ctl->type == ATH9K_HTC_AMPDU) && + (tx_ctl->sta_idx == idx)) + return true; + + return false; +} + +static void hif_usb_sta_drain(void *hif_handle, u8 idx) +{ + struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + struct sk_buff *skb, *tmp; + unsigned long flags; + + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); + + skb_queue_walk_safe(&hif_dev->tx.tx_skb_queue, skb, tmp) { + if (check_index(skb, idx)) { + __skb_unlink(skb, &hif_dev->tx.tx_skb_queue); + ath9k_htc_txcompletion_cb(hif_dev->htc_handle, + skb, false); + hif_dev->tx.tx_skb_cnt--; + TX_STAT_INC(skb_failed); + } + } + + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); +} + static struct ath9k_htc_hif hif_usb = { .transport = ATH9K_HIF_USB, .name = "ath9k_hif_usb", @@ -386,6 +504,7 @@ static struct ath9k_htc_hif hif_usb = { .start = hif_usb_start, .stop = hif_usb_stop, + .sta_drain = hif_usb_sta_drain, .send = hif_usb_send, }; @@ -567,6 +686,9 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) case -ESHUTDOWN: goto free; default: + skb_reset_tail_pointer(skb); + skb_trim(skb, 0); + goto resubmit; } @@ -591,23 +713,15 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) USB_REG_IN_PIPE), nskb->data, MAX_REG_IN_BUF_SIZE, ath9k_hif_usb_reg_in_cb, nskb); - - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - kfree_skb(nskb); - urb->context = NULL; - } - - return; } resubmit: - skb_reset_tail_pointer(skb); - skb_trim(skb, 0); - + usb_anchor_urb(urb, &hif_dev->reg_in_submitted); ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) + if (ret) { + usb_unanchor_urb(urb); goto free; + } return; free: @@ -641,6 +755,8 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) kfree(tx_buf->buf); kfree(tx_buf); } + + usb_kill_anchored_urbs(&hif_dev->mgmt_submitted); } static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) @@ -652,6 +768,7 @@ static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) INIT_LIST_HEAD(&hif_dev->tx.tx_pending); spin_lock_init(&hif_dev->tx.tx_lock); __skb_queue_head_init(&hif_dev->tx.tx_skb_queue); + init_usb_anchor(&hif_dev->mgmt_submitted); for (i = 0; i < MAX_TX_URB_NUM; i++) { tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL); @@ -748,43 +865,67 @@ static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev) return ret; } -static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev) +static void ath9k_hif_usb_dealloc_reg_in_urbs(struct hif_device_usb *hif_dev) { - if (hif_dev->reg_in_urb) { - usb_kill_urb(hif_dev->reg_in_urb); - if (hif_dev->reg_in_urb->context) - kfree_skb((void *)hif_dev->reg_in_urb->context); - usb_free_urb(hif_dev->reg_in_urb); - hif_dev->reg_in_urb = NULL; - } + usb_kill_anchored_urbs(&hif_dev->reg_in_submitted); } -static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev) +static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev) { - struct sk_buff *skb; + struct urb *urb = NULL; + struct sk_buff *skb = NULL; + int i, ret; - hif_dev->reg_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (hif_dev->reg_in_urb == NULL) - return -ENOMEM; + init_usb_anchor(&hif_dev->reg_in_submitted); - skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL); - if (!skb) - goto err; + for (i = 0; i < MAX_REG_IN_URB_NUM; i++) { - usb_fill_bulk_urb(hif_dev->reg_in_urb, hif_dev->udev, - usb_rcvbulkpipe(hif_dev->udev, - USB_REG_IN_PIPE), - skb->data, MAX_REG_IN_BUF_SIZE, - ath9k_hif_usb_reg_in_cb, skb); + /* Allocate URB */ + urb = usb_alloc_urb(0, GFP_KERNEL); + if (urb == NULL) { + ret = -ENOMEM; + goto err_urb; + } - if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0) - goto err; + /* Allocate buffer */ + skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL); + if (!skb) { + ret = -ENOMEM; + goto err_skb; + } + + usb_fill_bulk_urb(urb, hif_dev->udev, + usb_rcvbulkpipe(hif_dev->udev, + USB_REG_IN_PIPE), + skb->data, MAX_REG_IN_BUF_SIZE, + ath9k_hif_usb_reg_in_cb, skb); + + /* Anchor URB */ + usb_anchor_urb(urb, &hif_dev->reg_in_submitted); + + /* Submit URB */ + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret) { + usb_unanchor_urb(urb); + goto err_submit; + } + + /* + * Drop reference count. + * This ensures that the URB is freed when killing them. + */ + usb_free_urb(urb); + } return 0; -err: - ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); - return -ENOMEM; +err_submit: + kfree_skb(skb); +err_skb: + usb_free_urb(urb); +err_urb: + ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev); + return ret; } static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev) @@ -801,7 +942,7 @@ static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev) goto err_rx; /* Register Read */ - if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0) + if (ath9k_hif_usb_alloc_reg_in_urbs(hif_dev) < 0) goto err_reg; return 0; @@ -816,7 +957,7 @@ static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev) static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev) { usb_kill_anchored_urbs(&hif_dev->regout_submitted); - ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); + ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev); ath9k_hif_usb_dealloc_tx_urbs(hif_dev); ath9k_hif_usb_dealloc_rx_urbs(hif_dev); } @@ -1026,10 +1167,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, /* Find out which firmware to load */ if (IS_AR7010_DEVICE(id->driver_info)) - if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202) - hif_dev->fw_name = FIRMWARE_AR7010_1_1; - else - hif_dev->fw_name = FIRMWARE_AR7010; + hif_dev->fw_name = FIRMWARE_AR7010_1_1; else hif_dev->fw_name = FIRMWARE_AR9271; @@ -1040,7 +1178,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, } ret = ath9k_htc_hw_init(hif_dev->htc_handle, - &hif_dev->udev->dev, hif_dev->device_id, + &interface->dev, hif_dev->device_id, hif_dev->udev->product, id->driver_info); if (ret) { ret = -EINVAL; @@ -1158,7 +1296,7 @@ static int ath9k_hif_usb_resume(struct usb_interface *interface) #endif static struct usb_driver ath9k_hif_usb_driver = { - .name = "ath9k_hif_usb", + .name = KBUILD_MODNAME, .probe = ath9k_hif_usb_probe, .disconnect = ath9k_hif_usb_disconnect, #ifdef CONFIG_PM diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index 7b9d863d4035..2bdcdbc14b1e 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -17,6 +17,9 @@ #ifndef HTC_USB_H #define HTC_USB_H +#define MAJOR_VERSION_REQ 1 +#define MINOR_VERSION_REQ 2 + #define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB)) #define AR9271_FIRMWARE 0x501000 @@ -31,7 +34,7 @@ /* FIXME: Verify these numbers (with Windows) */ #define MAX_TX_URB_NUM 8 -#define MAX_TX_BUF_NUM 1024 +#define MAX_TX_BUF_NUM 256 #define MAX_TX_BUF_SIZE 32768 #define MAX_TX_AGGR_NUM 20 @@ -40,7 +43,7 @@ #define MAX_PKT_NUM_IN_TRANSFER 10 #define MAX_REG_OUT_URB_NUM 1 -#define MAX_REG_OUT_BUF_NUM 8 +#define MAX_REG_IN_URB_NUM 64 #define MAX_REG_IN_BUF_SIZE 64 @@ -90,9 +93,10 @@ struct hif_device_usb { const struct firmware *firmware; struct htc_target *htc_handle; struct hif_usb_tx tx; - struct urb *reg_in_urb; struct usb_anchor regout_submitted; struct usb_anchor rx_submitted; + struct usb_anchor reg_in_submitted; + struct usb_anchor mgmt_submitted; struct sk_buff *remain_skb; const char *fw_name; int rx_remain_len; diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 753a245c5ad1..dfc7a982fc7e 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -66,13 +66,13 @@ enum htc_opmode { HTC_M_WDS = 2 }; -#define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr) -#define ATH9K_HTC_AMPDU 1 +#define ATH9K_HTC_AMPDU 1 #define ATH9K_HTC_NORMAL 2 +#define ATH9K_HTC_BEACON 3 +#define ATH9K_HTC_MGMT 4 #define ATH9K_HTC_TX_CTSONLY 0x1 #define ATH9K_HTC_TX_RTSCTS 0x2 -#define ATH9K_HTC_TX_USE_MIN_RATE 0x100 struct tx_frame_hdr { u8 data_type; @@ -82,7 +82,8 @@ struct tx_frame_hdr { __be32 flags; /* ATH9K_HTC_TX_* */ u8 key_type; u8 keyix; - u8 reserved[26]; + u8 cookie; + u8 pad; } __packed; struct tx_mgmt_hdr { @@ -92,50 +93,34 @@ struct tx_mgmt_hdr { u8 flags; u8 key_type; u8 keyix; - u16 reserved; + u8 cookie; + u8 pad; } __packed; struct tx_beacon_header { - u8 len_changed; u8 vif_index; + u8 len_changed; u16 rev; } __packed; -struct ath9k_htc_target_hw { - u32 flags; - u32 flags_ext; - u32 ampdu_limit; - u8 ampdu_subframes; - u8 tx_chainmask; - u8 tx_chainmask_legacy; - u8 rtscts_ratecode; - u8 protmode; -} __packed; +#define MAX_TX_AMPDU_SUBFRAMES_9271 17 +#define MAX_TX_AMPDU_SUBFRAMES_7010 22 struct ath9k_htc_cap_target { - u32 flags; - u32 flags_ext; - u32 ampdu_limit; + __be32 ampdu_limit; u8 ampdu_subframes; + u8 enable_coex; u8 tx_chainmask; - u8 tx_chainmask_legacy; - u8 rtscts_ratecode; - u8 protmode; + u8 pad; } __packed; struct ath9k_htc_target_vif { u8 index; - u8 des_bssid[ETH_ALEN]; - __be32 opmode; + u8 opmode; u8 myaddr[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - u32 flags; - u32 flags_ext; - u16 ps_sta; - __be16 rtsthreshold; u8 ath_cap; - u8 node; - s8 mcast_rate; + __be16 rtsthreshold; + u8 pad; } __packed; #define ATH_HTC_STA_AUTH 0x0001 @@ -143,27 +128,16 @@ struct ath9k_htc_target_vif { #define ATH_HTC_STA_ERP 0x0004 #define ATH_HTC_STA_HT 0x0008 -/* FIXME: UAPSD variables */ struct ath9k_htc_target_sta { - u16 associd; - u16 txpower; - u32 ucastkey; u8 macaddr[ETH_ALEN]; u8 bssid[ETH_ALEN]; u8 sta_index; u8 vif_index; - u8 vif_sta; - __be16 flags; /* ATH_HTC_STA_* */ - u16 htcap; - u8 valid; - u16 capinfo; - struct ath9k_htc_target_hw *hw; - struct ath9k_htc_target_vif *vif; - u16 txseqmgmt; u8 is_vif_sta; - u16 maxampdu; - u16 iv16; - u32 iv32; + __be16 flags; /* ATH_HTC_STA_* */ + __be16 htcap; + __be16 maxampdu; + u8 pad; } __packed; struct ath9k_htc_target_aggr { @@ -197,12 +171,38 @@ struct ath9k_htc_target_rate { struct ath9k_htc_rate rates; }; -struct ath9k_htc_target_stats { - __be32 tx_shortretry; - __be32 tx_longretry; - __be32 tx_xretries; - __be32 ht_txunaggr_xretry; - __be32 ht_tx_xretries; +struct ath9k_htc_target_rate_mask { + u8 vif_index; + u8 band; + __be32 mask; + u16 pad; +} __packed; + +struct ath9k_htc_target_int_stats { + __be32 rx; + __be32 rxorn; + __be32 rxeol; + __be32 txurn; + __be32 txto; + __be32 cst; +} __packed; + +struct ath9k_htc_target_tx_stats { + __be32 xretries; + __be32 fifoerr; + __be32 filtered; + __be32 timer_exp; + __be32 shortretries; + __be32 longretries; + __be32 qnull; + __be32 encap_fail; + __be32 nobuf; +} __packed; + +struct ath9k_htc_target_rx_stats { + __be32 nobuf; + __be32 host_send; + __be32 host_done; } __packed; #define ATH9K_HTC_MAX_VIF 2 @@ -244,6 +244,8 @@ struct ath9k_htc_vif { u8 index; u16 seq_no; bool beacon_configured; + int bslot; + __le64 tsfadjust; }; struct ath9k_vif_iter_data { @@ -282,23 +284,65 @@ struct ath9k_htc_rx { spinlock_t rxbuflock; }; +#define ATH9K_HTC_TX_CLEANUP_INTERVAL 50 /* ms */ +#define ATH9K_HTC_TX_TIMEOUT_INTERVAL 2500 /* ms */ +#define ATH9K_HTC_TX_RESERVE 10 +#define ATH9K_HTC_TX_TIMEOUT_COUNT 20 +#define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE) + +#define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0) +#define ATH9K_HTC_OP_TX_DRAIN BIT(1) + +struct ath9k_htc_tx { + u8 flags; + int queued_cnt; + struct sk_buff_head mgmt_ep_queue; + struct sk_buff_head cab_ep_queue; + struct sk_buff_head data_be_queue; + struct sk_buff_head data_bk_queue; + struct sk_buff_head data_vi_queue; + struct sk_buff_head data_vo_queue; + struct sk_buff_head tx_failed; + DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); + struct timer_list cleanup_timer; + spinlock_t tx_lock; +}; + struct ath9k_htc_tx_ctl { u8 type; /* ATH9K_HTC_* */ + u8 epid; + u8 txok; + u8 sta_idx; + unsigned long timestamp; }; +static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + + BUILD_BUG_ON(sizeof(struct ath9k_htc_tx_ctl) > + IEEE80211_TX_INFO_DRIVER_DATA_SIZE); + return (struct ath9k_htc_tx_ctl *) &tx_info->driver_data; +} + #ifdef CONFIG_ATH9K_HTC_DEBUGFS #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++) #define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++) +#define CAB_STAT_INC priv->debug.tx_stats.cab_queued++ #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++) +void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, + struct ath_htc_rx_status *rxs); + struct ath_tx_stats { u32 buf_queued; u32 buf_completed; u32 skb_queued; - u32 skb_completed; - u32 skb_dropped; + u32 skb_success; + u32 skb_failed; + u32 cab_queued; u32 queue_stats[WME_NUM_AC]; }; @@ -306,55 +350,57 @@ struct ath_rx_stats { u32 skb_allocated; u32 skb_completed; u32 skb_dropped; + u32 err_crc; + u32 err_decrypt_crc; + u32 err_mic; + u32 err_pre_delim; + u32 err_post_delim; + u32 err_decrypt_busy; + u32 err_phy; + u32 err_phy_stats[ATH9K_PHYERR_MAX]; }; struct ath9k_debug { struct dentry *debugfs_phy; - struct dentry *debugfs_tgt_stats; - struct dentry *debugfs_xmit; - struct dentry *debugfs_recv; struct ath_tx_stats tx_stats; struct ath_rx_stats rx_stats; - u32 txrate; }; #else #define TX_STAT_INC(c) do { } while (0) #define RX_STAT_INC(c) do { } while (0) +#define CAB_STAT_INC do { } while (0) #define TX_QSTAT_INC(c) do { } while (0) +static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, + struct ath_htc_rx_status *rxs) +{ +} + #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ #define ATH_LED_PIN_DEF 1 -#define ATH_LED_PIN_9287 8 +#define ATH_LED_PIN_9287 10 #define ATH_LED_PIN_9271 15 #define ATH_LED_PIN_7010 12 -#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ -#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ -enum ath_led_type { - ATH_LED_RADIO, - ATH_LED_ASSOC, - ATH_LED_TX, - ATH_LED_RX -}; +#define BSTUCK_THRESHOLD 10 -struct ath_led { - struct ath9k_htc_priv *priv; - struct led_classdev led_cdev; - enum ath_led_type led_type; - struct delayed_work brightness_work; - char name[32]; - bool registered; - int brightness; -}; +/* + * Adjust these when the max. no of beaconing interfaces is + * increased. + */ +#define DEFAULT_SWBA_RESPONSE 40 /* in TUs */ +#define MIN_SWBA_RESPONSE 10 /* in TUs */ struct htc_beacon_config { + struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; u16 beacon_interval; u16 dtim_period; u16 bmiss_timeout; + u32 bmiss_cnt; }; struct ath_btcoex { @@ -372,14 +418,11 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv); #define OP_INVALID BIT(0) #define OP_SCANNING BIT(1) -#define OP_LED_ASSOCIATED BIT(2) -#define OP_LED_ON BIT(3) -#define OP_ENABLE_BEACON BIT(4) -#define OP_LED_DEINIT BIT(5) -#define OP_BT_PRIORITY_DETECTED BIT(6) -#define OP_BT_SCAN BIT(7) -#define OP_ANI_RUNNING BIT(8) -#define OP_TSF_RESET BIT(9) +#define OP_ENABLE_BEACON BIT(2) +#define OP_BT_PRIORITY_DETECTED BIT(3) +#define OP_BT_SCAN BIT(4) +#define OP_ANI_RUNNING BIT(5) +#define OP_TSF_RESET BIT(6) struct ath9k_htc_priv { struct device *dev; @@ -388,6 +431,9 @@ struct ath9k_htc_priv { struct htc_target *htc; struct wmi *wmi; + u16 fw_version_major; + u16 fw_version_minor; + enum htc_endpoint_id wmi_cmd_ep; enum htc_endpoint_id beacon_ep; enum htc_endpoint_id cab_ep; @@ -411,27 +457,23 @@ struct ath9k_htc_priv { u16 txpowlimit; u16 nvifs; u16 nstations; - u32 bmiss_cnt; bool rearm_ani; bool reconfig_beacon; + unsigned int rxfilter; struct ath9k_hw_cal_data caldata; + struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; spinlock_t beacon_lock; - - bool tx_queues_stop; - spinlock_t tx_lock; - - struct ieee80211_vif *vif; struct htc_beacon_config cur_beacon_conf; - unsigned int rxfilter; + + struct ath9k_htc_rx rx; + struct ath9k_htc_tx tx; + struct tasklet_struct swba_tasklet; struct tasklet_struct rx_tasklet; - struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; - struct ath9k_htc_rx rx; - struct tasklet_struct tx_tasklet; - struct sk_buff_head tx_queue; struct delayed_work ani_work; + struct tasklet_struct tx_failed_tasklet; struct work_struct ps_work; struct work_struct fatal_work; @@ -440,15 +482,13 @@ struct ath9k_htc_priv { bool ps_enabled; bool ps_idle; - struct ath_led radio_led; - struct ath_led assoc_led; - struct ath_led tx_led; - struct ath_led rx_led; - struct delayed_work ath9k_led_blink_work; - int led_on_duration; - int led_off_duration; - int led_on_cnt; - int led_off_cnt; +#ifdef CONFIG_MAC80211_LEDS + enum led_brightness brightness; + bool led_registered; + char led_name[32]; + struct led_classdev led_cdev; + struct work_struct led_work; +#endif int beaconq; int cabq; @@ -470,11 +510,18 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz) void ath9k_htc_reset(struct ath9k_htc_priv *priv); +void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif); +void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif); +void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif); void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv); void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif); void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv); -void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending); +void ath9k_htc_swba(struct ath9k_htc_priv *priv, + struct wmi_event_swba *swba); void ath9k_htc_rxep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id); @@ -483,7 +530,8 @@ void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, bool txok); -int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv); +int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv, + u8 enable_coex); void ath9k_htc_station_work(struct work_struct *work); void ath9k_htc_aggr_work(struct work_struct *work); void ath9k_htc_ani_work(struct work_struct *work); @@ -491,14 +539,23 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv); void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); int ath9k_tx_init(struct ath9k_htc_priv *priv); -void ath9k_tx_tasklet(unsigned long data); -int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb); +int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, + struct sk_buff *skb, u8 slot, bool is_cab); void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype); int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv); int get_hw_qnum(u16 queue, int *hwq_map); int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, struct ath9k_tx_queue_info *qinfo); +void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv); +void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv); +int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv); +void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot); +void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); +void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event); +void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv); +void ath9k_tx_failed_tasklet(unsigned long data); +void ath9k_htc_tx_cleanup_timer(unsigned long data); int ath9k_rx_init(struct ath9k_htc_priv *priv); void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); @@ -516,9 +573,24 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv); void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw); void ath9k_htc_radio_enable(struct ieee80211_hw *hw); void ath9k_htc_radio_disable(struct ieee80211_hw *hw); -void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv); + +#ifdef CONFIG_MAC80211_LEDS void ath9k_init_leds(struct ath9k_htc_priv *priv); void ath9k_deinit_leds(struct ath9k_htc_priv *priv); +void ath9k_led_work(struct work_struct *work); +#else +static inline void ath9k_init_leds(struct ath9k_htc_priv *priv) +{ +} + +static inline void ath9k_deinit_leds(struct ath9k_htc_priv *priv) +{ +} + +static inline void ath9k_led_work(struct work_struct *work) +{ +} +#endif int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, u16 devid, char *product, u32 drv_info); @@ -528,15 +600,9 @@ void ath9k_htc_suspend(struct htc_target *htc_handle); int ath9k_htc_resume(struct htc_target *htc_handle); #endif #ifdef CONFIG_ATH9K_HTC_DEBUGFS -int ath9k_htc_debug_create_root(void); -void ath9k_htc_debug_remove_root(void); int ath9k_htc_init_debug(struct ath_hw *ah); -void ath9k_htc_exit_debug(struct ath_hw *ah); #else -static inline int ath9k_htc_debug_create_root(void) { return 0; }; -static inline void ath9k_htc_debug_remove_root(void) {}; static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; }; -static inline void ath9k_htc_exit_debug(struct ath_hw *ah) {}; #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ #endif /* HTC_H */ diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 8d1d8792436d..0ded2c66d5ff 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -18,6 +18,50 @@ #define FUDGE 2 +void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) +{ + struct ath_hw *ah = priv->ah; + struct ath9k_tx_queue_info qi, qi_be; + + memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); + memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); + + ath9k_hw_get_txq_props(ah, priv->beaconq, &qi); + + if (priv->ah->opmode == NL80211_IFTYPE_AP) { + qi.tqi_aifs = 1; + qi.tqi_cwmin = 0; + qi.tqi_cwmax = 0; + } else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) { + int qnum = priv->hwq_map[WME_AC_BE]; + + ath9k_hw_get_txq_props(ah, qnum, &qi_be); + + qi.tqi_aifs = qi_be.tqi_aifs; + + /* + * For WIFI Beacon Distribution + * Long slot time : 2x cwmin + * Short slot time : 4x cwmin + */ + if (ah->slottime == ATH9K_SLOT_TIME_20) + qi.tqi_cwmin = 2*qi_be.tqi_cwmin; + else + qi.tqi_cwmin = 4*qi_be.tqi_cwmin; + + qi.tqi_cwmax = qi_be.tqi_cwmax; + + } + + if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { + ath_err(ath9k_hw_common(ah), + "Unable to update beacon queue %u!\n", priv->beaconq); + } else { + ath9k_hw_resettxqueue(ah, priv->beaconq); + } +} + + static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, struct htc_beacon_config *bss_conf) { @@ -30,7 +74,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, __be32 htc_imask = 0; u64 tsf; int num_beacons, offset, dtim_dec_count, cfp_dec_count; - int ret; + int ret __attribute__ ((unused)); u8 cmd_rsp; memset(&bs, 0, sizeof(bs)); @@ -146,7 +190,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, enum ath9k_int imask = 0; u32 nexttbtt, intval, tsftu; __be32 htc_imask = 0; - int ret; + int ret __attribute__ ((unused)); u8 cmd_rsp; u64 tsf; @@ -154,8 +198,17 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, intval /= ATH9K_HTC_MAX_BCN_VIF; nexttbtt = intval; + /* + * To reduce beacon misses under heavy TX load, + * set the beacon response time to a larger value. + */ + if (intval > DEFAULT_SWBA_RESPONSE) + priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; + else + priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; + if (priv->op_flags & OP_TSF_RESET) { - intval |= ATH9K_BEACON_RESET_TSF; + ath9k_hw_reset_tsf(priv->ah); priv->op_flags &= ~OP_TSF_RESET; } else { /* @@ -168,18 +221,20 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, } while (nexttbtt < tsftu); } - intval |= ATH9K_BEACON_ENA; - if (priv->op_flags & OP_ENABLE_BEACON) imask |= ATH9K_INT_SWBA; ath_dbg(common, ATH_DBG_CONFIG, - "AP Beacon config, intval: %d, nexttbtt: %u imask: 0x%x\n", - bss_conf->beacon_interval, nexttbtt, imask); + "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d " + "imask: 0x%x\n", + bss_conf->beacon_interval, nexttbtt, + priv->ah->config.sw_beacon_response_time, imask); + + ath9k_htc_beaconq_config(priv); WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); - priv->bmiss_cnt = 0; + ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); + priv->cur_beacon_conf.bmiss_cnt = 0; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } @@ -191,7 +246,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, enum ath9k_int imask = 0; u32 nexttbtt, intval, tsftu; __be32 htc_imask = 0; - int ret; + int ret __attribute__ ((unused)); u8 cmd_rsp; u64 tsf; @@ -207,17 +262,26 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, nexttbtt += intval; } while (nexttbtt < tsftu); - intval |= ATH9K_BEACON_ENA; + /* + * Only one IBSS interfce is allowed. + */ + if (intval > DEFAULT_SWBA_RESPONSE) + priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; + else + priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; + if (priv->op_flags & OP_ENABLE_BEACON) imask |= ATH9K_INT_SWBA; ath_dbg(common, ATH_DBG_CONFIG, - "IBSS Beacon config, intval: %d, nexttbtt: %u, imask: 0x%x\n", - bss_conf->beacon_interval, nexttbtt, imask); + "IBSS Beacon config, intval: %d, nexttbtt: %u, " + "resp_time: %d, imask: 0x%x\n", + bss_conf->beacon_interval, nexttbtt, + priv->ah->config.sw_beacon_response_time, imask); WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); - priv->bmiss_cnt = 0; + ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); + priv->cur_beacon_conf.bmiss_cnt = 0; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } @@ -228,38 +292,101 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, dev_kfree_skb_any(skb); } -void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) +static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, + int slot) { - struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv; - struct tx_beacon_header beacon_hdr; - struct ath9k_htc_tx_ctl tx_ctl; - struct ieee80211_tx_info *info; - struct sk_buff *beacon; - u8 *tx_fhdr; - - memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header)); - memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); - - /* FIXME: Handle BMISS */ - if (beacon_pending != 0) { - priv->bmiss_cnt++; - return; - } + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ieee80211_vif *vif; + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + int padpos, padsize, ret, tx_slot; spin_lock_bh(&priv->beacon_lock); + vif = priv->cur_beacon_conf.bslot[slot]; + + skb = ieee80211_get_buffered_bc(priv->hw, vif); + + while(skb) { + hdr = (struct ieee80211_hdr *) skb->data; + + padpos = ath9k_cmn_padpos(hdr->frame_control); + padsize = padpos & 3; + if (padsize && skb->len > padpos) { + if (skb_headroom(skb) < padsize) { + dev_kfree_skb_any(skb); + goto next; + } + skb_push(skb, padsize); + memmove(skb->data, skb->data + padsize, padpos); + } + + tx_slot = ath9k_htc_tx_get_slot(priv); + if (tx_slot < 0) { + ath_dbg(common, ATH_DBG_XMIT, "No free CAB slot\n"); + dev_kfree_skb_any(skb); + goto next; + } + + ret = ath9k_htc_tx_start(priv, skb, tx_slot, true); + if (ret != 0) { + ath9k_htc_tx_clear_slot(priv, tx_slot); + dev_kfree_skb_any(skb); + + ath_dbg(common, ATH_DBG_XMIT, + "Failed to send CAB frame\n"); + } else { + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.queued_cnt++; + spin_unlock_bh(&priv->tx.tx_lock); + } + next: + skb = ieee80211_get_buffered_bc(priv->hw, vif); + } + + spin_unlock_bh(&priv->beacon_lock); +} + +static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, + int slot) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ieee80211_vif *vif; + struct ath9k_htc_vif *avp; + struct tx_beacon_header beacon_hdr; + struct ath9k_htc_tx_ctl *tx_ctl; + struct ieee80211_tx_info *info; + struct ieee80211_mgmt *mgmt; + struct sk_buff *beacon; + u8 *tx_fhdr; + int ret; + + memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header)); + + spin_lock_bh(&priv->beacon_lock); + + vif = priv->cur_beacon_conf.bslot[slot]; + avp = (struct ath9k_htc_vif *)vif->drv_priv; + if (unlikely(priv->op_flags & OP_SCANNING)) { spin_unlock_bh(&priv->beacon_lock); return; } /* Get a new beacon */ - beacon = ieee80211_beacon_get(priv->hw, priv->vif); + beacon = ieee80211_beacon_get(priv->hw, vif); if (!beacon) { spin_unlock_bh(&priv->beacon_lock); return; } + /* + * Update the TSF adjust value here, the HW will + * add this value for every beacon. + */ + mgmt = (struct ieee80211_mgmt *)beacon->data; + mgmt->u.beacon.timestamp = avp->tsfadjust; + info = IEEE80211_SKB_CB(beacon); if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { struct ieee80211_hdr *hdr = @@ -269,45 +396,149 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); } - tx_ctl.type = ATH9K_HTC_NORMAL; + tx_ctl = HTC_SKB_CB(beacon); + memset(tx_ctl, 0, sizeof(*tx_ctl)); + + tx_ctl->type = ATH9K_HTC_BEACON; + tx_ctl->epid = priv->beacon_ep; + beacon_hdr.vif_index = avp->index; tx_fhdr = skb_push(beacon, sizeof(beacon_hdr)); memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr)); - htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl); + ret = htc_send(priv->htc, beacon); + if (ret != 0) { + if (ret == -ENOMEM) { + ath_dbg(common, ATH_DBG_BSTUCK, + "Failed to send beacon, no free TX buffer\n"); + } + dev_kfree_skb_any(beacon); + } spin_unlock_bh(&priv->beacon_lock); } -/* Currently, only for IBSS */ -void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) +static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv, + struct wmi_event_swba *swba) { - struct ath_hw *ah = priv->ah; - struct ath9k_tx_queue_info qi, qi_be; - int qnum = priv->hwq_map[WME_AC_BE]; + struct ath_common *common = ath9k_hw_common(priv->ah); + u64 tsf; + u32 tsftu; + u16 intval; + int slot; - memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); - memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); + intval = priv->cur_beacon_conf.beacon_interval & ATH9K_BEACON_PERIOD; - ath9k_hw_get_txq_props(ah, qnum, &qi_be); + tsf = be64_to_cpu(swba->tsf); + tsftu = TSF_TO_TU(tsf >> 32, tsf); + slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval; + slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1; - qi.tqi_aifs = qi_be.tqi_aifs; - /* For WIFI Beacon Distribution - * Long slot time : 2x cwmin - * Short slot time : 4x cwmin - */ - if (ah->slottime == ATH9K_SLOT_TIME_20) - qi.tqi_cwmin = 2*qi_be.tqi_cwmin; - else - qi.tqi_cwmin = 4*qi_be.tqi_cwmin; - qi.tqi_cwmax = qi_be.tqi_cwmax; + ath_dbg(common, ATH_DBG_BEACON, + "Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n", + slot, tsf, tsftu, intval); - if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { - ath_err(ath9k_hw_common(ah), - "Unable to update beacon queue %u!\n", qnum); - } else { - ath9k_hw_resettxqueue(ah, priv->beaconq); + return slot; +} + +void ath9k_htc_swba(struct ath9k_htc_priv *priv, + struct wmi_event_swba *swba) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + int slot; + + if (swba->beacon_pending != 0) { + priv->cur_beacon_conf.bmiss_cnt++; + if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) { + ath_dbg(common, ATH_DBG_BSTUCK, + "Beacon stuck, HW reset\n"); + ieee80211_queue_work(priv->hw, + &priv->fatal_work); + } + return; } + + if (priv->cur_beacon_conf.bmiss_cnt) { + ath_dbg(common, ATH_DBG_BSTUCK, + "Resuming beacon xmit after %u misses\n", + priv->cur_beacon_conf.bmiss_cnt); + priv->cur_beacon_conf.bmiss_cnt = 0; + } + + slot = ath9k_htc_choose_bslot(priv, swba); + spin_lock_bh(&priv->beacon_lock); + if (priv->cur_beacon_conf.bslot[slot] == NULL) { + spin_unlock_bh(&priv->beacon_lock); + return; + } + spin_unlock_bh(&priv->beacon_lock); + + ath9k_htc_send_buffered(priv, slot); + ath9k_htc_send_beacon(priv, slot); +} + +void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; + int i = 0; + + spin_lock_bh(&priv->beacon_lock); + for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) { + if (priv->cur_beacon_conf.bslot[i] == NULL) { + avp->bslot = i; + break; + } + } + + priv->cur_beacon_conf.bslot[avp->bslot] = vif; + spin_unlock_bh(&priv->beacon_lock); + + ath_dbg(common, ATH_DBG_CONFIG, + "Added interface at beacon slot: %d\n", avp->bslot); +} + +void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; + + spin_lock_bh(&priv->beacon_lock); + priv->cur_beacon_conf.bslot[avp->bslot] = NULL; + spin_unlock_bh(&priv->beacon_lock); + + ath_dbg(common, ATH_DBG_CONFIG, + "Removed interface at beacon slot: %d\n", avp->bslot); +} + +/* + * Calculate the TSF adjustment value for all slots + * other than zero. + */ +void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; + struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + u64 tsfadjust; + + if (avp->bslot == 0) + return; + + /* + * The beacon interval cannot be different for multi-AP mode, + * and we reach here only for VIF slots greater than zero, + * so beacon_interval is guaranteed to be set in cur_conf. + */ + tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF; + avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); + + ath_dbg(common, ATH_DBG_CONFIG, + "tsfadjust is: %llu for bslot: %d\n", + (unsigned long long)tsfadjust, avp->bslot); } static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c new file mode 100644 index 000000000000..aa48b3abbc48 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -0,0 +1,960 @@ +/* + * Copyright (c) 2010-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 "htc.h" + +static int ath9k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath9k_htc_target_int_stats cmd_rsp; + char buf[512]; + unsigned int len = 0; + int ret = 0; + + memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + + ath9k_htc_ps_wakeup(priv); + + WMI_CMD(WMI_INT_STATS_CMDID); + if (ret) { + ath9k_htc_ps_restore(priv); + return -EINVAL; + } + + ath9k_htc_ps_restore(priv); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "RX", + be32_to_cpu(cmd_rsp.rx)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "RXORN", + be32_to_cpu(cmd_rsp.rxorn)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "RXEOL", + be32_to_cpu(cmd_rsp.rxeol)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "TXURN", + be32_to_cpu(cmd_rsp.txurn)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "TXTO", + be32_to_cpu(cmd_rsp.txto)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "CST", + be32_to_cpu(cmd_rsp.cst)); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_tgt_int_stats = { + .read = read_file_tgt_int_stats, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath9k_htc_target_tx_stats cmd_rsp; + char buf[512]; + unsigned int len = 0; + int ret = 0; + + memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + + ath9k_htc_ps_wakeup(priv); + + WMI_CMD(WMI_TX_STATS_CMDID); + if (ret) { + ath9k_htc_ps_restore(priv); + return -EINVAL; + } + + ath9k_htc_ps_restore(priv); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Xretries", + be32_to_cpu(cmd_rsp.xretries)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "FifoErr", + be32_to_cpu(cmd_rsp.fifoerr)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Filtered", + be32_to_cpu(cmd_rsp.filtered)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "TimerExp", + be32_to_cpu(cmd_rsp.timer_exp)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "ShortRetries", + be32_to_cpu(cmd_rsp.shortretries)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "LongRetries", + be32_to_cpu(cmd_rsp.longretries)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "QueueNull", + be32_to_cpu(cmd_rsp.qnull)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "EncapFail", + be32_to_cpu(cmd_rsp.encap_fail)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "NoBuf", + be32_to_cpu(cmd_rsp.nobuf)); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_tgt_tx_stats = { + .read = read_file_tgt_tx_stats, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath9k_htc_target_rx_stats cmd_rsp; + char buf[512]; + unsigned int len = 0; + int ret = 0; + + memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + + ath9k_htc_ps_wakeup(priv); + + WMI_CMD(WMI_RX_STATS_CMDID); + if (ret) { + ath9k_htc_ps_restore(priv); + return -EINVAL; + } + + ath9k_htc_ps_restore(priv); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "NoBuf", + be32_to_cpu(cmd_rsp.nobuf)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "HostSend", + be32_to_cpu(cmd_rsp.host_send)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "HostDone", + be32_to_cpu(cmd_rsp.host_done)); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_tgt_rx_stats = { + .read = read_file_tgt_rx_stats, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_xmit(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + char buf[512]; + unsigned int len = 0; + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Buffers queued", + priv->debug.tx_stats.buf_queued); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Buffers completed", + priv->debug.tx_stats.buf_completed); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs queued", + priv->debug.tx_stats.skb_queued); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs success", + priv->debug.tx_stats.skb_success); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs failed", + priv->debug.tx_stats.skb_failed); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "CAB queued", + priv->debug.tx_stats.cab_queued); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "BE queued", + priv->debug.tx_stats.queue_stats[WME_AC_BE]); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "BK queued", + priv->debug.tx_stats.queue_stats[WME_AC_BK]); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "VI queued", + priv->debug.tx_stats.queue_stats[WME_AC_VI]); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "VO queued", + priv->debug.tx_stats.queue_stats[WME_AC_VO]); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_xmit = { + .read = read_file_xmit, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, + struct ath_htc_rx_status *rxs) +{ +#define RX_PHY_ERR_INC(c) priv->debug.rx_stats.err_phy_stats[c]++ + + if (rxs->rs_status & ATH9K_RXERR_CRC) + priv->debug.rx_stats.err_crc++; + if (rxs->rs_status & ATH9K_RXERR_DECRYPT) + priv->debug.rx_stats.err_decrypt_crc++; + if (rxs->rs_status & ATH9K_RXERR_MIC) + priv->debug.rx_stats.err_mic++; + if (rxs->rs_status & ATH9K_RX_DELIM_CRC_PRE) + priv->debug.rx_stats.err_pre_delim++; + if (rxs->rs_status & ATH9K_RX_DELIM_CRC_POST) + priv->debug.rx_stats.err_post_delim++; + if (rxs->rs_status & ATH9K_RX_DECRYPT_BUSY) + priv->debug.rx_stats.err_decrypt_busy++; + + if (rxs->rs_status & ATH9K_RXERR_PHY) { + priv->debug.rx_stats.err_phy++; + if (rxs->rs_phyerr < ATH9K_PHYERR_MAX) + RX_PHY_ERR_INC(rxs->rs_phyerr); + } + +#undef RX_PHY_ERR_INC +} + +static ssize_t read_file_recv(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PHY_ERR(s, p) \ + len += snprintf(buf + len, size - len, "%20s : %10u\n", s, \ + priv->debug.rx_stats.err_phy_stats[p]); + + struct ath9k_htc_priv *priv = file->private_data; + char *buf; + unsigned int len = 0, size = 1500; + ssize_t retval = 0; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "SKBs allocated", + priv->debug.rx_stats.skb_allocated); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "SKBs completed", + priv->debug.rx_stats.skb_completed); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "SKBs Dropped", + priv->debug.rx_stats.skb_dropped); + + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "CRC ERR", + priv->debug.rx_stats.err_crc); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "DECRYPT CRC ERR", + priv->debug.rx_stats.err_decrypt_crc); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "MIC ERR", + priv->debug.rx_stats.err_mic); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "PRE-DELIM CRC ERR", + priv->debug.rx_stats.err_pre_delim); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "POST-DELIM CRC ERR", + priv->debug.rx_stats.err_post_delim); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "DECRYPT BUSY ERR", + priv->debug.rx_stats.err_decrypt_busy); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "TOTAL PHY ERR", + priv->debug.rx_stats.err_phy); + + + PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); + PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); + PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); + PHY_ERR("RATE", ATH9K_PHYERR_RATE); + PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH); + PHY_ERR("RADAR", ATH9K_PHYERR_RADAR); + PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE); + PHY_ERR("TOR", ATH9K_PHYERR_TOR); + PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING); + PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); + PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); + PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); + PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP); + PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE); + PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART); + PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT); + PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING); + PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC); + PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL); + PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE); + PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART); + PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); + PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP); + PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR); + PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); + PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PHY_ERR +} + +static const struct file_operations fops_recv = { + .read = read_file_recv, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_slot(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + char buf[512]; + unsigned int len = 0; + + spin_lock_bh(&priv->tx.tx_lock); + + len += snprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : "); + + len += bitmap_scnprintf(buf + len, sizeof(buf) - len, + priv->tx.tx_slot, MAX_TX_BUF_NUM); + + len += snprintf(buf + len, sizeof(buf) - len, "\n"); + + len += snprintf(buf + len, sizeof(buf) - len, + "Used slots : %d\n", + bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM)); + + spin_unlock_bh(&priv->tx.tx_lock); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_slot = { + .read = read_file_slot, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_queue(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + char buf[512]; + unsigned int len = 0; + + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue)); + + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue)); + + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue)); + + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue)); + + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue)); + + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue)); + + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Failed queue", skb_queue_len(&priv->tx.tx_failed)); + + spin_lock_bh(&priv->tx.tx_lock); + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Queued count", priv->tx.queued_cnt); + spin_unlock_bh(&priv->tx.tx_lock); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); + +} + +static const struct file_operations fops_queue = { + .read = read_file_queue, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_debug(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath_common *common = ath9k_hw_common(priv->ah); + char buf[32]; + unsigned int len; + + len = sprintf(buf, "0x%08x\n", common->debug_mask); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_debug(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath_common *common = ath9k_hw_common(priv->ah); + unsigned long mask; + 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, &mask)) + return -EINVAL; + + common->debug_mask = mask; + return count; +} + +static const struct file_operations fops_debug = { + .read = read_file_debug, + .write = write_file_debug, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct base_eep_header *pBase = NULL; + unsigned int len = 0, size = 1500; + ssize_t retval = 0; + char *buf; + + /* + * This can be done since all the 3 EEPROM families have the + * same base header upto a certain point, and we are interested in + * the data only upto that point. + */ + + if (AR_SREV_9271(priv->ah)) + pBase = (struct base_eep_header *) + &priv->ah->eeprom.map4k.baseEepHeader; + else if (priv->ah->hw_version.usbdev == AR9280_USB) + pBase = (struct base_eep_header *) + &priv->ah->eeprom.def.baseEepHeader; + else if (priv->ah->hw_version.usbdev == AR9287_USB) + pBase = (struct base_eep_header *) + &priv->ah->eeprom.map9287.baseEepHeader; + + if (pBase == NULL) { + ath_err(common, "Unknown EEPROM type\n"); + return 0; + } + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "Major Version", + pBase->version >> 12); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "Minor Version", + pBase->version & 0xFFF); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "Checksum", + pBase->checksum); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "Length", + pBase->length); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "RegDomain1", + pBase->regDmn[0]); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "RegDomain2", + pBase->regDmn[1]); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "TX Mask", pBase->txMask); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "RX Mask", pBase->rxMask); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Allow 5GHz", + !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Allow 2GHz", + !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Disable 2GHz HT20", + !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT20)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Disable 2GHz HT40", + !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT40)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Disable 5Ghz HT20", + !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT20)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Disable 5Ghz HT40", + !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Big Endian", + !!(pBase->eepMisc & 0x01)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Cal Bin Major Ver", + (pBase->binBuildNumber >> 24) & 0xFF); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Cal Bin Minor Ver", + (pBase->binBuildNumber >> 16) & 0xFF); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Cal Bin Build", + (pBase->binBuildNumber >> 8) & 0xFF); + + /* + * UB91 specific data. + */ + if (AR_SREV_9271(priv->ah)) { + struct base_eep_header_4k *pBase4k = + &priv->ah->eeprom.map4k.baseEepHeader; + + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "TX Gain type", + pBase4k->txGainType); + } + + /* + * UB95 specific data. + */ + if (priv->ah->hw_version.usbdev == AR9287_USB) { + struct base_eep_ar9287_header *pBase9287 = + &priv->ah->eeprom.map9287.baseEepHeader; + + len += snprintf(buf + len, size - len, + "%20s : %10ddB\n", + "Power Table Offset", + pBase9287->pwrTableOffset); + + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "OpenLoop Power Ctrl", + pBase9287->openLoopPwrCntl); + } + + len += snprintf(buf + len, size - len, + "%20s : %02X:%02X:%02X:%02X:%02X:%02X\n", + "MacAddress", + pBase->macAddr[0], pBase->macAddr[1], pBase->macAddr[2], + pBase->macAddr[3], pBase->macAddr[4], pBase->macAddr[5]); + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_base_eeprom = { + .read = read_file_base_eeprom, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_4k_modal_eeprom(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PR_EEP(_s, _val) \ + do { \ + len += snprintf(buf + len, size - len, "%20s : %10d\n", \ + _s, (_val)); \ + } while (0) + + struct ath9k_htc_priv *priv = file->private_data; + struct modal_eep_4k_header *pModal = &priv->ah->eeprom.map4k.modalHeader; + unsigned int len = 0, size = 2048; + ssize_t retval = 0; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); + PR_EEP("Ant. Common Control", pModal->antCtrlCommon); + PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); + PR_EEP("Switch Settle", pModal->switchSettling); + PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); + PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); + PR_EEP("ADC Desired size", pModal->adcDesiredSize); + PR_EEP("PGA Desired size", pModal->pgaDesiredSize); + PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); + PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); + PR_EEP("txEndToRxOn", pModal->txEndToRxOn); + PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); + PR_EEP("CCA Threshold)", pModal->thresh62); + PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); + PR_EEP("xpdGain", pModal->xpdGain); + PR_EEP("External PD", pModal->xpd); + PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); + PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); + PR_EEP("pdGainOverlap", pModal->pdGainOverlap); + PR_EEP("O/D Bias Version", pModal->version); + PR_EEP("CCK OutputBias", pModal->ob_0); + PR_EEP("BPSK OutputBias", pModal->ob_1); + PR_EEP("QPSK OutputBias", pModal->ob_2); + PR_EEP("16QAM OutputBias", pModal->ob_3); + PR_EEP("64QAM OutputBias", pModal->ob_4); + PR_EEP("CCK Driver1_Bias", pModal->db1_0); + PR_EEP("BPSK Driver1_Bias", pModal->db1_1); + PR_EEP("QPSK Driver1_Bias", pModal->db1_2); + PR_EEP("16QAM Driver1_Bias", pModal->db1_3); + PR_EEP("64QAM Driver1_Bias", pModal->db1_4); + PR_EEP("CCK Driver2_Bias", pModal->db2_0); + PR_EEP("BPSK Driver2_Bias", pModal->db2_1); + PR_EEP("QPSK Driver2_Bias", pModal->db2_2); + PR_EEP("16QAM Driver2_Bias", pModal->db2_3); + PR_EEP("64QAM Driver2_Bias", pModal->db2_4); + PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); + PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); + PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); + PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); + PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); + PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); + PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); + PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); + PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); + PR_EEP("Ant. Diversity ctl1", pModal->antdiv_ctl1); + PR_EEP("Ant. Diversity ctl2", pModal->antdiv_ctl2); + PR_EEP("TX Diversity", pModal->tx_diversity); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PR_EEP +} + +static ssize_t read_def_modal_eeprom(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PR_EEP(_s, _val) \ + do { \ + if (pBase->opCapFlags & AR5416_OPFLAGS_11G) { \ + pModal = &priv->ah->eeprom.def.modalHeader[1]; \ + len += snprintf(buf + len, size - len, "%20s : %8d%7s", \ + _s, (_val), "|"); \ + } \ + if (pBase->opCapFlags & AR5416_OPFLAGS_11A) { \ + pModal = &priv->ah->eeprom.def.modalHeader[0]; \ + len += snprintf(buf + len, size - len, "%9d\n", \ + (_val)); \ + } \ + } while (0) + + struct ath9k_htc_priv *priv = file->private_data; + struct base_eep_header *pBase = &priv->ah->eeprom.def.baseEepHeader; + struct modal_eep_header *pModal = NULL; + unsigned int len = 0, size = 3500; + ssize_t retval = 0; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len += snprintf(buf + len, size - len, + "%31s %15s\n", "2G", "5G"); + len += snprintf(buf + len, size - len, + "%32s %16s\n", "====", "====\n"); + + PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); + PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); + PR_EEP("Chain2 Ant. Control", pModal->antCtrlChain[2]); + PR_EEP("Ant. Common Control", pModal->antCtrlCommon); + PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); + PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); + PR_EEP("Chain2 Ant. Gain", pModal->antennaGainCh[2]); + PR_EEP("Switch Settle", pModal->switchSettling); + PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); + PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); + PR_EEP("Chain2 TxRxAtten", pModal->txRxAttenCh[2]); + PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); + PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); + PR_EEP("Chain2 RxTxMargin", pModal->rxTxMarginCh[2]); + PR_EEP("ADC Desired size", pModal->adcDesiredSize); + PR_EEP("PGA Desired size", pModal->pgaDesiredSize); + PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); + PR_EEP("Chain1 xlna Gain", pModal->xlnaGainCh[1]); + PR_EEP("Chain2 xlna Gain", pModal->xlnaGainCh[2]); + PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); + PR_EEP("txEndToRxOn", pModal->txEndToRxOn); + PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); + PR_EEP("CCA Threshold)", pModal->thresh62); + PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); + PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); + PR_EEP("Chain2 NF Threshold", pModal->noiseFloorThreshCh[2]); + PR_EEP("xpdGain", pModal->xpdGain); + PR_EEP("External PD", pModal->xpd); + PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); + PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); + PR_EEP("Chain2 I Coefficient", pModal->iqCalICh[2]); + PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); + PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); + PR_EEP("Chain2 Q Coefficient", pModal->iqCalQCh[2]); + PR_EEP("pdGainOverlap", pModal->pdGainOverlap); + PR_EEP("Chain0 OutputBias", pModal->ob); + PR_EEP("Chain0 DriverBias", pModal->db); + PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); + PR_EEP("2chain pwr decrease", pModal->pwrDecreaseFor2Chain); + PR_EEP("3chain pwr decrease", pModal->pwrDecreaseFor3Chain); + PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); + PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); + PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); + PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); + PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); + PR_EEP("Chain2 bswAtten", pModal->bswAtten[2]); + PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); + PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); + PR_EEP("Chain2 bswMargin", pModal->bswMargin[2]); + PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); + PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); + PR_EEP("Chain1 xatten2Db", pModal->xatten2Db[1]); + PR_EEP("Chain2 xatten2Db", pModal->xatten2Db[2]); + PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); + PR_EEP("Chain1 xatten2Margin", pModal->xatten2Margin[1]); + PR_EEP("Chain2 xatten2Margin", pModal->xatten2Margin[2]); + PR_EEP("Chain1 OutputBias", pModal->ob_ch1); + PR_EEP("Chain1 DriverBias", pModal->db_ch1); + PR_EEP("LNA Control", pModal->lna_ctl); + PR_EEP("XPA Bias Freq0", pModal->xpaBiasLvlFreq[0]); + PR_EEP("XPA Bias Freq1", pModal->xpaBiasLvlFreq[1]); + PR_EEP("XPA Bias Freq2", pModal->xpaBiasLvlFreq[2]); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PR_EEP +} + +static ssize_t read_9287_modal_eeprom(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PR_EEP(_s, _val) \ + do { \ + len += snprintf(buf + len, size - len, "%20s : %10d\n", \ + _s, (_val)); \ + } while (0) + + struct ath9k_htc_priv *priv = file->private_data; + struct modal_eep_ar9287_header *pModal = &priv->ah->eeprom.map9287.modalHeader; + unsigned int len = 0, size = 3000; + ssize_t retval = 0; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); + PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); + PR_EEP("Ant. Common Control", pModal->antCtrlCommon); + PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); + PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); + PR_EEP("Switch Settle", pModal->switchSettling); + PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); + PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); + PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); + PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); + PR_EEP("ADC Desired size", pModal->adcDesiredSize); + PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); + PR_EEP("txEndToRxOn", pModal->txEndToRxOn); + PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); + PR_EEP("CCA Threshold)", pModal->thresh62); + PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); + PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); + PR_EEP("xpdGain", pModal->xpdGain); + PR_EEP("External PD", pModal->xpd); + PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); + PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); + PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); + PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); + PR_EEP("pdGainOverlap", pModal->pdGainOverlap); + PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); + PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); + PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); + PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); + PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); + PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); + PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); + PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); + PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); + PR_EEP("AR92x7 Version", pModal->version); + PR_EEP("DriverBias1", pModal->db1); + PR_EEP("DriverBias2", pModal->db1); + PR_EEP("CCK OutputBias", pModal->ob_cck); + PR_EEP("PSK OutputBias", pModal->ob_psk); + PR_EEP("QAM OutputBias", pModal->ob_qam); + PR_EEP("PAL_OFF OutputBias", pModal->ob_pal_off); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PR_EEP +} + +static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + + if (AR_SREV_9271(priv->ah)) + return read_4k_modal_eeprom(file, user_buf, count, ppos); + else if (priv->ah->hw_version.usbdev == AR9280_USB) + return read_def_modal_eeprom(file, user_buf, count, ppos); + else if (priv->ah->hw_version.usbdev == AR9287_USB) + return read_9287_modal_eeprom(file, user_buf, count, ppos); + + return 0; +} + +static const struct file_operations fops_modal_eeprom = { + .read = read_file_modal_eeprom, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int ath9k_htc_init_debug(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + + priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME, + priv->hw->wiphy->debugfsdir); + if (!priv->debug.debugfs_phy) + return -ENOMEM; + + debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_tgt_int_stats); + debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_tgt_tx_stats); + debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_tgt_rx_stats); + debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_xmit); + debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_recv); + debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_slot); + debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_queue); + debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, + priv, &fops_debug); + debugfs_create_file("base_eeprom", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_base_eeprom); + debugfs_create_file("modal_eeprom", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_modal_eeprom); + + return 0; +} diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 7e630a81b453..af57fe5aab98 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -65,17 +65,19 @@ static void ath_btcoex_period_work(struct work_struct *work) u32 timer_period; bool is_btscan; int ret; - u8 cmd_rsp, aggr; ath_detect_bt_priority(priv); is_btscan = !!(priv->op_flags & OP_BT_SCAN); - aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED; + ret = ath9k_htc_update_cap_target(priv, + !!(priv->op_flags & OP_BT_PRIORITY_DETECTED)); + if (ret) { + ath_err(common, "Unable to set BTCOEX parameters\n"); + return; + } - WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr); - - ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL : + ath9k_hw_btcoex_bt_stomp(priv->ah, is_btscan ? ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type); timer_period = is_btscan ? btcoex->btscan_no_stomp : @@ -103,9 +105,9 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work) "time slice work for bt and wlan\n"); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) - ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE); + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) - ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW); + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); } void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv) @@ -152,140 +154,41 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv) /* LED */ /*******/ -static void ath9k_led_blink_work(struct work_struct *work) +#ifdef CONFIG_MAC80211_LEDS +void ath9k_led_work(struct work_struct *work) { - struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv, - ath9k_led_blink_work.work); + struct ath9k_htc_priv *priv = container_of(work, + struct ath9k_htc_priv, + led_work); - if (!(priv->op_flags & OP_LED_ASSOCIATED)) - return; - - if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) || - (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); - else - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, - (priv->op_flags & OP_LED_ON) ? 1 : 0); - - ieee80211_queue_delayed_work(priv->hw, - &priv->ath9k_led_blink_work, - (priv->op_flags & OP_LED_ON) ? - msecs_to_jiffies(priv->led_off_duration) : - msecs_to_jiffies(priv->led_on_duration)); - - priv->led_on_duration = priv->led_on_cnt ? - max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) : - ATH_LED_ON_DURATION_IDLE; - priv->led_off_duration = priv->led_off_cnt ? - max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) : - ATH_LED_OFF_DURATION_IDLE; - priv->led_on_cnt = priv->led_off_cnt = 0; - - if (priv->op_flags & OP_LED_ON) - priv->op_flags &= ~OP_LED_ON; - else - priv->op_flags |= OP_LED_ON; -} - -static void ath9k_led_brightness_work(struct work_struct *work) -{ - struct ath_led *led = container_of(work, struct ath_led, - brightness_work.work); - struct ath9k_htc_priv *priv = led->priv; - - switch (led->brightness) { - case LED_OFF: - if (led->led_type == ATH_LED_ASSOC || - led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, - (led->led_type == ATH_LED_RADIO)); - priv->op_flags &= ~OP_LED_ASSOCIATED; - if (led->led_type == ATH_LED_RADIO) - priv->op_flags &= ~OP_LED_ON; - } else { - priv->led_off_cnt++; - } - break; - case LED_FULL: - if (led->led_type == ATH_LED_ASSOC) { - priv->op_flags |= OP_LED_ASSOCIATED; - ieee80211_queue_delayed_work(priv->hw, - &priv->ath9k_led_blink_work, 0); - } else if (led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); - priv->op_flags |= OP_LED_ON; - } else { - priv->led_on_cnt++; - } - break; - default: - break; - } + ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, + (priv->brightness == LED_OFF)); } static void ath9k_led_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { - struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); - struct ath9k_htc_priv *priv = led->priv; + struct ath9k_htc_priv *priv = container_of(led_cdev, + struct ath9k_htc_priv, + led_cdev); - led->brightness = brightness; - if (!(priv->op_flags & OP_LED_DEINIT)) - ieee80211_queue_delayed_work(priv->hw, - &led->brightness_work, 0); -} - -void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv) -{ - cancel_delayed_work_sync(&priv->radio_led.brightness_work); - cancel_delayed_work_sync(&priv->assoc_led.brightness_work); - cancel_delayed_work_sync(&priv->tx_led.brightness_work); - cancel_delayed_work_sync(&priv->rx_led.brightness_work); -} - -static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led, - char *trigger) -{ - int ret; - - led->priv = priv; - led->led_cdev.name = led->name; - led->led_cdev.default_trigger = trigger; - led->led_cdev.brightness_set = ath9k_led_brightness; - - ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev); - if (ret) - ath_err(ath9k_hw_common(priv->ah), - "Failed to register led:%s", led->name); - else - led->registered = 1; - - INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work); - - return ret; -} - -static void ath9k_unregister_led(struct ath_led *led) -{ - if (led->registered) { - led_classdev_unregister(&led->led_cdev); - led->registered = 0; - } + /* Not locked, but it's just a tiny green light..*/ + priv->brightness = brightness; + ieee80211_queue_work(priv->hw, &priv->led_work); } void ath9k_deinit_leds(struct ath9k_htc_priv *priv) { - priv->op_flags |= OP_LED_DEINIT; - ath9k_unregister_led(&priv->assoc_led); - priv->op_flags &= ~OP_LED_ASSOCIATED; - ath9k_unregister_led(&priv->tx_led); - ath9k_unregister_led(&priv->rx_led); - ath9k_unregister_led(&priv->radio_led); + if (!priv->led_registered) + return; + + ath9k_led_brightness(&priv->led_cdev, LED_OFF); + led_classdev_unregister(&priv->led_cdev); + cancel_work_sync(&priv->led_work); } void ath9k_init_leds(struct ath9k_htc_priv *priv) { - char *trigger; int ret; if (AR_SREV_9287(priv->ah)) @@ -303,48 +206,21 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv) /* LED off, active low */ ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); - INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work); + snprintf(priv->led_name, sizeof(priv->led_name), + "ath9k_htc-%s", wiphy_name(priv->hw->wiphy)); + priv->led_cdev.name = priv->led_name; + priv->led_cdev.brightness_set = ath9k_led_brightness; - trigger = ieee80211_get_radio_led_name(priv->hw); - snprintf(priv->radio_led.name, sizeof(priv->radio_led.name), - "ath9k-%s::radio", wiphy_name(priv->hw->wiphy)); - ret = ath9k_register_led(priv, &priv->radio_led, trigger); - priv->radio_led.led_type = ATH_LED_RADIO; - if (ret) - goto fail; + ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &priv->led_cdev); + if (ret < 0) + return; - trigger = ieee80211_get_assoc_led_name(priv->hw); - snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name), - "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy)); - ret = ath9k_register_led(priv, &priv->assoc_led, trigger); - priv->assoc_led.led_type = ATH_LED_ASSOC; - if (ret) - goto fail; - - trigger = ieee80211_get_tx_led_name(priv->hw); - snprintf(priv->tx_led.name, sizeof(priv->tx_led.name), - "ath9k-%s::tx", wiphy_name(priv->hw->wiphy)); - ret = ath9k_register_led(priv, &priv->tx_led, trigger); - priv->tx_led.led_type = ATH_LED_TX; - if (ret) - goto fail; - - trigger = ieee80211_get_rx_led_name(priv->hw); - snprintf(priv->rx_led.name, sizeof(priv->rx_led.name), - "ath9k-%s::rx", wiphy_name(priv->hw->wiphy)); - ret = ath9k_register_led(priv, &priv->rx_led, trigger); - priv->rx_led.led_type = ATH_LED_RX; - if (ret) - goto fail; - - priv->op_flags &= ~OP_LED_DEINIT; + INIT_WORK(&priv->led_work, ath9k_led_work); + priv->led_registered = true; return; - -fail: - cancel_delayed_work_sync(&priv->ath9k_led_blink_work); - ath9k_deinit_leds(priv); } +#endif /*******************/ /* Rfkill */ @@ -398,9 +274,9 @@ void ath9k_htc_radio_enable(struct ieee80211_hw *hw) /* Start TX */ htc_start(priv->htc); - spin_lock_bh(&priv->tx_lock); - priv->tx_queues_stop = false; - spin_unlock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP; + spin_unlock_bh(&priv->tx.tx_lock); ieee80211_wake_queues(hw); WMI_CMD(WMI_ENABLE_INTR_CMDID); @@ -429,13 +305,15 @@ void ath9k_htc_radio_disable(struct ieee80211_hw *hw) /* Stop TX */ ieee80211_stop_queues(hw); - htc_stop(priv->htc); + ath9k_htc_tx_drain(priv); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); - skb_queue_purge(&priv->tx_queue); /* Stop RX */ WMI_CMD(WMI_STOP_RECV_CMDID); + /* Clear the WMI event queue */ + ath9k_wmi_event_drain(priv); + /* * The MIB counters have to be disabled here, * since the target doesn't do it. diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index fc67c937e172..bfdc8a887183 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -117,6 +117,21 @@ static struct ieee80211_rate ath9k_legacy_rates[] = { RATE(540, 0x0c, 0), }; +#ifdef CONFIG_MAC80211_LEDS +static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { + { .throughput = 0 * 1024, .blink_time = 334 }, + { .throughput = 1 * 1024, .blink_time = 260 }, + { .throughput = 5 * 1024, .blink_time = 220 }, + { .throughput = 10 * 1024, .blink_time = 190 }, + { .throughput = 20 * 1024, .blink_time = 170 }, + { .throughput = 50 * 1024, .blink_time = 150 }, + { .throughput = 70 * 1024, .blink_time = 130 }, + { .throughput = 100 * 1024, .blink_time = 110 }, + { .throughput = 200 * 1024, .blink_time = 80 }, + { .throughput = 300 * 1024, .blink_time = 50 }, +}; +#endif + static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) { int time_left; @@ -140,7 +155,6 @@ static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) static void ath9k_deinit_priv(struct ath9k_htc_priv *priv) { - ath9k_htc_exit_debug(priv->ah); ath9k_hw_deinit(priv->ah); kfree(priv->ah); priv->ah = NULL; @@ -244,7 +258,7 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid, */ if (IS_AR7010_DEVICE(drv_info)) - priv->htc->credits = 45; + priv->htc->credits = 48; else priv->htc->credits = 33; @@ -430,13 +444,16 @@ static void ath9k_regwrite_flush(void *hw_priv) mutex_unlock(&priv->wmi->multi_write_mutex); } -static const struct ath_ops ath9k_common_ops = { - .read = ath9k_regread, - .multi_read = ath9k_multi_regread, - .write = ath9k_regwrite, - .enable_write_buffer = ath9k_enable_regwrite_buffer, - .write_flush = ath9k_regwrite_flush, -}; +static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) +{ + u32 val; + + val = ath9k_regread(hw_priv, reg_offset); + val &= ~clr; + val |= set; + ath9k_regwrite(hw_priv, val, reg_offset); + return val; +} static void ath_usb_read_cachesize(struct ath_common *common, int *csz) { @@ -561,13 +578,7 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv) int i = 0; /* Get the hardware key cache size. */ - common->keymax = priv->ah->caps.keycache_size; - if (common->keymax > ATH_KEYMAX) { - ath_dbg(common, ATH_DBG_ANY, - "Warning, using only %u entries in %u key cache\n", - ATH_KEYMAX, common->keymax); - common->keymax = ATH_KEYMAX; - } + common->keymax = AR_KEYTABLE_SIZE; if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; @@ -646,7 +657,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, { struct ath_hw *ah = NULL; struct ath_common *common; - int ret = 0, csz = 0; + int i, ret = 0, csz = 0; priv->op_flags |= OP_INVALID; @@ -658,30 +669,35 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, ah->hw_version.subsysid = 0; /* FIXME */ ah->hw_version.usbdev = drv_info; ah->ah_flags |= AH_USE_EEPROM; + ah->reg_ops.read = ath9k_regread; + ah->reg_ops.multi_read = ath9k_multi_regread; + ah->reg_ops.write = ath9k_regwrite; + ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer; + ah->reg_ops.write_flush = ath9k_regwrite_flush; + ah->reg_ops.rmw = ath9k_reg_rmw; priv->ah = ah; common = ath9k_hw_common(ah); - common->ops = &ath9k_common_ops; + common->ops = &ah->reg_ops; common->bus_ops = &ath9k_usb_bus_ops; common->ah = ah; common->hw = priv->hw; common->priv = priv; common->debug_mask = ath9k_debug; - spin_lock_init(&priv->wmi->wmi_lock); spin_lock_init(&priv->beacon_lock); - spin_lock_init(&priv->tx_lock); + spin_lock_init(&priv->tx.tx_lock); mutex_init(&priv->mutex); mutex_init(&priv->htc_pm_lock); - tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet, - (unsigned long)priv); tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, (unsigned long)priv); - tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, + tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet, (unsigned long)priv); INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work); INIT_WORK(&priv->ps_work, ath9k_ps_work); INIT_WORK(&priv->fatal_work, ath9k_fatal_work); + setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer, + (unsigned long)priv); /* * Cache line size is used to size and align various @@ -698,16 +714,13 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, goto err_hw; } - ret = ath9k_htc_init_debug(ah); - if (ret) { - ath_err(common, "Unable to create debugfs files\n"); - goto err_debug; - } - ret = ath9k_init_queues(priv); if (ret) goto err_queues; + for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) + priv->cur_beacon_conf.bslot[i] = NULL; + ath9k_init_crypto(priv); ath9k_init_channels_rates(priv); ath9k_init_misc(priv); @@ -720,8 +733,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, return 0; err_queues: - ath9k_htc_exit_debug(ah); -err_debug: ath9k_hw_deinit(ah); err_hw: @@ -742,17 +753,27 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_PS_NULLFUNC_STACK; + IEEE80211_HW_PS_NULLFUNC_STACK | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT); hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->queues = 4; hw->channel_change_time = 5000; hw->max_listen_interval = 10; + + if (AR_SREV_9271(priv->ah)) + hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_9271; + else + hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_7010; + hw->vif_data_size = sizeof(struct ath9k_htc_vif); hw->sta_data_size = sizeof(struct ath9k_htc_sta); @@ -779,6 +800,43 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, SET_IEEE80211_PERM_ADDR(hw, common->macaddr); } +static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv) +{ + struct ieee80211_hw *hw = priv->hw; + struct wmi_fw_version cmd_rsp; + int ret; + + memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + + WMI_CMD(WMI_GET_FW_VERSION); + if (ret) + return -EINVAL; + + priv->fw_version_major = be16_to_cpu(cmd_rsp.major); + priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor); + + snprintf(hw->wiphy->fw_version, ETHTOOL_BUSINFO_LEN, "%d.%d", + priv->fw_version_major, + priv->fw_version_minor); + + dev_info(priv->dev, "ath9k_htc: FW Version: %d.%d\n", + priv->fw_version_major, + priv->fw_version_minor); + + /* + * Check if the available FW matches the driver's + * required version. + */ + if (priv->fw_version_major != MAJOR_VERSION_REQ || + priv->fw_version_minor != MINOR_VERSION_REQ) { + dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n", + MAJOR_VERSION_REQ, MINOR_VERSION_REQ); + return -EINVAL; + } + + return 0; +} + static int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid, char *product, u32 drv_info) { @@ -798,6 +856,10 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, common = ath9k_hw_common(ah); ath9k_set_hw_capab(priv, hw); + error = ath9k_init_firmware_version(priv); + if (error != 0) + goto err_fw; + /* Initialize regulatory */ error = ath_regd_init(&common->regulatory, priv->hw->wiphy, ath9k_reg_notifier); @@ -816,6 +878,13 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, if (error != 0) goto err_rx; +#ifdef CONFIG_MAC80211_LEDS + /* must be initialized before ieee80211_register_hw */ + priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw, + IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_htc_tpt_blink, + ARRAY_SIZE(ath9k_htc_tpt_blink)); +#endif + /* Register with mac80211 */ error = ieee80211_register_hw(hw); if (error) @@ -828,6 +897,12 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, goto err_world; } + error = ath9k_htc_init_debug(priv->ah); + if (error) { + ath_err(common, "Unable to create debugfs files\n"); + goto err_world; + } + ath_dbg(common, ATH_DBG_CONFIG, "WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, " "BE:%d, BK:%d, VI:%d, VO:%d\n", @@ -858,6 +933,8 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, err_tx: /* Nothing */ err_regd: + /* Nothing */ +err_fw: ath9k_deinit_priv(priv); err_init: return error; @@ -946,38 +1023,20 @@ int ath9k_htc_resume(struct htc_target *htc_handle) static int __init ath9k_htc_init(void) { - int error; - - error = ath9k_htc_debug_create_root(); - if (error < 0) { - printk(KERN_ERR - "ath9k_htc: Unable to create debugfs root: %d\n", - error); - goto err_dbg; - } - - error = ath9k_hif_usb_init(); - if (error < 0) { + if (ath9k_hif_usb_init() < 0) { printk(KERN_ERR "ath9k_htc: No USB devices found," " driver not installed.\n"); - error = -ENODEV; - goto err_usb; + return -ENODEV; } return 0; - -err_usb: - ath9k_htc_debug_remove_root(); -err_dbg: - return error; } module_init(ath9k_htc_init); static void __exit ath9k_htc_exit(void) { ath9k_hif_usb_exit(); - ath9k_htc_debug_remove_root(); printk(KERN_INFO "ath9k_htc: Driver unloaded\n"); } module_exit(ath9k_htc_exit); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index db8c0c044e9e..5aa104fe7eeb 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -16,10 +16,6 @@ #include "htc.h" -#ifdef CONFIG_ATH9K_HTC_DEBUGFS -static struct dentry *ath9k_debugfs_root; -#endif - /*************/ /* Utilities */ /*************/ @@ -197,11 +193,16 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) ath9k_htc_stop_ani(priv); ieee80211_stop_queues(priv->hw); - htc_stop(priv->htc); + + del_timer_sync(&priv->tx.cleanup_timer); + ath9k_htc_tx_drain(priv); + WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); + ath9k_wmi_event_drain(priv); + caldata = &priv->caldata; ret = ath9k_hw_reset(ah, ah->curchan, caldata, false); if (ret) { @@ -225,6 +226,9 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) ath9k_htc_vif_reconfig(priv); ieee80211_wake_queues(priv->hw); + mod_timer(&priv->tx.cleanup_timer, + jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); + ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); } @@ -250,11 +254,16 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); ath9k_htc_ps_wakeup(priv); - htc_stop(priv->htc); + + del_timer_sync(&priv->tx.cleanup_timer); + ath9k_htc_tx_drain(priv); + WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); + ath9k_wmi_event_drain(priv); + ath_dbg(common, ATH_DBG_CONFIG, "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n", priv->ah->curchan->channel, @@ -263,6 +272,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, if (!fastcc) caldata = &priv->caldata; + ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); if (ret) { ath_err(common, @@ -296,6 +306,9 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) ath9k_htc_vif_reconfig(priv); + mod_timer(&priv->tx.cleanup_timer, + jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); + err: ath9k_htc_ps_restore(priv); return ret; @@ -319,6 +332,11 @@ static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); hvif.index = priv->mon_vif_idx; WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); + if (ret) { + ath_err(common, "Unable to remove monitor interface at idx: %d\n", + priv->mon_vif_idx); + } + priv->nvifs--; priv->vif_slot &= ~(1 << priv->mon_vif_idx); } @@ -349,7 +367,7 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); - hvif.opmode = cpu_to_be32(HTC_M_MONITOR); + hvif.opmode = HTC_M_MONITOR; hvif.index = ffz(priv->vif_slot); WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); @@ -382,7 +400,7 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) tsta.is_vif_sta = 1; tsta.sta_index = sta_idx; tsta.vif_index = hvif.index; - tsta.maxampdu = 0xffff; + tsta.maxampdu = cpu_to_be16(0xffff); WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); if (ret) { @@ -449,6 +467,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, struct ath9k_htc_sta *ista; int ret, sta_idx; u8 cmd_rsp; + u16 maxampdu; if (priv->nstations >= ATH9K_HTC_MAX_STA) return -ENOBUFS; @@ -463,9 +482,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, ista = (struct ath9k_htc_sta *) sta->drv_priv; memcpy(&tsta.macaddr, sta->addr, ETH_ALEN); memcpy(&tsta.bssid, common->curbssid, ETH_ALEN); - tsta.associd = common->curaid; tsta.is_vif_sta = 0; - tsta.valid = true; ista->index = sta_idx; } else { memcpy(&tsta.macaddr, vif->addr, ETH_ALEN); @@ -474,7 +491,15 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, tsta.sta_index = sta_idx; tsta.vif_index = avp->index; - tsta.maxampdu = 0xffff; + + if (!sta) { + tsta.maxampdu = cpu_to_be16(0xffff); + } else { + maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + + sta->ht_cap.ampdu_factor); + tsta.maxampdu = cpu_to_be16(maxampdu); + } + if (sta && sta->ht_cap.ht_supported) tsta.flags = cpu_to_be16(ATH_HTC_STA_HT); @@ -547,7 +572,8 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, return 0; } -int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv) +int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv, + u8 enable_coex) { struct ath9k_htc_cap_target tcap; int ret; @@ -555,13 +581,9 @@ int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv) memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target)); - /* FIXME: Values are hardcoded */ - tcap.flags = 0x240c40; - tcap.flags_ext = 0x80601000; - tcap.ampdu_limit = 0xffff0000; - tcap.ampdu_subframes = 20; - tcap.tx_chainmask_legacy = priv->ah->caps.tx_chainmask; - tcap.protmode = 1; + tcap.ampdu_limit = cpu_to_be32(0xffff); + tcap.ampdu_subframes = priv->hw->max_tx_aggregation_subframes; + tcap.enable_coex = enable_coex; tcap.tx_chainmask = priv->ah->caps.tx_chainmask; WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap); @@ -709,218 +731,13 @@ static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv, (aggr.aggr_enable) ? "Starting" : "Stopping", sta->addr, tid); - spin_lock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP; - spin_unlock_bh(&priv->tx_lock); + spin_unlock_bh(&priv->tx.tx_lock); return ret; } -/*********/ -/* DEBUG */ -/*********/ - -#ifdef CONFIG_ATH9K_HTC_DEBUGFS - -static int ath9k_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath9k_htc_priv *priv = file->private_data; - struct ath9k_htc_target_stats cmd_rsp; - char buf[512]; - unsigned int len = 0; - int ret = 0; - - memset(&cmd_rsp, 0, sizeof(cmd_rsp)); - - WMI_CMD(WMI_TGT_STATS_CMDID); - if (ret) - return -EINVAL; - - - len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Short Retries", - be32_to_cpu(cmd_rsp.tx_shortretry)); - len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Long Retries", - be32_to_cpu(cmd_rsp.tx_longretry)); - len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Xretries", - be32_to_cpu(cmd_rsp.tx_xretries)); - len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Unaggr. Xretries", - be32_to_cpu(cmd_rsp.ht_txunaggr_xretry)); - len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Xretries (HT)", - be32_to_cpu(cmd_rsp.ht_tx_xretries)); - len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Rate", priv->debug.txrate); - - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static const struct file_operations fops_tgt_stats = { - .read = read_file_tgt_stats, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_xmit(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath9k_htc_priv *priv = file->private_data; - char buf[512]; - unsigned int len = 0; - - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "Buffers queued", - priv->debug.tx_stats.buf_queued); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "Buffers completed", - priv->debug.tx_stats.buf_completed); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs queued", - priv->debug.tx_stats.skb_queued); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs completed", - priv->debug.tx_stats.skb_completed); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs dropped", - priv->debug.tx_stats.skb_dropped); - - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "BE queued", - priv->debug.tx_stats.queue_stats[WME_AC_BE]); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "BK queued", - priv->debug.tx_stats.queue_stats[WME_AC_BK]); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "VI queued", - priv->debug.tx_stats.queue_stats[WME_AC_VI]); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "VO queued", - priv->debug.tx_stats.queue_stats[WME_AC_VO]); - - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static const struct file_operations fops_xmit = { - .read = read_file_xmit, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_recv(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath9k_htc_priv *priv = file->private_data; - char buf[512]; - unsigned int len = 0; - - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs allocated", - priv->debug.rx_stats.skb_allocated); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs completed", - priv->debug.rx_stats.skb_completed); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs Dropped", - priv->debug.rx_stats.skb_dropped); - - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static const struct file_operations fops_recv = { - .read = read_file_recv, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -int ath9k_htc_init_debug(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - - if (!ath9k_debugfs_root) - return -ENOENT; - - priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy), - ath9k_debugfs_root); - if (!priv->debug.debugfs_phy) - goto err; - - priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_tgt_stats); - if (!priv->debug.debugfs_tgt_stats) - goto err; - - - priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_xmit); - if (!priv->debug.debugfs_xmit) - goto err; - - priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_recv); - if (!priv->debug.debugfs_recv) - goto err; - - return 0; - -err: - ath9k_htc_exit_debug(ah); - return -ENOMEM; -} - -void ath9k_htc_exit_debug(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - - debugfs_remove(priv->debug.debugfs_recv); - debugfs_remove(priv->debug.debugfs_xmit); - debugfs_remove(priv->debug.debugfs_tgt_stats); - debugfs_remove(priv->debug.debugfs_phy); -} - -int ath9k_htc_debug_create_root(void) -{ - ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!ath9k_debugfs_root) - return -ENOENT; - - return 0; -} - -void ath9k_htc_debug_remove_root(void) -{ - debugfs_remove(ath9k_debugfs_root); - ath9k_debugfs_root = NULL; -} - -#endif /* CONFIG_ATH9K_HTC_DEBUGFS */ - /*******/ /* ANI */ /*******/ @@ -1040,7 +857,8 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_hdr *hdr; struct ath9k_htc_priv *priv = hw->priv; - int padpos, padsize, ret; + struct ath_common *common = ath9k_hw_common(priv->ah); + int padpos, padsize, ret, slot; hdr = (struct ieee80211_hdr *) skb->data; @@ -1048,30 +866,32 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) padpos = ath9k_cmn_padpos(hdr->frame_control); padsize = padpos & 3; if (padsize && skb->len > padpos) { - if (skb_headroom(skb) < padsize) + if (skb_headroom(skb) < padsize) { + ath_dbg(common, ATH_DBG_XMIT, "No room for padding\n"); goto fail_tx; + } skb_push(skb, padsize); memmove(skb->data, skb->data + padsize, padpos); } - ret = ath9k_htc_tx_start(priv, skb); - if (ret != 0) { - if (ret == -ENOMEM) { - ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, - "Stopping TX queues\n"); - ieee80211_stop_queues(hw); - spin_lock_bh(&priv->tx_lock); - priv->tx_queues_stop = true; - spin_unlock_bh(&priv->tx_lock); - } else { - ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, - "Tx failed\n"); - } + slot = ath9k_htc_tx_get_slot(priv); + if (slot < 0) { + ath_dbg(common, ATH_DBG_XMIT, "No free TX slot\n"); goto fail_tx; } + ret = ath9k_htc_tx_start(priv, skb, slot, false); + if (ret != 0) { + ath_dbg(common, ATH_DBG_XMIT, "Tx failed\n"); + goto clear_slot; + } + + ath9k_htc_check_stop_queues(priv); + return; +clear_slot: + ath9k_htc_tx_clear_slot(priv, slot); fail_tx: dev_kfree_skb_any(skb); } @@ -1122,7 +942,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) ath9k_host_rx_init(priv); - ret = ath9k_htc_update_cap_target(priv); + ret = ath9k_htc_update_cap_target(priv, 0); if (ret) ath_dbg(common, ATH_DBG_CONFIG, "Failed to update capability in target\n"); @@ -1130,12 +950,15 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) priv->op_flags &= ~OP_INVALID; htc_start(priv->htc); - spin_lock_bh(&priv->tx_lock); - priv->tx_queues_stop = false; - spin_unlock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP; + spin_unlock_bh(&priv->tx.tx_lock); ieee80211_wake_queues(hw); + mod_timer(&priv->tx.cleanup_timer, + jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); + if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) { ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, AR_STOMP_LOW_WLAN_WGHT); @@ -1152,7 +975,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) struct ath9k_htc_priv *priv = hw->priv; struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); - int ret = 0; + int ret __attribute__ ((unused)); u8 cmd_rsp; mutex_lock(&priv->mutex); @@ -1164,25 +987,27 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) } ath9k_htc_ps_wakeup(priv); - htc_stop(priv->htc); + WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); - tasklet_kill(&priv->swba_tasklet); tasklet_kill(&priv->rx_tasklet); - tasklet_kill(&priv->tx_tasklet); - skb_queue_purge(&priv->tx_queue); + del_timer_sync(&priv->tx.cleanup_timer); + ath9k_htc_tx_drain(priv); + ath9k_wmi_event_drain(priv); mutex_unlock(&priv->mutex); /* Cancel all the running timers/work .. */ cancel_work_sync(&priv->fatal_work); cancel_work_sync(&priv->ps_work); - cancel_delayed_work_sync(&priv->ath9k_led_blink_work); + +#ifdef CONFIG_MAC80211_LEDS + cancel_work_sync(&priv->led_work); +#endif ath9k_htc_stop_ani(priv); - ath9k_led_stop_brightness(priv); mutex_lock(&priv->mutex); @@ -1245,13 +1070,13 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, switch (vif->type) { case NL80211_IFTYPE_STATION: - hvif.opmode = cpu_to_be32(HTC_M_STA); + hvif.opmode = HTC_M_STA; break; case NL80211_IFTYPE_ADHOC: - hvif.opmode = cpu_to_be32(HTC_M_IBSS); + hvif.opmode = HTC_M_IBSS; break; case NL80211_IFTYPE_AP: - hvif.opmode = cpu_to_be32(HTC_M_HOSTAP); + hvif.opmode = HTC_M_HOSTAP; break; default: ath_err(common, @@ -1281,14 +1106,20 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, priv->vif_slot |= (1 << avp->index); priv->nvifs++; - priv->vif = vif; INC_VIF(priv, vif->type); + + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_ADHOC)) + ath9k_htc_assign_bslot(priv, vif); + ath9k_htc_set_opmode(priv); if ((priv->ah->opmode == NL80211_IFTYPE_AP) && - !(priv->op_flags & OP_ANI_RUNNING)) + !(priv->op_flags & OP_ANI_RUNNING)) { + ath9k_hw_set_tsfadjust(priv->ah, 1); ath9k_htc_start_ani(priv); + } ath_dbg(common, ATH_DBG_CONFIG, "Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index); @@ -1317,13 +1148,21 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); hvif.index = avp->index; WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); + if (ret) { + ath_err(common, "Unable to remove interface at idx: %d\n", + avp->index); + } priv->nvifs--; priv->vif_slot &= ~(1 << avp->index); ath9k_htc_remove_station(priv, vif, NULL); - priv->vif = NULL; DEC_VIF(priv, vif->type); + + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_ADHOC)) + ath9k_htc_remove_bslot(priv, vif); + ath9k_htc_set_opmode(priv); /* @@ -1493,10 +1332,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct ath9k_htc_priv *priv = hw->priv; + struct ath9k_htc_sta *ista; int ret; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); + ista = (struct ath9k_htc_sta *) sta->drv_priv; + htc_sta_drain(priv->htc, ista->index); ret = ath9k_htc_remove_station(priv, vif, sta); ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); @@ -1644,6 +1486,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) { ath_dbg(common, ATH_DBG_CONFIG, "Beacon enabled for BSS: %pM\n", bss_conf->bssid); + ath9k_htc_set_tsfadjust(priv, vif); priv->op_flags |= OP_ENABLE_BEACON; ath9k_htc_beacon_config(priv, vif); } @@ -1741,6 +1584,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, int ret = 0; mutex_lock(&priv->mutex); + ath9k_htc_ps_wakeup(priv); switch (action) { case IEEE80211_AMPDU_RX_START: @@ -1758,14 +1602,15 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, break; case IEEE80211_AMPDU_TX_OPERATIONAL: ista = (struct ath9k_htc_sta *) sta->drv_priv; - spin_lock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); ista->tid_state[tid] = AGGR_OPERATIONAL; - spin_unlock_bh(&priv->tx_lock); + spin_unlock_bh(&priv->tx.tx_lock); break; default: ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n"); } + ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); return ret; @@ -1816,6 +1661,55 @@ static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); } +/* + * Currently, this is used only for selecting the minimum rate + * for management frames, rate selection for data frames remain + * unaffected. + */ +static int ath9k_htc_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_target_rate_mask tmask; + struct ath9k_htc_vif *avp = (void *)vif->drv_priv; + int ret = 0; + u8 cmd_rsp; + + memset(&tmask, 0, sizeof(struct ath9k_htc_target_rate_mask)); + + tmask.vif_index = avp->index; + tmask.band = IEEE80211_BAND_2GHZ; + tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_2GHZ].legacy); + + WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask); + if (ret) { + ath_err(common, + "Unable to set 2G rate mask for " + "interface at idx: %d\n", avp->index); + goto out; + } + + tmask.band = IEEE80211_BAND_5GHZ; + tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_5GHZ].legacy); + + WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask); + if (ret) { + ath_err(common, + "Unable to set 5G rate mask for " + "interface at idx: %d\n", avp->index); + goto out; + } + + ath_dbg(common, ATH_DBG_CONFIG, + "Set bitrate masks: 0x%x, 0x%x\n", + mask->control[IEEE80211_BAND_2GHZ].legacy, + mask->control[IEEE80211_BAND_5GHZ].legacy); +out: + return ret; +} + struct ieee80211_ops ath9k_htc_ops = { .tx = ath9k_htc_tx, .start = ath9k_htc_start, @@ -1838,4 +1732,5 @@ struct ieee80211_ops ath9k_htc_ops = { .set_rts_threshold = ath9k_htc_set_rts_threshold, .rfkill_poll = ath9k_htc_rfkill_poll_state, .set_coverage_class = ath9k_htc_set_coverage_class, + .set_bitrate_mask = ath9k_htc_set_bitrate_mask, }; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 4a4f27ba96af..a898dac22337 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -53,6 +53,138 @@ int get_hw_qnum(u16 queue, int *hwq_map) } } +void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv) +{ + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.queued_cnt++; + if ((priv->tx.queued_cnt >= ATH9K_HTC_TX_THRESHOLD) && + !(priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) { + priv->tx.flags |= ATH9K_HTC_OP_TX_QUEUES_STOP; + ieee80211_stop_queues(priv->hw); + } + spin_unlock_bh(&priv->tx.tx_lock); +} + +void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv) +{ + spin_lock_bh(&priv->tx.tx_lock); + if ((priv->tx.queued_cnt < ATH9K_HTC_TX_THRESHOLD) && + (priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) { + priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP; + ieee80211_wake_queues(priv->hw); + } + spin_unlock_bh(&priv->tx.tx_lock); +} + +int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv) +{ + int slot; + + spin_lock_bh(&priv->tx.tx_lock); + slot = find_first_zero_bit(priv->tx.tx_slot, MAX_TX_BUF_NUM); + if (slot >= MAX_TX_BUF_NUM) { + spin_unlock_bh(&priv->tx.tx_lock); + return -ENOBUFS; + } + __set_bit(slot, priv->tx.tx_slot); + spin_unlock_bh(&priv->tx.tx_lock); + + return slot; +} + +void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot) +{ + spin_lock_bh(&priv->tx.tx_lock); + __clear_bit(slot, priv->tx.tx_slot); + spin_unlock_bh(&priv->tx.tx_lock); +} + +static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, + u16 qnum) +{ + enum htc_endpoint_id epid; + + switch (qnum) { + case 0: + TX_QSTAT_INC(WME_AC_VO); + epid = priv->data_vo_ep; + break; + case 1: + TX_QSTAT_INC(WME_AC_VI); + epid = priv->data_vi_ep; + break; + case 2: + TX_QSTAT_INC(WME_AC_BE); + epid = priv->data_be_ep; + break; + case 3: + default: + TX_QSTAT_INC(WME_AC_BK); + epid = priv->data_bk_ep; + break; + } + + return epid; +} + +static inline struct sk_buff_head* +get_htc_epid_queue(struct ath9k_htc_priv *priv, u8 epid) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct sk_buff_head *epid_queue = NULL; + + if (epid == priv->mgmt_ep) + epid_queue = &priv->tx.mgmt_ep_queue; + else if (epid == priv->cab_ep) + epid_queue = &priv->tx.cab_ep_queue; + else if (epid == priv->data_be_ep) + epid_queue = &priv->tx.data_be_queue; + else if (epid == priv->data_bk_ep) + epid_queue = &priv->tx.data_bk_queue; + else if (epid == priv->data_vi_ep) + epid_queue = &priv->tx.data_vi_queue; + else if (epid == priv->data_vo_ep) + epid_queue = &priv->tx.data_vo_queue; + else + ath_err(common, "Invalid EPID: %d\n", epid); + + return epid_queue; +} + +/* + * Removes the driver header and returns the TX slot number + */ +static inline int strip_drv_header(struct ath9k_htc_priv *priv, + struct sk_buff *skb) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_tx_ctl *tx_ctl; + int slot; + + tx_ctl = HTC_SKB_CB(skb); + + if (tx_ctl->epid == priv->mgmt_ep) { + struct tx_mgmt_hdr *tx_mhdr = + (struct tx_mgmt_hdr *)skb->data; + slot = tx_mhdr->cookie; + skb_pull(skb, sizeof(struct tx_mgmt_hdr)); + } else if ((tx_ctl->epid == priv->data_bk_ep) || + (tx_ctl->epid == priv->data_be_ep) || + (tx_ctl->epid == priv->data_vi_ep) || + (tx_ctl->epid == priv->data_vo_ep) || + (tx_ctl->epid == priv->cab_ep)) { + struct tx_frame_hdr *tx_fhdr = + (struct tx_frame_hdr *)skb->data; + slot = tx_fhdr->cookie; + skb_pull(skb, sizeof(struct tx_frame_hdr)); + } else { + ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid); + slot = -EINVAL; + } + + return slot; +} + int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, struct ath9k_tx_queue_info *qinfo) { @@ -79,23 +211,140 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, return error; } -int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) +static void ath9k_htc_tx_mgmt(struct ath9k_htc_priv *priv, + struct ath9k_htc_vif *avp, + struct sk_buff *skb, + u8 sta_idx, u8 vif_idx, u8 slot) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_mgmt *mgmt; + struct ieee80211_hdr *hdr; + struct tx_mgmt_hdr mgmt_hdr; + struct ath9k_htc_tx_ctl *tx_ctl; + u8 *tx_fhdr; + + tx_ctl = HTC_SKB_CB(skb); + hdr = (struct ieee80211_hdr *) skb->data; + + memset(tx_ctl, 0, sizeof(*tx_ctl)); + memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); + + /* + * Set the TSF adjust value for probe response + * frame also. + */ + if (avp && unlikely(ieee80211_is_probe_resp(hdr->frame_control))) { + mgmt = (struct ieee80211_mgmt *)skb->data; + mgmt->u.probe_resp.timestamp = avp->tsfadjust; + } + + tx_ctl->type = ATH9K_HTC_MGMT; + + mgmt_hdr.node_idx = sta_idx; + mgmt_hdr.vif_idx = vif_idx; + mgmt_hdr.tidno = 0; + mgmt_hdr.flags = 0; + mgmt_hdr.cookie = slot; + + mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); + if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) + mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; + else + mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; + + tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); + memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); + tx_ctl->epid = priv->mgmt_ep; +} + +static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif, + struct sk_buff *skb, + u8 sta_idx, u8 vif_idx, u8 slot, + bool is_cab) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr; + struct ath9k_htc_tx_ctl *tx_ctl; + struct tx_frame_hdr tx_hdr; + u32 flags = 0; + u8 *qc, *tx_fhdr; + u16 qnum; + + tx_ctl = HTC_SKB_CB(skb); + hdr = (struct ieee80211_hdr *) skb->data; + + memset(tx_ctl, 0, sizeof(*tx_ctl)); + memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); + + tx_hdr.node_idx = sta_idx; + tx_hdr.vif_idx = vif_idx; + tx_hdr.cookie = slot; + + /* + * This is a bit redundant but it helps to get + * the per-packet index quickly when draining the + * TX queue in the HIF layer. Otherwise we would + * have to parse the packet contents ... + */ + tx_ctl->sta_idx = sta_idx; + + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { + tx_ctl->type = ATH9K_HTC_AMPDU; + tx_hdr.data_type = ATH9K_HTC_AMPDU; + } else { + tx_ctl->type = ATH9K_HTC_NORMAL; + tx_hdr.data_type = ATH9K_HTC_NORMAL; + } + + if (ieee80211_is_data_qos(hdr->frame_control)) { + qc = ieee80211_get_qos_ctl(hdr); + tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + } + + /* Check for RTS protection */ + if (priv->hw->wiphy->rts_threshold != (u32) -1) + if (skb->len > priv->hw->wiphy->rts_threshold) + flags |= ATH9K_HTC_TX_RTSCTS; + + /* CTS-to-self */ + if (!(flags & ATH9K_HTC_TX_RTSCTS) && + (vif && vif->bss_conf.use_cts_prot)) + flags |= ATH9K_HTC_TX_CTSONLY; + + tx_hdr.flags = cpu_to_be32(flags); + tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); + if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) + tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; + else + tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; + + tx_fhdr = skb_push(skb, sizeof(tx_hdr)); + memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); + + if (is_cab) { + CAB_STAT_INC; + tx_ctl->epid = priv->cab_ep; + return; + } + + qnum = skb_get_queue_mapping(skb); + tx_ctl->epid = get_htc_epid(priv, qnum); +} + +int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, + struct sk_buff *skb, + u8 slot, bool is_cab) { struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = tx_info->control.sta; struct ieee80211_vif *vif = tx_info->control.vif; struct ath9k_htc_sta *ista; - struct ath9k_htc_vif *avp; - struct ath9k_htc_tx_ctl tx_ctl; - enum htc_endpoint_id epid; - u16 qnum; - __le16 fc; - u8 *tx_fhdr; + struct ath9k_htc_vif *avp = NULL; u8 sta_idx, vif_idx; hdr = (struct ieee80211_hdr *) skb->data; - fc = hdr->frame_control; /* * Find out on which interface this packet has to be @@ -124,218 +373,430 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) sta_idx = priv->vif_sta_pos[vif_idx]; } - memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); + if (ieee80211_is_data(hdr->frame_control)) + ath9k_htc_tx_data(priv, vif, skb, + sta_idx, vif_idx, slot, is_cab); + else + ath9k_htc_tx_mgmt(priv, avp, skb, + sta_idx, vif_idx, slot); - if (ieee80211_is_data(fc)) { - struct tx_frame_hdr tx_hdr; - u32 flags = 0; - u8 *qc; - memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); - - tx_hdr.node_idx = sta_idx; - tx_hdr.vif_idx = vif_idx; - - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { - tx_ctl.type = ATH9K_HTC_AMPDU; - tx_hdr.data_type = ATH9K_HTC_AMPDU; - } else { - tx_ctl.type = ATH9K_HTC_NORMAL; - tx_hdr.data_type = ATH9K_HTC_NORMAL; - } - - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - } - - /* Check for RTS protection */ - if (priv->hw->wiphy->rts_threshold != (u32) -1) - if (skb->len > priv->hw->wiphy->rts_threshold) - flags |= ATH9K_HTC_TX_RTSCTS; - - /* CTS-to-self */ - if (!(flags & ATH9K_HTC_TX_RTSCTS) && - (vif && vif->bss_conf.use_cts_prot)) - flags |= ATH9K_HTC_TX_CTSONLY; - - tx_hdr.flags = cpu_to_be32(flags); - tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); - if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) - tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; - else - tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; - - tx_fhdr = skb_push(skb, sizeof(tx_hdr)); - memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); - - qnum = skb_get_queue_mapping(skb); - - switch (qnum) { - case 0: - TX_QSTAT_INC(WME_AC_VO); - epid = priv->data_vo_ep; - break; - case 1: - TX_QSTAT_INC(WME_AC_VI); - epid = priv->data_vi_ep; - break; - case 2: - TX_QSTAT_INC(WME_AC_BE); - epid = priv->data_be_ep; - break; - case 3: - default: - TX_QSTAT_INC(WME_AC_BK); - epid = priv->data_bk_ep; - break; - } - } else { - struct tx_mgmt_hdr mgmt_hdr; - - memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); - - tx_ctl.type = ATH9K_HTC_NORMAL; - - mgmt_hdr.node_idx = sta_idx; - mgmt_hdr.vif_idx = vif_idx; - mgmt_hdr.tidno = 0; - mgmt_hdr.flags = 0; - - mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); - if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) - mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; - else - mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; - - tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); - memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); - epid = priv->mgmt_ep; - } - - return htc_send(priv->htc, skb, epid, &tx_ctl); + return htc_send(priv->htc, skb); } -static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, - struct ath9k_htc_sta *ista, u8 tid) +static inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, + struct ath9k_htc_sta *ista, u8 tid) { bool ret = false; - spin_lock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP)) ret = true; - spin_unlock_bh(&priv->tx_lock); + spin_unlock_bh(&priv->tx.tx_lock); return ret; } -void ath9k_tx_tasklet(unsigned long data) +static void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif, + struct sk_buff *skb) { - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; - struct ieee80211_vif *vif; struct ieee80211_sta *sta; struct ieee80211_hdr *hdr; - struct ieee80211_tx_info *tx_info; - struct sk_buff *skb = NULL; __le16 fc; - while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) { + hdr = (struct ieee80211_hdr *) skb->data; + fc = hdr->frame_control; - hdr = (struct ieee80211_hdr *) skb->data; - fc = hdr->frame_control; - tx_info = IEEE80211_SKB_CB(skb); - vif = tx_info->control.vif; + rcu_read_lock(); - memset(&tx_info->status, 0, sizeof(tx_info->status)); + sta = ieee80211_find_sta(vif, hdr->addr1); + if (!sta) { + rcu_read_unlock(); + return; + } - if (!vif) - goto send_mac80211; + if (sta && conf_is_ht(&priv->hw->conf) && + !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { + if (ieee80211_is_data_qos(fc)) { + u8 *qc, tid; + struct ath9k_htc_sta *ista; - rcu_read_lock(); + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + ista = (struct ath9k_htc_sta *)sta->drv_priv; + if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) { + ieee80211_start_tx_ba_session(sta, tid, 0); + spin_lock_bh(&priv->tx.tx_lock); + ista->tid_state[tid] = AGGR_PROGRESS; + spin_unlock_bh(&priv->tx.tx_lock); + } + } + } + + rcu_read_unlock(); +} + +static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, + struct sk_buff *skb, + struct __wmi_event_txstatus *txs) +{ + struct ieee80211_vif *vif; + struct ath9k_htc_tx_ctl *tx_ctl; + struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *rate; + struct ieee80211_conf *cur_conf = &priv->hw->conf; + bool txok; + int slot; + + slot = strip_drv_header(priv, skb); + if (slot < 0) { + dev_kfree_skb_any(skb); + return; + } + + tx_ctl = HTC_SKB_CB(skb); + txok = tx_ctl->txok; + tx_info = IEEE80211_SKB_CB(skb); + vif = tx_info->control.vif; + rate = &tx_info->status.rates[0]; + + memset(&tx_info->status, 0, sizeof(tx_info->status)); + + /* + * URB submission failed for this frame, it never reached + * the target. + */ + if (!txok || !vif || !txs) + goto send_mac80211; + + if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) + tx_info->flags |= IEEE80211_TX_STAT_ACK; + + if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT) + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + + if (txs->ts_flags & ATH9K_HTC_TXSTAT_RTC_CTS) + rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; + + rate->count = 1; + rate->idx = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_RATE); + + if (txs->ts_flags & ATH9K_HTC_TXSTAT_MCS) { + rate->flags |= IEEE80211_TX_RC_MCS; + + if (txs->ts_flags & ATH9K_HTC_TXSTAT_CW40) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; + } else { + if (cur_conf->channel->band == IEEE80211_BAND_5GHZ) + rate->idx += 4; /* No CCK rates */ + } + + ath9k_htc_check_tx_aggr(priv, vif, skb); + +send_mac80211: + spin_lock_bh(&priv->tx.tx_lock); + if (WARN_ON(--priv->tx.queued_cnt < 0)) + priv->tx.queued_cnt = 0; + spin_unlock_bh(&priv->tx.tx_lock); + + ath9k_htc_tx_clear_slot(priv, slot); + + /* Send status to mac80211 */ + ieee80211_tx_status(priv->hw, skb); +} + +static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv, + struct sk_buff_head *queue) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(queue)) != NULL) { + ath9k_htc_tx_process(priv, skb, NULL); + } +} + +void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) +{ + struct ath9k_htc_tx_event *event, *tmp; + + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN; + spin_unlock_bh(&priv->tx.tx_lock); + + /* + * Ensure that all pending TX frames are flushed, + * and that the TX completion/failed tasklets is killed. + */ + htc_stop(priv->htc); + tasklet_kill(&priv->wmi->wmi_event_tasklet); + tasklet_kill(&priv->tx_failed_tasklet); + + ath9k_htc_tx_drainq(priv, &priv->tx.mgmt_ep_queue); + ath9k_htc_tx_drainq(priv, &priv->tx.cab_ep_queue); + ath9k_htc_tx_drainq(priv, &priv->tx.data_be_queue); + ath9k_htc_tx_drainq(priv, &priv->tx.data_bk_queue); + ath9k_htc_tx_drainq(priv, &priv->tx.data_vi_queue); + ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue); + ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); + + /* + * The TX cleanup timer has already been killed. + */ + spin_lock_bh(&priv->wmi->event_lock); + list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { + list_del(&event->list); + kfree(event); + } + spin_unlock_bh(&priv->wmi->event_lock); + + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN; + spin_unlock_bh(&priv->tx.tx_lock); +} + +void ath9k_tx_failed_tasklet(unsigned long data) +{ + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; + + spin_lock_bh(&priv->tx.tx_lock); + if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { + spin_unlock_bh(&priv->tx.tx_lock); + return; + } + spin_unlock_bh(&priv->tx.tx_lock); + + ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); +} + +static inline bool check_cookie(struct ath9k_htc_priv *priv, + struct sk_buff *skb, + u8 cookie, u8 epid) +{ + u8 fcookie = 0; + + if (epid == priv->mgmt_ep) { + struct tx_mgmt_hdr *hdr; + hdr = (struct tx_mgmt_hdr *) skb->data; + fcookie = hdr->cookie; + } else if ((epid == priv->data_bk_ep) || + (epid == priv->data_be_ep) || + (epid == priv->data_vi_ep) || + (epid == priv->data_vo_ep) || + (epid == priv->cab_ep)) { + struct tx_frame_hdr *hdr; + hdr = (struct tx_frame_hdr *) skb->data; + fcookie = hdr->cookie; + } + + if (fcookie == cookie) + return true; + + return false; +} + +static struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv, + struct __wmi_event_txstatus *txs) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct sk_buff_head *epid_queue; + struct sk_buff *skb, *tmp; + unsigned long flags; + u8 epid = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_EPID); + + epid_queue = get_htc_epid_queue(priv, epid); + if (!epid_queue) + return NULL; + + spin_lock_irqsave(&epid_queue->lock, flags); + skb_queue_walk_safe(epid_queue, skb, tmp) { + if (check_cookie(priv, skb, txs->cookie, epid)) { + __skb_unlink(skb, epid_queue); + spin_unlock_irqrestore(&epid_queue->lock, flags); + return skb; + } + } + spin_unlock_irqrestore(&epid_queue->lock, flags); + + ath_dbg(common, ATH_DBG_XMIT, + "No matching packet for cookie: %d, epid: %d\n", + txs->cookie, epid); + + return NULL; +} + +void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) +{ + struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event; + struct __wmi_event_txstatus *__txs; + struct sk_buff *skb; + struct ath9k_htc_tx_event *tx_pend; + int i; + + for (i = 0; i < txs->cnt; i++) { + WARN_ON(txs->cnt > HTC_MAX_TX_STATUS); + + __txs = &txs->txstatus[i]; + + skb = ath9k_htc_tx_get_packet(priv, __txs); + if (!skb) { + /* + * Store this event, so that the TX cleanup + * routine can check later for the needed packet. + */ + tx_pend = kzalloc(sizeof(struct ath9k_htc_tx_event), + GFP_ATOMIC); + if (!tx_pend) + continue; + + memcpy(&tx_pend->txs, __txs, + sizeof(struct __wmi_event_txstatus)); + + spin_lock(&priv->wmi->event_lock); + list_add_tail(&tx_pend->list, + &priv->wmi->pending_tx_events); + spin_unlock(&priv->wmi->event_lock); - sta = ieee80211_find_sta(vif, hdr->addr1); - if (!sta) { - rcu_read_unlock(); - ieee80211_tx_status(priv->hw, skb); continue; } - /* Check if we need to start aggregation */ - - if (sta && conf_is_ht(&priv->hw->conf) && - !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { - if (ieee80211_is_data_qos(fc)) { - u8 *qc, tid; - struct ath9k_htc_sta *ista; - - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - ista = (struct ath9k_htc_sta *)sta->drv_priv; - - if (ath9k_htc_check_tx_aggr(priv, ista, tid)) { - ieee80211_start_tx_ba_session(sta, tid, 0); - spin_lock_bh(&priv->tx_lock); - ista->tid_state[tid] = AGGR_PROGRESS; - spin_unlock_bh(&priv->tx_lock); - } - } - } - - rcu_read_unlock(); - - send_mac80211: - /* Send status to mac80211 */ - ieee80211_tx_status(priv->hw, skb); + ath9k_htc_tx_process(priv, skb, __txs); } /* Wake TX queues if needed */ - spin_lock_bh(&priv->tx_lock); - if (priv->tx_queues_stop) { - priv->tx_queues_stop = false; - spin_unlock_bh(&priv->tx_lock); - ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, - "Waking up TX queues\n"); - ieee80211_wake_queues(priv->hw); - return; - } - spin_unlock_bh(&priv->tx_lock); + ath9k_htc_check_wake_queues(priv); } void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, bool txok) { struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; - struct ath_common *common = ath9k_hw_common(priv->ah); - struct ieee80211_tx_info *tx_info; + struct ath9k_htc_tx_ctl *tx_ctl; + struct sk_buff_head *epid_queue; - if (!skb) + tx_ctl = HTC_SKB_CB(skb); + tx_ctl->txok = txok; + tx_ctl->timestamp = jiffies; + + if (!txok) { + skb_queue_tail(&priv->tx.tx_failed, skb); + tasklet_schedule(&priv->tx_failed_tasklet); return; + } - if (ep_id == priv->mgmt_ep) { - skb_pull(skb, sizeof(struct tx_mgmt_hdr)); - } else if ((ep_id == priv->data_bk_ep) || - (ep_id == priv->data_be_ep) || - (ep_id == priv->data_vi_ep) || - (ep_id == priv->data_vo_ep)) { - skb_pull(skb, sizeof(struct tx_frame_hdr)); - } else { - ath_err(common, "Unsupported TX EPID: %d\n", ep_id); + epid_queue = get_htc_epid_queue(priv, ep_id); + if (!epid_queue) { dev_kfree_skb_any(skb); return; } - tx_info = IEEE80211_SKB_CB(skb); + skb_queue_tail(epid_queue, skb); +} - if (txok) - tx_info->flags |= IEEE80211_TX_STAT_ACK; +static inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_tx_ctl *tx_ctl; - skb_queue_tail(&priv->tx_queue, skb); - tasklet_schedule(&priv->tx_tasklet); + tx_ctl = HTC_SKB_CB(skb); + + if (time_after(jiffies, + tx_ctl->timestamp + + msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) { + ath_dbg(common, ATH_DBG_XMIT, + "Dropping a packet due to TX timeout\n"); + return true; + } + + return false; +} + +static void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv, + struct sk_buff_head *epid_queue) +{ + bool process = false; + unsigned long flags; + struct sk_buff *skb, *tmp; + struct sk_buff_head queue; + + skb_queue_head_init(&queue); + + spin_lock_irqsave(&epid_queue->lock, flags); + skb_queue_walk_safe(epid_queue, skb, tmp) { + if (check_packet(priv, skb)) { + __skb_unlink(skb, epid_queue); + __skb_queue_tail(&queue, skb); + process = true; + } + } + spin_unlock_irqrestore(&epid_queue->lock, flags); + + if (process) { + skb_queue_walk_safe(&queue, skb, tmp) { + __skb_unlink(skb, &queue); + ath9k_htc_tx_process(priv, skb, NULL); + } + } +} + +void ath9k_htc_tx_cleanup_timer(unsigned long data) +{ + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) data; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_tx_event *event, *tmp; + struct sk_buff *skb; + + spin_lock(&priv->wmi->event_lock); + list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { + + skb = ath9k_htc_tx_get_packet(priv, &event->txs); + if (skb) { + ath_dbg(common, ATH_DBG_XMIT, + "Found packet for cookie: %d, epid: %d\n", + event->txs.cookie, + MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID)); + + ath9k_htc_tx_process(priv, skb, &event->txs); + list_del(&event->list); + kfree(event); + continue; + } + + if (++event->count >= ATH9K_HTC_TX_TIMEOUT_COUNT) { + list_del(&event->list); + kfree(event); + } + } + spin_unlock(&priv->wmi->event_lock); + + /* + * Check if status-pending packets have to be cleaned up. + */ + ath9k_htc_tx_cleanup_queue(priv, &priv->tx.mgmt_ep_queue); + ath9k_htc_tx_cleanup_queue(priv, &priv->tx.cab_ep_queue); + ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_be_queue); + ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_bk_queue); + ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vi_queue); + ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vo_queue); + + /* Wake TX queues if needed */ + ath9k_htc_check_wake_queues(priv); + + mod_timer(&priv->tx.cleanup_timer, + jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); } int ath9k_tx_init(struct ath9k_htc_priv *priv) { - skb_queue_head_init(&priv->tx_queue); + skb_queue_head_init(&priv->tx.mgmt_ep_queue); + skb_queue_head_init(&priv->tx.cab_ep_queue); + skb_queue_head_init(&priv->tx.data_be_queue); + skb_queue_head_init(&priv->tx.data_bk_queue); + skb_queue_head_init(&priv->tx.data_vi_queue); + skb_queue_head_init(&priv->tx.data_vo_queue); + skb_queue_head_init(&priv->tx.tx_failed); return 0; } @@ -507,8 +968,9 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, int last_rssi = ATH_RSSI_DUMMY_MARKER; __le16 fc; - if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) { - ath_err(common, "Corrupted RX frame, dropping\n"); + if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { + ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", + skb->len); goto rx_next; } @@ -522,6 +984,8 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, goto rx_next; } + ath9k_htc_err_stat_rx(priv, rxstatus); + /* Get the RX status information */ memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 62e139a30a74..cee970fdf652 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -17,8 +17,8 @@ #include "htc.h" static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, - u16 len, u8 flags, u8 epid, - struct ath9k_htc_tx_ctl *tx_ctl) + u16 len, u8 flags, u8 epid) + { struct htc_frame_hdr *hdr; struct htc_endpoint *endpoint = &target->endpoint[epid]; @@ -30,8 +30,8 @@ static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, hdr->flags = flags; hdr->payload_len = cpu_to_be16(len); - status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb, - tx_ctl); + status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb); + return status; } @@ -162,7 +162,7 @@ static int htc_config_pipe_credits(struct htc_target *target) target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS; - ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); + ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); if (ret) goto err; @@ -197,7 +197,7 @@ static int htc_setup_complete(struct htc_target *target) target->htc_flags |= HTC_OP_START_WAIT; - ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); + ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); if (ret) goto err; @@ -268,7 +268,7 @@ int htc_connect_service(struct htc_target *target, conn_msg->dl_pipeid = endpoint->dl_pipeid; conn_msg->ul_pipeid = endpoint->ul_pipeid; - ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); + ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); if (ret) goto err; @@ -286,35 +286,33 @@ int htc_connect_service(struct htc_target *target, return ret; } -int htc_send(struct htc_target *target, struct sk_buff *skb, - enum htc_endpoint_id epid, struct ath9k_htc_tx_ctl *tx_ctl) +int htc_send(struct htc_target *target, struct sk_buff *skb) { - return htc_issue_send(target, skb, skb->len, 0, epid, tx_ctl); + struct ath9k_htc_tx_ctl *tx_ctl; + + tx_ctl = HTC_SKB_CB(skb); + return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid); +} + +int htc_send_epid(struct htc_target *target, struct sk_buff *skb, + enum htc_endpoint_id epid) +{ + return htc_issue_send(target, skb, skb->len, 0, epid); } void htc_stop(struct htc_target *target) { - enum htc_endpoint_id epid; - struct htc_endpoint *endpoint; - - for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) { - endpoint = &target->endpoint[epid]; - if (endpoint->service_id != 0) - target->hif->stop(target->hif_dev, endpoint->ul_pipeid); - } + target->hif->stop(target->hif_dev); } void htc_start(struct htc_target *target) { - enum htc_endpoint_id epid; - struct htc_endpoint *endpoint; + target->hif->start(target->hif_dev); +} - for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) { - endpoint = &target->endpoint[epid]; - if (endpoint->service_id != 0) - target->hif->start(target->hif_dev, - endpoint->ul_pipeid); - } +void htc_sta_drain(struct htc_target *target, u8 idx) +{ + target->hif->sta_drain(target->hif_dev, idx); } void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index ecd018798c47..91a5305db95a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -33,10 +33,10 @@ struct ath9k_htc_hif { u8 control_dl_pipe; u8 control_ul_pipe; - void (*start) (void *hif_handle, u8 pipe); - void (*stop) (void *hif_handle, u8 pipe); - int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf, - struct ath9k_htc_tx_ctl *tx_ctl); + void (*start) (void *hif_handle); + void (*stop) (void *hif_handle); + void (*sta_drain) (void *hif_handle, u8 idx); + int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf); }; enum htc_endpoint_id { @@ -83,21 +83,10 @@ struct htc_ep_callbacks { void (*rx) (void *, struct sk_buff *, enum htc_endpoint_id); }; -#define HTC_TX_QUEUE_SIZE 256 - -struct htc_txq { - struct sk_buff *buf[HTC_TX_QUEUE_SIZE]; - u32 txqdepth; - u16 txbuf_cnt; - u16 txq_head; - u16 txq_tail; -}; - struct htc_endpoint { u16 service_id; struct htc_ep_callbacks ep_callbacks; - struct htc_txq htc_txq; u32 max_txqdepth; int max_msglen; @@ -205,10 +194,12 @@ int htc_init(struct htc_target *target); int htc_connect_service(struct htc_target *target, struct htc_service_connreq *service_connreq, enum htc_endpoint_id *conn_rsp_eid); -int htc_send(struct htc_target *target, struct sk_buff *skb, - enum htc_endpoint_id eid, struct ath9k_htc_tx_ctl *tx_ctl); +int htc_send(struct htc_target *target, struct sk_buff *skb); +int htc_send_epid(struct htc_target *target, struct sk_buff *skb, + enum htc_endpoint_id epid); void htc_stop(struct htc_target *target); void htc_start(struct htc_target *target); +void htc_sta_drain(struct htc_target *target, u8 idx); void ath9k_htc_rx_msg(struct htc_target *htc_handle, struct sk_buff *skb, u32 len, u8 pipe_id); diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index c8f254fe0f0b..8b8f0445aef8 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -116,16 +116,21 @@ static inline void ath9k_hw_clr11n_aggr(struct ath_hw *ah, void *ds) ath9k_hw_ops(ah)->clr11n_aggr(ah, ds); } -static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds, - u32 burstDuration) +static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) { - ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration); + ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val); } -static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, - u32 vmf) +static inline void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf) { - ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf); + ath9k_hw_ops(ah)->antdiv_comb_conf_get(ah, antconf); +} + +static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf) +{ + ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf); } /* Private hardware call ops */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 1ec9bcd6b281..b75b5dca4e29 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -130,6 +130,20 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) } EXPORT_SYMBOL(ath9k_hw_wait); +void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, + int column, unsigned int *writecnt) +{ + int r; + + ENABLE_REGWRITE_BUFFER(ah); + for (r = 0; r < array->ia_rows; r++) { + REG_WRITE(ah, INI_RA(array, r, 0), + INI_RA(array, r, column)); + DO_DELAY(*writecnt); + } + REGWRITE_BUFFER_FLUSH(ah); +} + u32 ath9k_hw_reverse_bits(u32 val, u32 n) { u32 retval; @@ -142,25 +156,6 @@ u32 ath9k_hw_reverse_bits(u32 val, u32 n) return retval; } -bool ath9k_get_channel_edges(struct ath_hw *ah, - u16 flags, u16 *low, - u16 *high) -{ - struct ath9k_hw_capabilities *pCap = &ah->caps; - - if (flags & CHANNEL_5GHZ) { - *low = pCap->low_5ghz_chan; - *high = pCap->high_5ghz_chan; - return true; - } - if ((flags & CHANNEL_2GHZ)) { - *low = pCap->low_2ghz_chan; - *high = pCap->high_2ghz_chan; - return true; - } - return false; -} - u16 ath9k_hw_computetxtime(struct ath_hw *ah, u8 phy, int kbps, u32 frameLen, u16 rateix, @@ -252,6 +247,17 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) { u32 val; + switch (ah->hw_version.devid) { + case AR5416_AR9100_DEVID: + ah->hw_version.macVersion = AR_SREV_VERSION_9100; + break; + case AR9300_DEVID_AR9340: + ah->hw_version.macVersion = AR_SREV_VERSION_9340; + val = REG_READ(ah, AR_SREV); + ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); + return; + } + val = REG_READ(ah, AR_SREV) & AR_SREV_ID; if (val == 0xFF) { @@ -364,11 +370,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.spurchans[i][1] = AR_NO_SPUR; } - if (ah->hw_version.devid != AR2427_DEVID_PCIE) - ah->config.ht_enable = 1; - else - ah->config.ht_enable = 0; - /* PAPRD needs some more work to be enabled */ ah->config.paprd_disable = 1; @@ -410,6 +411,8 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE | 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 = 20; ah->globaltxtimeout = (u32) -1; @@ -470,7 +473,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah) return ecode; } - if (!AR_SREV_9100(ah)) { + if (!AR_SREV_9100(ah) && !AR_SREV_9340(ah)) { ath9k_hw_ani_setup(ah); ath9k_hw_ani_init(ah); } @@ -492,9 +495,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); int r = 0; - if (ah->hw_version.devid == AR5416_AR9100_DEVID) - ah->hw_version.macVersion = AR_SREV_VERSION_9100; - ath9k_hw_read_revisions(ah); /* @@ -552,6 +552,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) case AR_SREV_VERSION_9271: case AR_SREV_VERSION_9300: case AR_SREV_VERSION_9485: + case AR_SREV_VERSION_9340: break; default: ath_err(common, @@ -560,7 +561,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) return -EOPNOTSUPP; } - if (AR_SREV_9271(ah) || AR_SREV_9100(ah)) + if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah)) ah->is_pciexpress = false; ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); @@ -629,6 +630,7 @@ int ath9k_hw_init(struct ath_hw *ah) case AR2427_DEVID_PCIE: case AR9300_DEVID_PCIE: case AR9300_DEVID_AR9485_PCIE: + case AR9300_DEVID_AR9340: break; default: if (common->bus_ops->ath_bus_type == ATH_USB) @@ -671,48 +673,89 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) REGWRITE_BUFFER_FLUSH(ah); } -unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) +u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) { - REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) & ~(PLL3_DO_MEAS_MASK))); + REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); + udelay(100); + REG_SET_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); + + while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) udelay(100); - REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) | PLL3_DO_MEAS_MASK)); - while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) - udelay(100); - - return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; + return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; } EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); -#define DPLL2_KD_VAL 0x3D -#define DPLL2_KI_VAL 0x06 -#define DPLL3_PHASE_SHIFT_VAL 0x1 - static void ath9k_hw_init_pll(struct ath_hw *ah, struct ath9k_channel *chan) { u32 pll; if (AR_SREV_9485(ah)) { - REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); - REG_WRITE(ah, AR_CH0_DDR_DPLL2, 0x19e82f01); - REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3, - AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); + /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */ + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_BB_DPLL2_PLL_PWD, 0x1); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_DPLL2_KD, 0x40); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_DPLL2_KI, 0x4); + + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1, + AR_CH0_BB_DPLL1_REFDIV, 0x5); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1, + AR_CH0_BB_DPLL1_NINI, 0x58); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1, + AR_CH0_BB_DPLL1_NFRAC, 0x0); + + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_BB_DPLL2_OUTDIV, 0x1); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_BB_DPLL2_LOCAL_PLL, 0x1); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_BB_DPLL2_EN_NEGTRIG, 0x1); + + /* program BB PLL phase_shift to 0x6 */ + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, + AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x6); + + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_BB_DPLL2_PLL_PWD, 0x0); + udelay(1000); + } else if (AR_SREV_9340(ah)) { + u32 regval, pll2_divint, pll2_divfrac, refdiv; REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); udelay(1000); - REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); + REG_SET_BIT(ah, AR_PHY_PLL_MODE, 0x1 << 16); + udelay(100); - REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, - AR_CH0_DPLL2_KD, DPLL2_KD_VAL); - REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, - AR_CH0_DPLL2_KI, DPLL2_KI_VAL); + if (ah->is_clk_25mhz) { + pll2_divint = 0x54; + pll2_divfrac = 0x1eb85; + refdiv = 3; + } else { + pll2_divint = 88; + pll2_divfrac = 0; + refdiv = 5; + } - REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, - AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); - REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); + regval = REG_READ(ah, AR_PHY_PLL_MODE); + regval |= (0x1 << 16); + REG_WRITE(ah, AR_PHY_PLL_MODE, regval); + udelay(100); + + REG_WRITE(ah, AR_PHY_PLL_CONTROL, (refdiv << 27) | + (pll2_divint << 18) | pll2_divfrac); + udelay(100); + + regval = REG_READ(ah, AR_PHY_PLL_MODE); + regval = (regval & 0x80071fff) | (0x1 << 30) | (0x1 << 13) | + (0x4 << 26) | (0x18 << 19); + REG_WRITE(ah, AR_PHY_PLL_MODE, regval); + REG_WRITE(ah, AR_PHY_PLL_MODE, + REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); udelay(1000); } @@ -720,6 +763,9 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) + udelay(1000); + /* Switch the core clock for ar9271 to 117Mhz */ if (AR_SREV_9271(ah)) { udelay(500); @@ -729,17 +775,34 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, udelay(RTC_PLL_SETTLE_DELAY); REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); + + if (AR_SREV_9340(ah)) { + if (ah->is_clk_25mhz) { + REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1); + REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); + REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae); + } else { + REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1); + REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400); + REG_WRITE(ah, AR_SLP32_INC, 0x0001e800); + } + udelay(100); + } } static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, enum nl80211_iftype opmode) { + u32 sync_default = AR_INTR_SYNC_DEFAULT; u32 imr_reg = AR_IMR_TXERR | AR_IMR_TXURN | AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_BCNMISC; + if (AR_SREV_9340(ah)) + sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; + if (AR_SREV_9300_20_OR_LATER(ah)) { imr_reg |= AR_IMR_RXOK_HP; if (ah->config.rx_intr_mitigation) @@ -770,7 +833,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, if (!AR_SREV_9100(ah)) { REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); } @@ -830,8 +893,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) ah->misc_mode); if (ah->misc_mode != 0) - REG_WRITE(ah, AR_PCU_MISC, - REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); + REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode); if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ) sifstime = 16; @@ -899,23 +961,19 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan) static inline void ath9k_hw_set_dma(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - u32 regval; ENABLE_REGWRITE_BUFFER(ah); /* * set AHB_MODE not to do cacheline prefetches */ - if (!AR_SREV_9300_20_OR_LATER(ah)) { - regval = REG_READ(ah, AR_AHB_MODE); - REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); - } + if (!AR_SREV_9300_20_OR_LATER(ah)) + REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN); /* * let mac dma reads be in 128 byte chunks */ - regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + REG_RMW(ah, AR_TXCFG, AR_TXCFG_DMASZ_128B, AR_TXCFG_DMASZ_MASK); REGWRITE_BUFFER_FLUSH(ah); @@ -932,8 +990,7 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) /* * let mac dma writes be in 128 byte chunks */ - regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); + REG_RMW(ah, AR_RXCFG, AR_RXCFG_DMASZ_128B, AR_RXCFG_DMASZ_MASK); /* * Setup receive FIFO threshold to hold off TX activities @@ -972,30 +1029,27 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) { - u32 val; + u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC; + u32 set = AR_STA_ID1_KSRCH_MODE; - val = REG_READ(ah, AR_STA_ID1); - val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); switch (opmode) { - case NL80211_IFTYPE_AP: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP - | AR_STA_ID1_KSRCH_MODE); - REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); - break; case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC - | AR_STA_ID1_KSRCH_MODE); + set |= AR_STA_ID1_ADHOC; REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; + case NL80211_IFTYPE_AP: + set |= AR_STA_ID1_STA_AP; + /* fall through */ case NL80211_IFTYPE_STATION: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); + REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; default: - if (ah->is_monitoring) - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); + if (!ah->is_monitoring) + set = 0; break; } + REG_RMW(ah, AR_STA_ID1, set, mask); } void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, @@ -1021,10 +1075,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) u32 tmpReg; if (AR_SREV_9100(ah)) { - u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK); - val &= ~AR_RTC_DERIVED_CLK_PERIOD; - val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD); - REG_WRITE(ah, AR_RTC_DERIVED_CLK, val); + REG_RMW_FIELD(ah, AR_RTC_DERIVED_CLK, + AR_RTC_DERIVED_CLK_PERIOD, 1); (void)REG_READ(ah, AR_RTC_DERIVED_CLK); } @@ -1212,6 +1264,20 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, return true; } +static void ath9k_hw_apply_gpio_override(struct ath_hw *ah) +{ + u32 gpio_mask = ah->gpio_mask; + int i; + + for (i = 0; gpio_mask; i++, gpio_mask >>= 1) { + if (!(gpio_mask & 1)) + continue; + + ath9k_hw_cfg_output(ah, i, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i))); + } +} + bool ath9k_hw_check_alive(struct ath_hw *ah) { int count = 50; @@ -1254,15 +1320,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ah->txchainmask = common->tx_chainmask; ah->rxchainmask = common->rx_chainmask; - if ((common->bus_ops->ath_bus_type != ATH_USB) && !ah->chip_fullsleep) { - ath9k_hw_abortpcurecv(ah); - if (!ath9k_hw_stopdmarecv(ah)) { - ath_dbg(common, ATH_DBG_XMIT, - "Failed to stop receive dma\n"); - bChannelChange = false; - } - } - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; @@ -1418,7 +1475,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REGWRITE_BUFFER_FLUSH(ah); ah->intr_txqs = 0; - for (i = 0; i < ah->caps.total_queues; i++) + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) ath9k_hw_resettxqueue(ah, i); ath9k_hw_init_interrupt_masks(ah, ah->opmode); @@ -1435,8 +1492,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ar9002_hw_enable_wep_aggregation(ah); } - REG_WRITE(ah, AR_STA_ID1, - REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); ath9k_hw_set_dma(ah); @@ -1489,7 +1545,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); } #ifdef __BIG_ENDIAN - else + else if (AR_SREV_9340(ah)) + REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0); + else REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); #endif } @@ -1500,6 +1558,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9300_20_OR_LATER(ah)) ar9003_hw_bb_watchdog_config(ah); + ath9k_hw_apply_gpio_override(ah); + return 0; } EXPORT_SYMBOL(ath9k_hw_reset); @@ -1679,21 +1739,15 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) case NL80211_IFTYPE_MESH_POINT: REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); - REG_WRITE(ah, AR_NEXT_NDP_TIMER, - TU_TO_USEC(next_beacon + - (ah->atim_window ? ah-> - atim_window : 1))); + REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon + + TU_TO_USEC(ah->atim_window ? ah->atim_window : 1)); flags |= AR_NDP_TIMER_EN; case NL80211_IFTYPE_AP: - REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); - REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, - TU_TO_USEC(next_beacon - - ah->config. - dma_beacon_response_time)); - REG_WRITE(ah, AR_NEXT_SWBA, - TU_TO_USEC(next_beacon - - ah->config. - sw_beacon_response_time)); + REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); + REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon - + TU_TO_USEC(ah->config.dma_beacon_response_time)); + REG_WRITE(ah, AR_NEXT_SWBA, next_beacon - + TU_TO_USEC(ah->config.sw_beacon_response_time)); flags |= AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; break; @@ -1705,18 +1759,13 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) break; } - REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period)); - REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period)); - REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period)); - REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period)); + REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period); + REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period); + REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period); + REG_WRITE(ah, AR_NDP_PERIOD, beacon_period); REGWRITE_BUFFER_FLUSH(ah); - beacon_period &= ~ATH9K_BEACON_ENA; - if (beacon_period & ATH9K_BEACON_RESET_TSF) { - ath9k_hw_reset_tsf(ah); - } - REG_SET_BIT(ah, AR_TIMER_MODE, flags); } EXPORT_SYMBOL(ath9k_hw_beaconinit); @@ -1804,7 +1853,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - u16 capField = 0, eeval; + u16 eeval; u8 ant_div_ctl1, tx_chainmask, rx_chainmask; eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); @@ -1815,8 +1864,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) eeval |= AR9285_RDEXT_DEFAULT; regulatory->current_rd_ext = eeval; - capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP); - if (ah->opmode != NL80211_IFTYPE_AP && ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) { if (regulatory->current_rd == 0x64 || @@ -1851,6 +1898,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) !(AR_SREV_9271(ah))) /* CB71: GPIO 0 is pulled down to indicate 3 rx chains */ pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7; + else if (AR_SREV_9100(ah)) + pCap->rx_chainmask = 0x7; else /* Use rx_chainmask from EEPROM. */ pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); @@ -1861,36 +1910,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) ah->misc_mode |= AR_PCU_ALWAYS_PERFORM_KEYSEARCH; - pCap->low_2ghz_chan = 2312; - pCap->high_2ghz_chan = 2732; - - pCap->low_5ghz_chan = 4920; - pCap->high_5ghz_chan = 6100; - common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; - if (ah->config.ht_enable) + if (ah->hw_version.devid != AR2427_DEVID_PCIE) pCap->hw_caps |= ATH9K_HW_CAP_HT; else pCap->hw_caps &= ~ATH9K_HW_CAP_HT; - if (capField & AR_EEPROM_EEPCAP_MAXQCU) - pCap->total_queues = - MS(capField, AR_EEPROM_EEPCAP_MAXQCU); - else - pCap->total_queues = ATH9K_NUM_TX_QUEUES; - - if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) - pCap->keycache_size = - 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); - else - pCap->keycache_size = AR_KEYTABLE_SIZE; - - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) - pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1; - else - pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - if (AR_SREV_9271(ah)) pCap->num_gpio_pins = AR9271_NUM_GPIO; else if (AR_DEVID_7010(ah)) @@ -1909,8 +1935,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->rts_aggr_limit = (8 * 1024); } - pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; - #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); if (ah->rfsilent & EEP_RFSILENT_ENABLED) { @@ -1932,32 +1956,23 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | - AR_EEPROM_EEREGCAP_EN_KK_U2 | - AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; - } else { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; - } - - /* Advertise midband for AR5416 with FCC midband set in eeprom */ - if (regulatory->current_rd_ext & (1 << REG_EXT_FCC_MIDBAND) && - AR_SREV_5416(ah)) - pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; - - if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) { - btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO; - btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO; - - if (AR_SREV_9285(ah)) { + if (common->btcoex_enabled) { + if (AR_SREV_9300_20_OR_LATER(ah)) { btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; - btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO; - } else { - btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; + btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; + btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; + btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300; + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280; + btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280; + + if (AR_SREV_9285(ah)) { + btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; + btcoex_hw->btpriority_gpio = + ATH_BTPRIORITY_GPIO_9285; + } else { + btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; + } } } else { btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE; @@ -2007,6 +2022,22 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) } + if (AR_SREV_9485(ah)) { + ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); + /* + * enable the diversity-combining algorithm only when + * both enable_lna_div and enable_fast_div are set + * Table for Diversity + * ant_div_alt_lnaconf bit 0-1 + * ant_div_main_lnaconf bit 2-3 + * ant_div_alt_gaintb bit 4 + * ant_div_main_gaintb bit 5 + * enable_ant_div_lnadiv bit 6 + * enable_ant_fast_div bit 7 + */ + if ((ant_div_ctl1 >> 0x6) == 0x3) + pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB; + } if (AR_SREV_9485_10(ah)) { pCap->pcie_lcr_extsync_en = true; @@ -2195,11 +2226,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) REG_WRITE(ah, AR_PHY_ERR, phybits); if (phybits) - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); + REG_SET_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA); else - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); + REG_CLR_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA); REGWRITE_BUFFER_FLUSH(ah); } @@ -2375,10 +2404,11 @@ static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) return timer_table->gen_timer_index[b]; } -static u32 ath9k_hw_gettsf32(struct ath_hw *ah) +u32 ath9k_hw_gettsf32(struct ath_hw *ah) { return REG_READ(ah, AR_TSF_L32); } +EXPORT_SYMBOL(ath9k_hw_gettsf32); struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, void (*trigger)(void *), @@ -2411,11 +2441,11 @@ EXPORT_SYMBOL(ath_gen_timer_alloc); void ath9k_hw_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, - u32 timer_next, + u32 trig_timeout, u32 timer_period) { struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; - u32 tsf; + u32 tsf, timer_next; BUG_ON(!timer_period); @@ -2423,17 +2453,12 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah, tsf = ath9k_hw_gettsf32(ah); + timer_next = tsf + trig_timeout; + ath_dbg(ath9k_hw_common(ah), ATH_DBG_HWTIMER, "current tsf %x period %x timer_next %x\n", tsf, timer_period, timer_next); - /* - * Pull timer_next forward if the current TSF already passed it - * because of software latency - */ - if (timer_next < tsf) - timer_next = tsf + timer_period; - /* * Program generic timer registers */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6650fd48415c..7af2773d2bfc 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -43,6 +43,7 @@ #define AR9287_DEVID_PCI 0x002d #define AR9287_DEVID_PCIE 0x002e #define AR9300_DEVID_PCIE 0x0030 +#define AR9300_DEVID_AR9340 0x0031 #define AR9300_DEVID_AR9485_PCIE 0x0032 #define AR5416_AR9100_DEVID 0x000b @@ -55,6 +56,9 @@ #define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa #define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab +#define AR9300_NUM_BT_WEIGHTS 4 +#define AR9300_NUM_WLAN_WEIGHTS 4 + #define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) #define ATH_DEFAULT_NOISE_FLOOR -95 @@ -65,53 +69,49 @@ /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) \ - ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg)) + (_ah)->reg_ops.write((_ah), (_val), (_reg)) #define REG_READ(_ah, _reg) \ - ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) + (_ah)->reg_ops.read((_ah), (_reg)) #define REG_READ_MULTI(_ah, _addr, _val, _cnt) \ - ath9k_hw_common(_ah)->ops->multi_read((_ah), (_addr), (_val), (_cnt)) + (_ah)->reg_ops.multi_read((_ah), (_addr), (_val), (_cnt)) + +#define REG_RMW(_ah, _reg, _set, _clr) \ + (_ah)->reg_ops.rmw((_ah), (_reg), (_set), (_clr)) #define ENABLE_REGWRITE_BUFFER(_ah) \ do { \ - if (ath9k_hw_common(_ah)->ops->enable_write_buffer) \ - ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \ + if ((_ah)->reg_ops.enable_write_buffer) \ + (_ah)->reg_ops.enable_write_buffer((_ah)); \ } while (0) #define REGWRITE_BUFFER_FLUSH(_ah) \ do { \ - if (ath9k_hw_common(_ah)->ops->write_flush) \ - ath9k_hw_common(_ah)->ops->write_flush((_ah)); \ + if ((_ah)->reg_ops.write_flush) \ + (_ah)->reg_ops.write_flush((_ah)); \ } while (0) #define SM(_v, _f) (((_v) << _f##_S) & _f) #define MS(_v, _f) (((_v) & _f) >> _f##_S) -#define REG_RMW(_a, _r, _set, _clr) \ - REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set)) #define REG_RMW_FIELD(_a, _r, _f, _v) \ - REG_WRITE(_a, _r, \ - (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f)) + REG_RMW(_a, _r, (((_v) << _f##_S) & _f), (_f)) #define REG_READ_FIELD(_a, _r, _f) \ (((REG_READ(_a, _r) & _f) >> _f##_S)) #define REG_SET_BIT(_a, _r, _f) \ - REG_WRITE(_a, _r, REG_READ(_a, _r) | (_f)) + REG_RMW(_a, _r, (_f), 0) #define REG_CLR_BIT(_a, _r, _f) \ - REG_WRITE(_a, _r, REG_READ(_a, _r) & ~(_f)) + REG_RMW(_a, _r, 0, (_f)) -#define DO_DELAY(x) do { \ - if ((++(x) % 64) == 0) \ - udelay(1); \ +#define DO_DELAY(x) do { \ + if (((++(x) % 64) == 0) && \ + (ath9k_hw_common(ah)->bus_ops->ath_bus_type \ + != ATH_USB)) \ + udelay(1); \ } while (0) -#define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ - int r; \ - for (r = 0; r < ((iniarray)->ia_rows); r++) { \ - REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ - INI_RA((iniarray), r, (column))); \ - DO_DELAY(regWr); \ - } \ - } while (0) +#define REG_WRITE_ARRAY(iniarray, column, regWr) \ + ath9k_hw_write_array(ah, iniarray, column, &(regWr)) #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 @@ -125,7 +125,7 @@ #define AR_GPIO_BIT(_gpio) (1 << (_gpio)) #define BASE_ACTIVATE_DELAY 100 -#define RTC_PLL_SETTLE_DELAY 100 +#define RTC_PLL_SETTLE_DELAY (AR_SREV_9340(ah) ? 1000 : 100) #define COEF_SCALE_S 24 #define HT40_CHANNEL_CENTER_SHIFT 10 @@ -178,7 +178,6 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_HT = BIT(0), ATH9K_HW_CAP_RFSILENT = BIT(1), ATH9K_HW_CAP_CST = BIT(2), - ATH9K_HW_CAP_ENHANCEDPM = BIT(3), ATH9K_HW_CAP_AUTOSLEEP = BIT(4), ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(5), ATH9K_HW_CAP_EDMA = BIT(6), @@ -195,17 +194,11 @@ enum ath9k_hw_caps { struct ath9k_hw_capabilities { u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ - u16 total_queues; - u16 keycache_size; - u16 low_5ghz_chan, high_5ghz_chan; - u16 low_2ghz_chan, high_2ghz_chan; u16 rts_aggr_limit; u8 tx_chainmask; u8 rx_chainmask; u8 max_txchains; u8 max_rxchains; - u16 tx_triglevel_max; - u16 reg_cap; u8 num_gpio_pins; u8 rx_hp_qdepth; u8 rx_lp_qdepth; @@ -227,7 +220,6 @@ struct ath9k_ops_config { u8 pcie_clock_req; u32 pcie_waen; u8 analog_shiftreg; - u8 ht_enable; u8 paprd_disable; u32 ofdm_trig_low; u32 ofdm_trig_high; @@ -412,8 +404,6 @@ struct ath9k_beacon_state { u32 bs_nextdtim; u32 bs_intval; #define ATH9K_BEACON_PERIOD 0x0000ffff -#define ATH9K_BEACON_ENA 0x00800000 -#define ATH9K_BEACON_RESET_TSF 0x01000000 #define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */ u32 bs_dtimperiod; u16 bs_cfpperiod; @@ -489,6 +479,10 @@ struct ath_hw_antcomb_conf { u8 main_lna_conf; u8 alt_lna_conf; u8 fast_div_bias; + u8 main_gaintb; + u8 alt_gaintb; + int lna1_lna2_delta; + u8 div_group; }; /** @@ -638,10 +632,12 @@ struct ath_hw_ops { u32 numDelims); void (*set11n_aggr_last)(struct ath_hw *ah, void *ds); void (*clr11n_aggr)(struct ath_hw *ah, void *ds); - void (*set11n_burstduration)(struct ath_hw *ah, void *ds, - u32 burstDuration); - void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds, - u32 vmf); + void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val); + void (*antdiv_comb_conf_get)(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf); + void (*antdiv_comb_conf_set)(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf); + }; struct ath_nf_limits { @@ -655,6 +651,8 @@ struct ath_nf_limits { #define AH_UNPLUGGED 0x2 /* The card has been physically removed. */ struct ath_hw { + struct ath_ops reg_ops; + struct ieee80211_hw *hw; struct ath_common common; struct ath9k_hw_version hw_version; @@ -784,6 +782,8 @@ struct ath_hw { /* Bluetooth coexistance */ struct ath_btcoex_hw btcoex_hw; + u32 bt_coex_bt_weight[AR9300_NUM_BT_WEIGHTS]; + u32 bt_coex_wlan_weight[AR9300_NUM_WLAN_WEIGHTS]; u32 intr_txqs; u8 txchainmask; @@ -794,7 +794,9 @@ struct ath_hw { u32 originalGain[22]; int initPDADC; int PDADCdelta; - u8 led_pin; + int led_pin; + u32 gpio_mask; + u32 gpio_val; struct ar5416IniArray iniModes; struct ar5416IniArray iniCommon; @@ -810,6 +812,7 @@ struct ath_hw { struct ar5416IniArray iniPcieSerdes; struct ar5416IniArray iniPcieSerdesLowPower; struct ar5416IniArray iniModesAdditional; + struct ar5416IniArray iniModesAdditional_40M; struct ar5416IniArray iniModesRxGain; struct ar5416IniArray iniModesTxGain; struct ar5416IniArray iniModes_9271_1_0_only; @@ -856,6 +859,16 @@ struct ath_hw { /* Enterprise mode cap */ u32 ent_mode; + + bool is_clk_25mhz; +}; + +struct ath_bus_ops { + enum ath_bus_type ath_bus_type; + void (*read_cachesize)(struct ath_common *common, int *csz); + bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); + void (*bt_coex_prep)(struct ath_common *common); + void (*extn_synch_en)(struct ath_common *common); }; static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) @@ -900,15 +913,12 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); u32 ath9k_hw_getdefantenna(struct ath_hw *ah); void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); -void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah, - struct ath_hw_antcomb_conf *antconf); -void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, - struct ath_hw_antcomb_conf *antconf); /* General Operation */ 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); u32 ath9k_hw_reverse_bits(u32 val, u32 n); -bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); u16 ath9k_hw_computetxtime(struct ath_hw *ah, u8 phy, int kbps, u32 frameLen, u16 rateix, bool shortPreamble); @@ -924,12 +934,13 @@ void ath9k_hw_setopmode(struct ath_hw *ah); void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); void ath9k_hw_setbssidmask(struct ath_hw *ah); void ath9k_hw_write_associd(struct ath_hw *ah); +u32 ath9k_hw_gettsf32(struct ath_hw *ah); u64 ath9k_hw_gettsf64(struct ath_hw *ah); void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); void ath9k_hw_init_global_settings(struct ath_hw *ah); -unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); +u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); void ath9k_hw_set11nmac2040(struct ath_hw *ah); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 79aec983279f..b172d1509515 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -15,6 +15,7 @@ */ #include +#include #include "ath9k.h" @@ -195,10 +196,27 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) return val; } -static const struct ath_ops ath9k_common_ops = { - .read = ath9k_ioread32, - .write = ath9k_iowrite32, -}; +static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; + unsigned long uninitialized_var(flags); + u32 val; + + if (ah->config.serialize_regmode == SER_REG_MODE_ON) + spin_lock_irqsave(&sc->sc_serial_rw, flags); + + val = ioread32(sc->mem + reg_offset); + val &= ~clr; + val |= set; + iowrite32(val, sc->mem + reg_offset); + + if (ah->config.serialize_regmode == SER_REG_MODE_ON) + spin_unlock_irqrestore(&sc->sc_serial_rw, flags); + + return val; +} /**************************/ /* Initialization */ @@ -389,13 +407,7 @@ void ath9k_init_crypto(struct ath_softc *sc) int i = 0; /* Get the hardware key cache size. */ - common->keymax = sc->sc_ah->caps.keycache_size; - if (common->keymax > ATH_KEYMAX) { - ath_dbg(common, ATH_DBG_ANY, - "Warning, using only %u entries in %u key cache\n", - ATH_KEYMAX, common->keymax); - common->keymax = ATH_KEYMAX; - } + common->keymax = AR_KEYTABLE_SIZE; /* * Reset the key cache since some parts do not @@ -537,6 +549,7 @@ static void ath9k_init_misc(struct ath_softc *sc) static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops) { + struct ath9k_platform_data *pdata = sc->dev->platform_data; struct ath_hw *ah = NULL; struct ath_common *common; int ret = 0, i; @@ -549,13 +562,23 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, ah->hw = sc->hw; ah->hw_version.devid = devid; ah->hw_version.subsysid = subsysid; + ah->reg_ops.read = ath9k_ioread32; + ah->reg_ops.write = ath9k_iowrite32; + ah->reg_ops.rmw = ath9k_reg_rmw; sc->sc_ah = ah; - if (!sc->dev->platform_data) + if (!pdata) { ah->ah_flags |= AH_USE_EEPROM; + sc->sc_ah->led_pin = -1; + } else { + sc->sc_ah->gpio_mask = pdata->gpio_mask; + sc->sc_ah->gpio_val = pdata->gpio_val; + sc->sc_ah->led_pin = pdata->led_pin; + ah->is_clk_25mhz = pdata->is_clk_25mhz; + } common = ath9k_hw_common(ah); - common->ops = &ath9k_common_ops; + common->ops = &ah->reg_ops; common->bus_ops = bus_ops; common->ah = ah; common->hw = sc->hw; @@ -587,6 +610,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, if (ret) goto err_hw; + if (pdata && pdata->macaddr) + memcpy(common->macaddr, pdata->macaddr, ETH_ALEN); + ret = ath9k_init_queues(sc); if (ret) goto err_queues; @@ -679,6 +705,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) if (AR_SREV_5416(sc->sc_ah)) hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->queues = 4; hw->max_rates = 4; hw->channel_change_time = 5000; @@ -773,6 +801,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, INIT_WORK(&sc->hw_check_work, ath_hw_check); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); + INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); sc->last_rssi = ATH_RSSI_DUMMY_MARKER; ath_init_leds(sc); diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 562257ac52cf..bd6d2b9d736f 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -209,15 +209,8 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, { u32 cw; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_tx_queue_info *qi; - if (q >= pCap->total_queues) { - ath_dbg(common, ATH_DBG_QUEUE, - "Set TXQ properties, invalid queue: %u\n", q); - return false; - } - qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, ATH_DBG_QUEUE, @@ -280,15 +273,8 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, struct ath9k_tx_queue_info *qinfo) { struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_tx_queue_info *qi; - if (q >= pCap->total_queues) { - ath_dbg(common, ATH_DBG_QUEUE, - "Get TXQ properties, invalid queue: %u\n", q); - return false; - } - qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, ATH_DBG_QUEUE, @@ -320,28 +306,27 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info *qi; - struct ath9k_hw_capabilities *pCap = &ah->caps; int q; switch (type) { case ATH9K_TX_QUEUE_BEACON: - q = pCap->total_queues - 1; + q = ATH9K_NUM_TX_QUEUES - 1; break; case ATH9K_TX_QUEUE_CAB: - q = pCap->total_queues - 2; + q = ATH9K_NUM_TX_QUEUES - 2; break; case ATH9K_TX_QUEUE_PSPOLL: q = 1; break; case ATH9K_TX_QUEUE_UAPSD: - q = pCap->total_queues - 3; + q = ATH9K_NUM_TX_QUEUES - 3; break; case ATH9K_TX_QUEUE_DATA: - for (q = 0; q < pCap->total_queues; q++) + for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++) if (ah->txq[q].tqi_type == ATH9K_TX_QUEUE_INACTIVE) break; - if (q == pCap->total_queues) { + if (q == ATH9K_NUM_TX_QUEUES) { ath_err(common, "No available TX queue\n"); return -1; } @@ -382,15 +367,9 @@ EXPORT_SYMBOL(ath9k_hw_setuptxqueue); bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) { - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info *qi; - if (q >= pCap->total_queues) { - ath_dbg(common, ATH_DBG_QUEUE, - "Release TXQ, invalid queue: %u\n", q); - return false; - } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, ATH_DBG_QUEUE, @@ -414,18 +393,11 @@ EXPORT_SYMBOL(ath9k_hw_releasetxqueue); bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) { - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; struct ath9k_tx_queue_info *qi; u32 cwMin, chanCwMin, value; - if (q >= pCap->total_queues) { - ath_dbg(common, ATH_DBG_QUEUE, - "Reset TXQ, invalid queue: %u\n", q); - return false; - } - qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, ATH_DBG_QUEUE, @@ -458,17 +430,21 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)); REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); - REG_WRITE(ah, AR_DMISC(q), - AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); + + if (AR_SREV_9340(ah)) + REG_WRITE(ah, AR_DMISC(q), + AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1); + else + REG_WRITE(ah, AR_DMISC(q), + AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); if (qi->tqi_cbrPeriod) { REG_WRITE(ah, AR_QCBRCFG(q), SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH)); - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | - (qi->tqi_cbrOverflowLimit ? - AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); + REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_CBR | + (qi->tqi_cbrOverflowLimit ? + AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); } if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { REG_WRITE(ah, AR_QRDYTIMECFG(q), @@ -481,40 +457,31 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); if (qi->tqi_burstTime - && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, AR_QMISC(q)) | - AR_Q_MISC_RDYTIME_EXP_POLICY); + && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) + REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_RDYTIME_EXP_POLICY); - } - - if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_POST_FR_BKOFF_DIS); - } + if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) + REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS); REGWRITE_BUFFER_FLUSH(ah); - if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_FRAG_BKOFF_EN); - } + if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) + REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_FRAG_BKOFF_EN); + switch (qi->tqi_type) { case ATH9K_TX_QUEUE_BEACON: ENABLE_REGWRITE_BUFFER(ah); - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_BEACON_USE - | AR_Q_MISC_CBR_INCR_DIS1); + REG_SET_BIT(ah, AR_QMISC(q), + AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_BEACON_USE + | AR_Q_MISC_CBR_INCR_DIS1); - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + REG_SET_BIT(ah, AR_DMISC(q), + (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S) - | AR_D_MISC_BEACON_USE - | AR_D_MISC_POST_FR_BKOFF_DIS); + | AR_D_MISC_BEACON_USE + | AR_D_MISC_POST_FR_BKOFF_DIS); REGWRITE_BUFFER_FLUSH(ah); @@ -533,41 +500,38 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) case ATH9K_TX_QUEUE_CAB: ENABLE_REGWRITE_BUFFER(ah); - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_CBR_INCR_DIS1 - | AR_Q_MISC_CBR_INCR_DIS0); + REG_SET_BIT(ah, AR_QMISC(q), + AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_CBR_INCR_DIS1 + | AR_Q_MISC_CBR_INCR_DIS0); value = (qi->tqi_readyTime - (ah->config.sw_beacon_response_time - ah->config.dma_beacon_response_time) - ah->config.additional_swba_backoff) * 1024; REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN); - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + REG_SET_BIT(ah, AR_DMISC(q), + (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); REGWRITE_BUFFER_FLUSH(ah); break; case ATH9K_TX_QUEUE_PSPOLL: - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); + REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_CBR_INCR_DIS1); break; case ATH9K_TX_QUEUE_UAPSD: - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_POST_FR_BKOFF_DIS); + REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS); break; default: break; } if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, - AR_D_MISC_ARB_LOCKOUT_CNTRL) | - AR_D_MISC_POST_FR_BKOFF_DIS); + REG_SET_BIT(ah, AR_DMISC(q), + SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, + AR_D_MISC_ARB_LOCKOUT_CNTRL) | + AR_D_MISC_POST_FR_BKOFF_DIS); } if (AR_SREV_9300_20_OR_LATER(ah)) @@ -751,34 +715,51 @@ void ath9k_hw_abortpcurecv(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_abortpcurecv); -bool ath9k_hw_stopdmarecv(struct ath_hw *ah) +bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset) { #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ -#define AH_RX_TIME_QUANTUM 100 /* usec */ struct ath_common *common = ath9k_hw_common(ah); + u32 mac_status, last_mac_status = 0; int i; + /* Enable access to the DMA observation bus */ + REG_WRITE(ah, AR_MACMISC, + ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | + (AR_MACMISC_MISC_OBS_BUS_1 << + AR_MACMISC_MISC_OBS_BUS_MSB_S))); + REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Wait for rx enable bit to go low */ for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) { if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) break; + + if (!AR_SREV_9300_20_OR_LATER(ah)) { + mac_status = REG_READ(ah, AR_DMADBG_7) & 0x7f0; + if (mac_status == 0x1c0 && mac_status == last_mac_status) { + *reset = true; + break; + } + + last_mac_status = mac_status; + } + udelay(AH_TIME_QUANTUM); } if (i == 0) { ath_err(common, - "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", + "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n", AH_RX_STOP_DMA_TIMEOUT / 1000, REG_READ(ah, AR_CR), - REG_READ(ah, AR_DIAG_SW)); + REG_READ(ah, AR_DIAG_SW), + REG_READ(ah, AR_DMADBG_7)); return false; } else { return true; } -#undef AH_RX_TIME_QUANTUM #undef AH_RX_STOP_DMA_TIMEOUT } EXPORT_SYMBOL(ath9k_hw_stopdmarecv); @@ -836,10 +817,14 @@ EXPORT_SYMBOL(ath9k_hw_disable_interrupts); void ath9k_hw_enable_interrupts(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); + u32 sync_default = AR_INTR_SYNC_DEFAULT; if (!(ah->imask & ATH9K_INT_GLOBAL)) return; + if (AR_SREV_9340(ah)) + sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; + ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_ENABLE); if (!AR_SREV_9100(ah)) { @@ -848,10 +833,8 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, - AR_INTR_SYNC_DEFAULT); - REG_WRITE(ah, AR_INTR_SYNC_MASK, - AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); + REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default); } ath_dbg(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); @@ -907,6 +890,9 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) mask |= AR_IMR_GENTMR; } + if (ints & ATH9K_INT_GENTIMER) + mask |= AR_IMR_GENTMR; + if (ints & (ATH9K_INT_BMISC)) { mask |= AR_IMR_BCNMISC; if (ints & ATH9K_INT_TIM) diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index b2b2ff852c32..b60c130917f7 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -239,7 +239,6 @@ struct ath_desc { void *ds_vdata; } __packed __aligned(4); -#define ATH9K_TXDESC_CLRDMASK 0x0001 #define ATH9K_TXDESC_NOACK 0x0002 #define ATH9K_TXDESC_RTSENA 0x0004 #define ATH9K_TXDESC_CTSENA 0x0008 @@ -695,7 +694,7 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp); void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning); void ath9k_hw_abortpcurecv(struct ath_hw *ah); -bool ath9k_hw_stopdmarecv(struct ath_hw *ah); +bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset); int ath9k_hw_beaconq_setup(struct ath_hw *ah); /* Interrupt Handling */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index dddb85de622d..17ebdf1e8b7b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -299,7 +299,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, NULL); + ath_set_beacon(sc); 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_ani(common); @@ -624,6 +624,43 @@ void ath_hw_check(struct work_struct *work) ath9k_ps_restore(sc); } +static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) +{ + static int count; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + if (pll_sqsum >= 0x40000) { + count++; + if (count == 3) { + /* Rx is hung for more than 500ms. Reset it */ + ath_dbg(common, ATH_DBG_RESET, + "Possible RX hang, resetting"); + ath_reset(sc, true); + count = 0; + } + } else + count = 0; +} + +void ath_hw_pll_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + hw_pll_work.work); + u32 pll_sqsum; + + if (AR_SREV_9485(sc->sc_ah)) { + + ath9k_ps_wakeup(sc); + pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); + ath9k_ps_restore(sc); + + ath_hw_pll_rx_hang_check(sc, pll_sqsum); + + ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); + } +} + + void ath9k_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; @@ -652,6 +689,17 @@ void ath9k_tasklet(unsigned long data) !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 + * the next Beacon. + */ + ath_dbg(common, ATH_DBG_PS, + "TSFOOR - Sync with next Beacon\n"); + sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC | + PS_TSFOOR_SYNC; + } + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); @@ -674,16 +722,6 @@ void ath9k_tasklet(unsigned long data) ath_tx_tasklet(sc); } - if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { - /* - * TSF sync does not look correct; remain awake to sync with - * the next Beacon. - */ - ath_dbg(common, ATH_DBG_PS, - "TSFOOR - Sync with next Beacon\n"); - sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; - } - if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) if (status & ATH9K_INT_GENTIMER) ath_gen_timer_isr(sc->sc_ah); @@ -828,48 +866,6 @@ irqreturn_t ath_isr(int irq, void *dev) #undef SCHED_INTR } -static void ath9k_bss_assoc_info(struct ath_softc *sc, - struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - - if (bss_conf->assoc) { - ath_dbg(common, ATH_DBG_CONFIG, - "Bss Info ASSOC %d, bssid: %pM\n", - bss_conf->aid, common->curbssid); - - /* New association, store aid */ - common->curaid = bss_conf->aid; - ath9k_hw_write_associd(ah); - - /* - * Request a re-configuration of Beacon related timers - * on the receipt of the first Beacon frame (i.e., - * after time sync with the AP). - */ - sc->ps_flags |= PS_BEACON_SYNC; - - /* Configure the beacon */ - ath_beacon_config(sc, vif); - - /* Reset rssi stats */ - sc->last_rssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - - sc->sc_flags |= SC_OP_ANI_RUN; - ath_start_ani(common); - } else { - ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); - common->curaid = 0; - /* Stop ANI */ - sc->sc_flags &= ~SC_OP_ANI_RUN; - del_timer_sync(&common->ani.timer); - } -} - void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; @@ -899,7 +895,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) goto out; } if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, NULL); /* restart beacons */ + ath_set_beacon(sc); /* restart beacons */ /* Re-Enable interrupts */ ath9k_hw_set_interrupts(ah, ah->imask); @@ -1006,7 +1002,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) sc->config.txpowlimit, &sc->curtxpow); if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) - ath_beacon_config(sc, NULL); /* restart beacons */ + ath_set_beacon(sc); /* restart beacons */ ath9k_hw_set_interrupts(ah, ah->imask); @@ -1376,7 +1372,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ath9k_calculate_iter_data(hw, vif, &iter_data); - ath9k_ps_wakeup(sc); /* Set BSSID mask. */ memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); ath_hw_setbssidmask(common); @@ -1390,7 +1385,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ath9k_hw_set_tsfadjust(ah, 0); sc->sc_flags &= ~SC_OP_TSF_RESET; - if (iter_data.nwds + iter_data.nmeshes) + if (iter_data.nmeshes) + ah->opmode = NL80211_IFTYPE_MESH_POINT; + else if (iter_data.nwds) ah->opmode = NL80211_IFTYPE_AP; else if (iter_data.nadhocs) ah->opmode = NL80211_IFTYPE_ADHOC; @@ -1411,10 +1408,10 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, } ath9k_hw_set_interrupts(ah, ah->imask); - ath9k_ps_restore(sc); /* Set up ANI */ if ((iter_data.naps + iter_data.nadhocs) > 0) { + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); } else { @@ -1454,9 +1451,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - struct ath_vif *avp = (void *)vif->drv_priv; int ret = 0; + ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); switch (vif->type) { @@ -1483,8 +1480,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, } } - if ((vif->type == NL80211_IFTYPE_ADHOC) && - sc->nvifs > 0) { + if ((ah->opmode == NL80211_IFTYPE_ADHOC) || + ((vif->type == NL80211_IFTYPE_ADHOC) && + sc->nvifs > 0)) { ath_err(common, "Cannot create ADHOC interface when other" " interfaces already exist.\n"); ret = -EINVAL; @@ -1494,15 +1492,12 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath_dbg(common, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", vif->type); - /* Set the VIF opmode */ - avp->av_opmode = vif->type; - avp->av_bslot = -1; - sc->nvifs++; ath9k_do_vif_add_setup(hw, vif); out: mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); return ret; } @@ -1517,6 +1512,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n"); mutex_lock(&sc->mutex); + ath9k_ps_wakeup(sc); /* See if new interface type is valid. */ if ((new_type == NL80211_IFTYPE_ADHOC) && @@ -1546,6 +1542,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, ath9k_do_vif_add_setup(hw, vif); out: + ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); return ret; } @@ -1558,6 +1555,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n"); + ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); sc->nvifs--; @@ -1569,6 +1567,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath9k_calculate_summary_state(hw, NULL); mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); } static void ath9k_enable_ps(struct ath_softc *sc) @@ -1778,23 +1777,68 @@ static int ath9k_sta_add(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_node *an = (struct ath_node *) sta->drv_priv; + struct ieee80211_key_conf ps_key = { }; ath_node_attach(sc, sta); + if (vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_AP_VLAN) + return 0; + + an->ps_key = ath_key_config(common, vif, sta, &ps_key); + return 0; } +static void ath9k_del_ps_key(struct ath_softc *sc, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_node *an = (struct ath_node *) sta->drv_priv; + struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key }; + + if (!an->ps_key) + return; + + ath_key_delete(common, &ps_key); +} + static int ath9k_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct ath_softc *sc = hw->priv; + ath9k_del_ps_key(sc, vif, sta); ath_node_detach(sc, sta); return 0; } +static void ath9k_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + struct ath_softc *sc = hw->priv; + struct ath_node *an = (struct ath_node *) sta->drv_priv; + + switch (cmd) { + case STA_NOTIFY_SLEEP: + an->sleeping = true; + if (ath_tx_aggr_sleep(sc, an)) + ieee80211_sta_set_tim(sta); + break; + case STA_NOTIFY_AWAKE: + an->sleeping = false; + ath_tx_aggr_wakeup(sc, an); + break; + } +} + static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { @@ -1809,6 +1853,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, txq = sc->tx.txq_map[queue]; + ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); @@ -1832,6 +1877,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, ath_beaconq_config(sc); mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); return ret; } @@ -1849,12 +1895,29 @@ static int ath9k_set_key(struct ieee80211_hw *hw, if (ath9k_modparam_nohwcrypt) return -ENOSPC; + if (vif->type == NL80211_IFTYPE_ADHOC && + (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 to use a modified key cache + * design to support per-STA RX GTK, 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(&sc->mutex); ath9k_ps_wakeup(sc); ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n"); switch (cmd) { case SET_KEY: + if (sta) + ath9k_del_ps_key(sc, vif, sta); + ret = ath_key_config(common, vif, sta, key); if (ret >= 0) { key->hw_key_idx = ret; @@ -1880,6 +1943,92 @@ static int ath9k_set_key(struct ieee80211_hw *hw, return ret; } +static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_softc *sc = data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_vif *avp = (void *)vif->drv_priv; + + switch (sc->sc_ah->opmode) { + case NL80211_IFTYPE_ADHOC: + /* There can be only one vif available */ + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + common->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah); + /* configure beacon */ + if (bss_conf->enable_beacon) + ath_beacon_config(sc, vif); + break; + case NL80211_IFTYPE_STATION: + /* + * Skip iteration if primary station vif's bss info + * was not changed + */ + if (sc->sc_flags & SC_OP_PRIM_STA_VIF) + break; + + if (bss_conf->assoc) { + sc->sc_flags |= SC_OP_PRIM_STA_VIF; + avp->primary_sta_vif = true; + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + common->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah); + ath_dbg(common, ATH_DBG_CONFIG, + "Bss Info ASSOC %d, bssid: %pM\n", + bss_conf->aid, common->curbssid); + ath_beacon_config(sc, vif); + /* + * Request a re-configuration of Beacon related timers + * on the receipt of the first Beacon frame (i.e., + * after time sync with the AP). + */ + sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; + /* Reset rssi stats */ + sc->last_rssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; + + sc->sc_flags |= SC_OP_ANI_RUN; + ath_start_ani(common); + } + break; + default: + break; + } +} + +static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_vif *avp = (void *)vif->drv_priv; + + /* Reconfigure bss info */ + if (avp->primary_sta_vif && !bss_conf->assoc) { + ath_dbg(common, ATH_DBG_CONFIG, + "Bss Info DISASSOC %d, bssid %pM\n", + common->curaid, common->curbssid); + sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS); + avp->primary_sta_vif = false; + memset(common->curbssid, 0, ETH_ALEN); + common->curaid = 0; + } + + ieee80211_iterate_active_interfaces_atomic( + sc->hw, ath9k_bss_iter, sc); + + /* + * None of station vifs are associated. + * Clear bssid & aid + */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && + !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) { + ath9k_hw_write_associd(sc->sc_ah); + /* Stop ANI */ + sc->sc_flags &= ~SC_OP_ANI_RUN; + del_timer_sync(&common->ani.timer); + } +} static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1887,30 +2036,20 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, u32 changed) { struct ath_softc *sc = hw->priv; - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; struct ath_hw *ah = sc->sc_ah; 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); if (changed & BSS_CHANGED_BSSID) { - /* Set BSSID */ - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); - common->curaid = 0; - ath9k_hw_write_associd(ah); - - /* Set aggregation protection mode parameters */ - sc->config.ath_aggr_prot = 0; + ath9k_config_bss(sc, vif); ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n", common->curbssid, common->curaid); - - /* need to reconfigure the beacon */ - sc->sc_flags &= ~SC_OP_BEACONS ; } /* Enable transmission of beacons (AP, IBSS, MESH) */ @@ -1951,7 +2090,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BEACON_INT) { - cur_conf->beacon_interval = bss_conf->beacon_int; /* * In case of AP mode, the HW TSF has to be reset * when the beacon interval changes. @@ -1963,9 +2101,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (!error) ath_beacon_config(sc, vif); ath9k_set_beaconing_status(sc, true); - } else { + } else ath_beacon_config(sc, vif); - } } if (changed & BSS_CHANGED_ERP_PREAMBLE) { @@ -1987,13 +2124,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; } - if (changed & BSS_CHANGED_ASSOC) { - ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", - bss_conf->assoc); - ath9k_bss_assoc_info(sc, hw, vif, bss_conf); - } - mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); } static u64 ath9k_get_tsf(struct ieee80211_hw *hw) @@ -2133,19 +2265,26 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) static void ath9k_flush(struct ieee80211_hw *hw, bool drop) { struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); int timeout = 200; /* ms */ int i, j; + bool drain_txq; - ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); - cancel_delayed_work_sync(&sc->tx_complete_work); + if (sc->sc_flags & SC_OP_INVALID) { + ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); + mutex_unlock(&sc->mutex); + return; + } + if (drop) timeout = 1; for (j = 0; j < timeout; j++) { - int npend = 0; + bool npend = false; if (j) usleep_range(1000, 2000); @@ -2154,22 +2293,43 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) if (!ATH_TXQ_SETUP(sc, i)) continue; - npend += ath9k_has_pending_frames(sc, &sc->tx.txq[i]); + npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]); + + if (npend) + break; } if (!npend) goto out; } - if (!ath_drain_all_txq(sc, false)) + ath9k_ps_wakeup(sc); + spin_lock_bh(&sc->sc_pcu_lock); + drain_txq = ath_drain_all_txq(sc, false); + spin_unlock_bh(&sc->sc_pcu_lock); + if (!drain_txq) ath_reset(sc, false); - + ath9k_ps_restore(sc); ieee80211_wake_queues(hw); out: ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); mutex_unlock(&sc->mutex); - ath9k_ps_restore(sc); +} + +static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + int i; + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (!ATH_TXQ_SETUP(sc, i)) + continue; + + if (ath9k_has_pending_frames(sc, &sc->tx.txq[i])) + return true; + } + return false; } struct ieee80211_ops ath9k_ops = { @@ -2183,6 +2343,7 @@ struct ieee80211_ops ath9k_ops = { .configure_filter = ath9k_configure_filter, .sta_add = ath9k_sta_add, .sta_remove = ath9k_sta_remove, + .sta_notify = ath9k_sta_notify, .conf_tx = ath9k_conf_tx, .bss_info_changed = ath9k_bss_info_changed, .set_key = ath9k_set_key, @@ -2194,4 +2355,5 @@ struct ieee80211_ops ath9k_ops = { .rfkill_poll = ath9k_rfkill_poll_state, .set_coverage_class = ath9k_set_coverage_class, .flush = ath9k_flush, + .tx_frames_pending = ath9k_tx_frames_pending, }; diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 5e3d7496986e..9441bf8ca2fd 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -19,7 +19,6 @@ #define CHANSEL_DIV 15 #define CHANSEL_2G(_freq) (((_freq) * 0x10000) / CHANSEL_DIV) -#define CHANSEL_2G_9485(_freq) ((((_freq) * 0x10000) - 215) / CHANSEL_DIV) #define CHANSEL_5G(_freq) (((_freq) * 0x8000) / CHANSEL_DIV) #define AR_PHY_BASE 0x9800 @@ -38,26 +37,15 @@ #define AR_PHY_CLC_Q0 0x0000ffd0 #define AR_PHY_CLC_Q0_S 5 -#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do { \ - int r; \ - for (r = 0; r < ((iniarray)->ia_rows); r++) { \ - REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \ - DO_DELAY(regWr); \ - } \ - } while (0) - #define ANTSWAP_AB 0x0001 #define REDUCE_CHAIN_0 0x00000050 #define REDUCE_CHAIN_1 0x00000051 #define AR_PHY_CHIP_ID 0x9818 -#define RF_BANK_SETUP(_bank, _iniarray, _col) do { \ - int i; \ - for (i = 0; i < (_iniarray)->ia_rows; i++) \ - (_bank)[i] = INI_RA((_iniarray), i, _col);; \ - } while (0) - #define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 #define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 +#define AR_PHY_PLL_CONTROL 0x16180 +#define AR_PHY_PLL_MODE 0x16184 + #endif diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 4c0d36a6980f..4ccbf2ddb553 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -854,14 +854,13 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, ath_rc_rate_set_rtscts(sc, rate_table, tx_info); } -static bool ath_rc_update_per(struct ath_softc *sc, +static void ath_rc_update_per(struct ath_softc *sc, const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv, struct ieee80211_tx_info *tx_info, int tx_rate, int xretries, int retries, u32 now_msec) { - bool state_change = false; int count, n_bad_frames; u8 last_per; static const u32 nretry_to_per_lookup[10] = { @@ -992,8 +991,6 @@ static bool ath_rc_update_per(struct ath_softc *sc, } } - - return state_change; } static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, @@ -1017,7 +1014,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, u32 now_msec = jiffies_to_msecs(jiffies); int rate; u8 last_per; - bool state_change = false; const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; int size = ath_rc_priv->rate_table_size; @@ -1027,9 +1023,9 @@ static void ath_rc_update_ht(struct ath_softc *sc, last_per = ath_rc_priv->per[tx_rate]; /* Update PER first */ - state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, - tx_info, tx_rate, xretries, - retries, now_msec); + ath_rc_update_per(sc, rate_table, ath_rc_priv, + tx_info, tx_rate, xretries, + retries, now_msec); /* * If this rate looks bad (high PER) then stop using it for @@ -1092,8 +1088,7 @@ static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, if (!(rate->flags & IEEE80211_TX_RC_MCS)) return rate->idx; - while (rate->idx > mcs_rix_off[i] && - i < ARRAY_SIZE(mcs_rix_off)) { + while (i < ARRAY_SIZE(mcs_rix_off) && rate->idx > mcs_rix_off[i]) { rix++; i++; } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a9c3f4672aa0..4f52e0429f99 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -28,6 +28,33 @@ static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50); } +static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio, + int curr_main_set, int curr_alt_set, + int alt_rssi_avg, int main_rssi_avg) +{ + bool result = false; + switch (div_group) { + case 0: + if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) + result = true; + break; + case 1: + if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) && + (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) && + (alt_rssi_avg >= (main_rssi_avg - 5))) || + ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) && + (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) && + (alt_rssi_avg >= (main_rssi_avg - 2)))) && + (alt_rssi_avg >= 4)) + result = true; + else + result = false; + break; + } + + return result; +} + static inline bool ath9k_check_auto_sleep(struct ath_softc *sc) { return sc->ps_enabled && @@ -75,7 +102,6 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) *sc->rx.rxlink = bf->bf_daddr; sc->rx.rxlink = &ds->ds_link; - ath9k_hw_rxena(ah); } static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) @@ -426,9 +452,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) else rfilt |= ATH9K_RX_FILTER_BEACON; - if ((AR_SREV_9280_20_OR_LATER(sc->sc_ah) || - AR_SREV_9285_12_OR_LATER(sc->sc_ah)) && - (sc->sc_ah->opmode == NL80211_IFTYPE_AP) && + if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || (sc->rx.rxfilter & FIF_PSPOLL)) rfilt |= ATH9K_RX_FILTER_PSPOLL; @@ -486,12 +510,12 @@ int ath_startrecv(struct ath_softc *sc) bool ath_stoprecv(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - bool stopped; + bool stopped, reset = false; spin_lock_bh(&sc->rx.rxbuflock); ath9k_hw_abortpcurecv(ah); ath9k_hw_setrxfilter(ah, 0); - stopped = ath9k_hw_stopdmarecv(ah); + stopped = ath9k_hw_stopdmarecv(ah, &reset); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ath_edma_stop_recv(sc); @@ -506,7 +530,7 @@ bool ath_stoprecv(struct ath_softc *sc) "confusing the DMA engine when we start RX up\n"); ATH_DBG_WARN_ON_ONCE(!stopped); } - return stopped; + return stopped && !reset; } void ath_flushrecv(struct ath_softc *sc) @@ -574,7 +598,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, ATH_DBG_PS, "Reconfigure Beacon timers based on timestamp from the AP\n"); - ath_beacon_config(sc, NULL); + ath_set_beacon(sc); + sc->ps_flags &= ~PS_TSFOOR_SYNC; } if (ath_beacon_dtim_pending_cab(skb)) { @@ -919,7 +944,8 @@ static void ath9k_process_rssi(struct ath_common *common, int last_rssi; __le16 fc; - if (ah->opmode != NL80211_IFTYPE_STATION) + if ((ah->opmode != NL80211_IFTYPE_STATION) && + (ah->opmode != NL80211_IFTYPE_ADHOC)) return; fc = hdr->frame_control; @@ -1291,49 +1317,138 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, } } -static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf) +static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, + struct ath_ant_comb *antcomb, int alt_ratio) { - /* Adjust the fast_div_bias based on main and alt lna conf */ - switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) { - case (0x01): /* A-B LNA2 */ - ant_conf->fast_div_bias = 0x3b; - break; - case (0x02): /* A-B LNA1 */ - ant_conf->fast_div_bias = 0x3d; - break; - case (0x03): /* A-B A+B */ - ant_conf->fast_div_bias = 0x1; - break; - case (0x10): /* LNA2 A-B */ - ant_conf->fast_div_bias = 0x7; - break; - case (0x12): /* LNA2 LNA1 */ - ant_conf->fast_div_bias = 0x2; - break; - case (0x13): /* LNA2 A+B */ - ant_conf->fast_div_bias = 0x7; - break; - case (0x20): /* LNA1 A-B */ - ant_conf->fast_div_bias = 0x6; - break; - case (0x21): /* LNA1 LNA2 */ - ant_conf->fast_div_bias = 0x0; - break; - case (0x23): /* LNA1 A+B */ - ant_conf->fast_div_bias = 0x6; - break; - case (0x30): /* A+B A-B */ - ant_conf->fast_div_bias = 0x1; - break; - case (0x31): /* A+B LNA2 */ - ant_conf->fast_div_bias = 0x3b; - break; - case (0x32): /* A+B LNA1 */ - ant_conf->fast_div_bias = 0x3d; - break; - default: - break; + if (ant_conf->div_group == 0) { + /* Adjust the fast_div_bias based on main and alt lna conf */ + switch ((ant_conf->main_lna_conf << 4) | + ant_conf->alt_lna_conf) { + case (0x01): /* A-B LNA2 */ + ant_conf->fast_div_bias = 0x3b; + break; + case (0x02): /* A-B LNA1 */ + ant_conf->fast_div_bias = 0x3d; + break; + case (0x03): /* A-B A+B */ + ant_conf->fast_div_bias = 0x1; + break; + case (0x10): /* LNA2 A-B */ + ant_conf->fast_div_bias = 0x7; + break; + case (0x12): /* LNA2 LNA1 */ + ant_conf->fast_div_bias = 0x2; + break; + case (0x13): /* LNA2 A+B */ + ant_conf->fast_div_bias = 0x7; + break; + case (0x20): /* LNA1 A-B */ + ant_conf->fast_div_bias = 0x6; + break; + case (0x21): /* LNA1 LNA2 */ + ant_conf->fast_div_bias = 0x0; + break; + case (0x23): /* LNA1 A+B */ + ant_conf->fast_div_bias = 0x6; + break; + case (0x30): /* A+B A-B */ + ant_conf->fast_div_bias = 0x1; + break; + case (0x31): /* A+B LNA2 */ + ant_conf->fast_div_bias = 0x3b; + break; + case (0x32): /* A+B LNA1 */ + ant_conf->fast_div_bias = 0x3d; + break; + default: + break; + } + } else if (ant_conf->div_group == 2) { + /* Adjust the fast_div_bias based on main and alt_lna_conf */ + switch ((ant_conf->main_lna_conf << 4) | + ant_conf->alt_lna_conf) { + case (0x01): /* A-B LNA2 */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x02): /* A-B LNA1 */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x03): /* A-B A+B */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x10): /* LNA2 A-B */ + if (!(antcomb->scan) && + (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + ant_conf->fast_div_bias = 0x1; + else + ant_conf->fast_div_bias = 0x2; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x12): /* LNA2 LNA1 */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x13): /* LNA2 A+B */ + if (!(antcomb->scan) && + (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + ant_conf->fast_div_bias = 0x1; + else + ant_conf->fast_div_bias = 0x2; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x20): /* LNA1 A-B */ + if (!(antcomb->scan) && + (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + ant_conf->fast_div_bias = 0x1; + else + ant_conf->fast_div_bias = 0x2; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x21): /* LNA1 LNA2 */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x23): /* LNA1 A+B */ + if (!(antcomb->scan) && + (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + ant_conf->fast_div_bias = 0x1; + else + ant_conf->fast_div_bias = 0x2; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x30): /* A+B A-B */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x31): /* A+B LNA2 */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x32): /* A+B LNA1 */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + default: + break; + } + } + } /* Antenna diversity and combining */ @@ -1342,7 +1457,7 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) struct ath_hw_antcomb_conf div_ant_conf; struct ath_ant_comb *antcomb = &sc->ant_comb; int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; - int curr_main_set, curr_bias; + int curr_main_set; int main_rssi = rs->rs_rssi_ctl0; int alt_rssi = rs->rs_rssi_ctl1; int rx_ant_conf, main_ant_conf; @@ -1353,8 +1468,8 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) & ATH_ANT_RX_MASK; - /* Record packet only when alt_rssi is positive */ - if (alt_rssi > 0) { + /* Record packet only when both main_rssi and alt_rssi is positive */ + if (main_rssi > 0 && alt_rssi > 0) { antcomb->total_pkt_count++; antcomb->main_total_rssi += main_rssi; antcomb->alt_total_rssi += alt_rssi; @@ -1396,7 +1511,6 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf); curr_alt_set = div_ant_conf.alt_lna_conf; curr_main_set = div_ant_conf.main_lna_conf; - curr_bias = div_ant_conf.fast_div_bias; antcomb->count++; @@ -1415,7 +1529,9 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) } if (!antcomb->scan) { - if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { + if (ath_ant_div_comb_alt_check(div_ant_conf.div_group, + alt_ratio, curr_main_set, curr_alt_set, + alt_rssi_avg, main_rssi_avg)) { if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) { /* Switch main and alt LNA */ div_ant_conf.main_lna_conf = @@ -1444,7 +1560,7 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) } if ((alt_rssi_avg < (main_rssi_avg + - ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA))) + div_ant_conf.lna1_lna2_delta))) goto div_comb_done; } @@ -1558,8 +1674,7 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) antcomb->quick_scan_cnt++; div_comb_done: - ath_ant_div_conf_fast_divbias(&div_ant_conf); - + ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio); ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf); antcomb->scan_start_time = jiffies; @@ -1746,7 +1861,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA)) || - unlikely(ath9k_check_auto_sleep(sc))) + ath9k_check_auto_sleep(sc)) ath_rx_ps(sc, skb); spin_unlock_irqrestore(&sc->sc_pm_lock, flags); @@ -1767,6 +1882,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) } else { list_move_tail(&bf->list, &sc->rx.rxbuf); ath_rx_buf_link(sc, bf); + ath9k_hw_rxena(ah); } } while (1); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 8fa8acfde62e..456f3ec20fef 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -693,7 +693,7 @@ #define AR_RC_APB 0x00000002 #define AR_RC_HOSTIF 0x00000100 -#define AR_WA 0x4004 +#define AR_WA (AR_SREV_9340(ah) ? 0x40c4 : 0x4004) #define AR_WA_BIT6 (1 << 6) #define AR_WA_BIT7 (1 << 7) #define AR_WA_BIT23 (1 << 23) @@ -712,7 +712,7 @@ #define AR_PM_STATE 0x4008 #define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000 -#define AR_HOST_TIMEOUT 0x4018 +#define AR_HOST_TIMEOUT (AR_SREV_9340(ah) ? 0x4008 : 0x4018) #define AR_HOST_TIMEOUT_APB_CNTR 0x0000FFFF #define AR_HOST_TIMEOUT_APB_CNTR_S 0 #define AR_HOST_TIMEOUT_LCL_CNTR 0xFFFF0000 @@ -742,7 +742,8 @@ #define EEPROM_PROTECT_WP_1024_2047 0x8000 #define AR_SREV \ - ((AR_SREV_9100(ah)) ? 0x0600 : 0x4020) + ((AR_SREV_9100(ah)) ? 0x0600 : (AR_SREV_9340(ah) \ + ? 0x400c : 0x4020)) #define AR_SREV_ID \ ((AR_SREV_9100(ah)) ? 0x00000FFF : 0x000000FF) @@ -790,6 +791,7 @@ #define AR_SREV_VERSION_9485 0x240 #define AR_SREV_REVISION_9485_10 0 #define AR_SREV_REVISION_9485_11 1 +#define AR_SREV_VERSION_9340 0x300 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -858,9 +860,7 @@ #define AR_SREV_9300(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300)) #define AR_SREV_9300_20_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9300) || \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \ - ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9300_20))) + ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300) #define AR_SREV_9485(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485)) @@ -870,6 +870,11 @@ #define AR_SREV_9485_11(_ah) \ (AR_SREV_9485(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11)) +#define AR_SREV_9485_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485)) + +#define AR_SREV_9340(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340)) #define AR_SREV_9285E_20(_ah) \ (AR_SREV_9285_12_OR_LATER(_ah) && \ @@ -912,11 +917,11 @@ enum ath_usb_dev { #define AR_INTR_SPURIOUS 0xFFFFFFFF -#define AR_INTR_SYNC_CAUSE_CLR 0x4028 +#define AR_INTR_SYNC_CAUSE (AR_SREV_9340(ah) ? 0x4010 : 0x4028) +#define AR_INTR_SYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4010 : 0x4028) -#define AR_INTR_SYNC_CAUSE 0x4028 -#define AR_INTR_SYNC_ENABLE 0x402c +#define AR_INTR_SYNC_ENABLE (AR_SREV_9340(ah) ? 0x4014 : 0x402c) #define AR_INTR_SYNC_ENABLE_GPIO 0xFFFC0000 #define AR_INTR_SYNC_ENABLE_GPIO_S 18 @@ -956,24 +961,24 @@ enum { }; -#define AR_INTR_ASYNC_MASK 0x4030 +#define AR_INTR_ASYNC_MASK (AR_SREV_9340(ah) ? 0x4018 : 0x4030) #define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000 #define AR_INTR_ASYNC_MASK_GPIO_S 18 -#define AR_INTR_SYNC_MASK 0x4034 +#define AR_INTR_SYNC_MASK (AR_SREV_9340(ah) ? 0x401c : 0x4034) #define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000 #define AR_INTR_SYNC_MASK_GPIO_S 18 -#define AR_INTR_ASYNC_CAUSE_CLR 0x4038 -#define AR_INTR_ASYNC_CAUSE 0x4038 +#define AR_INTR_ASYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4020 : 0x4038) +#define AR_INTR_ASYNC_CAUSE (AR_SREV_9340(ah) ? 0x4020 : 0x4038) -#define AR_INTR_ASYNC_ENABLE 0x403c +#define AR_INTR_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4024 : 0x403c) #define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000 #define AR_INTR_ASYNC_ENABLE_GPIO_S 18 #define AR_PCIE_SERDES 0x4040 #define AR_PCIE_SERDES2 0x4044 -#define AR_PCIE_PM_CTRL 0x4014 +#define AR_PCIE_PM_CTRL (AR_SREV_9340(ah) ? 0x4004 : 0x4014) #define AR_PCIE_PM_CTRL_ENA 0x00080000 #define AR_NUM_GPIO 14 @@ -984,7 +989,7 @@ enum { #define AR9300_NUM_GPIO 17 #define AR7010_NUM_GPIO 16 -#define AR_GPIO_IN_OUT 0x4048 +#define AR_GPIO_IN_OUT (AR_SREV_9340(ah) ? 0x4028 : 0x4048) #define AR_GPIO_IN_VAL 0x0FFFC000 #define AR_GPIO_IN_VAL_S 14 #define AR928X_GPIO_IN_VAL 0x000FFC00 @@ -998,11 +1003,12 @@ enum { #define AR7010_GPIO_IN_VAL 0x0000FFFF #define AR7010_GPIO_IN_VAL_S 0 -#define AR_GPIO_IN 0x404c +#define AR_GPIO_IN (AR_SREV_9340(ah) ? 0x402c : 0x404c) #define AR9300_GPIO_IN_VAL 0x0001FFFF #define AR9300_GPIO_IN_VAL_S 0 -#define AR_GPIO_OE_OUT (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c) +#define AR_GPIO_OE_OUT (AR_SREV_9340(ah) ? 0x4030 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)) #define AR_GPIO_OE_OUT_DRV 0x3 #define AR_GPIO_OE_OUT_DRV_NO 0x0 #define AR_GPIO_OE_OUT_DRV_LOW 0x1 @@ -1024,11 +1030,13 @@ enum { #define AR7010_GPIO_INT_MASK 0x52024 #define AR7010_GPIO_FUNCTION 0x52028 -#define AR_GPIO_INTR_POL (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050) +#define AR_GPIO_INTR_POL (AR_SREV_9340(ah) ? 0x4038 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050)) #define AR_GPIO_INTR_POL_VAL 0x0001FFFF #define AR_GPIO_INTR_POL_VAL_S 0 -#define AR_GPIO_INPUT_EN_VAL (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054) +#define AR_GPIO_INPUT_EN_VAL (AR_SREV_9340(ah) ? 0x403c : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054)) #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF 0x00000004 #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S 2 #define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF 0x00000008 @@ -1046,13 +1054,15 @@ enum { #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 #define AR_GPIO_JTAG_DISABLE 0x00020000 -#define AR_GPIO_INPUT_MUX1 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058) +#define AR_GPIO_INPUT_MUX1 (AR_SREV_9340(ah) ? 0x4040 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058)) #define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8 -#define AR_GPIO_INPUT_MUX2 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c) +#define AR_GPIO_INPUT_MUX2 (AR_SREV_9340(ah) ? 0x4044 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c)) #define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f #define AR_GPIO_INPUT_MUX2_CLK25_S 0 #define AR_GPIO_INPUT_MUX2_RFSILENT 0x000000f0 @@ -1060,13 +1070,18 @@ enum { #define AR_GPIO_INPUT_MUX2_RTC_RESET 0x00000f00 #define AR_GPIO_INPUT_MUX2_RTC_RESET_S 8 -#define AR_GPIO_OUTPUT_MUX1 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060) -#define AR_GPIO_OUTPUT_MUX2 (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064) -#define AR_GPIO_OUTPUT_MUX3 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068) +#define AR_GPIO_OUTPUT_MUX1 (AR_SREV_9340(ah) ? 0x4048 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060)) +#define AR_GPIO_OUTPUT_MUX2 (AR_SREV_9340(ah) ? 0x404c : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064)) +#define AR_GPIO_OUTPUT_MUX3 (AR_SREV_9340(ah) ? 0x4050 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068)) -#define AR_INPUT_STATE (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c) +#define AR_INPUT_STATE (AR_SREV_9340(ah) ? 0x4054 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c)) -#define AR_EEPROM_STATUS_DATA (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c) +#define AR_EEPROM_STATUS_DATA (AR_SREV_9340(ah) ? 0x40c8 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c)) #define AR_EEPROM_STATUS_DATA_VAL 0x0000ffff #define AR_EEPROM_STATUS_DATA_VAL_S 0 #define AR_EEPROM_STATUS_DATA_BUSY 0x00010000 @@ -1074,28 +1089,51 @@ enum { #define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000 #define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000 -#define AR_OBS (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080) +#define AR_OBS (AR_SREV_9340(ah) ? 0x405c : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080)) #define AR_GPIO_PDPU (AR_SREV_9300_20_OR_LATER(ah) ? 0x4090 : 0x4088) -#define AR_PCIE_MSI (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094) +#define AR_PCIE_MSI (AR_SREV_9340(ah) ? 0x40d8 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094)) #define AR_PCIE_MSI_ENABLE 0x00000001 -#define AR_INTR_PRIO_SYNC_ENABLE 0x40c4 -#define AR_INTR_PRIO_ASYNC_MASK 0x40c8 -#define AR_INTR_PRIO_SYNC_MASK 0x40cc -#define AR_INTR_PRIO_ASYNC_ENABLE 0x40d4 +#define AR_INTR_PRIO_SYNC_ENABLE (AR_SREV_9340(ah) ? 0x4088 : 0x40c4) +#define AR_INTR_PRIO_ASYNC_MASK (AR_SREV_9340(ah) ? 0x408c : 0x40c8) +#define AR_INTR_PRIO_SYNC_MASK (AR_SREV_9340(ah) ? 0x4090 : 0x40cc) +#define AR_INTR_PRIO_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4094 : 0x40d4) #define AR_ENT_OTP 0x40d8 #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 #define AR_ENT_OTP_MPSD 0x00800000 -#define AR_CH0_BB_DPLL2 0x16184 -#define AR_CH0_BB_DPLL3 0x16188 -#define AR_CH0_DDR_DPLL2 0x16244 -#define AR_CH0_DDR_DPLL3 0x16248 -#define AR_CH0_DPLL2_KD 0x03F80000 -#define AR_CH0_DPLL2_KD_S 19 + +#define AR_CH0_BB_DPLL1 0x16180 +#define AR_CH0_BB_DPLL1_REFDIV 0xF8000000 +#define AR_CH0_BB_DPLL1_REFDIV_S 27 +#define AR_CH0_BB_DPLL1_NINI 0x07FC0000 +#define AR_CH0_BB_DPLL1_NINI_S 18 +#define AR_CH0_BB_DPLL1_NFRAC 0x0003FFFF +#define AR_CH0_BB_DPLL1_NFRAC_S 0 + +#define AR_CH0_BB_DPLL2 0x16184 +#define AR_CH0_BB_DPLL2_LOCAL_PLL 0x40000000 +#define AR_CH0_BB_DPLL2_LOCAL_PLL_S 30 #define AR_CH0_DPLL2_KI 0x3C000000 #define AR_CH0_DPLL2_KI_S 26 +#define AR_CH0_DPLL2_KD 0x03F80000 +#define AR_CH0_DPLL2_KD_S 19 +#define AR_CH0_BB_DPLL2_EN_NEGTRIG 0x00040000 +#define AR_CH0_BB_DPLL2_EN_NEGTRIG_S 18 +#define AR_CH0_BB_DPLL2_PLL_PWD 0x00010000 +#define AR_CH0_BB_DPLL2_PLL_PWD_S 16 +#define AR_CH0_BB_DPLL2_OUTDIV 0x0000E000 +#define AR_CH0_BB_DPLL2_OUTDIV_S 13 + +#define AR_CH0_BB_DPLL3 0x16188 +#define AR_CH0_BB_DPLL3_PHASE_SHIFT 0x3F800000 +#define AR_CH0_BB_DPLL3_PHASE_SHIFT_S 23 + +#define AR_CH0_DDR_DPLL2 0x16244 +#define AR_CH0_DDR_DPLL3 0x16248 #define AR_CH0_DPLL3_PHASE_SHIFT 0x3F800000 #define AR_CH0_DPLL3_PHASE_SHIFT_S 23 #define AR_PHY_CCA_NOM_VAL_2GHZ -118 @@ -1144,6 +1182,7 @@ enum { #define AR_RTC_PLL_REFDIV_5 0x000000c0 #define AR_RTC_PLL_CLKSEL 0x00000300 #define AR_RTC_PLL_CLKSEL_S 8 +#define AR_RTC_PLL_BYPASS 0x00010000 #define PLL3 0x16188 #define PLL3_DO_MEAS_MASK 0x40000000 @@ -1190,7 +1229,8 @@ enum { /* RTC_DERIVED_* - only for AR9100 */ -#define AR_RTC_DERIVED_CLK (AR_RTC_BASE + 0x0038) +#define AR_RTC_DERIVED_CLK \ + (AR_SREV_9100(ah) ? (AR_RTC_BASE + 0x0038) : 0x7038) #define AR_RTC_DERIVED_CLK_PERIOD 0x0000fffe #define AR_RTC_DERIVED_CLK_PERIOD_S 1 @@ -1396,6 +1436,7 @@ enum { #define AR_STA_ID1_PCF 0x00100000 #define AR_STA_ID1_USE_DEFANT 0x00200000 #define AR_STA_ID1_DEFANT_UPDATE 0x00400000 +#define AR_STA_ID1_AR9100_BA_FIX 0x00400000 #define AR_STA_ID1_RTS_USE_DEF 0x00800000 #define AR_STA_ID1_ACKCTS_6MB 0x01000000 #define AR_STA_ID1_BASE_RATE_11B 0x02000000 @@ -1668,6 +1709,22 @@ enum { #define AR_BTCOEX_WL_WGHT 0xffff0000 #define AR_BTCOEX_WL_WGHT_S 16 +#define AR_BT_COEX_WL_WEIGHTS0 0x8174 +#define AR_BT_COEX_WL_WEIGHTS1 0x81c4 + +#define AR_BT_COEX_BT_WEIGHTS0 0x83ac +#define AR_BT_COEX_BT_WEIGHTS1 0x83b0 +#define AR_BT_COEX_BT_WEIGHTS2 0x83b4 +#define AR_BT_COEX_BT_WEIGHTS3 0x83b8 + +#define AR9300_BT_WGHT 0xcccc4444 +#define AR9300_STOMP_ALL_WLAN_WGHT0 0xfffffff0 +#define AR9300_STOMP_ALL_WLAN_WGHT1 0xfffffff0 +#define AR9300_STOMP_LOW_WLAN_WGHT0 0x88888880 +#define AR9300_STOMP_LOW_WLAN_WGHT1 0x88888880 +#define AR9300_STOMP_NONE_WLAN_WGHT0 0x00000000 +#define AR9300_STOMP_NONE_WLAN_WGHT1 0x00000000 + #define AR_BT_COEX_MODE2 0x817c #define AR_BT_BCN_MISS_THRESH 0x000000ff #define AR_BT_BCN_MISS_THRESH_S 0 diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index d3d24904f62f..f9b1eb4853c4 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -23,20 +23,18 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_ECHO_CMDID"; case WMI_ACCESS_MEMORY_CMDID: return "WMI_ACCESS_MEMORY_CMDID"; + case WMI_GET_FW_VERSION: + return "WMI_GET_FW_VERSION"; case WMI_DISABLE_INTR_CMDID: return "WMI_DISABLE_INTR_CMDID"; case WMI_ENABLE_INTR_CMDID: return "WMI_ENABLE_INTR_CMDID"; - case WMI_RX_LINK_CMDID: - return "WMI_RX_LINK_CMDID"; case WMI_ATH_INIT_CMDID: return "WMI_ATH_INIT_CMDID"; case WMI_ABORT_TXQ_CMDID: return "WMI_ABORT_TXQ_CMDID"; case WMI_STOP_TX_DMA_CMDID: return "WMI_STOP_TX_DMA_CMDID"; - case WMI_STOP_DMA_RECV_CMDID: - return "WMI_STOP_DMA_RECV_CMDID"; case WMI_ABORT_TX_DMA_CMDID: return "WMI_ABORT_TX_DMA_CMDID"; case WMI_DRAIN_TXQ_CMDID: @@ -51,8 +49,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_FLUSH_RECV_CMDID"; case WMI_SET_MODE_CMDID: return "WMI_SET_MODE_CMDID"; - case WMI_RESET_CMDID: - return "WMI_RESET_CMDID"; case WMI_NODE_CREATE_CMDID: return "WMI_NODE_CREATE_CMDID"; case WMI_NODE_REMOVE_CMDID: @@ -61,8 +57,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_VAP_REMOVE_CMDID"; case WMI_VAP_CREATE_CMDID: return "WMI_VAP_CREATE_CMDID"; - case WMI_BEACON_UPDATE_CMDID: - return "WMI_BEACON_UPDATE_CMDID"; case WMI_REG_READ_CMDID: return "WMI_REG_READ_CMDID"; case WMI_REG_WRITE_CMDID: @@ -71,22 +65,22 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_RC_STATE_CHANGE_CMDID"; case WMI_RC_RATE_UPDATE_CMDID: return "WMI_RC_RATE_UPDATE_CMDID"; - case WMI_DEBUG_INFO_CMDID: - return "WMI_DEBUG_INFO_CMDID"; - case WMI_HOST_ATTACH: - return "WMI_HOST_ATTACH"; case WMI_TARGET_IC_UPDATE_CMDID: return "WMI_TARGET_IC_UPDATE_CMDID"; - case WMI_TGT_STATS_CMDID: - return "WMI_TGT_STATS_CMDID"; case WMI_TX_AGGR_ENABLE_CMDID: return "WMI_TX_AGGR_ENABLE_CMDID"; case WMI_TGT_DETACH_CMDID: return "WMI_TGT_DETACH_CMDID"; - case WMI_TGT_TXQ_ENABLE_CMDID: - return "WMI_TGT_TXQ_ENABLE_CMDID"; - case WMI_AGGR_LIMIT_CMD: - return "WMI_AGGR_LIMIT_CMD"; + case WMI_NODE_UPDATE_CMDID: + return "WMI_NODE_UPDATE_CMDID"; + case WMI_INT_STATS_CMDID: + return "WMI_INT_STATS_CMDID"; + case WMI_TX_STATS_CMDID: + return "WMI_TX_STATS_CMDID"; + case WMI_RX_STATS_CMDID: + return "WMI_RX_STATS_CMDID"; + case WMI_BITRATE_MASK_CMDID: + return "WMI_BITRATE_MASK_CMDID"; } return "Bogus"; @@ -102,9 +96,15 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv) wmi->drv_priv = priv; wmi->stopped = false; + skb_queue_head_init(&wmi->wmi_event_queue); + spin_lock_init(&wmi->wmi_lock); + spin_lock_init(&wmi->event_lock); mutex_init(&wmi->op_mutex); mutex_init(&wmi->multi_write_mutex); init_completion(&wmi->cmd_wait); + INIT_LIST_HEAD(&wmi->pending_tx_events); + tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet, + (unsigned long)wmi); return wmi; } @@ -120,11 +120,65 @@ void ath9k_deinit_wmi(struct ath9k_htc_priv *priv) kfree(priv->wmi); } -void ath9k_swba_tasklet(unsigned long data) +void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv) { - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; + unsigned long flags; - ath9k_htc_swba(priv, priv->wmi->beacon_pending); + tasklet_kill(&priv->wmi->wmi_event_tasklet); + spin_lock_irqsave(&priv->wmi->wmi_lock, flags); + __skb_queue_purge(&priv->wmi->wmi_event_queue); + spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); +} + +void ath9k_wmi_event_tasklet(unsigned long data) +{ + struct wmi *wmi = (struct wmi *)data; + struct ath9k_htc_priv *priv = wmi->drv_priv; + struct wmi_cmd_hdr *hdr; + void *wmi_event; + struct wmi_event_swba *swba; + struct sk_buff *skb = NULL; + unsigned long flags; + u16 cmd_id; + + do { + spin_lock_irqsave(&wmi->wmi_lock, flags); + skb = __skb_dequeue(&wmi->wmi_event_queue); + if (!skb) { + spin_unlock_irqrestore(&wmi->wmi_lock, flags); + return; + } + spin_unlock_irqrestore(&wmi->wmi_lock, flags); + + hdr = (struct wmi_cmd_hdr *) skb->data; + cmd_id = be16_to_cpu(hdr->command_id); + wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); + + switch (cmd_id) { + case WMI_SWBA_EVENTID: + swba = (struct wmi_event_swba *) wmi_event; + ath9k_htc_swba(priv, swba); + break; + case WMI_FATAL_EVENTID: + ieee80211_queue_work(wmi->drv_priv->hw, + &wmi->drv_priv->fatal_work); + break; + case WMI_TXSTATUS_EVENTID: + spin_lock_bh(&priv->tx.tx_lock); + if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { + spin_unlock_bh(&priv->tx.tx_lock); + break; + } + spin_unlock_bh(&priv->tx.tx_lock); + + ath9k_htc_txstatus(priv, wmi_event); + break; + default: + break; + } + + kfree_skb(skb); + } while (1); } void ath9k_fatal_work(struct work_struct *work) @@ -153,10 +207,6 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, struct wmi *wmi = (struct wmi *) priv; struct wmi_cmd_hdr *hdr; u16 cmd_id; - void *wmi_event; -#ifdef CONFIG_ATH9K_HTC_DEBUGFS - __be32 txrate; -#endif if (unlikely(wmi->stopped)) goto free_skb; @@ -165,26 +215,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, cmd_id = be16_to_cpu(hdr->command_id); if (cmd_id & 0x1000) { - wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); - switch (cmd_id) { - case WMI_SWBA_EVENTID: - wmi->beacon_pending = *(u8 *)wmi_event; - tasklet_schedule(&wmi->drv_priv->swba_tasklet); - break; - case WMI_FATAL_EVENTID: - ieee80211_queue_work(wmi->drv_priv->hw, - &wmi->drv_priv->fatal_work); - break; - case WMI_TXRATE_EVENTID: -#ifdef CONFIG_ATH9K_HTC_DEBUGFS - txrate = ((struct wmi_event_txrate *)wmi_event)->txrate; - wmi->drv_priv->debug.txrate = be32_to_cpu(txrate); -#endif - break; - default: - break; - } - kfree_skb(skb); + spin_lock(&wmi->wmi_lock); + __skb_queue_tail(&wmi->wmi_event_queue, skb); + spin_unlock(&wmi->wmi_lock); + tasklet_schedule(&wmi->wmi_event_tasklet); return; } @@ -243,7 +277,7 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi, hdr->command_id = cpu_to_be16(cmd); hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); - return htc_send(wmi->htc, skb, wmi->ctrl_epid, NULL); + return htc_send_epid(wmi->htc, skb, wmi->ctrl_epid); } int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 42084277522d..6095eeb6e025 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -17,7 +17,6 @@ #ifndef WMI_H #define WMI_H - struct wmi_event_txrate { __be32 txrate; struct { @@ -31,18 +30,65 @@ struct wmi_cmd_hdr { __be16 seq_no; } __packed; +struct wmi_fw_version { + __be16 major; + __be16 minor; + +} __packed; + +struct wmi_event_swba { + __be64 tsf; + u8 beacon_pending; +}; + +/* + * 64 - HTC header - WMI header - 1 / txstatus + * And some other hdr. space is also accounted for. + * 12 seems to be the magic number. + */ +#define HTC_MAX_TX_STATUS 12 + +#define ATH9K_HTC_TXSTAT_ACK BIT(0) +#define ATH9K_HTC_TXSTAT_FILT BIT(1) +#define ATH9K_HTC_TXSTAT_RTC_CTS BIT(2) +#define ATH9K_HTC_TXSTAT_MCS BIT(3) +#define ATH9K_HTC_TXSTAT_CW40 BIT(4) +#define ATH9K_HTC_TXSTAT_SGI BIT(5) + +/* + * Legacy rates are indicated as indices. + * HT rates are indicated as dot11 numbers. + * This allows us to resrict the rate field + * to 4 bits. + */ +#define ATH9K_HTC_TXSTAT_RATE 0x0f +#define ATH9K_HTC_TXSTAT_RATE_S 0 + +#define ATH9K_HTC_TXSTAT_EPID 0xf0 +#define ATH9K_HTC_TXSTAT_EPID_S 4 + +struct __wmi_event_txstatus { + u8 cookie; + u8 ts_rate; /* Also holds EP ID */ + u8 ts_flags; +}; + +struct wmi_event_txstatus { + u8 cnt; + struct __wmi_event_txstatus txstatus[HTC_MAX_TX_STATUS]; +} __packed; + enum wmi_cmd_id { WMI_ECHO_CMDID = 0x0001, WMI_ACCESS_MEMORY_CMDID, /* Commands to Target */ + WMI_GET_FW_VERSION, WMI_DISABLE_INTR_CMDID, WMI_ENABLE_INTR_CMDID, - WMI_RX_LINK_CMDID, WMI_ATH_INIT_CMDID, WMI_ABORT_TXQ_CMDID, WMI_STOP_TX_DMA_CMDID, - WMI_STOP_DMA_RECV_CMDID, WMI_ABORT_TX_DMA_CMDID, WMI_DRAIN_TXQ_CMDID, WMI_DRAIN_TXQ_ALL_CMDID, @@ -50,24 +96,22 @@ enum wmi_cmd_id { WMI_STOP_RECV_CMDID, WMI_FLUSH_RECV_CMDID, WMI_SET_MODE_CMDID, - WMI_RESET_CMDID, WMI_NODE_CREATE_CMDID, WMI_NODE_REMOVE_CMDID, WMI_VAP_REMOVE_CMDID, WMI_VAP_CREATE_CMDID, - WMI_BEACON_UPDATE_CMDID, WMI_REG_READ_CMDID, WMI_REG_WRITE_CMDID, WMI_RC_STATE_CHANGE_CMDID, WMI_RC_RATE_UPDATE_CMDID, - WMI_DEBUG_INFO_CMDID, - WMI_HOST_ATTACH, WMI_TARGET_IC_UPDATE_CMDID, - WMI_TGT_STATS_CMDID, WMI_TX_AGGR_ENABLE_CMDID, WMI_TGT_DETACH_CMDID, - WMI_TGT_TXQ_ENABLE_CMDID, - WMI_AGGR_LIMIT_CMD = 0x0026, + WMI_NODE_UPDATE_CMDID, + WMI_INT_STATS_CMDID, + WMI_TX_STATS_CMDID, + WMI_RX_STATS_CMDID, + WMI_BITRATE_MASK_CMDID, }; enum wmi_event_id { @@ -76,9 +120,8 @@ enum wmi_event_id { WMI_FATAL_EVENTID, WMI_TXTO_EVENTID, WMI_BMISS_EVENTID, - WMI_WLAN_TXCOMP_EVENTID, WMI_DELBA_EVENTID, - WMI_TXRATE_EVENTID, + WMI_TXSTATUS_EVENTID, }; #define MAX_CMD_NUMBER 62 @@ -88,6 +131,12 @@ struct register_write { __be32 val; }; +struct ath9k_htc_tx_event { + int count; + struct __wmi_event_txstatus txs; + struct list_head list; +}; + struct wmi { struct ath9k_htc_priv *drv_priv; struct htc_target *htc; @@ -95,12 +144,16 @@ struct wmi { struct mutex op_mutex; struct completion cmd_wait; enum wmi_cmd_id last_cmd_id; + struct sk_buff_head wmi_event_queue; + struct tasklet_struct wmi_event_tasklet; u16 tx_seq_id; u8 *cmd_rsp_buf; u32 cmd_rsp_len; bool stopped; - u8 beacon_pending; + struct list_head pending_tx_events; + spinlock_t event_lock; + spinlock_t wmi_lock; atomic_t mwrite_cnt; @@ -117,8 +170,9 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, u8 *cmd_buf, u32 cmd_len, u8 *rsp_buf, u32 rsp_len, u32 timeout); -void ath9k_swba_tasklet(unsigned long data); +void ath9k_wmi_event_tasklet(unsigned long data); void ath9k_fatal_work(struct work_struct *work); +void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv); #define WMI_CMD(_wmi_cmd) \ do { \ diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 88fa7fdffd05..97dd1fac98b6 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -357,6 +357,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_frame_info *fi; int nframes; u8 tidno; + bool clear_filter; skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; @@ -441,22 +442,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, /* transmit completion */ acked_cnt++; } else { - if (!(tid->state & AGGR_CLEANUP) && retry) { - if (fi->retries < ATH_MAX_SW_RETRIES) { - ath_tx_set_retry(sc, txq, bf->bf_mpdu); - txpending = 1; - } else { - bf->bf_state.bf_type |= BUF_XRETRY; - txfail = 1; - sendbar = 1; - txfail_cnt++; - } - } else { + if ((tid->state & AGGR_CLEANUP) || !retry) { /* * cleanup in progress, just fail * the un-acked sub-frames */ txfail = 1; + } else if (fi->retries < ATH_MAX_SW_RETRIES) { + if (!(ts->ts_status & ATH9K_TXERR_FILT) || + !an->sleeping) + ath_tx_set_retry(sc, txq, bf->bf_mpdu); + + clear_filter = true; + txpending = 1; + } else { + bf->bf_state.bf_type |= BUF_XRETRY; + txfail = 1; + sendbar = 1; + txfail_cnt++; } } @@ -496,6 +499,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, !txfail, sendbar); } else { /* retry the un-acked ones */ + ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false); if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) { if (bf->bf_next == NULL && bf_last->bf_stale) { struct ath_buf *tbf; @@ -546,7 +550,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, /* prepend un-acked frames to the beginning of the pending frame queue */ if (!list_empty(&bf_pending)) { + if (an->sleeping) + ieee80211_sta_set_tim(sta); + spin_lock_bh(&txq->axq_lock); + if (clear_filter) + tid->ac->clear_ps_filter = true; list_splice(&bf_pending, &tid->buf_q); ath_tx_queue_tid(txq, tid); spin_unlock_bh(&txq->axq_lock); @@ -816,6 +825,11 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, bf = list_first_entry(&bf_q, struct ath_buf, list); bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); + if (tid->ac->clear_ps_filter) { + tid->ac->clear_ps_filter = false; + ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true); + } + /* if only one frame, send as non-aggregate */ if (bf == bf->bf_lastbf) { fi = get_frame_info(bf->bf_mpdu); @@ -896,6 +910,67 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) ath_tx_flush_tid(sc, txtid); } +bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) +{ + struct ath_atx_tid *tid; + struct ath_atx_ac *ac; + struct ath_txq *txq; + bool buffered = false; + int tidno; + + for (tidno = 0, tid = &an->tid[tidno]; + tidno < WME_NUM_TID; tidno++, tid++) { + + if (!tid->sched) + continue; + + ac = tid->ac; + txq = ac->txq; + + spin_lock_bh(&txq->axq_lock); + + if (!list_empty(&tid->buf_q)) + buffered = true; + + tid->sched = false; + list_del(&tid->list); + + if (ac->sched) { + ac->sched = false; + list_del(&ac->list); + } + + spin_unlock_bh(&txq->axq_lock); + } + + return buffered; +} + +void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) +{ + struct ath_atx_tid *tid; + struct ath_atx_ac *ac; + struct ath_txq *txq; + int tidno; + + for (tidno = 0, tid = &an->tid[tidno]; + tidno < WME_NUM_TID; tidno++, tid++) { + + ac = tid->ac; + txq = ac->txq; + + spin_lock_bh(&txq->axq_lock); + ac->clear_ps_filter = true; + + if (!list_empty(&tid->buf_q) && !tid->paused) { + ath_tx_queue_tid(txq, tid); + ath_txq_schedule(sc, txq); + } + + spin_unlock_bh(&txq->axq_lock); + } +} + void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { struct ath_atx_tid *txtid; @@ -1451,7 +1526,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; struct ieee80211_hdr *hdr; struct ath_frame_info *fi = get_frame_info(skb); - struct ath_node *an; + struct ath_node *an = NULL; struct ath_atx_tid *tid; enum ath9k_key_type keytype; u16 seqno = 0; @@ -1459,11 +1534,13 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, keytype = ath9k_cmn_get_hw_crypto_keytype(skb); + if (sta) + an = (struct ath_node *) sta->drv_priv; + hdr = (struct ieee80211_hdr *)skb->data; - if (sta && ieee80211_is_data_qos(hdr->frame_control) && + if (an && ieee80211_is_data_qos(hdr->frame_control) && conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) { - an = (struct ath_node *) sta->drv_priv; tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; /* @@ -1479,6 +1556,8 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, memset(fi, 0, sizeof(*fi)); if (hw_key) fi->keyix = hw_key->hw_key_idx; + else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0) + fi->keyix = an->ps_key; else fi->keyix = ATH9K_TXKEYIX_INVALID; fi->keytype = keytype; @@ -1491,7 +1570,6 @@ static int setup_tx_flags(struct sk_buff *skb) struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); int flags = 0; - flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ flags |= ATH9K_TXDESC_INTREQ; if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) @@ -1585,8 +1663,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) rix = rates[i].idx; series[i].Tries = rates[i].count; - if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) || - (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) { + if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) { series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; flags |= ATH9K_TXDESC_RTSENA; } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { @@ -1655,8 +1732,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) !is_pspoll, ctsrate, 0, series, 4, flags); - if (sc->config.ath_aggr_prot && flags) - ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192); } static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, @@ -1754,6 +1829,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, if (txctl->paprd) bf->bf_state.bfs_paprd_timestamp = jiffies; + if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) + ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true); + ath_tx_send_normal(sc, txctl->txq, tid, &bf_head); } @@ -1767,6 +1845,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = info->control.sta; + struct ieee80211_vif *vif = info->control.vif; struct ath_softc *sc = hw->priv; struct ath_txq *txq = txctl->txq; struct ath_buf *bf; @@ -1804,6 +1883,11 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, memmove(skb->data, skb->data + padsize, padpos); } + if ((vif && vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_AP_VLAN) || + !ieee80211_is_data(hdr->frame_control)) + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; + setup_frame_info(hw, skb, frmlen); /* @@ -1980,7 +2064,7 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, if (ieee80211_is_data(hdr->frame_control) && (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN)) && - ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max) + ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level) tx_info->status.rates[tx_rateindex].count = hw->max_rate_tries; } @@ -2099,28 +2183,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) } } -static void ath_hw_pll_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, - hw_pll_work.work); - static int count; - - if (AR_SREV_9485(sc->sc_ah)) { - if (ar9003_get_pll_sqsum_dvc(sc->sc_ah) >= 0x40000) { - count++; - - if (count == 3) { - /* Rx is hung for more than 500ms. Reset it */ - ath_reset(sc, true); - count = 0; - } - } else - count = 0; - - ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); - } -} - static void ath_tx_complete_poll_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, @@ -2144,33 +2206,6 @@ static void ath_tx_complete_poll_work(struct work_struct *work) } else { txq->axq_tx_inprogress = true; } - } else { - /* If the queue has pending buffers, then it - * should be doing tx work (and have axq_depth). - * Shouldn't get to this state I think..but - * we do. - */ - if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && - (txq->pending_frames > 0 || - !list_empty(&txq->axq_acq) || - txq->stopped)) { - ath_err(ath9k_hw_common(sc->sc_ah), - "txq: %p axq_qnum: %u," - " mac80211_qnum: %i" - " axq_link: %p" - " pending frames: %i" - " axq_acq empty: %i" - " stopped: %i" - " axq_depth: 0 Attempting to" - " restart tx logic.\n", - txq, txq->axq_qnum, - txq->mac80211_qnum, - txq->axq_link, - txq->pending_frames, - list_empty(&txq->axq_acq), - txq->stopped); - ath_txq_schedule(sc, txq); - } } spin_unlock_bh(&txq->axq_lock); } @@ -2342,7 +2377,6 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) } INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); - INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { error = ath_tx_edma_init(sc); diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 3d4ed5863732..bb578690935e 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -448,6 +448,8 @@ struct carl9170_ba_stats { struct carl9170_sta_info { bool ht_sta; + bool sleeping; + atomic_t pending_frames; unsigned int ampdu_max_len; struct carl9170_sta_tid *agg[CARL9170_NUM_TID]; struct carl9170_ba_stats stats[CARL9170_NUM_TID]; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 89fe60accf85..7d5c65ea94e6 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -883,7 +883,7 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw, * then checking the error flags, later. */ - if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) + if (*new_flags & FIF_ALLMULTI) multicast = ~0ULL; if (multicast != ar->cur_mc_hash) @@ -1193,6 +1193,8 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw, struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; unsigned int i; + atomic_set(&sta_info->pending_frames, 0); + if (sta->ht_cap.ht_supported) { if (sta->ht_cap.ampdu_density > 6) { /* @@ -1467,99 +1469,17 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { - struct ar9170 *ar = hw->priv; struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; - struct sk_buff *skb, *tmp; - struct sk_buff_head free; - int i; switch (cmd) { case STA_NOTIFY_SLEEP: - /* - * Since the peer is no longer listening, we have to return - * as many SKBs as possible back to the mac80211 stack. - * It will deal with the retry procedure, once the peer - * has become available again. - * - * NB: Ideally, the driver should return the all frames in - * the correct, ascending order. However, I think that this - * functionality should be implemented in the stack and not - * here... - */ - - __skb_queue_head_init(&free); - - if (sta->ht_cap.ht_supported) { - rcu_read_lock(); - for (i = 0; i < CARL9170_NUM_TID; i++) { - struct carl9170_sta_tid *tid_info; - - tid_info = rcu_dereference(sta_info->agg[i]); - - if (!tid_info) - continue; - - spin_lock_bh(&ar->tx_ampdu_list_lock); - if (tid_info->state > - CARL9170_TID_STATE_SUSPEND) - tid_info->state = - CARL9170_TID_STATE_SUSPEND; - spin_unlock_bh(&ar->tx_ampdu_list_lock); - - spin_lock_bh(&tid_info->lock); - while ((skb = __skb_dequeue(&tid_info->queue))) - __skb_queue_tail(&free, skb); - spin_unlock_bh(&tid_info->lock); - } - rcu_read_unlock(); - } - - for (i = 0; i < ar->hw->queues; i++) { - spin_lock_bh(&ar->tx_pending[i].lock); - skb_queue_walk_safe(&ar->tx_pending[i], skb, tmp) { - struct _carl9170_tx_superframe *super; - struct ieee80211_hdr *hdr; - struct ieee80211_tx_info *info; - - super = (void *) skb->data; - hdr = (void *) super->frame_data; - - if (compare_ether_addr(hdr->addr1, sta->addr)) - continue; - - __skb_unlink(skb, &ar->tx_pending[i]); - - info = IEEE80211_SKB_CB(skb); - if (info->flags & IEEE80211_TX_CTL_AMPDU) - atomic_dec(&ar->tx_ampdu_upload); - - carl9170_tx_status(ar, skb, false); - } - spin_unlock_bh(&ar->tx_pending[i].lock); - } - - while ((skb = __skb_dequeue(&free))) - carl9170_tx_status(ar, skb, false); - + sta_info->sleeping = true; + if (atomic_read(&sta_info->pending_frames)) + ieee80211_sta_block_awake(hw, sta, true); break; case STA_NOTIFY_AWAKE: - if (!sta->ht_cap.ht_supported) - return; - - rcu_read_lock(); - for (i = 0; i < CARL9170_NUM_TID; i++) { - struct carl9170_sta_tid *tid_info; - - tid_info = rcu_dereference(sta_info->agg[i]); - - if (!tid_info) - continue; - - if ((tid_info->state == CARL9170_TID_STATE_SUSPEND)) - tid_info->state = CARL9170_TID_STATE_IDLE; - } - rcu_read_unlock(); + sta_info->sleeping = false; break; } } diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index cb70ed7ec5cc..e94084fcf6f5 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -104,12 +104,60 @@ static void carl9170_tx_accounting(struct ar9170 *ar, struct sk_buff *skb) spin_unlock_bh(&ar->tx_stats_lock); } +/* needs rcu_read_lock */ +static struct ieee80211_sta *__carl9170_get_tx_sta(struct ar9170 *ar, + struct sk_buff *skb) +{ + struct _carl9170_tx_superframe *super = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *) super->frame_data; + struct ieee80211_vif *vif; + unsigned int vif_id; + + vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> + CARL9170_TX_SUPER_MISC_VIF_ID_S; + + if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC)) + return NULL; + + vif = rcu_dereference(ar->vif_priv[vif_id].vif); + if (unlikely(!vif)) + return NULL; + + /* + * Normally we should use wrappers like ieee80211_get_DA to get + * the correct peer ieee80211_sta. + * + * But there is a problem with indirect traffic (broadcasts, or + * data which is designated for other stations) in station mode. + * The frame will be directed to the AP for distribution and not + * to the actual destination. + */ + + return ieee80211_find_sta(vif, hdr->addr1); +} + +static void carl9170_tx_ps_unblock(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ieee80211_sta *sta; + struct carl9170_sta_info *sta_info; + + rcu_read_lock(); + sta = __carl9170_get_tx_sta(ar, skb); + if (unlikely(!sta)) + goto out_rcu; + + sta_info = (struct carl9170_sta_info *) sta->drv_priv; + if (atomic_dec_return(&sta_info->pending_frames) == 0) + ieee80211_sta_block_awake(ar->hw, sta, false); + +out_rcu: + rcu_read_unlock(); +} + static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) { - struct ieee80211_tx_info *txinfo; int queue; - txinfo = IEEE80211_SKB_CB(skb); queue = skb_get_queue_mapping(skb); spin_lock_bh(&ar->tx_stats_lock); @@ -135,6 +183,7 @@ static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) } spin_unlock_bh(&ar->tx_stats_lock); + if (atomic_dec_and_test(&ar->tx_total_queued)) complete(&ar->tx_flush); } @@ -329,13 +378,9 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, { struct _carl9170_tx_superframe *super = (void *) skb->data; struct ieee80211_hdr *hdr = (void *) super->frame_data; - struct ieee80211_tx_info *tx_info; - struct carl9170_tx_info *ar_info; - struct carl9170_sta_info *sta_info; struct ieee80211_sta *sta; + struct carl9170_sta_info *sta_info; struct carl9170_sta_tid *tid_info; - struct ieee80211_vif *vif; - unsigned int vif_id; u8 tid; if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) || @@ -343,30 +388,8 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, (!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR)))) return; - tx_info = IEEE80211_SKB_CB(skb); - ar_info = (void *) tx_info->rate_driver_data; - - vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> - CARL9170_TX_SUPER_MISC_VIF_ID_S; - - if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC)) - return; - rcu_read_lock(); - vif = rcu_dereference(ar->vif_priv[vif_id].vif); - if (unlikely(!vif)) - goto out_rcu; - - /* - * Normally we should use wrappers like ieee80211_get_DA to get - * the correct peer ieee80211_sta. - * - * But there is a problem with indirect traffic (broadcasts, or - * data which is designated for other stations) in station mode. - * The frame will be directed to the AP for distribution and not - * to the actual destination. - */ - sta = ieee80211_find_sta(vif, hdr->addr1); + sta = __carl9170_get_tx_sta(ar, skb); if (unlikely(!sta)) goto out_rcu; @@ -427,6 +450,7 @@ void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, if (txinfo->flags & IEEE80211_TX_CTL_AMPDU) carl9170_tx_status_process_ampdu(ar, skb, txinfo); + carl9170_tx_ps_unblock(ar, skb); carl9170_tx_put_skb(skb); } @@ -540,11 +564,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar) struct sk_buff *skb; struct ieee80211_tx_info *txinfo; struct carl9170_tx_info *arinfo; - struct _carl9170_tx_superframe *super; struct ieee80211_sta *sta; - struct ieee80211_vif *vif; - struct ieee80211_hdr *hdr; - unsigned int vif_id; rcu_read_lock(); list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) { @@ -562,20 +582,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar) msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT))) goto unlock; - super = (void *) skb->data; - hdr = (void *) super->frame_data; - - vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> - CARL9170_TX_SUPER_MISC_VIF_ID_S; - - if (WARN_ON(vif_id >= AR9170_MAX_VIRTUAL_MAC)) - goto unlock; - - vif = rcu_dereference(ar->vif_priv[vif_id].vif); - if (WARN_ON(!vif)) - goto unlock; - - sta = ieee80211_find_sta(vif, hdr->addr1); + sta = __carl9170_get_tx_sta(ar, skb); if (WARN_ON(!sta)) goto unlock; @@ -611,7 +618,6 @@ static void __carl9170_tx_process_status(struct ar9170 *ar, { struct sk_buff *skb; struct ieee80211_tx_info *txinfo; - struct carl9170_tx_info *arinfo; unsigned int r, t, q; bool success = true; @@ -627,7 +633,6 @@ static void __carl9170_tx_process_status(struct ar9170 *ar, } txinfo = IEEE80211_SKB_CB(skb); - arinfo = (void *) txinfo->rate_driver_data; if (!(info & CARL9170_TX_STATUS_SUCCESS)) success = false; @@ -1199,15 +1204,6 @@ static struct sk_buff *carl9170_tx_pick_skb(struct ar9170 *ar, arinfo = (void *) info->rate_driver_data; arinfo->timeout = jiffies; - - /* - * increase ref count to "2". - * Ref counting is the easiest way to solve the race between - * the the urb's completion routine: carl9170_tx_callback and - * wlan tx status functions: carl9170_tx_status/janitor. - */ - carl9170_tx_get_skb(skb); - return skb; err_unlock: @@ -1228,6 +1224,36 @@ void carl9170_tx_drop(struct ar9170 *ar, struct sk_buff *skb) __carl9170_tx_process_status(ar, super->s.cookie, q); } +static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ieee80211_sta *sta; + struct carl9170_sta_info *sta_info; + + rcu_read_lock(); + sta = __carl9170_get_tx_sta(ar, skb); + if (!sta) + goto out_rcu; + + sta_info = (void *) sta->drv_priv; + if (unlikely(sta_info->sleeping)) { + struct ieee80211_tx_info *tx_info; + + rcu_read_unlock(); + + tx_info = IEEE80211_SKB_CB(skb); + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + atomic_dec(&ar->tx_ampdu_upload); + + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + carl9170_tx_status(ar, skb, false); + return true; + } + +out_rcu: + rcu_read_unlock(); + return false; +} + static void carl9170_tx(struct ar9170 *ar) { struct sk_buff *skb; @@ -1247,6 +1273,9 @@ static void carl9170_tx(struct ar9170 *ar) if (unlikely(!skb)) break; + if (unlikely(carl9170_tx_ps_drop(ar, skb))) + continue; + atomic_inc(&ar->tx_total_pending); q = __carl9170_get_queue(ar, i); @@ -1256,6 +1285,16 @@ static void carl9170_tx(struct ar9170 *ar) */ skb_queue_tail(&ar->tx_status[q], skb); + /* + * increase ref count to "2". + * Ref counting is the easiest way to solve the + * race between the urb's completion routine: + * carl9170_tx_callback + * and wlan tx status functions: + * carl9170_tx_status/janitor. + */ + carl9170_tx_get_skb(skb); + carl9170_usb_tx(ar, skb); schedule_garbagecollector = true; } @@ -1275,7 +1314,6 @@ static bool carl9170_tx_ampdu_queue(struct ar9170 *ar, struct carl9170_sta_info *sta_info; struct carl9170_sta_tid *agg; struct sk_buff *iter; - unsigned int max; u16 tid, seq, qseq, off; bool run = false; @@ -1285,7 +1323,6 @@ static bool carl9170_tx_ampdu_queue(struct ar9170 *ar, rcu_read_lock(); agg = rcu_dereference(sta_info->agg[tid]); - max = sta_info->ampdu_max_len; if (!agg) goto err_unlock_rcu; @@ -1368,6 +1405,11 @@ void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * all ressouces which are associated with the frame. */ + if (sta) { + struct carl9170_sta_info *stai = (void *) sta->drv_priv; + atomic_inc(&stai->pending_frames); + } + if (info->flags & IEEE80211_TX_CTL_AMPDU) { run = carl9170_tx_ampdu_queue(ar, sta, skb); if (run) diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index 37b8e115375a..a61ef3d6d89c 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c @@ -23,6 +23,14 @@ #define REG_READ (common->ops->read) #define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) +#define ENABLE_REGWRITE_BUFFER(_ah) \ + if (common->ops->enable_write_buffer) \ + common->ops->enable_write_buffer((_ah)); + +#define REGWRITE_BUFFER_FLUSH(_ah) \ + if (common->ops->write_flush) \ + common->ops->write_flush((_ah)); + #define IEEE80211_WEP_NKID 4 /* number of key ids */ @@ -42,6 +50,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry) keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); @@ -66,6 +76,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry) } + REGWRITE_BUFFER_FLUSH(ah); + return true; } EXPORT_SYMBOL(ath_hw_keyreset); @@ -104,9 +116,13 @@ static bool ath_hw_keysetmac(struct ath_common *common, } else { macLo = macHi = 0; } + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag); + REGWRITE_BUFFER_FLUSH(ah); + return true; } @@ -223,6 +239,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; mic4 = get_unaligned_le32(k->kv_txmic + 4); + ENABLE_REGWRITE_BUFFER(ah); + /* Write RX[31:0] and TX[31:16] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); @@ -236,6 +254,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), AR_KEYTABLE_TYPE_CLR); + REGWRITE_BUFFER_FLUSH(ah); + } else { /* * TKIP uses four key cache entries (two for group @@ -258,6 +278,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, mic0 = get_unaligned_le32(k->kv_mic + 0); mic2 = get_unaligned_le32(k->kv_mic + 4); + ENABLE_REGWRITE_BUFFER(ah); + /* Write MIC key[31:0] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); @@ -270,8 +292,12 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), AR_KEYTABLE_TYPE_CLR); + + REGWRITE_BUFFER_FLUSH(ah); } + ENABLE_REGWRITE_BUFFER(ah); + /* MAC address registers are reserved for the MIC entry */ REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); @@ -283,7 +309,11 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, */ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + + REGWRITE_BUFFER_FLUSH(ah); } else { + ENABLE_REGWRITE_BUFFER(ah); + /* Write key[47:0] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); @@ -296,6 +326,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + REGWRITE_BUFFER_FLUSH(ah); + /* Write MAC address for the entry */ (void) ath_hw_keysetmac(common, entry, mac); } @@ -451,6 +483,9 @@ int ath_key_config(struct ath_common *common, memset(&hk, 0, sizeof(hk)); switch (key->cipher) { + case 0: + hk.kv_type = ATH_CIPHER_CLR; + break; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: hk.kv_type = ATH_CIPHER_WEP; @@ -466,7 +501,8 @@ int ath_key_config(struct ath_common *common, } hk.kv_len = key->keylen; - memcpy(hk.kv_val, key->key, key->keylen); + if (key->keylen) + memcpy(hk.kv_val, key->key, key->keylen); if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { switch (vif->type) { diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 0e1b8793c864..028310f263c8 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -97,8 +97,8 @@ static const struct ieee80211_regdomain ath_world_regdom_66_69 = { } }; -/* Can be used by 0x67, 0x6A and 0x68 */ -static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = { +/* Can be used by 0x67, 0x68, 0x6A and 0x6C */ +static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = { .n_reg_rules = 4, .alpha2 = "99", .reg_rules = { @@ -151,7 +151,8 @@ ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) case 0x67: case 0x68: case 0x6A: - return &ath_world_regdom_67_68_6A; + case 0x6C: + return &ath_world_regdom_67_68_6A_6C; default: WARN_ON(1); return ath_default_world_regdomain(); @@ -333,6 +334,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy, case 0x63: case 0x66: case 0x67: + case 0x6C: ath_reg_apply_beaconing_flags(wiphy, initiator); break; case 0x68: diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 248c670fdfbe..24b53839fc3a 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -86,6 +86,7 @@ enum EnumRd { WOR9_WORLD = 0x69, WORA_WORLD = 0x6A, WORB_WORLD = 0x6B, + WORC_WORLD = 0x6C, MKK3_MKKB = 0x80, MKK3_MKKA2 = 0x81, @@ -195,6 +196,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {APL9_WORLD, CTL_ETSI, CTL_ETSI}, {APL3_FCCA, CTL_FCC, CTL_FCC}, + {APL7_FCCA, CTL_FCC, CTL_FCC}, {APL1_ETSIC, CTL_FCC, CTL_ETSI}, {APL2_ETSIC, CTL_FCC, CTL_ETSI}, {APL2_APLD, CTL_FCC, NO_CTL}, @@ -281,6 +283,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {WOR9_WORLD, NO_CTL, NO_CTL}, {WORA_WORLD, NO_CTL, NO_CTL}, {WORB_WORLD, NO_CTL, NO_CTL}, + {WORC_WORLD, NO_CTL, NO_CTL}, }; static struct country_code_to_enum_rd allCountries[] = { diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index d59b0168c14a..5a43984bdcea 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -72,6 +72,7 @@ MODULE_FIRMWARE("b43/ucode11.fw"); MODULE_FIRMWARE("b43/ucode13.fw"); MODULE_FIRMWARE("b43/ucode14.fw"); MODULE_FIRMWARE("b43/ucode15.fw"); +MODULE_FIRMWARE("b43/ucode16_mimo.fw"); MODULE_FIRMWARE("b43/ucode5.fw"); MODULE_FIRMWARE("b43/ucode9.fw"); @@ -2685,6 +2686,17 @@ void b43_mac_suspend(struct b43_wldev *dev) dev->mac_suspended++; } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */ +void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on) +{ + u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW); + if (on) + tmslow |= B43_TMSLOW_MACPHYCLKEN; + else + tmslow &= ~B43_TMSLOW_MACPHYCLKEN; + ssb_write32(dev->dev, SSB_TMSLOW, tmslow); +} + static void b43_adjust_opmode(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; @@ -2841,7 +2853,7 @@ static int b43_chip_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; int err; - u32 value32, macctl; + u32 macctl; u16 value16; /* Initialize the MAC control */ @@ -2919,9 +2931,7 @@ static int b43_chip_init(struct b43_wldev *dev) b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00); b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00); - value32 = ssb_read32(dev->dev, SSB_TMSLOW); - value32 |= 0x00100000; - ssb_write32(dev->dev, SSB_TMSLOW, value32); + b43_mac_phy_clock_set(dev, true); b43_write16(dev, B43_MMIO_POWERUP_DELAY, dev->dev->bus->chipco.fast_pwrup_delay); @@ -4212,33 +4222,18 @@ static void b43_bluetooth_coext_disable(struct b43_wldev *dev) static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) { -#ifdef CONFIG_SSB_DRIVER_PCICORE struct ssb_bus *bus = dev->dev->bus; u32 tmp; - if (bus->pcicore.dev && - bus->pcicore.dev->id.coreid == SSB_DEV_PCI && - bus->pcicore.dev->id.revision <= 5) { - /* IMCFGLO timeouts workaround. */ + if ((bus->chip_id == 0x4311 && bus->chip_rev == 2) || + (bus->chip_id == 0x4312)) { tmp = ssb_read32(dev->dev, SSB_IMCFGLO); - switch (bus->bustype) { - case SSB_BUSTYPE_PCI: - case SSB_BUSTYPE_PCMCIA: - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; - tmp |= 0x32; - break; - case SSB_BUSTYPE_SSB: - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; - tmp |= 0x53; - break; - default: - break; - } + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; + tmp |= 0x3; ssb_write32(dev->dev, SSB_IMCFGLO, tmp); + ssb_commit_settings(bus); } -#endif /* CONFIG_SSB_DRIVER_PCICORE */ } static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle) @@ -4862,25 +4857,8 @@ static void b43_one_core_detach(struct ssb_device *dev) static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) { struct b43_wldev *wldev; - struct pci_dev *pdev; int err = -ENOMEM; - if (!list_empty(&wl->devlist)) { - /* We are not the first core on this chip. */ - pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL; - /* Only special chips support more than one wireless - * core, although some of the other chips have more than - * one wireless core as well. Check for this and - * bail out early. - */ - if (!pdev || - ((pdev->device != 0x4321) && - (pdev->device != 0x4313) && (pdev->device != 0x431A))) { - b43dbg(wl, "Ignoring unconnected 802.11 core\n"); - return -ENODEV; - } - } - wldev = kzalloc(sizeof(*wldev), GFP_KERNEL); if (!wldev) goto out; @@ -5001,7 +4979,7 @@ static int b43_wireless_init(struct ssb_device *dev) return err; } -static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id) +static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id) { struct b43_wl *wl; int err; @@ -5039,7 +5017,7 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id) return err; } -static void b43_remove(struct ssb_device *dev) +static void b43_ssb_remove(struct ssb_device *dev) { struct b43_wl *wl = ssb_get_devtypedata(dev); struct b43_wldev *wldev = ssb_get_drvdata(dev); @@ -5082,8 +5060,8 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason) static struct ssb_driver b43_ssb_driver = { .name = KBUILD_MODNAME, .id_table = b43_ssb_tbl, - .probe = b43_probe, - .remove = b43_remove, + .probe = b43_ssb_probe, + .remove = b43_ssb_remove, }; static void b43_print_driverinfo(void) diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 40db03678d9f..a0d327f13183 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -133,6 +133,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags); void b43_mac_suspend(struct b43_wldev *dev); void b43_mac_enable(struct b43_wldev *dev); +void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on); struct b43_request_fw_context; diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8a00f9a95dbb..b075a3f82a43 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -2281,6 +2281,7 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0); save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1); + save_regs_phy[8] = 0; } else { save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); @@ -2289,6 +2290,8 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER); save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1); save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2); + save_regs_phy[7] = 0; + save_regs_phy[8] = 0; } b43_nphy_rssi_select(dev, 5, type); @@ -3537,17 +3540,6 @@ static int b43_nphy_cal_rx_iq(struct b43_wldev *dev, return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */ -static void b43_nphy_mac_phy_clock_set(struct b43_wldev *dev, bool on) -{ - u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW); - if (on) - tmslow |= B43_TMSLOW_MACPHYCLKEN; - else - tmslow &= ~B43_TMSLOW_MACPHYCLKEN; - ssb_write32(dev->dev, SSB_TMSLOW, tmslow); -} - /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask) { @@ -3688,7 +3680,7 @@ int b43_phy_initn(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA); b43_nphy_bmac_clock_fgc(dev, 0); - b43_nphy_mac_phy_clock_set(dev, true); + b43_mac_phy_clock_set(dev, true); b43_nphy_pa_override(dev, false); b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); @@ -3845,8 +3837,8 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, { struct b43_phy *phy = &dev->phy; - const struct b43_nphy_channeltab_entry_rev2 *tabent_r2; - const struct b43_nphy_channeltab_entry_rev3 *tabent_r3; + const struct b43_nphy_channeltab_entry_rev2 *tabent_r2 = NULL; + const struct b43_nphy_channeltab_entry_rev3 *tabent_r3 = NULL; u8 tmp; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index c7fd73e3ad76..1ab8861dd43a 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2234,7 +2234,7 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) b43legacy_write32(dev, B43legacy_MMIO_DMA5_IRQ_MASK, 0x0000DC00); value32 = ssb_read32(dev->dev, SSB_TMSLOW); - value32 |= 0x00100000; + value32 |= B43legacy_TMSLOW_MACPHYCLKEN; ssb_write32(dev->dev, SSB_TMSLOW, value32); b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY, @@ -3104,37 +3104,6 @@ static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev) memset(&dev->noisecalc, 0, sizeof(dev->noisecalc)); } -static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) -{ -#ifdef CONFIG_SSB_DRIVER_PCICORE - struct ssb_bus *bus = dev->dev->bus; - u32 tmp; - - if (bus->pcicore.dev && - bus->pcicore.dev->id.coreid == SSB_DEV_PCI && - bus->pcicore.dev->id.revision <= 5) { - /* IMCFGLO timeouts workaround. */ - tmp = ssb_read32(dev->dev, SSB_IMCFGLO); - switch (bus->bustype) { - case SSB_BUSTYPE_PCI: - case SSB_BUSTYPE_PCMCIA: - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; - tmp |= 0x32; - break; - case SSB_BUSTYPE_SSB: - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; - tmp |= 0x53; - break; - default: - break; - } - ssb_write32(dev->dev, SSB_IMCFGLO, tmp); - } -#endif /* CONFIG_SSB_DRIVER_PCICORE */ -} - static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev, bool idle) { u16 pu_delay = 1050; @@ -3278,7 +3247,6 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) /* Enable IRQ routing to this device. */ ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev); - b43legacy_imcfglo_timeouts_workaround(dev); prepare_phy_data_for_init(dev); b43legacy_phy_calibrate(dev); err = b43legacy_chip_init(dev); @@ -3728,26 +3696,8 @@ static int b43legacy_one_core_attach(struct ssb_device *dev, struct b43legacy_wl *wl) { struct b43legacy_wldev *wldev; - struct pci_dev *pdev; int err = -ENOMEM; - if (!list_empty(&wl->devlist)) { - /* We are not the first core on this chip. */ - pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL; - /* Only special chips support more than one wireless - * core, although some of the other chips have more than - * one wireless core as well. Check for this and - * bail out early. - */ - if (!pdev || - ((pdev->device != 0x4321) && - (pdev->device != 0x4313) && - (pdev->device != 0x431A))) { - b43legacydbg(wl, "Ignoring unconnected 802.11 core\n"); - return -ENODEV; - } - } - wldev = kzalloc(sizeof(*wldev), GFP_KERNEL); if (!wldev) goto out; diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 1d9aed645723..d5084829c9e5 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -79,13 +79,8 @@ struct net_device * hostap_add_interface(struct local_info *local, if (!rtnl_locked) rtnl_lock(); - ret = 0; - if (strchr(dev->name, '%')) - ret = dev_alloc_name(dev, dev->name); - SET_NETDEV_DEV(dev, mdev->dev.parent); - if (ret >= 0) - ret = register_netdevice(dev); + ret = register_netdevice(dev); if (!rtnl_locked) rtnl_unlock(); diff --git a/drivers/net/wireless/iwlegacy/Kconfig b/drivers/net/wireless/iwlegacy/Kconfig index 2a45dd44cc12..aef65cd47661 100644 --- a/drivers/net/wireless/iwlegacy/Kconfig +++ b/drivers/net/wireless/iwlegacy/Kconfig @@ -1,6 +1,5 @@ config IWLWIFI_LEGACY - tristate "Intel Wireless Wifi legacy devices" - depends on PCI && MAC80211 + tristate select FW_LOADER select NEW_LEDS select LEDS_CLASS @@ -65,7 +64,8 @@ endmenu config IWL4965 tristate "Intel Wireless WiFi 4965AGN (iwl4965)" - depends on IWLWIFI_LEGACY + depends on PCI && MAC80211 + select IWLWIFI_LEGACY ---help--- This option enables support for @@ -92,7 +92,8 @@ config IWL4965 config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)" - depends on IWLWIFI_LEGACY + depends on PCI && MAC80211 + select IWLWIFI_LEGACY ---help--- Select to build the driver supporting the: diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-hw.h b/drivers/net/wireless/iwlegacy/iwl-3945-hw.h index 779d3cb86e2c..5c3a68d3af12 100644 --- a/drivers/net/wireless/iwlegacy/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlegacy/iwl-3945-hw.h @@ -74,8 +74,6 @@ /* RSSI to dBm */ #define IWL39_RSSI_OFFSET 95 -#define IWL_DEFAULT_TX_POWER 0x0F - /* * EEPROM related constants, enums, and structures. */ diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-hw.h b/drivers/net/wireless/iwlegacy/iwl-4965-hw.h index 08b189c8472d..fc6fa2886d9c 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlegacy/iwl-4965-hw.h @@ -804,9 +804,6 @@ struct iwl4965_scd_bc_tbl { #define IWL4965_DEFAULT_TX_RETRY 15 -/* Limit range of txpower output target to be between these values */ -#define IWL4965_TX_POWER_TARGET_POWER_MIN (0) /* 0 dBm: 1 milliwatt */ - /* EEPROM */ #define IWL4965_FIRST_AMPDU_QUEUE 10 diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-lib.c b/drivers/net/wireless/iwlegacy/iwl-4965-lib.c index 5a8a3cce27bc..7e5e85a017b5 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-lib.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-lib.c @@ -955,9 +955,6 @@ int iwl4965_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) if (priv->cfg->scan_rx_antennas[band]) rx_ant = priv->cfg->scan_rx_antennas[band]; - if (priv->cfg->scan_tx_antennas[band]) - scan_tx_antennas = priv->cfg->scan_tx_antennas[band]; - priv->scan_tx_ant[band] = iwl4965_toggle_tx_ant(priv, priv->scan_tx_ant[band], scan_tx_antennas); diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c index 31ac672b64e1..24d149909ba3 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c @@ -2604,7 +2604,7 @@ static ssize_t iwl4965_rs_sta_dbgfs_scale_table_write(struct file *file, struct iwl_lq_sta *lq_sta = file->private_data; struct iwl_priv *priv; char buf[64]; - int buf_size; + size_t buf_size; u32 parsed_rate; struct iwl_station_priv *sta_priv = container_of(lq_sta, struct iwl_station_priv, lq_sta); @@ -2860,7 +2860,6 @@ static struct rate_control_ops rs_4965_ops = { int iwl4965_rate_control_register(void) { - pr_err("Registering 4965 rate control operations\n"); return ieee80211_rate_control_register(&rs_4965_ops); } diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c index 5c40502f869a..79ac081832fb 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c @@ -316,12 +316,18 @@ int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); - /* Find index into station table for destination station */ - sta_id = iwl_legacy_sta_id_or_broadcast(priv, ctx, info->control.sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", - hdr->addr1); - goto drop_unlock; + /* For management frames use broadcast id to do not break aggregation */ + if (!ieee80211_is_data(fc)) + sta_id = ctx->bcast_sta_id; + else { + /* Find index into station table for destination station */ + sta_id = iwl_legacy_sta_id_or_broadcast(priv, ctx, info->control.sta); + + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", + hdr->addr1); + goto drop_unlock; + } } IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); @@ -1127,12 +1133,16 @@ int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - iwl4965_tx_status(priv, tx_info, - txq_id >= IWL4965_FIRST_AMPDU_QUEUE); + + if (WARN_ON_ONCE(tx_info->skb == NULL)) + continue; hdr = (struct ieee80211_hdr *)tx_info->skb->data; - if (hdr && ieee80211_is_data_qos(hdr->frame_control)) + if (ieee80211_is_data_qos(hdr->frame_control)) nfreed++; + + iwl4965_tx_status(priv, tx_info, + txq_id >= IWL4965_FIRST_AMPDU_QUEUE); tx_info->skb = NULL; priv->cfg->ops->lib->txq_free_tfd(priv, txq); diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 7007d61bb6b5..42df8321dae8 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -160,6 +160,7 @@ int iwl_legacy_init_geos(struct iwl_priv *priv) struct ieee80211_channel *geo_ch; struct ieee80211_rate *rates; int i = 0; + s8 max_tx_power = 0; if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { @@ -210,10 +211,7 @@ int iwl_legacy_init_geos(struct iwl_priv *priv) if (!iwl_legacy_is_channel_valid(ch)) continue; - if (iwl_legacy_is_channel_a_band(ch)) - sband = &priv->bands[IEEE80211_BAND_5GHZ]; - else - sband = &priv->bands[IEEE80211_BAND_2GHZ]; + sband = &priv->bands[ch->band]; geo_ch = &sband->channels[sband->n_channels++]; @@ -235,8 +233,8 @@ int iwl_legacy_init_geos(struct iwl_priv *priv) geo_ch->flags |= ch->ht40_extension_channel; - if (ch->max_power_avg > priv->tx_power_device_lmt) - priv->tx_power_device_lmt = ch->max_power_avg; + if (ch->max_power_avg > max_tx_power) + max_tx_power = ch->max_power_avg; } else { geo_ch->flags |= IEEE80211_CHAN_DISABLED; } @@ -249,6 +247,10 @@ int iwl_legacy_init_geos(struct iwl_priv *priv) 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->cfg->sku & IWL_SKU_A) { IWL_INFO(priv, "Incorrectly detected BG card as ABG. " @@ -1124,11 +1126,11 @@ int iwl_legacy_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) if (!priv->cfg->ops->lib->send_tx_power) return -EOPNOTSUPP; - if (tx_power < IWL4965_TX_POWER_TARGET_POWER_MIN) { + /* 0 dBm mean 1 milliwatt */ + if (tx_power < 0) { IWL_WARN(priv, - "Requested user TXPOWER %d below lower limit %d.\n", - tx_power, - IWL4965_TX_POWER_TARGET_POWER_MIN); + "Requested user TXPOWER %d below 1 mW.\n", + tx_power); return -EINVAL; } @@ -2112,10 +2114,9 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", channel->hw_value, changed); - if (unlikely(!priv->cfg->mod_params->disable_hw_scan && - test_bit(STATUS_SCANNING, &priv->status))) { + if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { scan_active = 1; - IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); + IWL_DEBUG_MAC80211(priv, "scan active\n"); } if (changed & (IEEE80211_CONF_CHANGE_SMPS | @@ -2150,6 +2151,13 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) goto set_ch_out; } + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && + !iwl_legacy_is_channel_ibss(ch_info)) { + IWL_DEBUG_MAC80211(priv, "leave - not IBSS channel\n"); + ret = -EINVAL; + goto set_ch_out; + } + spin_lock_irqsave(&priv->lock, flags); for_each_context(priv, ctx) { @@ -2428,11 +2436,13 @@ void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); - if (!iwl_legacy_is_alive(priv)) - return; - mutex_lock(&priv->mutex); + if (!iwl_legacy_is_alive(priv)) { + mutex_unlock(&priv->mutex); + return; + } + if (changes & BSS_CHANGED_QOS) { unsigned long flags; @@ -2641,7 +2651,7 @@ irqreturn_t iwl_legacy_isr(int irq, void *data) none: /* re-enable interrupts here since we don't have anything to service. */ - /* only Re-enable if diabled by irq */ + /* only Re-enable if disabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_legacy_enable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h index f03b463e4378..bc66c604106c 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.h +++ b/drivers/net/wireless/iwlegacy/iwl-core.h @@ -287,7 +287,6 @@ struct iwl_cfg { struct iwl_base_params *base_params; /* params likely to change within a device family */ u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; - u8 scan_tx_antennas[IEEE80211_NUM_BANDS]; enum iwl_led_mode led_mode; }; diff --git a/drivers/net/wireless/iwlegacy/iwl-dev.h b/drivers/net/wireless/iwlegacy/iwl-dev.h index 9ee849d669f3..be0106c6a2da 100644 --- a/drivers/net/wireless/iwlegacy/iwl-dev.h +++ b/drivers/net/wireless/iwlegacy/iwl-dev.h @@ -134,7 +134,7 @@ struct iwl_queue { * space more than this */ int high_mark; /* high watermark, stop queue if free * space less than this */ -} __packed; +}; /* One for each TFD */ struct iwl_tx_info { @@ -290,6 +290,7 @@ enum { CMD_SIZE_HUGE = (1 << 0), CMD_ASYNC = (1 << 1), CMD_WANT_SKB = (1 << 2), + CMD_MAPPED = (1 << 3), }; #define DEF_CMD_PAYLOAD_SIZE 320 @@ -1076,7 +1077,6 @@ struct iwl_priv { spinlock_t hcmd_lock; /* protect hcmd */ spinlock_t reg_lock; /* protect hw register access */ struct mutex mutex; - struct mutex sync_cmd_mutex; /* enable serialization of sync commands */ /* basic pci-network driver stuff */ struct pci_dev *pci_dev; @@ -1411,6 +1411,12 @@ iwl_legacy_is_channel_passive(const struct iwl_channel_info *ch) return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0; } +static inline int +iwl_legacy_is_channel_ibss(const struct iwl_channel_info *ch) +{ + return (ch->flags & EEPROM_CHANNEL_IBSS) ? 1 : 0; +} + static inline void __iwl_legacy_free_pages(struct iwl_priv *priv, struct page *page) { diff --git a/drivers/net/wireless/iwlegacy/iwl-eeprom.c b/drivers/net/wireless/iwlegacy/iwl-eeprom.c index 04c5648027df..cb346d1a9ffa 100644 --- a/drivers/net/wireless/iwlegacy/iwl-eeprom.c +++ b/drivers/net/wireless/iwlegacy/iwl-eeprom.c @@ -471,13 +471,6 @@ int iwl_legacy_init_channel_map(struct iwl_priv *priv) flags & EEPROM_CHANNEL_RADAR)) ? "" : "not "); - /* Set the tx_power_user_lmt to the highest power - * supported by any channel */ - if (eeprom_ch_info[ch].max_power_avg > - priv->tx_power_user_lmt) - priv->tx_power_user_lmt = - eeprom_ch_info[ch].max_power_avg; - ch_info++; } } diff --git a/drivers/net/wireless/iwlegacy/iwl-hcmd.c b/drivers/net/wireless/iwlegacy/iwl-hcmd.c index 9d721cbda5bb..62b4b09122cb 100644 --- a/drivers/net/wireless/iwlegacy/iwl-hcmd.c +++ b/drivers/net/wireless/iwlegacy/iwl-hcmd.c @@ -145,6 +145,8 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int cmd_idx; int ret; + lockdep_assert_held(&priv->mutex); + BUG_ON(cmd->flags & CMD_ASYNC); /* A synchronous command can not have a callback set. */ @@ -152,7 +154,6 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", iwl_legacy_get_cmd_string(cmd->id)); - mutex_lock(&priv->sync_cmd_mutex); set_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", @@ -224,7 +225,6 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) cmd->reply_page = 0; } out: - mutex_unlock(&priv->sync_cmd_mutex); return ret; } EXPORT_SYMBOL(iwl_legacy_send_cmd_sync); diff --git a/drivers/net/wireless/iwlegacy/iwl-helpers.h b/drivers/net/wireless/iwlegacy/iwl-helpers.h index 02132e755831..a6effdae63f9 100644 --- a/drivers/net/wireless/iwlegacy/iwl-helpers.h +++ b/drivers/net/wireless/iwlegacy/iwl-helpers.h @@ -149,6 +149,12 @@ static inline void iwl_legacy_disable_interrupts(struct iwl_priv *priv) IWL_DEBUG_ISR(priv, "Disabled interrupts\n"); } +static inline void iwl_legacy_enable_rfkill_int(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n"); + iwl_write32(priv, CSR_INT_MASK, CSR_INT_BIT_RF_KILL); +} + static inline void iwl_legacy_enable_interrupts(struct iwl_priv *priv) { IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); diff --git a/drivers/net/wireless/iwlegacy/iwl-led.c b/drivers/net/wireless/iwlegacy/iwl-led.c index 15eb8b707157..bda0d61b2c0d 100644 --- a/drivers/net/wireless/iwlegacy/iwl-led.c +++ b/drivers/net/wireless/iwlegacy/iwl-led.c @@ -48,8 +48,21 @@ module_param(led_mode, int, S_IRUGO); MODULE_PARM_DESC(led_mode, "0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking"); +/* Throughput OFF time(ms) ON time (ms) + * >300 25 25 + * >200 to 300 40 40 + * >100 to 200 55 55 + * >70 to 100 65 65 + * >50 to 70 75 75 + * >20 to 50 85 85 + * >10 to 20 95 95 + * >5 to 10 110 110 + * >1 to 5 130 130 + * >0 to 1 167 167 + * <=0 SOLID ON + */ static const struct ieee80211_tpt_blink iwl_blink[] = { - { .throughput = 0 * 1024 - 1, .blink_time = 334 }, + { .throughput = 0, .blink_time = 334 }, { .throughput = 1 * 1024 - 1, .blink_time = 260 }, { .throughput = 5 * 1024 - 1, .blink_time = 220 }, { .throughput = 10 * 1024 - 1, .blink_time = 190 }, @@ -101,6 +114,11 @@ static int iwl_legacy_led_cmd(struct iwl_priv *priv, if (priv->blink_on == on && priv->blink_off == off) return 0; + if (off == 0) { + /* led is SOLID_ON */ + on = IWL_LED_SOLID; + } + IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n", priv->cfg->base_params->led_compensation); led_cmd.on = iwl_legacy_blink_compensation(priv, on, diff --git a/drivers/net/wireless/iwlegacy/iwl-tx.c b/drivers/net/wireless/iwlegacy/iwl-tx.c index a227773cb384..4fff995c6f3e 100644 --- a/drivers/net/wireless/iwlegacy/iwl-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-tx.c @@ -146,33 +146,32 @@ void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv) { struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; struct iwl_queue *q = &txq->q; - bool huge = false; int i; if (q->n_bd == 0) return; while (q->read_ptr != q->write_ptr) { - /* we have no way to tell if it is a huge cmd ATM */ i = iwl_legacy_get_cmd_index(q, q->read_ptr, 0); - if (txq->meta[i].flags & CMD_SIZE_HUGE) - huge = true; - else + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; + } q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd); } - if (huge) { - i = q->n_window; + i = q->n_window; + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; } } EXPORT_SYMBOL(iwl_legacy_cmd_queue_unmap); @@ -467,29 +466,27 @@ int iwl_legacy_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } - if (iwl_legacy_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { - IWL_ERR(priv, "No space in command queue\n"); - IWL_ERR(priv, "Restarting adapter due to queue full\n"); - queue_work(priv->workqueue, &priv->restart); - return -ENOSPC; - } - spin_lock_irqsave(&priv->hcmd_lock, flags); - /* If this is a huge cmd, mark the huge flag also on the meta.flags - * of the _original_ cmd. This is used for DMA mapping clean up. - */ - if (cmd->flags & CMD_SIZE_HUGE) { - idx = iwl_legacy_get_cmd_index(q, q->write_ptr, 0); - txq->meta[idx].flags = CMD_SIZE_HUGE; + if (iwl_legacy_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + + IWL_ERR(priv, "Restarting adapter due to command queue full\n"); + queue_work(priv->workqueue, &priv->restart); + return -ENOSPC; } idx = iwl_legacy_get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); out_cmd = txq->cmd[idx]; out_meta = &txq->meta[idx]; + if (WARN_ON(out_meta->flags & CMD_MAPPED)) { + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return -ENOSPC; + } + memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ - out_meta->flags = cmd->flags; + out_meta->flags = cmd->flags | CMD_MAPPED; if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; if (cmd->flags & CMD_ASYNC) @@ -610,6 +607,7 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_device_cmd *cmd; struct iwl_cmd_meta *meta; struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; + unsigned long flags; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -623,14 +621,6 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) return; } - /* If this is a huge cmd, clear the huge flag on the meta.flags - * of the _original_ cmd. So that iwl_legacy_cmd_queue_free won't unmap - * the DMA buffer for the scan (huge) command. - */ - if (huge) { - cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, 0); - txq->meta[cmd_index].flags = 0; - } cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, huge); cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; @@ -647,6 +637,8 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) } else if (meta->callback) meta->callback(priv, cmd, pkt); + spin_lock_irqsave(&priv->hcmd_lock, flags); + iwl_legacy_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); if (!(meta->flags & CMD_ASYNC)) { @@ -655,6 +647,10 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) iwl_legacy_get_cmd_string(cmd->hdr.cmd)); wake_up_interruptible(&priv->wait_command_queue); } + + /* Mark as unmapped */ meta->flags = 0; + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); } EXPORT_SYMBOL(iwl_legacy_tx_cmd_complete); diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index 28eb3d885ba1..0ee6be6a9c5d 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c @@ -2748,11 +2748,12 @@ static void iwl3945_bg_init_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, init_alive_start.work); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + goto out; + iwl3945_init_alive_start(priv); +out: mutex_unlock(&priv->mutex); } @@ -2761,11 +2762,12 @@ static void iwl3945_bg_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, alive_start.work); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + goto out; + iwl3945_alive_start(priv); +out: mutex_unlock(&priv->mutex); } @@ -2995,10 +2997,12 @@ static void iwl3945_bg_restart(struct work_struct *data) } else { iwl3945_down(priv); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + mutex_unlock(&priv->mutex); + return; + } + __iwl3945_up(priv); mutex_unlock(&priv->mutex); } @@ -3009,11 +3013,12 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, rx_replenish); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + goto out; + iwl3945_rx_replenish(priv); +out: mutex_unlock(&priv->mutex); } @@ -3810,7 +3815,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); priv->ieee_channels = NULL; priv->ieee_rates = NULL; @@ -3825,10 +3829,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) priv->force_reset[IWL_FW_RESET].reset_duration = IWL_DELAY_NEXT_FORCE_FW_RELOAD; - - priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; - priv->tx_power_next = IWL_DEFAULT_TX_POWER; - if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { IWL_WARN(priv, "Unsupported EEPROM version: 0x%04X\n", eeprom->version); diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index 91b3d8b9d7a5..af2ae22fcfd3 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -1069,9 +1069,12 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) } /* Re-enable all interrupts */ - /* only Re-enable if diabled by irq */ + /* only Re-enable if disabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_legacy_enable_interrupts(priv); + /* Re-enable RF_KILL if it occurred */ + else if (handled & CSR_INT_BIT_RF_KILL) + iwl_legacy_enable_rfkill_int(priv); #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG if (iwl_legacy_get_debug_level(priv) & (IWL_DL_ISR)) { @@ -2139,7 +2142,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv); static void __iwl4965_down(struct iwl_priv *priv) { unsigned long flags; - int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); + int exit_pending; IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); @@ -2401,11 +2404,12 @@ static void iwl4965_bg_init_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, init_alive_start.work); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + goto out; + priv->cfg->ops->lib->init_alive_start(priv); +out: mutex_unlock(&priv->mutex); } @@ -2414,11 +2418,12 @@ static void iwl4965_bg_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, alive_start.work); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + goto out; + iwl4965_alive_start(priv); +out: mutex_unlock(&priv->mutex); } @@ -2468,10 +2473,12 @@ static void iwl4965_bg_restart(struct work_struct *data) } else { iwl4965_down(priv); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + mutex_unlock(&priv->mutex); + return; + } + __iwl4965_up(priv); mutex_unlock(&priv->mutex); } @@ -2624,9 +2631,10 @@ void iwl4965_mac_stop(struct ieee80211_hw *hw) flush_workqueue(priv->workqueue); - /* enable interrupts again in order to receive rfkill changes */ + /* User space software may expect getting rfkill changes + * even if interface is down */ iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl_legacy_enable_interrupts(priv); + iwl_legacy_enable_rfkill_int(priv); IWL_DEBUG_MAC80211(priv, "leave\n"); } @@ -2847,21 +2855,22 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->mutex); + if (iwl_legacy_is_rfkill(priv)) - goto out_exit; + goto out; if (test_bit(STATUS_EXIT_PENDING, &priv->status) || test_bit(STATUS_SCANNING, &priv->status)) - goto out_exit; + goto out; if (!iwl_legacy_is_associated_ctx(ctx)) - goto out_exit; + goto out; /* channel switch in progress */ if (priv->switch_rxon.switch_in_progress == true) - goto out_exit; + goto out; - mutex_lock(&priv->mutex); if (priv->cfg->ops->lib->set_channel_switch) { ch = channel->hw_value; @@ -2917,7 +2926,6 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw, } out: mutex_unlock(&priv->mutex); -out_exit: if (!priv->switch_rxon.switch_in_progress) ieee80211_chswitch_done(ctx->vif, false); IWL_DEBUG_MAC80211(priv, "leave\n"); @@ -2984,15 +2992,15 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, txpower_work); + mutex_lock(&priv->mutex); + /* If a scan happened to start before we got here * then just return; the statistics notification will * kick off another scheduled work to compensate for * any temperature delta we missed here. */ if (test_bit(STATUS_EXIT_PENDING, &priv->status) || test_bit(STATUS_SCANNING, &priv->status)) - return; - - mutex_lock(&priv->mutex); + goto out; /* Regardless of if we are associated, we must reconfigure the * TX power since frames can be sent on non-radar channels while @@ -3002,7 +3010,7 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) /* Update last_temperature to keep is_calib_needed from running * when it isn't needed... */ priv->last_temperature = priv->temperature; - +out: mutex_unlock(&priv->mutex); } @@ -3116,7 +3124,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv) INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); priv->ieee_channels = NULL; priv->ieee_rates = NULL; @@ -3140,12 +3147,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv) iwl_legacy_init_scan_params(priv); - /* Set the tx_power_user_lmt to the lowest power level - * this value will get overwritten by channel max power avg - * from eeprom */ - priv->tx_power_user_lmt = IWL4965_TX_POWER_TARGET_POWER_MIN; - priv->tx_power_next = IWL4965_TX_POWER_TARGET_POWER_MIN; - ret = iwl_legacy_init_channel_map(priv); if (ret) { IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); @@ -3179,7 +3180,7 @@ static void iwl4965_hw_detect(struct iwl_priv *priv) { priv->hw_rev = _iwl_legacy_read32(priv, CSR_HW_REV); priv->hw_wa_rev = _iwl_legacy_read32(priv, CSR_HW_REV_WA_REG); - pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id); + priv->rev_id = priv->pci_dev->revision; IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); } @@ -3412,14 +3413,14 @@ iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * 8. Enable interrupts and read RFKILL state *********************************************/ - /* enable interrupts if needed: hw bug w/a */ + /* enable rfkill interrupt: hw bug w/a */ pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); } - iwl_legacy_enable_interrupts(priv); + iwl_legacy_enable_rfkill_int(priv); /* If platform's RF_KILL switch is NOT set to KILL */ if (iwl_read32(priv, CSR_GP_CNTRL) & diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 17d555f2215a..ad3bdba6beed 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -102,6 +102,16 @@ config IWLWIFI_DEVICE_TRACING occur. endmenu +config IWLWIFI_DEVICE_SVTOOL + bool "iwlwifi device svtool support" + depends on IWLAGN + select NL80211_TESTMODE + help + This option enables the svtool support for iwlwifi device through + NL80211_TESTMODE. svtool is a software validation tool that runs in + the user space and interacts with the device in the kernel space + through the generic netlink message via NL80211_TESTMODE channel. + config IWL_P2P bool "iwlwifi experimental P2P support" depends on IWLAGN diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 9d6ee836426c..822660483f9f 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,8 +1,8 @@ # AGN obj-$(CONFIG_IWLAGN) += iwlagn.o -iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o +iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o -iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o +iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o @@ -14,9 +14,9 @@ iwlagn-objs += iwl-6000.o iwlagn-objs += iwl-1000.o iwlagn-objs += iwl-2000.o -iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o +iwlagn-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o CFLAGS_iwl-devtrace.o := -I$(src) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 27c5007e577c..b4c81931e136 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -45,8 +45,6 @@ #include "iwl-agn.h" #include "iwl-helpers.h" #include "iwl-agn-hw.h" -#include "iwl-agn-led.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL1000_UCODE_API_MAX 5 @@ -57,12 +55,10 @@ #define IWL100_UCODE_API_MIN 5 #define IWL1000_FW_PRE "iwlwifi-1000-" -#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" -#define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api) +#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" #define IWL100_FW_PRE "iwlwifi-100-" -#define _IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode" -#define IWL100_MODULE_FIRMWARE(api) _IWL100_MODULE_FIRMWARE(api) +#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode" /* @@ -124,10 +120,10 @@ static struct iwl_sensitivity_ranges iwl1000_sensitivity = { static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -141,7 +137,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -176,24 +171,13 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) static struct iwl_lib_ops iwl1000_lib = { .set_hw_params = iwl1000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { @@ -208,45 +192,21 @@ static struct iwl_lib_ops iwl1000_lib = { EEPROM_REG_BAND_4_CHANNELS, EEPROM_REG_BAND_5_CHANNELS, EEPROM_REG_BAND_24_HT40_CHANNELS, - EEPROM_REG_BAND_52_HT40_CHANNELS + EEPROM_REGULATORY_BAND_NO_HT40, }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static const struct iwl_ops iwl1000_ops = { .lib = &iwl1000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl1000_base_params = { @@ -254,8 +214,6 @@ static struct iwl_base_params iwl1000_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .eeprom_size = OTP_LOW_IMAGE_SIZE, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, .led_compensation = 51, @@ -265,9 +223,6 @@ static struct iwl_base_params iwl1000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 128, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, }; static struct iwl_ht_params iwl1000_ht_params = { .ht_greenfield_support = true, @@ -281,7 +236,6 @@ static struct iwl_ht_params iwl1000_ht_params = { .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .ops = &iwl1000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl1000_base_params, \ .led_mode = IWL_LED_BLINK @@ -303,7 +257,6 @@ struct iwl_cfg iwl1000_bg_cfg = { .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .ops = &iwl1000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl1000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ .rx_with_siso_diversity = true diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index d7b6126408c9..89b8da7a6c8b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -46,30 +46,25 @@ #include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-6000-hw.h" -#include "iwl-agn-led.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL2030_UCODE_API_MAX 5 #define IWL2000_UCODE_API_MAX 5 -#define IWL200_UCODE_API_MAX 5 +#define IWL105_UCODE_API_MAX 5 /* Lowest firmware API version supported */ #define IWL2030_UCODE_API_MIN 5 #define IWL2000_UCODE_API_MIN 5 -#define IWL200_UCODE_API_MIN 5 +#define IWL105_UCODE_API_MIN 5 #define IWL2030_FW_PRE "iwlwifi-2030-" -#define _IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" -#define IWL2030_MODULE_FIRMWARE(api) _IWL2030_MODULE_FIRMWARE(api) +#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" #define IWL2000_FW_PRE "iwlwifi-2000-" -#define _IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" -#define IWL2000_MODULE_FIRMWARE(api) _IWL2000_MODULE_FIRMWARE(api) +#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" -#define IWL200_FW_PRE "iwlwifi-200-" -#define _IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode" -#define IWL200_MODULE_FIRMWARE(api) _IWL200_MODULE_FIRMWARE(api) +#define IWL105_FW_PRE "iwlwifi-105-" +#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE #api ".ucode" static void iwl2000_set_ct_threshold(struct iwl_priv *priv) { @@ -101,6 +96,8 @@ static void iwl2000_nic_config(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); + if (priv->cfg->disable_otp_refresh) + iwl_write_prph(priv, APMG_ANALOG_SVR_REG, 0x80000010); } static struct iwl_sensitivity_ranges iwl2000_sensitivity = { @@ -130,10 +127,10 @@ static struct iwl_sensitivity_ranges iwl2000_sensitivity = { static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -147,7 +144,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -256,11 +252,7 @@ static int iwl2030_hw_channel_switch(struct iwl_priv *priv, static struct iwl_lib_ops iwl2000_lib = { .set_hw_params = iwl2000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, @@ -268,13 +260,6 @@ static struct iwl_lib_ops iwl2000_lib = { .setup_deferred_work = iwlagn_bt_setup_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl2030_hw_channel_switch, @@ -290,70 +275,40 @@ static struct iwl_lib_ops iwl2000_lib = { EEPROM_REG_BAND_4_CHANNELS, EEPROM_REG_BAND_5_CHANNELS, EEPROM_6000_REG_BAND_24_HT40_CHANNELS, - EEPROM_REG_BAND_52_HT40_CHANNELS + EEPROM_REGULATORY_BAND_NO_HT40, }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static const struct iwl_ops iwl2000_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl2030_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; -static const struct iwl_ops iwl200_ops = { +static const struct iwl_ops iwl105_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; -static const struct iwl_ops iwl230_ops = { +static const struct iwl_ops iwl135_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl2000_base_params = { @@ -361,8 +316,6 @@ static struct iwl_base_params iwl2000_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_2x00, .shadow_ram_support = true, .led_compensation = 51, @@ -373,9 +326,6 @@ static struct iwl_base_params iwl2000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; @@ -385,8 +335,6 @@ static struct iwl_base_params iwl2030_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_2x00, .shadow_ram_support = true, .led_compensation = 57, @@ -397,9 +345,6 @@ static struct iwl_base_params iwl2030_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; @@ -409,7 +354,6 @@ static struct iwl_ht_params iwl2000_ht_params = { }; static struct iwl_bt_params iwl2030_bt_params = { - .bt_statistics = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .advanced_bt_coexist = true, .agg_time_limit = BT_AGG_THRESHOLD_DEF, @@ -426,12 +370,12 @@ static struct iwl_bt_params iwl2030_bt_params = { .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .ops = &iwl2000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl2000_base_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ .led_mode = IWL_LED_RF_STATE, \ - .iq_invert = true \ + .iq_invert = true, \ + .disable_otp_refresh = true \ struct iwl_cfg iwl2000_2bgn_cfg = { .name = "2000 Series 2x2 BGN", @@ -451,7 +395,6 @@ struct iwl_cfg iwl2000_2bg_cfg = { .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .ops = &iwl2030_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl2030_base_params, \ .bt_params = &iwl2030_bt_params, \ .need_dc_calib = true, \ @@ -471,45 +414,13 @@ struct iwl_cfg iwl2030_2bg_cfg = { IWL_DEVICE_2030, }; -#define IWL_DEVICE_6035 \ - .fw_name_pre = IWL2030_FW_PRE, \ - .ucode_api_max = IWL2030_UCODE_API_MAX, \ - .ucode_api_min = IWL2030_UCODE_API_MIN, \ - .eeprom_ver = EEPROM_6035_EEPROM_VERSION, \ - .eeprom_calib_ver = EEPROM_6035_TX_POWER_VERSION, \ - .ops = &iwl2030_ops, \ - .mod_params = &iwlagn_mod_params, \ - .base_params = &iwl2030_base_params, \ - .bt_params = &iwl2030_bt_params, \ - .need_dc_calib = true, \ - .need_temp_offset_calib = true, \ - .led_mode = IWL_LED_RF_STATE, \ - .adv_pm = true \ - -struct iwl_cfg iwl6035_2agn_cfg = { - .name = "2000 Series 2x2 AGN/BT", - IWL_DEVICE_6035, - .ht_params = &iwl2000_ht_params, -}; - -struct iwl_cfg iwl6035_2abg_cfg = { - .name = "2000 Series 2x2 ABG/BT", - IWL_DEVICE_6035, -}; - -struct iwl_cfg iwl6035_2bg_cfg = { - .name = "2000 Series 2x2 BG/BT", - IWL_DEVICE_6035, -}; - -#define IWL_DEVICE_200 \ - .fw_name_pre = IWL200_FW_PRE, \ - .ucode_api_max = IWL200_UCODE_API_MAX, \ - .ucode_api_min = IWL200_UCODE_API_MIN, \ +#define IWL_DEVICE_105 \ + .fw_name_pre = IWL105_FW_PRE, \ + .ucode_api_max = IWL105_UCODE_API_MAX, \ + .ucode_api_min = IWL105_UCODE_API_MIN, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .ops = &iwl200_ops, \ - .mod_params = &iwlagn_mod_params, \ + .ops = &iwl105_ops, \ .base_params = &iwl2000_base_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ @@ -517,25 +428,24 @@ struct iwl_cfg iwl6035_2bg_cfg = { .adv_pm = true, \ .rx_with_siso_diversity = true \ -struct iwl_cfg iwl200_bg_cfg = { - .name = "200 Series 1x1 BG", - IWL_DEVICE_200, +struct iwl_cfg iwl105_bg_cfg = { + .name = "105 Series 1x1 BG", + IWL_DEVICE_105, }; -struct iwl_cfg iwl200_bgn_cfg = { - .name = "200 Series 1x1 BGN", - IWL_DEVICE_200, +struct iwl_cfg iwl105_bgn_cfg = { + .name = "105 Series 1x1 BGN", + IWL_DEVICE_105, .ht_params = &iwl2000_ht_params, }; -#define IWL_DEVICE_230 \ - .fw_name_pre = IWL200_FW_PRE, \ - .ucode_api_max = IWL200_UCODE_API_MAX, \ - .ucode_api_min = IWL200_UCODE_API_MIN, \ +#define IWL_DEVICE_135 \ + .fw_name_pre = IWL105_FW_PRE, \ + .ucode_api_max = IWL105_UCODE_API_MAX, \ + .ucode_api_min = IWL105_UCODE_API_MIN, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .ops = &iwl230_ops, \ - .mod_params = &iwlagn_mod_params, \ + .ops = &iwl135_ops, \ .base_params = &iwl2030_base_params, \ .bt_params = &iwl2030_bt_params, \ .need_dc_calib = true, \ @@ -544,17 +454,17 @@ struct iwl_cfg iwl200_bgn_cfg = { .adv_pm = true, \ .rx_with_siso_diversity = true \ -struct iwl_cfg iwl230_bg_cfg = { - .name = "200 Series 1x1 BG/BT", - IWL_DEVICE_230, +struct iwl_cfg iwl135_bg_cfg = { + .name = "105 Series 1x1 BG/BT", + IWL_DEVICE_135, }; -struct iwl_cfg iwl230_bgn_cfg = { - .name = "200 Series 1x1 BGN/BT", - IWL_DEVICE_230, +struct iwl_cfg iwl135_bgn_cfg = { + .name = "105 Series 1x1 BGN/BT", + IWL_DEVICE_135, .ht_params = &iwl2000_ht_params, }; MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL200_MODULE_FIRMWARE(IWL200_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 3975e45e7500..05ad47628b63 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 3ea31b659d1a..98f81df166e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 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 @@ -45,10 +45,8 @@ #include "iwl-sta.h" #include "iwl-helpers.h" #include "iwl-agn.h" -#include "iwl-agn-led.h" #include "iwl-agn-hw.h" #include "iwl-5000-hw.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL5000_UCODE_API_MAX 5 @@ -59,12 +57,10 @@ #define IWL5150_UCODE_API_MIN 1 #define IWL5000_FW_PRE "iwlwifi-5000-" -#define _IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" -#define IWL5000_MODULE_FIRMWARE(api) _IWL5000_MODULE_FIRMWARE(api) +#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" #define IWL5150_FW_PRE "iwlwifi-5150-" -#define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" -#define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api) +#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" /* NIC configuration for 5000 series */ static void iwl5000_nic_config(struct iwl_priv *priv) @@ -168,10 +164,10 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv) static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -185,7 +181,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -214,10 +209,10 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -231,7 +226,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -263,7 +257,7 @@ static void iwl5150_temperature(struct iwl_priv *priv) u32 vt = 0; s32 offset = iwl_temp_calib_to_offset(priv); - vt = le32_to_cpu(priv->_agn.statistics.general.common.temperature); + 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); @@ -345,24 +339,13 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, static struct iwl_lib_ops iwl5000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, - .load_ucode = iwlagn_load_ucode, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl5000_hw_channel_switch, @@ -380,56 +363,24 @@ static struct iwl_lib_ops iwl5000_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static struct iwl_lib_ops iwl5150_lib = { .set_hw_params = iwl5150_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .load_ucode = iwlagn_load_ucode, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl5000_hw_channel_switch, @@ -447,51 +398,25 @@ static struct iwl_lib_ops iwl5150_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwl5150_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static const struct iwl_ops iwl5000_ops = { .lib = &iwl5000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl5150_ops = { .lib = &iwl5150_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl5000_base_params = { @@ -499,17 +424,12 @@ static struct iwl_base_params iwl5000_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .use_bsm = false, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, }; static struct iwl_ht_params iwl5000_ht_params = { .ht_greenfield_support = true, @@ -523,13 +443,15 @@ static struct iwl_ht_params iwl5000_ht_params = { .eeprom_ver = EEPROM_5000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ .ops = &iwl5000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl5000_base_params, \ .led_mode = IWL_LED_BLINK struct iwl_cfg iwl5300_agn_cfg = { .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", IWL_DEVICE_5000, + /* at least EEPROM 0x11A has wrong info */ + .valid_tx_ant = ANT_ABC, /* .cfg overwrite */ + .valid_rx_ant = ANT_ABC, /* .cfg overwrite */ .ht_params = &iwl5000_ht_params, }; @@ -564,7 +486,6 @@ struct iwl_cfg iwl5350_agn_cfg = { .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .ops = &iwl5000_ops, - .mod_params = &iwlagn_mod_params, .base_params = &iwl5000_base_params, .ht_params = &iwl5000_ht_params, .led_mode = IWL_LED_BLINK, @@ -578,7 +499,6 @@ struct iwl_cfg iwl5350_agn_cfg = { .eeprom_ver = EEPROM_5050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ .ops = &iwl5150_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl5000_base_params, \ .need_dc_calib = true, \ .led_mode = IWL_LED_BLINK, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h index 47891e16a758..b27986e57c92 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a745b01c0ec1..a7921f9a03c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -46,8 +46,6 @@ #include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-6000-hw.h" -#include "iwl-agn-led.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL6000_UCODE_API_MAX 4 @@ -60,20 +58,16 @@ #define IWL6000G2_UCODE_API_MIN 4 #define IWL6000_FW_PRE "iwlwifi-6000-" -#define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" -#define IWL6000_MODULE_FIRMWARE(api) _IWL6000_MODULE_FIRMWARE(api) +#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" #define IWL6050_FW_PRE "iwlwifi-6050-" -#define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" -#define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api) +#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" #define IWL6005_FW_PRE "iwlwifi-6000g2a-" -#define _IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode" -#define IWL6005_MODULE_FIRMWARE(api) _IWL6005_MODULE_FIRMWARE(api) +#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode" #define IWL6030_FW_PRE "iwlwifi-6000g2b-" -#define _IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode" -#define IWL6030_MODULE_FIRMWARE(api) _IWL6030_MODULE_FIRMWARE(api) +#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode" static void iwl6000_set_ct_threshold(struct iwl_priv *priv) { @@ -85,7 +79,7 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv) static void iwl6050_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ - if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) + if (iwlagn_eeprom_calib_version(priv) >= 6) iwl_set_bit(priv, CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); } @@ -93,7 +87,7 @@ static void iwl6050_additional_nic_config(struct iwl_priv *priv) static void iwl6150_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ - if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) + if (iwlagn_eeprom_calib_version(priv) >= 6) iwl_set_bit(priv, CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); iwl_set_bit(priv, CSR_GP_DRIVER_REG, @@ -159,10 +153,10 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -176,7 +170,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -285,24 +278,13 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, static struct iwl_lib_ops iwl6000_lib = { .set_hw_params = iwl6000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl6000_hw_channel_switch, @@ -320,45 +302,19 @@ static struct iwl_lib_ops iwl6000_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static struct iwl_lib_ops iwl6030_lib = { .set_hw_params = iwl6000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, @@ -366,13 +322,6 @@ static struct iwl_lib_ops iwl6030_lib = { .setup_deferred_work = iwlagn_bt_setup_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl6000_hw_channel_switch, @@ -390,36 +339,14 @@ static struct iwl_lib_ops iwl6030_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static struct iwl_nic_ops iwl6050_nic_ops = { @@ -434,34 +361,26 @@ static const struct iwl_ops iwl6000_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl6050_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .nic = &iwl6050_nic_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl6150_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .nic = &iwl6150_nic_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl6030_ops = { .lib = &iwl6030_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl6000_base_params = { @@ -469,8 +388,6 @@ static struct iwl_base_params iwl6000_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .led_compensation = 51, @@ -481,9 +398,6 @@ static struct iwl_base_params iwl6000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; @@ -492,8 +406,6 @@ static struct iwl_base_params iwl6050_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .led_compensation = 51, @@ -504,9 +416,6 @@ static struct iwl_base_params iwl6050_base_params = { .chain_noise_scale = 1500, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 1024, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; static struct iwl_base_params iwl6000_g2_base_params = { @@ -514,8 +423,6 @@ static struct iwl_base_params iwl6000_g2_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .led_compensation = 57, @@ -526,9 +433,6 @@ static struct iwl_base_params iwl6000_g2_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; @@ -538,7 +442,6 @@ static struct iwl_ht_params iwl6000_ht_params = { }; static struct iwl_bt_params iwl6000_bt_params = { - .bt_statistics = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .advanced_bt_coexist = true, .agg_time_limit = BT_AGG_THRESHOLD_DEF, @@ -554,7 +457,6 @@ static struct iwl_bt_params iwl6000_bt_params = { .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ .ops = &iwl6000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_g2_base_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ @@ -583,7 +485,6 @@ struct iwl_cfg iwl6005_2bg_cfg = { .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ .ops = &iwl6030_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_g2_base_params, \ .bt_params = &iwl6000_bt_params, \ .need_dc_calib = true, \ @@ -613,6 +514,22 @@ struct iwl_cfg iwl6030_2bg_cfg = { IWL_DEVICE_6030, }; +struct iwl_cfg iwl6035_2agn_cfg = { + .name = "6035 Series 2x2 AGN/BT", + IWL_DEVICE_6030, + .ht_params = &iwl6000_ht_params, +}; + +struct iwl_cfg iwl6035_2abg_cfg = { + .name = "6035 Series 2x2 ABG/BT", + IWL_DEVICE_6030, +}; + +struct iwl_cfg iwl6035_2bg_cfg = { + .name = "6035 Series 2x2 BG/BT", + IWL_DEVICE_6030, +}; + struct iwl_cfg iwl1030_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN", IWL_DEVICE_6030, @@ -649,7 +566,6 @@ struct iwl_cfg iwl130_bg_cfg = { .eeprom_ver = EEPROM_6000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, \ .ops = &iwl6000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_base_params, \ .pa_type = IWL_PA_INTERNAL, \ .led_mode = IWL_LED_BLINK @@ -679,7 +595,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .ops = &iwl6050_ops, \ .eeprom_ver = EEPROM_6050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6050_base_params, \ .need_dc_calib = true, \ .led_mode = IWL_LED_BLINK, \ @@ -704,7 +619,6 @@ struct iwl_cfg iwl6150_bgn_cfg = { .eeprom_ver = EEPROM_6150_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION, .ops = &iwl6150_ops, - .mod_params = &iwlagn_mod_params, .base_params = &iwl6050_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, @@ -720,7 +634,6 @@ struct iwl_cfg iwl6000_3agn_cfg = { .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, .ops = &iwl6000_ops, - .mod_params = &iwlagn_mod_params, .base_params = &iwl6000_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 9006293e740c..0f6bb9b2e642 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -605,7 +605,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv) IWL_DEBUG_CALIB(priv, "<lock, flags); - if (iwl_bt_statistics(priv)) { - rx_info = &(((struct iwl_bt_notif_statistics *)resp)-> - rx.general.common); - ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm); - cck = &(((struct iwl_bt_notif_statistics *)resp)->rx.cck); - } else { - rx_info = &(((struct iwl_notif_statistics *)resp)->rx.general); - ofdm = &(((struct iwl_notif_statistics *)resp)->rx.ofdm); - cck = &(((struct iwl_notif_statistics *)resp)->rx.cck); - } + rx_info = &priv->statistics.rx_non_phy; + ofdm = &priv->statistics.rx_ofdm; + cck = &priv->statistics.rx_cck; if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { IWL_DEBUG_CALIB(priv, "<< invalid data.\n"); spin_unlock_irqrestore(&priv->lock, flags); @@ -851,7 +844,7 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig, * 1) Which antennas are connected. * 2) Differential rx gain settings to balance the 3 receivers. */ -void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) +void iwl_chain_noise_calibration(struct iwl_priv *priv) { struct iwl_chain_noise_data *data = NULL; @@ -896,13 +889,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) } spin_lock_irqsave(&priv->lock, flags); - if (iwl_bt_statistics(priv)) { - rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)-> - rx.general.common); - } else { - rx_info = &(((struct iwl_notif_statistics *)stat_resp)-> - rx.general); - } + + rx_info = &priv->statistics.rx_non_phy; + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n"); spin_unlock_irqrestore(&priv->lock, flags); @@ -911,19 +900,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK); rxon_chnum = le16_to_cpu(ctx->staging.channel); - if (iwl_bt_statistics(priv)) { - stat_band24 = !!(((struct iwl_bt_notif_statistics *) - stat_resp)->flag & - STATISTICS_REPLY_FLG_BAND_24G_MSK); - stat_chnum = le32_to_cpu(((struct iwl_bt_notif_statistics *) - stat_resp)->flag) >> 16; - } else { - stat_band24 = !!(((struct iwl_notif_statistics *) - stat_resp)->flag & - STATISTICS_REPLY_FLG_BAND_24G_MSK); - stat_chnum = le32_to_cpu(((struct iwl_notif_statistics *) - stat_resp)->flag) >> 16; - } + stat_band24 = + !!(priv->statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK); + stat_chnum = le32_to_cpu(priv->statistics.flag) >> 16; /* Make sure we accumulate data for just the associated channel * (even if scanning). */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h index e37ae7261630..4ef4dd934254 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,8 +66,8 @@ #include "iwl-core.h" #include "iwl-commands.h" -void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp); -void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp); +void iwl_chain_noise_calibration(struct iwl_priv *priv); +void iwl_sensitivity_calibration(struct iwl_priv *priv); void iwl_init_sensitivity(struct iwl_priv *priv); void iwl_reset_run_time_calib(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c deleted file mode 100644 index b500aaae53ec..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c +++ /dev/null @@ -1,1073 +0,0 @@ -/****************************************************************************** -* -* GPL LICENSE SUMMARY -* -* Copyright(c) 2008 - 2010 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 "iwl-agn.h" -#include "iwl-agn-debugfs.h" - -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"; -static const char *fmt_header = - "%-32s current cumulative delta max\n"; - -static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) -{ - int p = 0; - u32 flag; - - if (iwl_bt_statistics(priv)) - flag = le32_to_cpu(priv->_agn.statistics_bt.flag); - else - flag = le32_to_cpu(priv->_agn.statistics.flag); - - p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag); - if (flag & UCODE_STATISTICS_CLEAR_MSK) - p += scnprintf(buf + p, bufsz - p, - "\tStatistics have been cleared\n"); - p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", - (flag & UCODE_STATISTICS_FREQUENCY_MSK) - ? "2.4 GHz" : "5.2 GHz"); - p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", - (flag & UCODE_STATISTICS_NARROW_BAND_MSK) - ? "enabled" : "disabled"); - - return p; -} - -ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) - { - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = sizeof(struct statistics_rx_phy) * 40 + - sizeof(struct statistics_rx_non_phy) * 40 + - sizeof(struct statistics_rx_ht_phy) * 40 + 400; - ssize_t ret; - struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; - struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; - struct statistics_rx_non_phy *general, *accum_general; - struct statistics_rx_non_phy *delta_general, *max_general; - struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* - * the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - if (iwl_bt_statistics(priv)) { - ofdm = &priv->_agn.statistics_bt.rx.ofdm; - cck = &priv->_agn.statistics_bt.rx.cck; - general = &priv->_agn.statistics_bt.rx.general.common; - ht = &priv->_agn.statistics_bt.rx.ofdm_ht; - accum_ofdm = &priv->_agn.accum_statistics_bt.rx.ofdm; - accum_cck = &priv->_agn.accum_statistics_bt.rx.cck; - accum_general = - &priv->_agn.accum_statistics_bt.rx.general.common; - accum_ht = &priv->_agn.accum_statistics_bt.rx.ofdm_ht; - delta_ofdm = &priv->_agn.delta_statistics_bt.rx.ofdm; - delta_cck = &priv->_agn.delta_statistics_bt.rx.cck; - delta_general = - &priv->_agn.delta_statistics_bt.rx.general.common; - delta_ht = &priv->_agn.delta_statistics_bt.rx.ofdm_ht; - max_ofdm = &priv->_agn.max_delta_bt.rx.ofdm; - max_cck = &priv->_agn.max_delta_bt.rx.cck; - max_general = &priv->_agn.max_delta_bt.rx.general.common; - max_ht = &priv->_agn.max_delta_bt.rx.ofdm_ht; - } else { - ofdm = &priv->_agn.statistics.rx.ofdm; - cck = &priv->_agn.statistics.rx.cck; - general = &priv->_agn.statistics.rx.general; - ht = &priv->_agn.statistics.rx.ofdm_ht; - accum_ofdm = &priv->_agn.accum_statistics.rx.ofdm; - accum_cck = &priv->_agn.accum_statistics.rx.cck; - accum_general = &priv->_agn.accum_statistics.rx.general; - accum_ht = &priv->_agn.accum_statistics.rx.ofdm_ht; - delta_ofdm = &priv->_agn.delta_statistics.rx.ofdm; - delta_cck = &priv->_agn.delta_statistics.rx.cck; - delta_general = &priv->_agn.delta_statistics.rx.general; - delta_ht = &priv->_agn.delta_statistics.rx.ofdm_ht; - max_ofdm = &priv->_agn.max_delta.rx.ofdm; - max_cck = &priv->_agn.max_delta.rx.cck; - max_general = &priv->_agn.max_delta.rx.general; - max_ht = &priv->_agn.max_delta.rx.ofdm_ht; - } - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - OFDM:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ina_cnt:", - le32_to_cpu(ofdm->ina_cnt), - accum_ofdm->ina_cnt, - delta_ofdm->ina_cnt, max_ofdm->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_cnt:", - le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, - delta_ofdm->fina_cnt, max_ofdm->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "plcp_err:", - le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, - delta_ofdm->plcp_err, max_ofdm->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_err:", - le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, - delta_ofdm->crc32_err, max_ofdm->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "overrun_err:", - le32_to_cpu(ofdm->overrun_err), - accum_ofdm->overrun_err, delta_ofdm->overrun_err, - max_ofdm->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "early_overrun_err:", - le32_to_cpu(ofdm->early_overrun_err), - accum_ofdm->early_overrun_err, - delta_ofdm->early_overrun_err, - max_ofdm->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_good:", - le32_to_cpu(ofdm->crc32_good), - accum_ofdm->crc32_good, delta_ofdm->crc32_good, - max_ofdm->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "false_alarm_cnt:", - le32_to_cpu(ofdm->false_alarm_cnt), - accum_ofdm->false_alarm_cnt, - delta_ofdm->false_alarm_cnt, - max_ofdm->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_sync_err_cnt:", - le32_to_cpu(ofdm->fina_sync_err_cnt), - accum_ofdm->fina_sync_err_cnt, - delta_ofdm->fina_sync_err_cnt, - max_ofdm->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sfd_timeout:", - le32_to_cpu(ofdm->sfd_timeout), - accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout, - max_ofdm->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_timeout:", - le32_to_cpu(ofdm->fina_timeout), - accum_ofdm->fina_timeout, delta_ofdm->fina_timeout, - max_ofdm->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "unresponded_rts:", - le32_to_cpu(ofdm->unresponded_rts), - accum_ofdm->unresponded_rts, - delta_ofdm->unresponded_rts, - max_ofdm->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rxe_frame_lmt_ovrun:", - le32_to_cpu(ofdm->rxe_frame_limit_overrun), - accum_ofdm->rxe_frame_limit_overrun, - delta_ofdm->rxe_frame_limit_overrun, - max_ofdm->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ack_cnt:", - le32_to_cpu(ofdm->sent_ack_cnt), - accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt, - max_ofdm->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_cts_cnt:", - le32_to_cpu(ofdm->sent_cts_cnt), - accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt, - max_ofdm->sent_cts_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ba_rsp_cnt:", - le32_to_cpu(ofdm->sent_ba_rsp_cnt), - accum_ofdm->sent_ba_rsp_cnt, - delta_ofdm->sent_ba_rsp_cnt, - max_ofdm->sent_ba_rsp_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dsp_self_kill:", - le32_to_cpu(ofdm->dsp_self_kill), - accum_ofdm->dsp_self_kill, - delta_ofdm->dsp_self_kill, - max_ofdm->dsp_self_kill); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "mh_format_err:", - le32_to_cpu(ofdm->mh_format_err), - accum_ofdm->mh_format_err, - delta_ofdm->mh_format_err, - max_ofdm->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "re_acq_main_rssi_sum:", - le32_to_cpu(ofdm->re_acq_main_rssi_sum), - accum_ofdm->re_acq_main_rssi_sum, - delta_ofdm->re_acq_main_rssi_sum, - max_ofdm->re_acq_main_rssi_sum); - - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - CCK:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ina_cnt:", - le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, - delta_cck->ina_cnt, max_cck->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_cnt:", - le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, - delta_cck->fina_cnt, max_cck->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "plcp_err:", - le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, - delta_cck->plcp_err, max_cck->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_err:", - le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, - delta_cck->crc32_err, max_cck->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "overrun_err:", - le32_to_cpu(cck->overrun_err), - accum_cck->overrun_err, delta_cck->overrun_err, - max_cck->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "early_overrun_err:", - le32_to_cpu(cck->early_overrun_err), - accum_cck->early_overrun_err, - delta_cck->early_overrun_err, - max_cck->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_good:", - le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, - delta_cck->crc32_good, max_cck->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "false_alarm_cnt:", - le32_to_cpu(cck->false_alarm_cnt), - accum_cck->false_alarm_cnt, - delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_sync_err_cnt:", - le32_to_cpu(cck->fina_sync_err_cnt), - accum_cck->fina_sync_err_cnt, - delta_cck->fina_sync_err_cnt, - max_cck->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sfd_timeout:", - le32_to_cpu(cck->sfd_timeout), - accum_cck->sfd_timeout, delta_cck->sfd_timeout, - max_cck->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_timeout:", - le32_to_cpu(cck->fina_timeout), - accum_cck->fina_timeout, delta_cck->fina_timeout, - max_cck->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "unresponded_rts:", - le32_to_cpu(cck->unresponded_rts), - accum_cck->unresponded_rts, delta_cck->unresponded_rts, - max_cck->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rxe_frame_lmt_ovrun:", - le32_to_cpu(cck->rxe_frame_limit_overrun), - accum_cck->rxe_frame_limit_overrun, - delta_cck->rxe_frame_limit_overrun, - max_cck->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ack_cnt:", - le32_to_cpu(cck->sent_ack_cnt), - accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt, - max_cck->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_cts_cnt:", - le32_to_cpu(cck->sent_cts_cnt), - accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt, - max_cck->sent_cts_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ba_rsp_cnt:", - le32_to_cpu(cck->sent_ba_rsp_cnt), - accum_cck->sent_ba_rsp_cnt, - delta_cck->sent_ba_rsp_cnt, - max_cck->sent_ba_rsp_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dsp_self_kill:", - le32_to_cpu(cck->dsp_self_kill), - accum_cck->dsp_self_kill, delta_cck->dsp_self_kill, - max_cck->dsp_self_kill); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "mh_format_err:", - le32_to_cpu(cck->mh_format_err), - accum_cck->mh_format_err, delta_cck->mh_format_err, - max_cck->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "re_acq_main_rssi_sum:", - le32_to_cpu(cck->re_acq_main_rssi_sum), - accum_cck->re_acq_main_rssi_sum, - delta_cck->re_acq_main_rssi_sum, - max_cck->re_acq_main_rssi_sum); - - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - GENERAL:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bogus_cts:", - le32_to_cpu(general->bogus_cts), - accum_general->bogus_cts, delta_general->bogus_cts, - max_general->bogus_cts); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bogus_ack:", - le32_to_cpu(general->bogus_ack), - accum_general->bogus_ack, delta_general->bogus_ack, - max_general->bogus_ack); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "non_bssid_frames:", - le32_to_cpu(general->non_bssid_frames), - accum_general->non_bssid_frames, - delta_general->non_bssid_frames, - max_general->non_bssid_frames); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "filtered_frames:", - le32_to_cpu(general->filtered_frames), - accum_general->filtered_frames, - delta_general->filtered_frames, - max_general->filtered_frames); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "non_channel_beacons:", - le32_to_cpu(general->non_channel_beacons), - accum_general->non_channel_beacons, - delta_general->non_channel_beacons, - max_general->non_channel_beacons); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "channel_beacons:", - le32_to_cpu(general->channel_beacons), - accum_general->channel_beacons, - delta_general->channel_beacons, - max_general->channel_beacons); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "num_missed_bcon:", - le32_to_cpu(general->num_missed_bcon), - accum_general->num_missed_bcon, - delta_general->num_missed_bcon, - max_general->num_missed_bcon); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "adc_rx_saturation_time:", - le32_to_cpu(general->adc_rx_saturation_time), - accum_general->adc_rx_saturation_time, - delta_general->adc_rx_saturation_time, - max_general->adc_rx_saturation_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ina_detect_search_tm:", - le32_to_cpu(general->ina_detection_search_time), - accum_general->ina_detection_search_time, - delta_general->ina_detection_search_time, - max_general->ina_detection_search_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_silence_rssi_a:", - le32_to_cpu(general->beacon_silence_rssi_a), - accum_general->beacon_silence_rssi_a, - delta_general->beacon_silence_rssi_a, - max_general->beacon_silence_rssi_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_silence_rssi_b:", - le32_to_cpu(general->beacon_silence_rssi_b), - accum_general->beacon_silence_rssi_b, - delta_general->beacon_silence_rssi_b, - max_general->beacon_silence_rssi_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_silence_rssi_c:", - le32_to_cpu(general->beacon_silence_rssi_c), - accum_general->beacon_silence_rssi_c, - delta_general->beacon_silence_rssi_c, - max_general->beacon_silence_rssi_c); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "interference_data_flag:", - le32_to_cpu(general->interference_data_flag), - accum_general->interference_data_flag, - delta_general->interference_data_flag, - max_general->interference_data_flag); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "channel_load:", - le32_to_cpu(general->channel_load), - accum_general->channel_load, - delta_general->channel_load, - max_general->channel_load); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dsp_false_alarms:", - le32_to_cpu(general->dsp_false_alarms), - accum_general->dsp_false_alarms, - delta_general->dsp_false_alarms, - max_general->dsp_false_alarms); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_rssi_a:", - le32_to_cpu(general->beacon_rssi_a), - accum_general->beacon_rssi_a, - delta_general->beacon_rssi_a, - max_general->beacon_rssi_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_rssi_b:", - le32_to_cpu(general->beacon_rssi_b), - accum_general->beacon_rssi_b, - delta_general->beacon_rssi_b, - max_general->beacon_rssi_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_rssi_c:", - le32_to_cpu(general->beacon_rssi_c), - accum_general->beacon_rssi_c, - delta_general->beacon_rssi_c, - max_general->beacon_rssi_c); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_energy_a:", - le32_to_cpu(general->beacon_energy_a), - accum_general->beacon_energy_a, - delta_general->beacon_energy_a, - max_general->beacon_energy_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_energy_b:", - le32_to_cpu(general->beacon_energy_b), - accum_general->beacon_energy_b, - delta_general->beacon_energy_b, - max_general->beacon_energy_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_energy_c:", - le32_to_cpu(general->beacon_energy_c), - accum_general->beacon_energy_c, - delta_general->beacon_energy_c, - max_general->beacon_energy_c); - - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - OFDM_HT:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "plcp_err:", - le32_to_cpu(ht->plcp_err), accum_ht->plcp_err, - delta_ht->plcp_err, max_ht->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "overrun_err:", - le32_to_cpu(ht->overrun_err), accum_ht->overrun_err, - delta_ht->overrun_err, max_ht->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "early_overrun_err:", - le32_to_cpu(ht->early_overrun_err), - accum_ht->early_overrun_err, - delta_ht->early_overrun_err, - max_ht->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_good:", - le32_to_cpu(ht->crc32_good), accum_ht->crc32_good, - delta_ht->crc32_good, max_ht->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_err:", - le32_to_cpu(ht->crc32_err), accum_ht->crc32_err, - delta_ht->crc32_err, max_ht->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "mh_format_err:", - le32_to_cpu(ht->mh_format_err), - accum_ht->mh_format_err, - delta_ht->mh_format_err, max_ht->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg_crc32_good:", - le32_to_cpu(ht->agg_crc32_good), - accum_ht->agg_crc32_good, - delta_ht->agg_crc32_good, max_ht->agg_crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg_mpdu_cnt:", - le32_to_cpu(ht->agg_mpdu_cnt), - accum_ht->agg_mpdu_cnt, - delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg_cnt:", - le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt, - delta_ht->agg_cnt, max_ht->agg_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "unsupport_mcs:", - le32_to_cpu(ht->unsupport_mcs), - accum_ht->unsupport_mcs, - delta_ht->unsupport_mcs, max_ht->unsupport_mcs); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_ucode_tx_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct statistics_tx) * 48) + 250; - ssize_t ret; - struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - if (iwl_bt_statistics(priv)) { - tx = &priv->_agn.statistics_bt.tx; - accum_tx = &priv->_agn.accum_statistics_bt.tx; - delta_tx = &priv->_agn.delta_statistics_bt.tx; - max_tx = &priv->_agn.max_delta_bt.tx; - } else { - tx = &priv->_agn.statistics.tx; - accum_tx = &priv->_agn.accum_statistics.tx; - delta_tx = &priv->_agn.delta_statistics.tx; - max_tx = &priv->_agn.max_delta.tx; - } - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Tx:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "preamble:", - le32_to_cpu(tx->preamble_cnt), - accum_tx->preamble_cnt, - delta_tx->preamble_cnt, max_tx->preamble_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rx_detected_cnt:", - le32_to_cpu(tx->rx_detected_cnt), - accum_tx->rx_detected_cnt, - delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bt_prio_defer_cnt:", - le32_to_cpu(tx->bt_prio_defer_cnt), - accum_tx->bt_prio_defer_cnt, - delta_tx->bt_prio_defer_cnt, - max_tx->bt_prio_defer_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bt_prio_kill_cnt:", - le32_to_cpu(tx->bt_prio_kill_cnt), - accum_tx->bt_prio_kill_cnt, - delta_tx->bt_prio_kill_cnt, - max_tx->bt_prio_kill_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "few_bytes_cnt:", - le32_to_cpu(tx->few_bytes_cnt), - accum_tx->few_bytes_cnt, - delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "cts_timeout:", - le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, - delta_tx->cts_timeout, max_tx->cts_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ack_timeout:", - le32_to_cpu(tx->ack_timeout), - accum_tx->ack_timeout, - delta_tx->ack_timeout, max_tx->ack_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "expected_ack_cnt:", - le32_to_cpu(tx->expected_ack_cnt), - accum_tx->expected_ack_cnt, - delta_tx->expected_ack_cnt, - max_tx->expected_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "actual_ack_cnt:", - le32_to_cpu(tx->actual_ack_cnt), - accum_tx->actual_ack_cnt, - delta_tx->actual_ack_cnt, - max_tx->actual_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dump_msdu_cnt:", - le32_to_cpu(tx->dump_msdu_cnt), - accum_tx->dump_msdu_cnt, - delta_tx->dump_msdu_cnt, - max_tx->dump_msdu_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "abort_nxt_frame_mismatch:", - le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), - accum_tx->burst_abort_next_frame_mismatch_cnt, - delta_tx->burst_abort_next_frame_mismatch_cnt, - max_tx->burst_abort_next_frame_mismatch_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "abort_missing_nxt_frame:", - le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), - accum_tx->burst_abort_missing_next_frame_cnt, - delta_tx->burst_abort_missing_next_frame_cnt, - max_tx->burst_abort_missing_next_frame_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "cts_timeout_collision:", - le32_to_cpu(tx->cts_timeout_collision), - accum_tx->cts_timeout_collision, - delta_tx->cts_timeout_collision, - max_tx->cts_timeout_collision); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ack_ba_timeout_collision:", - le32_to_cpu(tx->ack_or_ba_timeout_collision), - accum_tx->ack_or_ba_timeout_collision, - delta_tx->ack_or_ba_timeout_collision, - max_tx->ack_or_ba_timeout_collision); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg ba_timeout:", - le32_to_cpu(tx->agg.ba_timeout), - accum_tx->agg.ba_timeout, - delta_tx->agg.ba_timeout, - max_tx->agg.ba_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg ba_resched_frames:", - le32_to_cpu(tx->agg.ba_reschedule_frames), - accum_tx->agg.ba_reschedule_frames, - delta_tx->agg.ba_reschedule_frames, - max_tx->agg.ba_reschedule_frames); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_agg_frame:", - le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), - accum_tx->agg.scd_query_agg_frame_cnt, - delta_tx->agg.scd_query_agg_frame_cnt, - max_tx->agg.scd_query_agg_frame_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_no_agg:", - le32_to_cpu(tx->agg.scd_query_no_agg), - accum_tx->agg.scd_query_no_agg, - delta_tx->agg.scd_query_no_agg, - max_tx->agg.scd_query_no_agg); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_agg:", - le32_to_cpu(tx->agg.scd_query_agg), - accum_tx->agg.scd_query_agg, - delta_tx->agg.scd_query_agg, - max_tx->agg.scd_query_agg); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_mismatch:", - le32_to_cpu(tx->agg.scd_query_mismatch), - accum_tx->agg.scd_query_mismatch, - delta_tx->agg.scd_query_mismatch, - max_tx->agg.scd_query_mismatch); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg frame_not_ready:", - le32_to_cpu(tx->agg.frame_not_ready), - accum_tx->agg.frame_not_ready, - delta_tx->agg.frame_not_ready, - max_tx->agg.frame_not_ready); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg underrun:", - le32_to_cpu(tx->agg.underrun), - accum_tx->agg.underrun, - delta_tx->agg.underrun, max_tx->agg.underrun); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg bt_prio_kill:", - le32_to_cpu(tx->agg.bt_prio_kill), - accum_tx->agg.bt_prio_kill, - delta_tx->agg.bt_prio_kill, - max_tx->agg.bt_prio_kill); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg rx_ba_rsp_cnt:", - le32_to_cpu(tx->agg.rx_ba_rsp_cnt), - accum_tx->agg.rx_ba_rsp_cnt, - delta_tx->agg.rx_ba_rsp_cnt, - max_tx->agg.rx_ba_rsp_cnt); - - if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) { - pos += scnprintf(buf + pos, bufsz - pos, - "tx power: (1/2 dB step)\n"); - if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a) - pos += scnprintf(buf + pos, bufsz - pos, - fmt_hex, "antenna A:", - tx->tx_power.ant_a); - if ((priv->cfg->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 ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c) - pos += scnprintf(buf + pos, bufsz - pos, - fmt_hex, "antenna C:", - tx->tx_power.ant_c); - } - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = sizeof(struct statistics_general) * 10 + 300; - ssize_t ret; - struct statistics_general_common *general, *accum_general; - struct statistics_general_common *delta_general, *max_general; - struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; - struct statistics_div *div, *accum_div, *delta_div, *max_div; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - if (iwl_bt_statistics(priv)) { - general = &priv->_agn.statistics_bt.general.common; - dbg = &priv->_agn.statistics_bt.general.common.dbg; - div = &priv->_agn.statistics_bt.general.common.div; - accum_general = &priv->_agn.accum_statistics_bt.general.common; - accum_dbg = &priv->_agn.accum_statistics_bt.general.common.dbg; - accum_div = &priv->_agn.accum_statistics_bt.general.common.div; - delta_general = &priv->_agn.delta_statistics_bt.general.common; - max_general = &priv->_agn.max_delta_bt.general.common; - delta_dbg = &priv->_agn.delta_statistics_bt.general.common.dbg; - max_dbg = &priv->_agn.max_delta_bt.general.common.dbg; - delta_div = &priv->_agn.delta_statistics_bt.general.common.div; - max_div = &priv->_agn.max_delta_bt.general.common.div; - } else { - general = &priv->_agn.statistics.general.common; - dbg = &priv->_agn.statistics.general.common.dbg; - div = &priv->_agn.statistics.general.common.div; - accum_general = &priv->_agn.accum_statistics.general.common; - accum_dbg = &priv->_agn.accum_statistics.general.common.dbg; - accum_div = &priv->_agn.accum_statistics.general.common.div; - delta_general = &priv->_agn.delta_statistics.general.common; - max_general = &priv->_agn.max_delta.general.common; - delta_dbg = &priv->_agn.delta_statistics.general.common.dbg; - max_dbg = &priv->_agn.max_delta.general.common.dbg; - delta_div = &priv->_agn.delta_statistics.general.common.div; - max_div = &priv->_agn.max_delta.general.common.div; - } - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_General:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_value, "temperature:", - le32_to_cpu(general->temperature)); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_value, "temperature_m:", - le32_to_cpu(general->temperature_m)); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_value, "ttl_timestamp:", - le32_to_cpu(general->ttl_timestamp)); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "burst_check:", - le32_to_cpu(dbg->burst_check), - accum_dbg->burst_check, - delta_dbg->burst_check, max_dbg->burst_check); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "burst_count:", - le32_to_cpu(dbg->burst_count), - accum_dbg->burst_count, - delta_dbg->burst_count, max_dbg->burst_count); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "wait_for_silence_timeout_count:", - le32_to_cpu(dbg->wait_for_silence_timeout_cnt), - accum_dbg->wait_for_silence_timeout_cnt, - delta_dbg->wait_for_silence_timeout_cnt, - max_dbg->wait_for_silence_timeout_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sleep_time:", - le32_to_cpu(general->sleep_time), - accum_general->sleep_time, - delta_general->sleep_time, max_general->sleep_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "slots_out:", - le32_to_cpu(general->slots_out), - accum_general->slots_out, - delta_general->slots_out, max_general->slots_out); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "slots_idle:", - le32_to_cpu(general->slots_idle), - accum_general->slots_idle, - delta_general->slots_idle, max_general->slots_idle); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "tx_on_a:", - le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, - delta_div->tx_on_a, max_div->tx_on_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "tx_on_b:", - le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, - delta_div->tx_on_b, max_div->tx_on_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "exec_time:", - le32_to_cpu(div->exec_time), accum_div->exec_time, - delta_div->exec_time, max_div->exec_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "probe_time:", - le32_to_cpu(div->probe_time), accum_div->probe_time, - delta_div->probe_time, max_div->probe_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rx_enable_counter:", - le32_to_cpu(general->rx_enable_counter), - accum_general->rx_enable_counter, - delta_general->rx_enable_counter, - max_general->rx_enable_counter); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "num_of_sos_states:", - le32_to_cpu(general->num_of_sos_states), - accum_general->num_of_sos_states, - delta_general->num_of_sos_states, - max_general->num_of_sos_states); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_ucode_bt_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200; - ssize_t ret; - struct statistics_bt_activity *bt, *accum_bt; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - if (!priv->bt_enable_flag) - return -EINVAL; - - /* make request to uCode to retrieve statistics information */ - mutex_lock(&priv->mutex); - 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); - return -EAGAIN; - } - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* - * the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - bt = &priv->_agn.statistics_bt.general.activity; - accum_bt = &priv->_agn.accum_statistics_bt.general.activity; - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "\t\t\tcurrent\t\t\taccumulative\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_tx_req_cnt), - accum_bt->hi_priority_tx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_tx_denied_cnt), - accum_bt->hi_priority_tx_denied_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_tx_req_cnt), - accum_bt->lo_priority_tx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_tx_denied_cnt), - accum_bt->lo_priority_tx_denied_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_rx_req_cnt), - accum_bt->hi_priority_rx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_rx_denied_cnt), - accum_bt->hi_priority_rx_denied_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_rx_req_cnt), - accum_bt->lo_priority_rx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_rx_denied_cnt), - accum_bt->lo_priority_rx_denied_cnt); - - pos += scnprintf(buf + pos, bufsz - pos, - "(rx)num_bt_kills:\t\t%u\t\t\t%u\n", - le32_to_cpu(priv->_agn.statistics_bt.rx. - general.num_bt_kills), - priv->_agn.accum_statistics_bt.rx. - general.num_bt_kills); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_reply_tx_error_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) + - (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200; - ssize_t ret; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - 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", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY), - priv->_agn.reply_tx_stats.pp_delay); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES), - priv->_agn.reply_tx_stats.pp_few_bytes); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO), - priv->_agn.reply_tx_stats.pp_bt_prio); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD), - priv->_agn.reply_tx_stats.pp_quiet_period); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK), - priv->_agn.reply_tx_stats.pp_calc_ttak); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_tx_fail_reason( - TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY), - priv->_agn.reply_tx_stats.int_crossed_retry); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT), - priv->_agn.reply_tx_stats.short_limit); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT), - priv->_agn.reply_tx_stats.long_limit); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN), - priv->_agn.reply_tx_stats.fifo_underrun); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW), - priv->_agn.reply_tx_stats.drain_flow); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH), - priv->_agn.reply_tx_stats.rfkill_flush); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE), - priv->_agn.reply_tx_stats.life_expire); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS), - priv->_agn.reply_tx_stats.dest_ps); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED), - priv->_agn.reply_tx_stats.host_abort); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY), - priv->_agn.reply_tx_stats.pp_delay); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID), - priv->_agn.reply_tx_stats.sta_invalid); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED), - priv->_agn.reply_tx_stats.frag_drop); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE), - priv->_agn.reply_tx_stats.tid_disable); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED), - priv->_agn.reply_tx_stats.fifo_flush); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_tx_fail_reason( - TX_STATUS_FAIL_INSUFFICIENT_CF_POLL), - priv->_agn.reply_tx_stats.insuff_cf_poll); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX), - priv->_agn.reply_tx_stats.fail_hw_drop); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_tx_fail_reason( - TX_STATUS_FAIL_NO_BEACON_ON_RADAR), - priv->_agn.reply_tx_stats.sta_color_mismatch); - pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", - priv->_agn.reply_tx_stats.unknown); - - pos += scnprintf(buf + pos, bufsz - pos, - "\nStatistics_Agg_TX_Error:\n"); - - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK), - priv->_agn.reply_agg_tx_stats.underrun); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK), - priv->_agn.reply_agg_tx_stats.bt_prio); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK), - priv->_agn.reply_agg_tx_stats.few_bytes); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK), - priv->_agn.reply_agg_tx_stats.abort); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_LAST_SENT_TTL_MSK), - priv->_agn.reply_agg_tx_stats.last_sent_ttl); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK), - priv->_agn.reply_agg_tx_stats.last_sent_try); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_LAST_SENT_BT_KILL_MSK), - priv->_agn.reply_agg_tx_stats.last_sent_bt_kill); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK), - priv->_agn.reply_agg_tx_stats.scd_query); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_TEST_BAD_CRC32_MSK), - priv->_agn.reply_agg_tx_stats.bad_crc32); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK), - priv->_agn.reply_agg_tx_stats.response); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK), - priv->_agn.reply_agg_tx_stats.dump_tx); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK), - priv->_agn.reply_agg_tx_stats.delay_tx); - pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", - priv->_agn.reply_agg_tx_stats.unknown); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h deleted file mode 100644 index f2573b5486cd..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h +++ /dev/null @@ -1,70 +0,0 @@ -/****************************************************************************** - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2010 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 "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-debug.h" - -#ifdef CONFIG_IWLWIFI_DEBUGFS -ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -#else -static ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c index 27b5a3eec9dc..2ef9448b1c20 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -81,52 +81,13 @@ * ******************************************************************************/ -/* - * The device's EEPROM semaphore prevents conflicts between driver and uCode - * when accessing the EEPROM; each access is a series of pulses to/from the - * EEPROM chip, not a single event, so even reads could conflict if they - * weren't arbitrated by the semaphore. - */ -int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) -{ - u16 count; - int ret; - - for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { - /* Request semaphore */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - - /* See if we got it */ - ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - EEPROM_SEM_TIMEOUT); - if (ret >= 0) { - IWL_DEBUG_IO(priv, - "Acquired semaphore after %d tries.\n", - count+1); - return ret; - } - } - - return ret; -} - -void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv) -{ - iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - -} - int iwl_eeprom_check_version(struct iwl_priv *priv) { u16 eeprom_ver; u16 calib_ver; eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv); + calib_ver = iwlagn_eeprom_calib_version(priv); if (eeprom_ver < priv->cfg->eeprom_ver || calib_ver < priv->cfg->eeprom_calib_ver) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 41543ad4cb84..b12c72d63ccb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -37,54 +37,6 @@ #include "iwl-io.h" #include "iwl-agn.h" -int iwlagn_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - int ret = 0; - struct iwl5000_rxon_assoc_cmd rxon_assoc; - const struct iwl_rxon_cmd *rxon1 = &ctx->staging; - const struct iwl_rxon_cmd *rxon2 = &ctx->active; - - if ((rxon1->flags == rxon2->flags) && - (rxon1->filter_flags == rxon2->filter_flags) && - (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && - (rxon1->ofdm_ht_single_stream_basic_rates == - rxon2->ofdm_ht_single_stream_basic_rates) && - (rxon1->ofdm_ht_dual_stream_basic_rates == - rxon2->ofdm_ht_dual_stream_basic_rates) && - (rxon1->ofdm_ht_triple_stream_basic_rates == - rxon2->ofdm_ht_triple_stream_basic_rates) && - (rxon1->acquisition_data == rxon2->acquisition_data) && - (rxon1->rx_chain == rxon2->rx_chain) && - (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { - IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); - return 0; - } - - rxon_assoc.flags = ctx->staging.flags; - rxon_assoc.filter_flags = ctx->staging.filter_flags; - rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; - rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; - rxon_assoc.reserved1 = 0; - rxon_assoc.reserved2 = 0; - rxon_assoc.reserved3 = 0; - rxon_assoc.ofdm_ht_single_stream_basic_rates = - ctx->staging.ofdm_ht_single_stream_basic_rates; - rxon_assoc.ofdm_ht_dual_stream_basic_rates = - ctx->staging.ofdm_ht_dual_stream_basic_rates; - rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; - rxon_assoc.ofdm_ht_triple_stream_basic_rates = - ctx->staging.ofdm_ht_triple_stream_basic_rates; - rxon_assoc.acquisition_data = ctx->staging.acquisition_data; - - ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd, - sizeof(rxon_assoc), &rxon_assoc, NULL); - if (ret) - return ret; - - return ret; -} - int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) { struct iwl_tx_ant_config_cmd tx_ant_cmd = { @@ -102,12 +54,6 @@ int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) } } -/* Currently this is the superset of everything */ -static u16 iwlagn_get_hcmd_size(u8 cmd_id, u16 len) -{ - return len; -} - static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { u16 size = (u16)sizeof(struct iwl_addsta_cmd); @@ -364,7 +310,6 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) } struct iwl_hcmd_ops iwlagn_hcmd = { - .rxon_assoc = iwlagn_send_rxon_assoc, .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwlagn_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, @@ -373,7 +318,6 @@ struct iwl_hcmd_ops iwlagn_hcmd = { }; struct iwl_hcmd_ops iwlagn_bt_hcmd = { - .rxon_assoc = iwlagn_send_rxon_assoc, .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwlagn_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, @@ -382,7 +326,6 @@ struct iwl_hcmd_ops iwlagn_bt_hcmd = { }; struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = { - .get_hcmd_size = iwlagn_get_hcmd_size, .build_addsta_hcmd = iwlagn_build_addsta_hcmd, .gain_computation = iwlagn_gain_computation, .chain_noise_reset = iwlagn_chain_noise_reset, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index a52b82c8e7a6..7bd19f4e66de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c index ed0148d714de..0d5fda44c3a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -59,8 +59,6 @@ void iwl_free_isr_ict(struct iwl_priv *priv) int iwl_alloc_isr_ict(struct iwl_priv *priv) { - if (priv->cfg->base_params->use_isr_legacy) - return 0; /* allocate shrared data table */ priv->_agn.ict_tbl_vir = dma_alloc_coherent(&priv->pci_dev->dev, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c deleted file mode 100644 index c1190d965614..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.c +++ /dev/null @@ -1,73 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2010 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 - * - *****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iwl-commands.h" -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-io.h" -#include "iwl-agn-led.h" - -/* Send led command */ -static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) -{ - struct iwl_host_cmd cmd = { - .id = REPLY_LEDS_CMD, - .len = sizeof(struct iwl_led_cmd), - .data = led_cmd, - .flags = CMD_ASYNC, - .callback = NULL, - }; - u32 reg; - - reg = iwl_read32(priv, CSR_LED_REG); - if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) - iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); - - return iwl_send_cmd(priv, &cmd); -} - -/* Set led register off */ -void iwlagn_led_enable(struct iwl_priv *priv) -{ - iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); -} - -const struct iwl_led_ops iwlagn_led_ops = { - .cmd = iwl_send_led_cmd, -}; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 08ccb9496f76..8e79653aed9a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -172,6 +172,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status) static void iwlagn_set_tx_status(struct iwl_priv *priv, struct ieee80211_tx_info *info, + struct iwl_rxon_context *ctx, struct iwlagn_tx_resp *tx_resp, int txq_id, bool is_agg) { @@ -186,6 +187,13 @@ static void iwlagn_set_tx_status(struct iwl_priv *priv, if (!iwl_is_tx_success(status)) iwlagn_count_tx_err_status(priv, status); + if (status == TX_STATUS_FAIL_PASSIVE_NO_RX && + iwl_is_associated_ctx(ctx) && ctx->vif && + ctx->vif->type == NL80211_IFTYPE_STATION) { + ctx->last_tx_rejected = true; + iwl_stop_queue(priv, &priv->txq[txq_id]); + } + IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags " "0x%x retries %d\n", txq_id, @@ -242,15 +250,16 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv, /* # frames attempted by Tx command */ if (agg->frame_count == 1) { + struct iwl_tx_info *txb; + /* Only one frame was attempted; no block-ack will arrive */ idx = start_idx; IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n", agg->frame_count, agg->start_idx, idx); - iwlagn_set_tx_status(priv, - IEEE80211_SKB_CB( - priv->txq[txq_id].txb[idx].skb), - tx_resp, txq_id, true); + txb = &priv->txq[txq_id].txb[idx]; + iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(txb->skb), + txb->ctx, tx_resp, txq_id, true); agg->wait_for_ba = 0; } else { /* Two or more frames were attempted; expect block-ack */ @@ -391,7 +400,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct ieee80211_tx_info *info; struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; - u32 status = le16_to_cpu(tx_resp->status.status); + struct iwl_tx_info *txb; + u32 status = le16_to_cpu(tx_resp->status.status); int tid; int sta_id; int freed; @@ -406,7 +416,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, } txq->time_stamp = jiffies; - info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb); + txb = &txq->txb[txq->q.read_ptr]; + info = IEEE80211_SKB_CB(txb->skb); memset(&info->status, 0, sizeof(info->status)); tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> @@ -450,12 +461,14 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, iwl_wake_queue(priv, txq); } } else { - iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false); + iwlagn_set_tx_status(priv, info, txb->ctx, tx_resp, + txq_id, false); freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); iwl_free_tfds_in_queue(priv, sta_id, tid, freed); if (priv->mac80211_registered && - (iwl_queue_space(&txq->q) > txq->q.low_mark)) + iwl_queue_space(&txq->q) > txq->q.low_mark && + status != TX_STATUS_FAIL_PASSIVE_NO_RX) iwl_wake_queue(priv, txq); } @@ -470,8 +483,6 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv) /* init calibration handlers */ priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = iwlagn_rx_calib_result; - priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] = - iwlagn_rx_calib_complete; priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; /* set up notification wait support */ @@ -482,8 +493,10 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv) void iwlagn_setup_deferred_work(struct iwl_priv *priv) { - /* in agn, the tx power calibration is done in uCode */ - priv->disable_tx_power_cal = 1; + /* + * nothing need to be done here anymore + * still keep for future use if needed + */ } int iwlagn_hw_valid_rtc_data_addr(u32 addr) @@ -534,9 +547,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv) void iwlagn_temperature(struct iwl_priv *priv) { /* store temperature from correct statistics (in Celsius) */ - priv->temperature = le32_to_cpu((iwl_bt_statistics(priv)) ? - priv->_agn.statistics_bt.general.common.temperature : - priv->_agn.statistics.general.common.temperature); + priv->temperature = le32_to_cpu(priv->statistics.common.temperature); iwl_tt_handler(priv); } @@ -652,10 +663,9 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ - if (!priv->cfg->base_params->use_isr_legacy) - rb_timeout = RX_RB_TIMEOUT; + rb_timeout = RX_RB_TIMEOUT; - if (priv->cfg->mod_params->amsdu_size_8K) + if (iwlagn_mod_params.amsdu_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; @@ -913,7 +923,6 @@ void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority) list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; - priv->alloc_rxb_page++; spin_unlock_irqrestore(&rxq->lock, flags); } @@ -1285,9 +1294,17 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) * mean we never reach it, but at the same time work around * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER * here instead of IWL_GOOD_CRC_TH_DISABLED. + * + * This was fixed in later versions along with some other + * scan changes, and the threshold behaves as a flag in those + * versions. */ - scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : - IWL_GOOD_CRC_TH_NEVER; + if (priv->new_scan_threshold_behaviour) + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_DISABLED; + else + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_NEVER; band = priv->scan_band; @@ -2245,34 +2262,44 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) /* notification wait support */ void iwlagn_init_notification_wait(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry, + u8 cmd, void (*fn)(struct iwl_priv *priv, - struct iwl_rx_packet *pkt), - u8 cmd) + struct iwl_rx_packet *pkt, + void *data), + void *fn_data) { wait_entry->fn = fn; + wait_entry->fn_data = fn_data; wait_entry->cmd = cmd; wait_entry->triggered = false; + wait_entry->aborted = false; spin_lock_bh(&priv->_agn.notif_wait_lock); list_add(&wait_entry->list, &priv->_agn.notif_waits); spin_unlock_bh(&priv->_agn.notif_wait_lock); } -signed long iwlagn_wait_notification(struct iwl_priv *priv, - struct iwl_notification_wait *wait_entry, - unsigned long timeout) +int iwlagn_wait_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + unsigned long timeout) { int ret; ret = wait_event_timeout(priv->_agn.notif_waitq, - wait_entry->triggered, + wait_entry->triggered || wait_entry->aborted, timeout); spin_lock_bh(&priv->_agn.notif_wait_lock); list_del(&wait_entry->list); spin_unlock_bh(&priv->_agn.notif_wait_lock); - return ret; + if (wait_entry->aborted) + return -EIO; + + /* return value is always >= 0 */ + if (ret <= 0) + return -ETIMEDOUT; + return 0; } void iwlagn_remove_notification(struct iwl_priv *priv, @@ -2282,3 +2309,87 @@ void iwlagn_remove_notification(struct iwl_priv *priv, list_del(&wait_entry->list); spin_unlock_bh(&priv->_agn.notif_wait_lock); } + +int iwlagn_start_device(struct iwl_priv *priv) +{ + int ret; + + if (iwl_prepare_card_hw(priv)) { + IWL_WARN(priv, "Exit HW not ready\n"); + return -EIO; + } + + /* If platform's RF_KILL switch is NOT set to KILL */ + if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) + clear_bit(STATUS_RF_KILL_HW, &priv->status); + else + set_bit(STATUS_RF_KILL_HW, &priv->status); + + if (iwl_is_rfkill(priv)) { + wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); + iwl_enable_interrupts(priv); + return -ERFKILL; + } + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + ret = iwlagn_hw_nic_init(priv); + if (ret) { + IWL_ERR(priv, "Unable to init nic\n"); + return ret; + } + + /* make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + /* clear (again), then enable host interrupts */ + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_enable_interrupts(priv); + + /* really make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + return 0; +} + +void iwlagn_stop_device(struct iwl_priv *priv) +{ + unsigned long flags; + + /* stop and reset the on-board processor */ + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + + /* tell the device to stop sending interrupts */ + spin_lock_irqsave(&priv->lock, flags); + iwl_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_synchronize_irq(priv); + + /* device going down, Stop using ICT table */ + iwl_disable_ict(priv); + + /* + * If a HW restart happens during firmware loading, + * then the firmware loading might call this function + * and later it might be called again due to the + * restart. So don't process again if the device is + * already dead. + */ + if (test_bit(STATUS_DEVICE_ENABLED, &priv->status)) { + iwlagn_txq_ctx_stop(priv); + iwlagn_rxq_stop(priv); + + /* Power-down device's busmaster DMA clocks */ + iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); + udelay(5); + } + + /* Make sure (redundant) we've released our request to stay awake */ + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* Stop the device, and put it in low power state */ + iwl_apm_stop(priv); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index d03b4734c892..91f26556ac23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 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 @@ -115,13 +115,18 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { /* FIXME:RS: ^^ should be INV (legacy) */ }; +static inline u8 rs_extract_rate(u32 rate_n_flags) +{ + return (u8)(rate_n_flags & RATE_MCS_RATE_MSK); +} + static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) { int idx = 0; /* HT rate format */ if (rate_n_flags & RATE_MCS_HT_MSK) { - idx = (rate_n_flags & 0xff); + idx = rs_extract_rate(rate_n_flags); if (idx >= IWL_RATE_MIMO3_6M_PLCP) idx = idx - IWL_RATE_MIMO3_6M_PLCP; @@ -138,7 +143,8 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) /* legacy rate format, search for match in table */ } else { for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) - if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) + if (iwl_rates[idx].plcp == + rs_extract_rate(rate_n_flags)) return idx; } @@ -239,11 +245,6 @@ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { #define MCS_INDEX_PER_STREAM (8) -static inline u8 rs_extract_rate(u32 rate_n_flags) -{ - return (u8)(rate_n_flags & 0xFF); -} - static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) { window->data = 0; @@ -2770,16 +2771,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, gfp_t gfp) { - struct iwl_lq_sta *lq_sta; struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; struct iwl_priv *priv; priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE(priv, "create station rate scale window\n"); - lq_sta = &sta_priv->lq_sta; - - return lq_sta; + return &sta_priv->lq_sta; } /* @@ -2912,7 +2910,8 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, ant_toggle_cnt = 1; repeat_rate = IWL_NUMBER_TRY; } else { - repeat_rate = IWL_HT_NUMBER_TRY; + repeat_rate = min(IWL_HT_NUMBER_TRY, + LINK_QUAL_AGG_DISABLE_START_DEF - 1); } lq_cmd->general_params.mimo_delimiter = @@ -3087,7 +3086,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, struct iwl_lq_sta *lq_sta = file->private_data; struct iwl_priv *priv; char buf[64]; - int buf_size; + size_t buf_size; u32 parsed_rate; struct iwl_station_priv *sta_priv = container_of(lq_sta, struct iwl_station_priv, lq_sta); @@ -3257,7 +3256,6 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, { char buff[120]; int desc = 0; - ssize_t ret; struct iwl_lq_sta *lq_sta = file->private_data; struct iwl_priv *priv; @@ -3274,8 +3272,7 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, "Bit Rate= %d Mb/s\n", iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); - ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); } static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 184828c72b31..bdae82e7fa90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 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 @@ -41,20 +41,6 @@ struct iwl_rate_info { u8 next_rs_tgg; /* next rate used in TGG rs algo */ }; -struct iwl3945_rate_info { - u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ - u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ - u8 prev_ieee; /* previous rate in IEEE speeds */ - u8 next_ieee; /* next rate in IEEE speeds */ - u8 prev_rs; /* previous rate used in rs algo */ - u8 next_rs; /* next rate used in rs algo */ - u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ - u8 next_rs_tgg; /* next rate used in TGG rs algo */ - u8 table_rs_index; /* index in rate scale table cmd */ - u8 prev_table_rs; /* prev in rate table cmd */ -}; - - /* * These serve as indexes into * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; @@ -75,7 +61,6 @@ enum { IWL_RATE_60M_INDEX, IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */ - IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1, IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, IWL_RATE_INVALID = IWL_RATE_COUNT, }; @@ -98,7 +83,6 @@ enum { enum { IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, - IWL39_LAST_OFDM_RATE = IWL_RATE_54M_INDEX, IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX, IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, @@ -213,7 +197,6 @@ enum { IWL_CCK_BASIC_RATES_MASK) #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) -#define IWL_RATES_MASK_3945 ((1 << IWL_RATE_COUNT_3945) - 1) #define IWL_INVALID_VALUE -1 @@ -453,19 +436,9 @@ static inline u8 first_antenna(u8 mask) } -/** - * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info - * - * The specific throughput table used is based on the type of network - * the associated with, including A, B, G, and G w/ TGG protection - */ -extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); - /* Initialize station's rate scaling information after adding station */ extern void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id); -extern void iwl3945_rs_rate_init(struct iwl_priv *priv, - struct ieee80211_sta *sta, u8 sta_id); /** * iwl_rate_control_register - Register the rate control algorithm callbacks @@ -478,7 +451,6 @@ extern void iwl3945_rs_rate_init(struct iwl_priv *priv, * */ extern int iwlagn_rate_control_register(void); -extern int iwl3945_rate_control_register(void); /** * iwl_rate_control_unregister - Unregister the rate control callbacks @@ -487,6 +459,5 @@ extern int iwl3945_rate_control_register(void); * the driver is unloaded. */ extern void iwlagn_rate_control_unregister(void); -extern void iwl3945_rate_control_unregister(void); #endif /* __iwl_agn__rs__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index dfdbea6e8f99..02387430f7fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 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 @@ -29,6 +29,7 @@ #include "iwl-sta.h" #include "iwl-core.h" #include "iwl-agn-calib.h" +#include "iwl-helpers.h" static int iwlagn_disable_bss(struct iwl_priv *priv, struct iwl_rxon_context *ctx, @@ -57,8 +58,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, u8 old_dev_type = send->dev_type; int ret; - iwlagn_init_notification_wait(priv, &disable_wait, NULL, - REPLY_WIPAN_DEACTIVATION_COMPLETE); + iwlagn_init_notification_wait(priv, &disable_wait, + REPLY_WIPAN_DEACTIVATION_COMPLETE, + NULL, NULL); send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; send->dev_type = RXON_DEV_TYPE_P2P; @@ -71,13 +73,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); iwlagn_remove_notification(priv, &disable_wait); } else { - signed long wait_res; - - wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ); - if (wait_res == 0) { + ret = iwlagn_wait_notification(priv, &disable_wait, HZ); + if (ret) IWL_ERR(priv, "Timed out waiting for PAN disable\n"); - ret = -EIO; - } } return ret; @@ -123,6 +121,151 @@ static int iwlagn_update_beacon(struct iwl_priv *priv, return iwlagn_send_beacon_cmd(priv); } +static int iwlagn_send_rxon_assoc(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret = 0; + struct iwl_rxon_assoc_cmd rxon_assoc; + const struct iwl_rxon_cmd *rxon1 = &ctx->staging; + const struct iwl_rxon_cmd *rxon2 = &ctx->active; + + if ((rxon1->flags == rxon2->flags) && + (rxon1->filter_flags == rxon2->filter_flags) && + (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && + (rxon1->ofdm_ht_single_stream_basic_rates == + rxon2->ofdm_ht_single_stream_basic_rates) && + (rxon1->ofdm_ht_dual_stream_basic_rates == + rxon2->ofdm_ht_dual_stream_basic_rates) && + (rxon1->ofdm_ht_triple_stream_basic_rates == + rxon2->ofdm_ht_triple_stream_basic_rates) && + (rxon1->acquisition_data == rxon2->acquisition_data) && + (rxon1->rx_chain == rxon2->rx_chain) && + (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { + IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); + return 0; + } + + rxon_assoc.flags = ctx->staging.flags; + rxon_assoc.filter_flags = ctx->staging.filter_flags; + rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; + rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; + rxon_assoc.reserved1 = 0; + rxon_assoc.reserved2 = 0; + rxon_assoc.reserved3 = 0; + rxon_assoc.ofdm_ht_single_stream_basic_rates = + ctx->staging.ofdm_ht_single_stream_basic_rates; + rxon_assoc.ofdm_ht_dual_stream_basic_rates = + ctx->staging.ofdm_ht_dual_stream_basic_rates; + rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; + rxon_assoc.ofdm_ht_triple_stream_basic_rates = + ctx->staging.ofdm_ht_triple_stream_basic_rates; + rxon_assoc.acquisition_data = ctx->staging.acquisition_data; + + ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd, + sizeof(rxon_assoc), &rxon_assoc, NULL); + if (ret) + return ret; + + return ret; +} + +static int iwlagn_rxon_disconn(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret; + struct iwl_rxon_cmd *active = (void *)&ctx->active; + + if (ctx->ctxid == IWL_RXON_CTX_BSS) + ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); + else + ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); + if (ret) + return ret; + + /* + * Un-assoc RXON clears the station table and WEP + * keys, so we have to restore those afterwards. + */ + iwl_clear_ucode_stations(priv, ctx); + iwl_restore_stations(priv, ctx); + ret = iwl_restore_default_wep_keys(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); + return ret; + } + + memcpy(active, &ctx->staging, sizeof(*active)); + return 0; +} + +static int iwlagn_rxon_connect(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret; + struct iwl_rxon_cmd *active = (void *)&ctx->active; + + /* RXON timing must be before associated RXON */ + ret = iwl_send_rxon_timing(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); + return ret; + } + /* QoS info may be cleared by previous un-assoc RXON */ + iwlagn_update_qos(priv, ctx); + + /* + * We'll run into this code path when beaconing is + * enabled, but then we also need to send the beacon + * to the device. + */ + if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { + ret = iwlagn_update_beacon(priv, ctx->vif); + if (ret) { + IWL_ERR(priv, + "Error sending required beacon (%d)!\n", + ret); + return ret; + } + } + + priv->start_calib = 0; + /* + * Apply the new configuration. + * + * Associated RXON doesn't clear the station table in uCode, + * so we don't need to restore stations etc. after this. + */ + ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, + sizeof(struct iwl_rxon_cmd), &ctx->staging); + if (ret) { + IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active, &ctx->staging, sizeof(*active)); + + iwl_reprogram_ap_sta(priv, ctx); + + /* IBSS beacon needs to be sent after setting assoc */ + if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) + if (iwlagn_update_beacon(priv, ctx->vif)) + IWL_ERR(priv, "Error sending IBSS beacon\n"); + iwl_init_sensitivity(priv); + + /* + * If we issue a new RXON command which required a tune then + * we must send a new TXPOWER command or we won't be able to + * Tx any frames. + * + * It's expected we set power here if channel is changing. + */ + ret = iwl_set_tx_power(priv, priv->tx_power_next, true); + if (ret) { + IWL_ERR(priv, "Error sending TX power (%d)\n", ret); + return ret; + } + return 0; +} + /** * iwlagn_commit_rxon - commit staging_rxon to hardware * @@ -130,6 +273,16 @@ static int iwlagn_update_beacon(struct iwl_priv *priv, * the active_rxon structure is updated with the new data. This * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. + * + * The connect/disconnect flow should be as the following: + * + * 1. make sure send RXON command with association bit unset if not connect + * this should include the channel and the band for the candidate + * to be connected to + * 2. Add Station before RXON association with the AP + * 3. RXON_timing has to send before RXON for connection + * 4. full RXON command - associated bit set + * 5. use RXON_ASSOC command to update any flags changes */ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { @@ -179,6 +332,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) else ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + iwl_print_rx_config_cmd(priv, ctx); ret = iwl_check_rxon_cmd(priv, ctx); if (ret) { IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); @@ -202,14 +356,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * and other flags for the current radio configuration. */ if (!iwl_full_rxon_required(priv, ctx)) { - ret = iwl_send_rxon_assoc(priv, ctx); + ret = iwlagn_send_rxon_assoc(priv, ctx); if (ret) { IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); return ret; } memcpy(active, &ctx->staging, sizeof(*active)); - iwl_print_rx_config_cmd(priv, ctx); return 0; } @@ -219,7 +372,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return ret; } - iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto); + iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto); IWL_DEBUG_INFO(priv, "Going to commit RXON\n" @@ -237,92 +390,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * set up filters in the device. */ if ((old_assoc && new_assoc) || !new_assoc) { - if (ctx->ctxid == IWL_RXON_CTX_BSS) - ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); - else - ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); + ret = iwlagn_rxon_disconn(priv, ctx); if (ret) return ret; - - memcpy(active, &ctx->staging, sizeof(*active)); - - /* - * Un-assoc RXON clears the station table and WEP - * keys, so we have to restore those afterwards. - */ - iwl_clear_ucode_stations(priv, ctx); - iwl_restore_stations(priv, ctx); - ret = iwl_restore_default_wep_keys(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); - return ret; - } } - /* RXON timing must be before associated RXON */ - ret = iwl_send_rxon_timing(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); - return ret; - } - - if (new_assoc) { - /* QoS info may be cleared by previous un-assoc RXON */ - iwlagn_update_qos(priv, ctx); - - /* - * We'll run into this code path when beaconing is - * enabled, but then we also need to send the beacon - * to the device. - */ - if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { - ret = iwlagn_update_beacon(priv, ctx->vif); - if (ret) { - IWL_ERR(priv, - "Error sending required beacon (%d)!\n", - ret); - return ret; - } - } - - priv->start_calib = 0; - /* - * Apply the new configuration. - * - * Associated RXON doesn't clear the station table in uCode, - * so we don't need to restore stations etc. after this. - */ - ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, - sizeof(struct iwl_rxon_cmd), &ctx->staging); - if (ret) { - IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); - return ret; - } - memcpy(active, &ctx->staging, sizeof(*active)); - - iwl_reprogram_ap_sta(priv, ctx); - - /* IBSS beacon needs to be sent after setting assoc */ - if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) - if (iwlagn_update_beacon(priv, ctx->vif)) - IWL_ERR(priv, "Error sending IBSS beacon\n"); - } - - iwl_print_rx_config_cmd(priv, ctx); - - iwl_init_sensitivity(priv); - - /* - * If we issue a new RXON command which required a tune then we must - * send a new TXPOWER command or we won't be able to Tx any frames. - * - * It's expected we set power here if channel is changing. - */ - ret = iwl_set_tx_power(priv, priv->tx_power_next, true); - if (ret) { - IWL_ERR(priv, "Error sending TX power (%d)\n", ret); - return ret; - } + if (new_assoc) + return iwlagn_rxon_connect(priv, ctx); return 0; } @@ -335,7 +409,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) struct ieee80211_channel *channel = conf->channel; const struct iwl_channel_info *ch_info; int ret = 0; - bool ht_changed[NUM_IWL_RXON_CTX] = {}; IWL_DEBUG_MAC80211(priv, "changed %#x", changed); @@ -383,10 +456,8 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) for_each_context(priv, ctx) { /* Configure HT40 channels */ - if (ctx->ht.enabled != conf_is_ht(conf)) { + if (ctx->ht.enabled != conf_is_ht(conf)) ctx->ht.enabled = conf_is_ht(conf); - ht_changed[ctx->ctxid] = true; - } if (ctx->ht.enabled) { if (conf_is_ht40_minus(conf)) { @@ -455,8 +526,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) continue; iwlagn_commit_rxon(priv, ctx); - if (ht_changed[ctx->ctxid]) - iwlagn_update_qos(priv, ctx); } out: mutex_unlock(&priv->mutex); @@ -600,6 +669,18 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, priv->timestamp = bss_conf->timestamp; ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; } else { + /* + * If we disassociate while there are pending + * frames, just wake up the queues and let the + * frames "escape" ... This shouldn't really + * be happening to start with, but we should + * not get stuck in this case either since it + * can happen if userspace gets confused. + */ + if (ctx->last_tx_rejected) { + ctx->last_tx_rejected = false; + iwl_wake_any_queue(priv, ctx); + } ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 35f085ac336b..079275f2c64d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -474,7 +474,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); memset(&priv->stations[sta_id].sta.key, 0, - sizeof(struct iwl4965_keyinfo)); + sizeof(struct iwl_keyinfo)); priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index e3a8216a033c..348f74f1c8e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h index d55060427cac..d118ed29bf3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index a709d05c5868..342de780a366 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -98,9 +98,9 @@ static inline int get_fifo_from_tid(struct iwl_rxon_context *ctx, u16 tid) /** * iwlagn_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ -void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - u16 byte_cnt) +static void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + u16 byte_cnt) { struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int write_ptr = txq->q.write_ptr; @@ -112,21 +112,19 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); - if (txq_id != priv->cmd_queue) { - sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; - sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; + sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; + sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; - switch (sec_ctl & TX_CMD_SEC_MSK) { - case TX_CMD_SEC_CCM: - len += CCMP_MIC_LEN; - break; - case TX_CMD_SEC_TKIP: - len += TKIP_ICV_LEN; - break; - case TX_CMD_SEC_WEP: - len += WEP_IV_LEN + WEP_ICV_LEN; - break; - } + switch (sec_ctl & TX_CMD_SEC_MSK) { + case TX_CMD_SEC_CCM: + len += CCMP_MIC_LEN; + break; + case TX_CMD_SEC_TKIP: + len += TKIP_ICV_LEN; + break; + case TX_CMD_SEC_WEP: + len += WEP_IV_LEN + WEP_ICV_LEN; + break; } bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12)); @@ -138,8 +136,8 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } -void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq) +static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq) { struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int txq_id = txq->q.id; @@ -222,13 +220,8 @@ void iwlagn_tx_queue_set_status(struct iwl_priv *priv, scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); } -int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, - int tx_fifo, int sta_id, int tid, u16 ssn_idx) +static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, int tid) { - unsigned long flags; - u16 ra_tid; - int ret; - if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { @@ -240,12 +233,33 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, return -EINVAL; } - ra_tid = BUILD_RAxTID(sta_id, tid); - /* Modify device's station table to Tx this TID */ - ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); - if (ret) - return ret; + return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); +} + +void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv, + struct ieee80211_sta *sta, + int tid, int frame_limit) +{ + int sta_id, tx_fifo, txq_id, ssn_idx; + u16 ra_tid; + unsigned long flags; + struct iwl_tid_data *tid_data; + + sta_id = iwl_sta_id(sta); + if (WARN_ON(sta_id == IWL_INVALID_STATION)) + return; + if (WARN_ON(tid >= MAX_TID_COUNT)) + return; + + spin_lock_irqsave(&priv->sta_lock, flags); + tid_data = &priv->stations[sta_id].tid[tid]; + ssn_idx = SEQ_TO_SN(tid_data->seq_number); + txq_id = tid_data->agg.txq_id; + tx_fifo = tid_data->agg.tx_fifo; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + ra_tid = BUILD_RAxTID(sta_id, tid); spin_lock_irqsave(&priv->lock, flags); @@ -271,10 +285,10 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, iwl_write_targ_mem(priv, priv->scd_base_addr + IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), - ((SCD_WIN_SIZE << + ((frame_limit << IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | - ((SCD_FRAME_LIMIT << + ((frame_limit << IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); @@ -284,12 +298,10 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); spin_unlock_irqrestore(&priv->lock, flags); - - return 0; } -int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo) +static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, + u16 ssn_idx, u8 tx_fifo) { if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || (IWLAGN_FIRST_AMPDU_QUEUE + @@ -525,7 +537,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) struct iwl_tx_cmd *tx_cmd; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; int txq_id; - dma_addr_t phys_addr; + dma_addr_t phys_addr = 0; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; u16 len, firstlen, secondlen; @@ -552,7 +564,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) spin_lock_irqsave(&priv->lock, flags); if (iwl_is_rfkill(priv)) { IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n"); - goto drop_unlock; + goto drop_unlock_priv; } fc = hdr->frame_control; @@ -568,12 +580,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); - /* Find index into station table for destination station */ - sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", - hdr->addr1); - goto drop_unlock; + /* For management frames use broadcast id to do not break aggregation */ + if (!ieee80211_is_data(fc)) + sta_id = ctx->bcast_sta_id; + else { + /* Find index into station table for destination station */ + sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", + hdr->addr1); + goto drop_unlock_priv; + } } IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); @@ -616,10 +633,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) { - spin_unlock(&priv->sta_lock); - goto drop_unlock; - } + + if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) + goto drop_unlock_sta; + seq_number = priv->stations[sta_id].tid[tid].seq_number; seq_number &= IEEE80211_SCTL_SEQ; hdr->seq_ctrl = hdr->seq_ctrl & @@ -637,18 +654,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) txq = &priv->txq[txq_id]; q = &txq->q; - if (unlikely(iwl_queue_space(q) < q->high_mark)) { - spin_unlock(&priv->sta_lock); - goto drop_unlock; - } - - if (ieee80211_is_data_qos(fc)) { - priv->stations[sta_id].tid[tid].tfds_in_queue++; - if (!ieee80211_has_morefrags(fc)) - priv->stations[sta_id].tid[tid].seq_number = seq_number; - } - - spin_unlock(&priv->sta_lock); + if (unlikely(iwl_queue_space(q) < q->high_mark)) + goto drop_unlock_sta; /* Set up driver data for this TFD */ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); @@ -712,12 +719,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) txcmd_phys = pci_map_single(priv->pci_dev, &out_cmd->hdr, firstlen, PCI_DMA_BIDIRECTIONAL); + if (unlikely(pci_dma_mapping_error(priv->pci_dev, txcmd_phys))) + goto drop_unlock_sta; dma_unmap_addr_set(out_meta, mapping, txcmd_phys); dma_unmap_len_set(out_meta, len, firstlen); - /* Add buffer containing Tx command and MAC(!) header to TFD's - * first entry */ - priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, - txcmd_phys, firstlen, 1, 0); if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; @@ -732,10 +737,30 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (secondlen > 0) { phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, secondlen, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) { + pci_unmap_single(priv->pci_dev, + dma_unmap_addr(out_meta, mapping), + dma_unmap_len(out_meta, len), + PCI_DMA_BIDIRECTIONAL); + goto drop_unlock_sta; + } + } + + if (ieee80211_is_data_qos(fc)) { + priv->stations[sta_id].tid[tid].tfds_in_queue++; + if (!ieee80211_has_morefrags(fc)) + priv->stations[sta_id].tid[tid].seq_number = seq_number; + } + + spin_unlock(&priv->sta_lock); + + /* Attach buffers to TFD */ + priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, + txcmd_phys, firstlen, 1, 0); + if (secondlen > 0) priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, phys_addr, secondlen, 0, 0); - } scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + offsetof(struct iwl_tx_cmd, scratch); @@ -754,8 +779,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Set up entry for this TFD in Tx byte-count array */ if (info->flags & IEEE80211_TX_CTL_AMPDU) - priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, - le16_to_cpu(tx_cmd->len)); + iwlagn_txq_update_byte_cnt_tbl(priv, txq, + le16_to_cpu(tx_cmd->len)); pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys, firstlen, PCI_DMA_BIDIRECTIONAL); @@ -801,7 +826,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) return 0; -drop_unlock: +drop_unlock_sta: + spin_unlock(&priv->sta_lock); +drop_unlock_priv: spin_unlock_irqrestore(&priv->lock, flags); return -1; } @@ -1034,11 +1061,11 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, tid_data = &priv->stations[sta_id].tid[tid]; *ssn = SEQ_TO_SN(tid_data->seq_number); tid_data->agg.txq_id = txq_id; + tid_data->agg.tx_fifo = tx_fifo; iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id); spin_unlock_irqrestore(&priv->sta_lock, flags); - ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo, - sta_id, tid, *ssn); + ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid); if (ret) return ret; @@ -1125,8 +1152,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, * to deactivate the uCode queue, just return "success" to allow * mac80211 to clean up it own data. */ - priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, - tx_fifo_id); + iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo_id); spin_unlock_irqrestore(&priv->lock, flags); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); @@ -1155,8 +1181,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, u16 ssn = SEQ_TO_SN(tid_data->seq_number); int tx_fifo = get_fifo_from_tid(ctx, tid); IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n"); - priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, - ssn, tx_fifo); + iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo); tid_data->agg.state = IWL_AGG_OFF; ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid); } @@ -1224,16 +1249,19 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - iwlagn_tx_status(priv, tx_info, - txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); + + if (WARN_ON_ONCE(tx_info->skb == NULL)) + continue; hdr = (struct ieee80211_hdr *)tx_info->skb->data; - if (hdr && ieee80211_is_data_qos(hdr->frame_control)) + if (ieee80211_is_data_qos(hdr->frame_control)) nfreed++; + + iwlagn_tx_status(priv, tx_info, + txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); tx_info->skb = NULL; - if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) - priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq); + iwlagn_txq_inval_byte_cnt_tbl(priv, txq); priv->cfg->ops->lib->txq_free_tfd(priv, txq); } @@ -1251,11 +1279,11 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, struct iwl_compressed_ba_resp *ba_resp) { - int i, sh, ack; + int sh; u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); - int successes = 0; struct ieee80211_tx_info *info; + u64 bitmap, sent_bitmap; if (unlikely(!agg->wait_for_ba)) { if (unlikely(ba_resp->bitmap)) @@ -1269,70 +1297,42 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, /* Calculate shift to align block-ack bits with our Tx window bits */ sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); - if (sh < 0) /* tbw something is wrong with indices */ + if (sh < 0) sh += 0x100; - if (agg->frame_count > (64 - sh)) { - IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size"); - return -1; - } - if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { + /* + * Check for success or failure according to the + * transmitted bitmap and block-ack bitmap + */ + bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; + sent_bitmap = bitmap & agg->bitmap; + + /* Sanity check values reported by uCode */ + if (ba_resp->txed_2_done > ba_resp->txed) { + IWL_DEBUG_TX_REPLY(priv, + "bogus sent(%d) and ack(%d) count\n", + ba_resp->txed, ba_resp->txed_2_done); /* - * sent and ack information provided by uCode - * use it instead of figure out ourself + * set txed_2_done = txed, + * so it won't impact rate scale */ - if (ba_resp->txed_2_done > ba_resp->txed) { - IWL_DEBUG_TX_REPLY(priv, - "bogus sent(%d) and ack(%d) count\n", - ba_resp->txed, ba_resp->txed_2_done); - /* - * set txed_2_done = txed, - * so it won't impact rate scale - */ - ba_resp->txed = ba_resp->txed_2_done; - } - IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", - ba_resp->txed, ba_resp->txed_2_done); - } else { - u64 bitmap, sent_bitmap; + ba_resp->txed = ba_resp->txed_2_done; + } + IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", + ba_resp->txed, ba_resp->txed_2_done); - /* don't use 64-bit values for now */ - bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; - - /* check for success or failure according to the - * transmitted bitmap and block-ack bitmap */ - sent_bitmap = bitmap & agg->bitmap; - - /* For each frame attempted in aggregation, - * update driver's record of tx frame's status. */ - i = 0; - while (sent_bitmap) { - ack = sent_bitmap & 1ULL; - successes += ack; - IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n", - ack ? "ACK" : "NACK", i, - (agg->start_idx + i) & 0xff, - agg->start_idx + i); - sent_bitmap >>= 1; - ++i; - } - - IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", - (unsigned long long)bitmap); + /* Find the first ACKed frame to store the TX status */ + while (sent_bitmap && !(sent_bitmap & 1)) { + agg->start_idx = (agg->start_idx + 1) & 0xff; + sent_bitmap >>= 1; } info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); memset(&info->status, 0, sizeof(info->status)); info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_AMPDU; - if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { - info->status.ampdu_ack_len = ba_resp->txed_2_done; - info->status.ampdu_len = ba_resp->txed; - - } else { - info->status.ampdu_ack_len = successes; - info->status.ampdu_len = agg->frame_count; - } + info->status.ampdu_ack_len = ba_resp->txed_2_done; + info->status.ampdu_len = ba_resp->txed; iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index d807e5e2b718..8bda0e8d6661 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -161,47 +161,19 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name, } static int iwlagn_load_given_ucode(struct iwl_priv *priv, - struct fw_desc *inst_image, - struct fw_desc *data_image) + struct fw_img *image) { int ret = 0; - ret = iwlagn_load_section(priv, "INST", inst_image, + ret = iwlagn_load_section(priv, "INST", &image->code, IWLAGN_RTC_INST_LOWER_BOUND); if (ret) return ret; - return iwlagn_load_section(priv, "DATA", data_image, + return iwlagn_load_section(priv, "DATA", &image->data, IWLAGN_RTC_DATA_LOWER_BOUND); } -int iwlagn_load_ucode(struct iwl_priv *priv) -{ - int ret = 0; - - /* check whether init ucode should be loaded, or rather runtime ucode */ - if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) { - IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n"); - ret = iwlagn_load_given_ucode(priv, - &priv->ucode_init, &priv->ucode_init_data); - if (!ret) { - IWL_DEBUG_INFO(priv, "Init ucode load complete.\n"); - priv->ucode_type = UCODE_INIT; - } - } else { - IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. " - "Loading runtime ucode...\n"); - ret = iwlagn_load_given_ucode(priv, - &priv->ucode_code, &priv->ucode_data); - if (!ret) { - IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n"); - priv->ucode_type = UCODE_RT; - } - } - - return ret; -} - /* * Calibration */ @@ -297,33 +269,9 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv, iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); } -void iwlagn_rx_calib_complete(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +int iwlagn_init_alive_start(struct iwl_priv *priv) { - IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n"); - queue_work(priv->workqueue, &priv->restart); -} - -void iwlagn_init_alive_start(struct iwl_priv *priv) -{ - int ret = 0; - - /* initialize uCode was loaded... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "initialize" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); - goto restart; - } - - ret = priv->cfg->ops->lib->alive_notify(priv); - if (ret) { - IWL_WARN(priv, - "Could not complete ALIVE transition: %d\n", ret); - goto restart; - } + int ret; if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) { @@ -333,24 +281,25 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) * no need to close the envlope since we are going * to load the runtime uCode later. */ - iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, + ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; } - iwlagn_send_calib_cfg(priv); + + ret = iwlagn_send_calib_cfg(priv); + if (ret) + return ret; /** * temperature offset calibration is only needed for runtime ucode, * so prepare the value now. */ if (priv->cfg->need_temp_offset_calib) - iwlagn_set_temperature_offset_calib(priv); + return iwlagn_set_temperature_offset_calib(priv); - return; - -restart: - /* real restart (first load init_ucode) */ - queue_work(priv->workqueue, &priv->restart); + return 0; } static int iwlagn_send_wimax_coex(struct iwl_priv *priv) @@ -413,25 +362,30 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv) IWL_ERR(priv, "failed to send BT prio tbl command\n"); } -void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) +int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) { struct iwl_bt_coex_prot_env_cmd env_cmd; + int ret; env_cmd.action = action; env_cmd.type = type; - if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, - sizeof(env_cmd), &env_cmd)) + ret = iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, + sizeof(env_cmd), &env_cmd); + if (ret) IWL_ERR(priv, "failed to send BT env command\n"); + return ret; } -int iwlagn_alive_notify(struct iwl_priv *priv) +static int iwlagn_alive_notify(struct iwl_priv *priv) { const struct queue_to_fifo_ac *queue_to_fifo; + struct iwl_rxon_context *ctx; u32 a; unsigned long flags; int i, chan; u32 reg_val; + int ret; spin_lock_irqsave(&priv->lock, flags); @@ -500,6 +454,8 @@ int iwlagn_alive_notify(struct iwl_priv *priv) memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped)); for (i = 0; i < 4; i++) atomic_set(&priv->queue_stop_count[i], 0); + for_each_context(priv, ctx) + ctx->last_tx_rejected = false; /* reset to 0 to enable all the queue first */ priv->txq_ctx_active_msk = 0; @@ -527,12 +483,15 @@ int iwlagn_alive_notify(struct iwl_priv *priv) iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwlagn_send_wimax_coex(priv); + ret = iwlagn_send_wimax_coex(priv); + if (ret) + return ret; - iwlagn_set_Xtal_calib(priv); - iwl_send_calib_results(priv); + ret = iwlagn_set_Xtal_calib(priv); + if (ret) + return ret; - return 0; + return iwl_send_calib_results(priv); } @@ -541,11 +500,12 @@ int iwlagn_alive_notify(struct iwl_priv *priv) * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ -static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) +static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, + struct fw_desc *fw_desc) { + __le32 *image = (__le32 *)fw_desc->v_addr; + u32 len = fw_desc->len; u32 val; - int ret = 0; - u32 errcnt = 0; u32 i; IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); @@ -556,104 +516,204 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 * if IWL_DL_IO is set */ iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, i + IWLAGN_RTC_INST_LOWER_BOUND); - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (val != le32_to_cpu(*image)) { - ret = -EIO; - errcnt++; - if (errcnt >= 3) - break; - } + val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) + return -EIO; } - return ret; + return 0; } -/** - * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host, - * looking at all data. - */ -static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, - u32 len) +static void iwl_print_mismatch_inst(struct iwl_priv *priv, + struct fw_desc *fw_desc) { + __le32 *image = (__le32 *)fw_desc->v_addr; + u32 len = fw_desc->len; u32 val; - u32 save_len = len; - int ret = 0; - u32 errcnt; + u32 offs; + int errors = 0; IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, IWLAGN_RTC_INST_LOWER_BOUND); - errcnt = 0; - for (; len > 0; len -= sizeof(u32), image++) { + for (offs = 0; + offs < len && errors < 20; + offs += sizeof(u32), image++) { /* 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 */ - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { - IWL_ERR(priv, "uCode INST section is invalid at " - "offset 0x%x, is 0x%x, s/b 0x%x\n", - save_len - len, val, le32_to_cpu(*image)); - ret = -EIO; - errcnt++; - if (errcnt >= 20) - break; + IWL_ERR(priv, "uCode INST section at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + offs, val, le32_to_cpu(*image)); + errors++; } } - - if (!errcnt) - IWL_DEBUG_INFO(priv, - "ucode image in INSTRUCTION memory is good\n"); - - return ret; } /** * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -int iwl_verify_ucode(struct iwl_priv *priv) +static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img) { - __le32 *image; - u32 len; + if (!iwlcore_verify_inst_sparse(priv, &img->code)) { + IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n"); + return 0; + } + + IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); + + iwl_print_mismatch_inst(priv, &img->code); + return -EIO; +} + +struct iwlagn_alive_data { + bool valid; + u8 subtype; +}; + +static void iwlagn_alive_fn(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + void *data) +{ + struct iwlagn_alive_data *alive_data = data; + struct iwl_alive_resp *palive; + + palive = &pkt->u.alive_frame; + + IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " + "0x%01X 0x%01X\n", + palive->is_valid, palive->ver_type, + palive->ver_subtype); + + priv->device_pointers.error_event_table = + le32_to_cpu(palive->error_event_table_ptr); + 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; +} + +#define UCODE_ALIVE_TIMEOUT HZ +#define UCODE_CALIB_TIMEOUT (2*HZ) + +int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, + struct fw_img *image, + int subtype, int alternate_subtype) +{ + struct iwl_notification_wait alive_wait; + struct iwlagn_alive_data alive_data; + int ret; + enum iwlagn_ucode_subtype old_type; + + ret = iwlagn_start_device(priv); + if (ret) + return ret; + + iwlagn_init_notification_wait(priv, &alive_wait, REPLY_ALIVE, + iwlagn_alive_fn, &alive_data); + + old_type = priv->ucode_type; + priv->ucode_type = subtype; + + ret = iwlagn_load_given_ucode(priv, image); + if (ret) { + priv->ucode_type = old_type; + iwlagn_remove_notification(priv, &alive_wait); + return ret; + } + + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); + + /* + * Some things may run in the background now, but we + * just wait for the ALIVE notification here. + */ + ret = iwlagn_wait_notification(priv, &alive_wait, UCODE_ALIVE_TIMEOUT); + if (ret) { + priv->ucode_type = old_type; + return ret; + } + + if (!alive_data.valid) { + IWL_ERR(priv, "Loaded ucode is not valid!\n"); + priv->ucode_type = old_type; + return -EIO; + } + + if (alive_data.subtype != subtype && + alive_data.subtype != alternate_subtype) { + IWL_ERR(priv, + "Loaded ucode is not expected type (got %d, expected %d)!\n", + alive_data.subtype, subtype); + priv->ucode_type = old_type; + return -EIO; + } + + ret = iwl_verify_ucode(priv, image); + if (ret) { + priv->ucode_type = old_type; + return ret; + } + + /* delay a bit to give rfkill time to run */ + msleep(5); + + ret = iwlagn_alive_notify(priv); + if (ret) { + IWL_WARN(priv, + "Could not complete ALIVE transition: %d\n", ret); + priv->ucode_type = old_type; + return ret; + } + + return 0; +} + +int iwlagn_run_init_ucode(struct iwl_priv *priv) +{ + struct iwl_notification_wait calib_wait; int ret; - /* Try bootstrap */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - ret = iwlcore_verify_inst_sparse(priv, image, len); - if (!ret) { - IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n"); + lockdep_assert_held(&priv->mutex); + + /* No init ucode required? Curious, but maybe ok */ + if (!priv->ucode_init.code.len) return 0; - } - /* Try initialize */ - image = (__le32 *)priv->ucode_init.v_addr; - len = priv->ucode_init.len; - ret = iwlcore_verify_inst_sparse(priv, image, len); - if (!ret) { - IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n"); + if (priv->ucode_type != UCODE_SUBTYPE_NONE_LOADED) return 0; - } - /* Try runtime/protocol */ - image = (__le32 *)priv->ucode_code.v_addr; - len = priv->ucode_code.len; - ret = iwlcore_verify_inst_sparse(priv, image, len); - if (!ret) { - IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n"); - return 0; - } + iwlagn_init_notification_wait(priv, &calib_wait, + CALIBRATION_COMPLETE_NOTIFICATION, + NULL, NULL); - IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); + /* Will also start the device */ + ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init, + UCODE_SUBTYPE_INIT, -1); + if (ret) + goto error; - /* Since nothing seems to match, show first several data entries in - * instruction SRAM, so maybe visual inspection will give a clue. - * Selection of bootstrap image (vs. other images) is arbitrary. */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - ret = iwl_verify_inst_full(priv, image, len); + ret = iwlagn_init_alive_start(priv); + if (ret) + goto error; + /* + * Some things may run in the background now, but we + * just wait for the calibration complete notification. + */ + ret = iwlagn_wait_notification(priv, &calib_wait, UCODE_CALIB_TIMEOUT); + + goto out; + + error: + iwlagn_remove_notification(priv, &calib_wait); + out: + /* Whatever happened, stop the device */ + iwlagn_stop_device(priv); return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 321b18b59135..3ecc3198d9bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -59,7 +59,6 @@ #include "iwl-sta.h" #include "iwl-agn-calib.h" #include "iwl-agn.h" -#include "iwl-agn-led.h" /****************************************************************************** @@ -103,70 +102,6 @@ void iwl_update_chain_flags(struct iwl_priv *priv) } } -static void iwl_clear_free_frames(struct iwl_priv *priv) -{ - struct list_head *element; - - IWL_DEBUG_INFO(priv, "%d frames on pre-allocated heap on clear.\n", - priv->frames_count); - - while (!list_empty(&priv->free_frames)) { - element = priv->free_frames.next; - list_del(element); - kfree(list_entry(element, struct iwl_frame, list)); - priv->frames_count--; - } - - if (priv->frames_count) { - IWL_WARN(priv, "%d frames still in use. Did we lose one?\n", - priv->frames_count); - priv->frames_count = 0; - } -} - -static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) -{ - struct iwl_frame *frame; - struct list_head *element; - if (list_empty(&priv->free_frames)) { - frame = kzalloc(sizeof(*frame), GFP_KERNEL); - if (!frame) { - IWL_ERR(priv, "Could not allocate frame!\n"); - return NULL; - } - - priv->frames_count++; - return frame; - } - - element = priv->free_frames.next; - list_del(element); - return list_entry(element, struct iwl_frame, list); -} - -static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) -{ - memset(frame, 0, sizeof(*frame)); - list_add(&frame->list, &priv->free_frames); -} - -static u32 iwl_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - int left) -{ - lockdep_assert_held(&priv->mutex); - - if (!priv->beacon_skb) - return 0; - - if (priv->beacon_skb->len > left) - return 0; - - memcpy(hdr, priv->beacon_skb->data, priv->beacon_skb->len); - - return priv->beacon_skb->len; -} - /* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */ static void iwl_set_beacon_tim(struct iwl_priv *priv, struct iwl_tx_beacon_cmd *tx_beacon_cmd, @@ -194,13 +129,18 @@ static void iwl_set_beacon_tim(struct iwl_priv *priv, IWL_WARN(priv, "Unable to find TIM Element in beacon\n"); } -static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl_frame *frame) +int iwlagn_send_beacon_cmd(struct iwl_priv *priv) { struct iwl_tx_beacon_cmd *tx_beacon_cmd; + struct iwl_host_cmd cmd = { + .id = REPLY_TX_BEACON, + .flags = CMD_SIZE_HUGE, + }; u32 frame_size; u32 rate_flags; u32 rate; + int err; + /* * We have to set up the TX command, the TX Beacon command, and the * beacon contents. @@ -213,17 +153,19 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, return 0; } - /* Initialize memory */ - tx_beacon_cmd = &frame->u.beacon; - memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); + if (WARN_ON(!priv->beacon_skb)) + return -EINVAL; + + /* Allocate beacon memory */ + tx_beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd) + priv->beacon_skb->len, + GFP_KERNEL); + if (!tx_beacon_cmd) + return -ENOMEM; + + frame_size = priv->beacon_skb->len; /* Set up TX beacon contents */ - frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, - sizeof(frame->u) - sizeof(*tx_beacon_cmd)); - if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE)) - return 0; - if (!frame_size) - return 0; + memcpy(tx_beacon_cmd->frame, priv->beacon_skb->data, frame_size); /* Set up TX command fields */ tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); @@ -246,35 +188,16 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); - return sizeof(*tx_beacon_cmd) + frame_size; -} + /* Submit command */ + cmd.len = sizeof(*tx_beacon_cmd) + frame_size; + cmd.data = tx_beacon_cmd; -int iwlagn_send_beacon_cmd(struct iwl_priv *priv) -{ - struct iwl_frame *frame; - unsigned int frame_size; - int rc; + err = iwl_send_cmd_sync(priv, &cmd); - frame = iwl_get_free_frame(priv); - if (!frame) { - IWL_ERR(priv, "Could not obtain free frame buffer for beacon " - "command.\n"); - return -ENOMEM; - } + /* Free temporary storage */ + kfree(tx_beacon_cmd); - frame_size = iwl_hw_get_beacon_cmd(priv, frame); - if (!frame_size) { - IWL_ERR(priv, "Error configuring the beacon command\n"); - iwl_free_frame(priv, frame); - return -EINVAL; - } - - rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, - &frame->u.cmd[0]); - - iwl_free_frame(priv, frame); - - return rc; + return err; } static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) @@ -395,7 +318,9 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, return -EINVAL; } - BUG_ON(addr & ~DMA_BIT_MASK(36)); + if (WARN_ON(addr & ~DMA_BIT_MASK(36))) + return -EINVAL; + if (unlikely(addr & ~IWL_TX_DMA_MASK)) IWL_ERR(priv, "Unaligned address = %llx\n", (unsigned long long)addr); @@ -409,7 +334,7 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, * Tell nic where to find circular buffer of Tx Frame Descriptors for * given Tx queue, and enable the DMA channel used for that queue. * - * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA + * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA * channels supported in hardware. */ int iwl_hw_tx_queue_init(struct iwl_priv *priv, @@ -483,12 +408,14 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) container_of(work, struct iwl_priv, bt_full_concurrency); struct iwl_rxon_context *ctx; + mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; /* dont send host command if rf-kill is on */ if (!iwl_is_ready_rf(priv)) - return; + goto out; IWL_DEBUG_INFO(priv, "BT coex in %s mode\n", priv->bt_full_concurrent ? @@ -498,15 +425,15 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) * LQ & RXON updated cmds must be sent before BT Config cmd * to avoid 3-wire collisions */ - mutex_lock(&priv->mutex); for_each_context(priv, ctx) { if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); iwlcore_commit_rxon(priv, ctx); } - mutex_unlock(&priv->mutex); priv->cfg->ops->hcmd->send_bt_config(priv); +out: + mutex_unlock(&priv->mutex); } /** @@ -556,7 +483,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, } /* Set starting address; reads will auto-increment */ - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); rmb(); /* @@ -564,13 +491,13 @@ 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_read_direct32(priv, HBUS_TARG_MEM_RDAT); - time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { trace_iwlwifi_dev_ucode_cont_event(priv, 0, time, ev); } else { - data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); trace_iwlwifi_dev_ucode_cont_event(priv, time, data, ev); } @@ -588,10 +515,7 @@ 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 */ - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); - else - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + base = priv->device_pointers.error_event_table; if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { capacity = iwl_read_targ_mem(priv, base); num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); @@ -720,7 +644,10 @@ static void iwl_rx_handle(struct iwl_priv *priv) /* If an RXB doesn't have a Rx queue slot associated with it, * then a bug has been introduced in the queue refilling * routines -- catch it here */ - BUG_ON(rxb == NULL); + if (WARN_ON(rxb == NULL)) { + i = (i + 1) & RX_QUEUE_MASK; + continue; + } rxq->queue[i] = NULL; @@ -760,13 +687,15 @@ static void iwl_rx_handle(struct iwl_priv *priv) if (w->cmd == pkt->hdr.cmd) { w->triggered = true; if (w->fn) - w->fn(priv, pkt); + w->fn(priv, pkt, w->fn_data); } } spin_unlock(&priv->_agn.notif_wait_lock); wake_up_all(&priv->_agn.notif_waitq); } + if (priv->pre_rx_handler) + priv->pre_rx_handler(priv, rxb); /* Based on type of command response or notification, * handle those that need handling via function in @@ -837,199 +766,6 @@ static void iwl_rx_handle(struct iwl_priv *priv) iwlagn_rx_queue_restock(priv); } -/* call this function to flush any scheduled tasklet */ -static inline void iwl_synchronize_irq(struct iwl_priv *priv) -{ - /* wait to make sure we flush pending tasklet*/ - synchronize_irq(priv->pci_dev->irq); - tasklet_kill(&priv->irq_tasklet); -} - -static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) -{ - u32 inta, handled = 0; - u32 inta_fh; - unsigned long flags; - u32 i; -#ifdef CONFIG_IWLWIFI_DEBUG - u32 inta_mask; -#endif - - spin_lock_irqsave(&priv->lock, flags); - - /* Ack/clear/reset pending uCode interrupts. - * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, - * and will clear only when CSR_FH_INT_STATUS gets cleared. */ - inta = iwl_read32(priv, CSR_INT); - iwl_write32(priv, CSR_INT, inta); - - /* Ack/clear/reset pending flow-handler (DMA) interrupts. - * Any new interrupts that happen after this, either while we're - * in this tasklet, or later, will show up in next ISR/tasklet. */ - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & IWL_DL_ISR) { - /* just for debug */ - inta_mask = iwl_read32(priv, CSR_INT_MASK); - IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", - inta, inta_mask, inta_fh); - } -#endif - - spin_unlock_irqrestore(&priv->lock, flags); - - /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not - * atomic, make sure that inta covers all the interrupts that - * we've discovered, even if FH interrupt came in just after - * reading CSR_INT. */ - if (inta_fh & CSR49_FH_INT_RX_MASK) - inta |= CSR_INT_BIT_FH_RX; - if (inta_fh & CSR49_FH_INT_TX_MASK) - inta |= CSR_INT_BIT_FH_TX; - - /* Now service all interrupt bits discovered above. */ - if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERR(priv, "Hardware error detected. Restarting.\n"); - - /* Tell the device to stop sending interrupts */ - iwl_disable_interrupts(priv); - - priv->isr_stats.hw++; - iwl_irq_handle_error(priv); - - handled |= CSR_INT_BIT_HW_ERR; - - return; - } - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { - /* NIC fires this, but we don't use it, redundant with WAKEUP */ - if (inta & CSR_INT_BIT_SCD) { - IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " - "the frame/frames.\n"); - priv->isr_stats.sch++; - } - - /* Alive notification via Rx interrupt will do the real work */ - if (inta & CSR_INT_BIT_ALIVE) { - IWL_DEBUG_ISR(priv, "Alive interrupt\n"); - priv->isr_stats.alive++; - } - } -#endif - /* Safely ignore these bits for debug checks below */ - inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); - - /* HW RF KILL switch toggled */ - if (inta & CSR_INT_BIT_RF_KILL) { - int hw_rf_kill = 0; - if (!(iwl_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) - hw_rf_kill = 1; - - IWL_WARN(priv, "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio" : "enable radio"); - - priv->isr_stats.rfkill++; - - /* driver only loads ucode once setting the interface up. - * the driver allows loading the ucode even if the radio - * is killed. Hence update the killswitch state here. The - * rfkill handler will care about restarting if needed. - */ - if (!test_bit(STATUS_ALIVE, &priv->status)) { - if (hw_rf_kill) - 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, hw_rf_kill); - } - - handled |= CSR_INT_BIT_RF_KILL; - } - - /* Chip got too hot and stopped itself */ - if (inta & CSR_INT_BIT_CT_KILL) { - IWL_ERR(priv, "Microcode CT kill error detected.\n"); - priv->isr_stats.ctkill++; - handled |= CSR_INT_BIT_CT_KILL; - } - - /* Error detected by uCode */ - if (inta & CSR_INT_BIT_SW_ERR) { - IWL_ERR(priv, "Microcode SW error detected. " - " Restarting 0x%X.\n", inta); - priv->isr_stats.sw++; - iwl_irq_handle_error(priv); - handled |= CSR_INT_BIT_SW_ERR; - } - - /* - * uCode wakes up after power-down sleep. - * Tell device about any new tx or host commands enqueued, - * and about any Rx buffers made available while asleep. - */ - if (inta & CSR_INT_BIT_WAKEUP) { - IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); - iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - for (i = 0; i < priv->hw_params.max_txq_num; i++) - iwl_txq_update_write_ptr(priv, &priv->txq[i]); - priv->isr_stats.wakeup++; - handled |= CSR_INT_BIT_WAKEUP; - } - - /* All uCode command responses, including Tx command responses, - * Rx "responses" (frame-received notification), and other - * notifications from uCode come through here*/ - if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { - iwl_rx_handle(priv); - priv->isr_stats.rx++; - handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); - } - - /* This "Tx" DMA channel is used only for loading uCode */ - if (inta & CSR_INT_BIT_FH_TX) { - IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); - priv->isr_stats.tx++; - handled |= CSR_INT_BIT_FH_TX; - /* Wake up uCode load routine, now that load is complete */ - priv->ucode_write_complete = 1; - wake_up_interruptible(&priv->wait_command_queue); - } - - if (inta & ~handled) { - IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); - priv->isr_stats.unhandled++; - } - - if (inta & ~(priv->inta_mask)) { - IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", - inta & ~priv->inta_mask); - IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); - } - - /* Re-enable all interrupts */ - /* only Re-enable if disabled by irq */ - if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl_enable_interrupts(priv); - /* Re-enable RF_KILL if it occurred */ - else if (handled & CSR_INT_BIT_RF_KILL) - iwl_enable_rfkill_int(priv); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { - inta = iwl_read32(priv, CSR_INT); - inta_mask = iwl_read32(priv, CSR_INT_MASK); - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - IWL_DEBUG_ISR(priv, "End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " - "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); - } -#endif -} - /* tasklet for iwlagn interrupt */ static void iwl_irq_tasklet(struct iwl_priv *priv) { @@ -1171,7 +907,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); iwl_write32(priv, CSR_FH_INT_STATUS, - CSR49_FH_INT_RX_MASK); + CSR_FH_INT_RX_MASK); } if (inta & CSR_INT_BIT_RX_PERIODIC) { handled |= CSR_INT_BIT_RX_PERIODIC; @@ -1209,7 +945,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* This "Tx" DMA channel is used only for loading uCode */ if (inta & CSR_INT_BIT_FH_TX) { - iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK); + iwl_write32(priv, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); priv->isr_stats.tx++; handled |= CSR_INT_BIT_FH_TX; @@ -1357,26 +1093,48 @@ static struct attribute_group iwl_attribute_group = { * ******************************************************************************/ -static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) +static void iwl_free_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc) { - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); + if (desc->v_addr) + dma_free_coherent(&pci_dev->dev, desc->len, + desc->v_addr, desc->p_addr); + desc->v_addr = NULL; + desc->len = 0; } -static void iwl_nic_start(struct iwl_priv *priv) +static void iwl_free_fw_img(struct pci_dev *pci_dev, struct fw_img *img) { - /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); + iwl_free_fw_desc(pci_dev, &img->code); + iwl_free_fw_desc(pci_dev, &img->data); +} + +static int iwl_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc, + const void *data, size_t len) +{ + if (!len) { + desc->v_addr = NULL; + return -EINVAL; + } + + desc->v_addr = dma_alloc_coherent(&pci_dev->dev, len, + &desc->p_addr, GFP_KERNEL); + if (!desc->v_addr) + return -ENOMEM; + desc->len = len; + memcpy(desc->v_addr, data, len); + return 0; +} + +static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) +{ + iwl_free_fw_img(priv->pci_dev, &priv->ucode_rt); + iwl_free_fw_img(priv->pci_dev, &priv->ucode_init); } struct iwlagn_ucode_capabilities { u32 max_probe_length; u32 standard_phy_calibration_size; - bool pan; + u32 flags; }; static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); @@ -1422,8 +1180,8 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) } struct iwlagn_firmware_pieces { - const void *inst, *data, *init, *init_data, *boot; - size_t inst_size, data_size, init_size, init_data_size, boot_size; + const void *inst, *data, *init, *init_data; + size_t inst_size, data_size, init_size, init_data_size; u32 build; @@ -1444,28 +1202,18 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, switch (api_ver) { default: - /* - * 4965 doesn't revision the firmware file format - * along with the API version, it always uses v1 - * file format. - */ - if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != - CSR_HW_REV_TYPE_4965) { - hdr_size = 28; - if (ucode_raw->size < hdr_size) { - IWL_ERR(priv, "File size too small!\n"); - return -EINVAL; - } - pieces->build = le32_to_cpu(ucode->u.v2.build); - pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); - pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); - pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); - pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); - pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size); - src = ucode->u.v2.data; - break; + hdr_size = 28; + if (ucode_raw->size < hdr_size) { + IWL_ERR(priv, "File size too small!\n"); + return -EINVAL; } - /* fall through for 4965 */ + pieces->build = le32_to_cpu(ucode->u.v2.build); + pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); + pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); + pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); + pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); + src = ucode->u.v2.data; + break; case 0: case 1: case 2: @@ -1479,7 +1227,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size); - pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size); src = ucode->u.v1.data; break; } @@ -1487,7 +1234,7 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, /* Verify size of file vs. image size info in file's header */ if (ucode_raw->size != hdr_size + pieces->inst_size + pieces->data_size + pieces->init_size + - pieces->init_data_size + pieces->boot_size) { + pieces->init_data_size) { IWL_ERR(priv, "uCode file size %d does not match expected size\n", @@ -1503,8 +1250,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, src += pieces->init_size; pieces->init_data = src; src += pieces->init_data_size; - pieces->boot = src; - src += pieces->boot_size; return 0; } @@ -1605,8 +1350,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, pieces->init_data_size = tlv_len; break; case IWL_UCODE_TLV_BOOT: - pieces->boot = tlv_data; - pieces->boot_size = tlv_len; + IWL_ERR(priv, "Found unexpected BOOT ucode\n"); break; case IWL_UCODE_TLV_PROBE_MAX_LEN: if (tlv_len != sizeof(u32)) @@ -1617,7 +1361,23 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, case IWL_UCODE_TLV_PAN: if (tlv_len) goto invalid_tlv_len; - capa->pan = true; + capa->flags |= IWL_UCODE_TLV_FLAGS_PAN; + break; + case IWL_UCODE_TLV_FLAGS: + /* must be at least one u32 */ + if (tlv_len < sizeof(u32)) + goto invalid_tlv_len; + /* and a proper number of u32s */ + if (tlv_len % sizeof(u32)) + goto invalid_tlv_len; + /* + * This driver only reads the first u32 as + * right now no more features are defined, + * if that changes then either the driver + * will not work with the new firmware, or + * it'll not take advantage of new features. + */ + capa->flags = le32_to_cpup((__le32 *)tlv_data); break; case IWL_UCODE_TLV_INIT_EVTLOG_PTR: if (tlv_len != sizeof(u32)) @@ -1667,7 +1427,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, le32_to_cpup((__le32 *)tlv_data); break; default: - IWL_WARN(priv, "unknown TLV: %d\n", tlv_type); + IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type); break; } } @@ -1806,8 +1566,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) pieces.init_size); IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n", pieces.init_data_size); - IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n", - pieces.boot_size); /* Verify that uCode images will fit in card's SRAM */ if (pieces.inst_size > priv->hw_params.max_inst_size) { @@ -1834,48 +1592,25 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) goto try_again; } - if (pieces.boot_size > priv->hw_params.max_bsm_size) { - IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n", - pieces.boot_size); - goto try_again; - } - /* Allocate ucode buffers for card's bus-master loading ... */ /* Runtime instructions and 2 copies of data: * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ - priv->ucode_code.len = pieces.inst_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); - - priv->ucode_data.len = pieces.data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); - - priv->ucode_data_backup.len = pieces.data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); - - if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || - !priv->ucode_data_backup.v_addr) + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.code, + pieces.inst, pieces.inst_size)) + goto err_pci_alloc; + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.data, + pieces.data, pieces.data_size)) goto err_pci_alloc; /* Initialization instructions and data */ if (pieces.init_size && pieces.init_data_size) { - priv->ucode_init.len = pieces.init_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init); - - priv->ucode_init_data.len = pieces.init_data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data); - - if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr) + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.code, + pieces.init, pieces.init_size)) goto err_pci_alloc; - } - - /* Bootstrap (instructions only, no data) */ - if (pieces.boot_size) { - priv->ucode_boot.len = pieces.boot_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); - - if (!priv->ucode_boot.v_addr) + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.data, + pieces.init_data, pieces.init_data_size)) goto err_pci_alloc; } @@ -1901,50 +1636,19 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->cfg->base_params->max_event_log_size; priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr; - if (ucode_capa.pan) { + priv->new_scan_threshold_behaviour = + !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); + + if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; } else priv->sta_key_max_num = STA_KEY_MAX_NUM; - /* Copy images into buffers for card's bus-master reads ... */ - - /* Runtime instructions (first block of data in file) */ - IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", - pieces.inst_size); - memcpy(priv->ucode_code.v_addr, pieces.inst, pieces.inst_size); - - IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", - priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); - - /* - * Runtime data - * NOTE: Copy into backup buffer will be done in iwl_up() - */ - IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", - pieces.data_size); - memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size); - memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size); - - /* Initialization instructions */ - if (pieces.init_size) { - IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n", - pieces.init_size); - memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size); - } - - /* Initialization data */ - if (pieces.init_data_size) { - IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n", - pieces.init_data_size); - memcpy(priv->ucode_init_data.v_addr, pieces.init_data, - pieces.init_data_size); - } - - /* Bootstrap instructions */ - IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", - pieces.boot_size); - memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size); + if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) + priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; + else + priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; /* * figure out the offset of chain noise reset and gain commands @@ -2076,13 +1780,13 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; u32 pc, hcmd; + struct iwl_error_event_table table; - if (priv->ucode_type == UCODE_INIT) { - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); + base = priv->device_pointers.error_event_table; + if (priv->ucode_type == UCODE_SUBTYPE_INIT) { if (!base) base = priv->_agn.init_errlog_ptr; } else { - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); if (!base) base = priv->_agn.inst_errlog_ptr; } @@ -2090,11 +1794,15 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Not valid error log pointer 0x%08X for %s uCode\n", - base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); + base, + (priv->ucode_type == UCODE_SUBTYPE_INIT) + ? "Init" : "RT"); return; } - count = iwl_read_targ_mem(priv, base); + iwl_read_targ_mem_words(priv, base, &table, sizeof(table)); + + count = table.valid; if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { IWL_ERR(priv, "Start IWL Error Log Dump:\n"); @@ -2102,18 +1810,18 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) priv->status, count); } - desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); + desc = table.error_id; priv->isr_stats.err_code = desc; - pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32)); - blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); - blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); - ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); - ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); - data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); - data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); - line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); - time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); - hcmd = iwl_read_targ_mem(priv, base + 22 * sizeof(u32)); + pc = table.pc; + blink1 = table.blink1; + blink2 = table.blink2; + ilink1 = table.ilink1; + ilink2 = table.ilink2; + data1 = table.data1; + data2 = table.data2; + line = table.line; + time = table.tsf_low; + hcmd = table.hcmd; trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line, blink1, blink2, ilink1, ilink2); @@ -2147,12 +1855,11 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, if (num_events == 0) return pos; - if (priv->ucode_type == UCODE_INIT) { - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + base = priv->device_pointers.log_event_table; + if (priv->ucode_type == UCODE_SUBTYPE_INIT) { if (!base) base = priv->_agn.init_evtlog_ptr; } else { - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (!base) base = priv->_agn.inst_evtlog_ptr; } @@ -2169,14 +1876,14 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, iwl_grab_nic_access(priv); /* Set starting address; reads will auto-increment */ - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); rmb(); /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ if (bufsz) { @@ -2190,7 +1897,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, time, ev); } } else { - data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (bufsz) { pos += scnprintf(*buf + pos, bufsz - pos, "EVT_LOGT:%010u:0x%08x:%04u\n", @@ -2261,13 +1968,12 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, int pos = 0; size_t bufsz = 0; - if (priv->ucode_type == UCODE_INIT) { - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + base = priv->device_pointers.log_event_table; + if (priv->ucode_type == UCODE_SUBTYPE_INIT) { logsize = priv->_agn.init_evtlog_size; if (!base) base = priv->_agn.init_evtlog_ptr; } else { - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); logsize = priv->_agn.inst_evtlog_size; if (!base) base = priv->_agn.inst_evtlog_ptr; @@ -2276,7 +1982,9 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Invalid event log pointer 0x%08X for %s uCode\n", - base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); + base, + (priv->ucode_type == UCODE_SUBTYPE_INIT) + ? "Init" : "RT"); return -EINVAL; } @@ -2423,31 +2131,15 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg) * from protocol/runtime uCode (initialization uCode's * Alive gets handled by iwl_init_alive_start()). */ -static void iwl_alive_start(struct iwl_priv *priv) +int iwl_alive_start(struct iwl_priv *priv) { int ret = 0; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + iwl_reset_ict(priv); + IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - /* Initialize uCode has loaded Runtime uCode ... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "runtime" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n"); - goto restart; - } - - ret = priv->cfg->ops->lib->alive_notify(priv); - if (ret) { - IWL_WARN(priv, - "Could not complete ALIVE transition [ntf]: %d\n", ret); - goto restart; - } - - /* After the ALIVE response, we can send host commands to the uCode */ set_bit(STATUS_ALIVE, &priv->status); @@ -2455,7 +2147,7 @@ static void iwl_alive_start(struct iwl_priv *priv) iwl_setup_watchdog(priv); if (iwl_is_rfkill(priv)) - return; + return -ERFKILL; /* download priority table before any calibration request */ if (priv->cfg->bt_params && @@ -2469,10 +2161,14 @@ static void iwl_alive_start(struct iwl_priv *priv) iwlagn_send_prio_tbl(priv); /* FIXME: w/a to force change uCode BT state machine */ - iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, - BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); - iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, - BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, + BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; + ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, + BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; } if (priv->hw_params.calib_rt_cfg) iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg); @@ -2514,30 +2210,23 @@ static void iwl_alive_start(struct iwl_priv *priv) set_bit(STATUS_READY, &priv->status); /* Configure the adapter for unassociated operation */ - iwlcore_commit_rxon(priv, ctx); + ret = iwlcore_commit_rxon(priv, ctx); + if (ret) + return ret; /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); - wake_up_interruptible(&priv->wait_command_queue); - iwl_power_update_mode(priv, true); - IWL_DEBUG_INFO(priv, "Updated power mode\n"); - - - return; - - restart: - queue_work(priv->workqueue, &priv->restart); + return iwl_power_update_mode(priv, true); } static void iwl_cancel_deferred_work(struct iwl_priv *priv); static void __iwl_down(struct iwl_priv *priv) { - unsigned long flags; - int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); + int exit_pending; IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); @@ -2563,40 +2252,15 @@ static void __iwl_down(struct iwl_priv *priv) priv->bt_full_concurrent = false; priv->bt_ci_compliance = 0; - /* Unblock any waiting calls */ - wake_up_interruptible_all(&priv->wait_command_queue); - /* Wipe out the EXIT_PENDING status bit if we are not actually * exiting the module */ if (!exit_pending) clear_bit(STATUS_EXIT_PENDING, &priv->status); - /* stop and reset the on-board processor */ - iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - - /* tell the device to stop sending interrupts */ - spin_lock_irqsave(&priv->lock, flags); - iwl_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - iwl_synchronize_irq(priv); - if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); - /* If we have not previously called iwl_init() then - * clear all bits but the RF Kill bit and return */ - if (!iwl_is_init(priv)) { - 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_EXIT_PENDING, &priv->status) << - STATUS_EXIT_PENDING; - goto exit; - } - - /* ...otherwise clear out all the status bits but the RF Kill - * bit and continue taking the NIC down. */ + /* 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) << @@ -2606,31 +2270,10 @@ static void __iwl_down(struct iwl_priv *priv) test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; - /* device going down, Stop using ICT table */ - if (priv->cfg->ops->lib->isr_ops.disable) - priv->cfg->ops->lib->isr_ops.disable(priv); - - iwlagn_txq_ctx_stop(priv); - iwlagn_rxq_stop(priv); - - /* Power-down device's busmaster DMA clocks */ - iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); - udelay(5); - - /* Make sure (redundant) we've released our request to stay awake */ - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - /* Stop the device, and put it in low power state */ - iwl_apm_stop(priv); - - exit: - memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); + iwlagn_stop_device(priv); dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = NULL; - - /* clear out any free frames */ - iwl_clear_free_frames(priv); } static void iwl_down(struct iwl_priv *priv) @@ -2644,9 +2287,10 @@ static void iwl_down(struct iwl_priv *priv) #define HW_READY_TIMEOUT (50) +/* Note: returns poll_bit return value, which is >= 0 if success */ static int iwl_set_hw_ready(struct iwl_priv *priv) { - int ret = 0; + int ret; iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); @@ -2656,25 +2300,21 @@ static int iwl_set_hw_ready(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, HW_READY_TIMEOUT); - if (ret != -ETIMEDOUT) - priv->hw_ready = true; - else - priv->hw_ready = false; - IWL_DEBUG_INFO(priv, "hardware %s\n", - (priv->hw_ready == 1) ? "ready" : "not ready"); + IWL_DEBUG_INFO(priv, "hardware%s ready\n", ret < 0 ? " not" : ""); return ret; } -static int iwl_prepare_card_hw(struct iwl_priv *priv) +/* Note: returns standard 0/-ERROR code */ +int iwl_prepare_card_hw(struct iwl_priv *priv) { - int ret = 0; + int ret; IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter\n"); ret = iwl_set_hw_ready(priv); - if (priv->hw_ready) - return ret; + if (ret >= 0) + return 0; /* If HW is not ready, prepare the conditions to check again */ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, @@ -2684,10 +2324,13 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv) ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); - /* HW should be ready by now, check again. */ - if (ret != -ETIMEDOUT) - iwl_set_hw_ready(priv); + if (ret < 0) + return ret; + /* HW should be ready by now, check again. */ + ret = iwl_set_hw_ready(priv); + if (ret >= 0) + return 0; return ret; } @@ -2696,19 +2339,15 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv) static int __iwl_up(struct iwl_priv *priv) { struct iwl_rxon_context *ctx; - int i; int ret; + lockdep_assert_held(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); return -EIO; } - if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { - IWL_ERR(priv, "ucode not available for device bringup\n"); - return -EIO; - } - for_each_context(priv, ctx) { ret = iwlagn_alloc_bcast_station(priv, ctx); if (ret) { @@ -2717,89 +2356,33 @@ static int __iwl_up(struct iwl_priv *priv) } } - iwl_prepare_card_hw(priv); - - if (!priv->hw_ready) { - IWL_WARN(priv, "Exit HW not ready\n"); - return -EIO; - } - - /* If platform's RF_KILL switch is NOT set to KILL */ - if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) - clear_bit(STATUS_RF_KILL_HW, &priv->status); - else - set_bit(STATUS_RF_KILL_HW, &priv->status); - - if (iwl_is_rfkill(priv)) { - wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); - - iwl_enable_interrupts(priv); - IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); - return 0; - } - - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - - /* must be initialised before iwl_hw_nic_init */ - if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) - priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; - else - priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; - - ret = iwlagn_hw_nic_init(priv); + ret = iwlagn_run_init_ucode(priv); if (ret) { - IWL_ERR(priv, "Unable to init nic\n"); - return ret; + IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret); + goto error; } - /* make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - - /* clear (again), then enable host interrupts */ - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl_enable_interrupts(priv); - - /* really make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - - /* Copy original ucode data image from disk into backup cache. - * This will be used to initialize the on-board processor's - * data SRAM for a clean start when the runtime program first loads. */ - memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, - priv->ucode_data.len); - - for (i = 0; i < MAX_HW_RESTARTS; i++) { - - /* load bootstrap state machine, - * load bootstrap program into processor's memory, - * prepare to load the "initialize" uCode */ - ret = priv->cfg->ops->lib->load_ucode(priv); - - if (ret) { - IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n", - ret); - continue; - } - - /* start card; "initialize" will load runtime ucode */ - iwl_nic_start(priv); - - IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); - - return 0; + ret = iwlagn_load_ucode_wait_alive(priv, + &priv->ucode_rt, + UCODE_SUBTYPE_REGULAR, + UCODE_SUBTYPE_REGULAR_NEW); + if (ret) { + IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret); + goto error; } + ret = iwl_alive_start(priv); + if (ret) + goto error; + return 0; + + error: set_bit(STATUS_EXIT_PENDING, &priv->status); __iwl_down(priv); clear_bit(STATUS_EXIT_PENDING, &priv->status); - /* tried to restart and config the device for as long as our - * patience could withstand */ - IWL_ERR(priv, "Unable to initialize device after %d attempts.\n", i); - return -EIO; + IWL_ERR(priv, "Unable to initialize device.\n"); + return ret; } @@ -2809,36 +2392,6 @@ static int __iwl_up(struct iwl_priv *priv) * *****************************************************************************/ -static void iwl_bg_init_alive_start(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, init_alive_start.work); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - priv->cfg->ops->lib->init_alive_start(priv); - mutex_unlock(&priv->mutex); -} - -static void iwl_bg_alive_start(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, alive_start.work); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - /* enable dram interrupt */ - if (priv->cfg->ops->lib->isr_ops.reset) - priv->cfg->ops->lib->isr_ops.reset(priv); - - mutex_lock(&priv->mutex); - iwl_alive_start(priv); - mutex_unlock(&priv->mutex); -} - static void iwl_bg_run_time_calib_work(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, @@ -2853,22 +2406,49 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) } if (priv->start_calib) { - if (iwl_bt_statistics(priv)) { - iwl_chain_noise_calibration(priv, - (void *)&priv->_agn.statistics_bt); - iwl_sensitivity_calibration(priv, - (void *)&priv->_agn.statistics_bt); - } else { - iwl_chain_noise_calibration(priv, - (void *)&priv->_agn.statistics); - iwl_sensitivity_calibration(priv, - (void *)&priv->_agn.statistics); - } + iwl_chain_noise_calibration(priv); + iwl_sensitivity_calibration(priv); } mutex_unlock(&priv->mutex); } +static void iwlagn_prepare_restart(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx; + bool bt_full_concurrent; + u8 bt_ci_compliance; + u8 bt_load; + u8 bt_status; + + lockdep_assert_held(&priv->mutex); + + for_each_context(priv, ctx) + ctx->vif = NULL; + priv->is_open = 0; + + /* + * __iwl_down() will clear the BT status variables, + * which is correct, but when we restart we really + * want to keep them so restore them afterwards. + * + * The restart process will later pick them up and + * re-configure the hw when we reconfigure the BT + * command. + */ + bt_full_concurrent = priv->bt_full_concurrent; + bt_ci_compliance = priv->bt_ci_compliance; + bt_load = priv->bt_traffic_load; + bt_status = priv->bt_status; + + __iwl_down(priv); + + priv->bt_full_concurrent = bt_full_concurrent; + priv->bt_ci_compliance = bt_ci_compliance; + priv->bt_traffic_load = bt_load; + priv->bt_status = bt_status; +} + static void iwl_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); @@ -2877,50 +2457,13 @@ static void iwl_bg_restart(struct work_struct *data) return; if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { - struct iwl_rxon_context *ctx; - bool bt_full_concurrent; - u8 bt_ci_compliance; - u8 bt_load; - u8 bt_status; - mutex_lock(&priv->mutex); - for_each_context(priv, ctx) - ctx->vif = NULL; - priv->is_open = 0; - - /* - * __iwl_down() will clear the BT status variables, - * which is correct, but when we restart we really - * want to keep them so restore them afterwards. - * - * The restart process will later pick them up and - * re-configure the hw when we reconfigure the BT - * command. - */ - bt_full_concurrent = priv->bt_full_concurrent; - bt_ci_compliance = priv->bt_ci_compliance; - bt_load = priv->bt_traffic_load; - bt_status = priv->bt_status; - - __iwl_down(priv); - - priv->bt_full_concurrent = bt_full_concurrent; - priv->bt_ci_compliance = bt_ci_compliance; - priv->bt_traffic_load = bt_load; - priv->bt_status = bt_status; - + iwlagn_prepare_restart(priv); mutex_unlock(&priv->mutex); iwl_cancel_deferred_work(priv); ieee80211_restart_hw(priv->hw); } else { - iwl_down(priv); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - __iwl_up(priv); - mutex_unlock(&priv->mutex); + WARN_ON(1); } } @@ -3031,8 +2574,6 @@ static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw) * *****************************************************************************/ -#define UCODE_READY_TIMEOUT (4 * HZ) - /* * Not a mac80211 entry point function, but it fits in with all the * other mac80211 functions grouped here. @@ -3055,14 +2596,16 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF; - if (!priv->cfg->base_params->broken_powersave) - hw->flags |= IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_DYNAMIC_PS; + hw->flags |= IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; if (priv->cfg->sku & IWL_SKU_N) hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_SUPPORTS_STATIC_SMPS; + if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP) + hw->flags |= IEEE80211_HW_MFP_CAPABLE; + hw->sta_data_size = sizeof(struct iwl_station_priv); hw->vif_data_size = sizeof(struct iwl_vif_priv); @@ -3112,7 +2655,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, } -int iwlagn_mac_start(struct ieee80211_hw *hw) +static int iwlagn_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; int ret; @@ -3123,37 +2666,23 @@ int iwlagn_mac_start(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); ret = __iwl_up(priv); mutex_unlock(&priv->mutex); - if (ret) return ret; - if (iwl_is_rfkill(priv)) - goto out; - IWL_DEBUG_INFO(priv, "Start UP work done.\n"); - /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from - * mac80211 will not be run successfully. */ - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - test_bit(STATUS_READY, &priv->status), - UCODE_READY_TIMEOUT); - if (!ret) { - if (!test_bit(STATUS_READY, &priv->status)) { - IWL_ERR(priv, "START_ALIVE timeout after %dms.\n", - jiffies_to_msecs(UCODE_READY_TIMEOUT)); - return -ETIMEDOUT; - } - } + /* Now we should be done, and the READY bit should be set. */ + if (WARN_ON(!test_bit(STATUS_READY, &priv->status))) + ret = -EIO; iwlagn_led_enable(priv); -out: priv->is_open = 1; IWL_DEBUG_MAC80211(priv, "leave\n"); return 0; } -void iwlagn_mac_stop(struct ieee80211_hw *hw) +static void iwlagn_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -3176,7 +2705,7 @@ void iwlagn_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "leave\n"); } -void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; @@ -3191,11 +2720,11 @@ void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) IWL_DEBUG_MACDUMP(priv, "leave\n"); } -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) +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) { struct iwl_priv *priv = hw->priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -3208,9 +2737,10 @@ void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "leave\n"); } -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) +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) { struct iwl_priv *priv = hw->priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -3221,7 +2751,7 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, IWL_DEBUG_MAC80211(priv, "enter\n"); - if (priv->cfg->mod_params->sw_crypto) { + if (iwlagn_mod_params.sw_crypto) { IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } @@ -3285,11 +2815,11 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -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) +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) { struct iwl_priv *priv = hw->priv; int ret = -EINVAL; @@ -3348,6 +2878,10 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, } break; case IEEE80211_AMPDU_TX_OPERATIONAL: + buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); + + iwlagn_txq_agg_queue_setup(priv, sta, tid, buf_size); + /* * If the limit is 0, then it wasn't initialised yet, * use the default. We can do that since we take the @@ -3392,9 +2926,9 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, return ret; } -int iwlagn_mac_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) { struct iwl_priv *priv = hw->priv; struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; @@ -3435,8 +2969,8 @@ int iwlagn_mac_sta_add(struct ieee80211_hw *hw, return 0; } -void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_channel_switch *ch_switch) +static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch) { struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; @@ -3457,21 +2991,22 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->mutex); + if (iwl_is_rfkill(priv)) - goto out_exit; + goto out; if (test_bit(STATUS_EXIT_PENDING, &priv->status) || test_bit(STATUS_SCANNING, &priv->status)) - goto out_exit; + goto out; if (!iwl_is_associated_ctx(ctx)) - goto out_exit; + goto out; /* channel switch in progress */ if (priv->switch_rxon.switch_in_progress == true) - goto out_exit; + goto out; - mutex_lock(&priv->mutex); if (priv->cfg->ops->lib->set_channel_switch) { ch = channel->hw_value; @@ -3527,16 +3062,15 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, } out: mutex_unlock(&priv->mutex); -out_exit: if (!priv->switch_rxon.switch_in_progress) ieee80211_chswitch_done(ctx->vif, false); IWL_DEBUG_MAC80211(priv, "leave\n"); } -void iwlagn_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) +static void iwlagn_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) { struct iwl_priv *priv = hw->priv; __le32 filter_or = 0, filter_nand = 0; @@ -3583,7 +3117,7 @@ void iwlagn_configure_filter(struct ieee80211_hw *hw, FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } -void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) +static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) { struct iwl_priv *priv = hw->priv; @@ -3729,8 +3263,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency); INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); - INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); - INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); INIT_DELAYED_WORK(&priv->_agn.hw_roc_work, iwlagn_bg_roc_done); iwl_setup_scan_deferred_work(priv); @@ -3750,12 +3282,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->watchdog.data = (unsigned long)priv; priv->watchdog.function = iwl_bg_watchdog; - if (!priv->cfg->base_params->use_isr_legacy) - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet, (unsigned long)priv); - else - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet_legacy, (unsigned long)priv); + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet, (unsigned long)priv); } static void iwl_cancel_deferred_work(struct iwl_priv *priv) @@ -3763,8 +3291,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) if (priv->cfg->ops->lib->cancel_deferred_work) priv->cfg->ops->lib->cancel_deferred_work(priv); - cancel_delayed_work_sync(&priv->init_alive_start); - cancel_delayed_work(&priv->alive_start); cancel_work_sync(&priv->run_time_calib_work); cancel_work_sync(&priv->beacon_update); @@ -3805,10 +3331,7 @@ static int iwl_init_drv(struct iwl_priv *priv) spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); - INIT_LIST_HEAD(&priv->free_frames); - mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); priv->ieee_channels = NULL; priv->ieee_rates = NULL; @@ -3845,12 +3368,6 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF; } - /* Set the tx_power_user_lmt to the lowest power level - * this value will get overwritten by channel max power avg - * from eeprom */ - priv->tx_power_user_lmt = IWLAGN_TX_POWER_TARGET_POWER_MIN; - priv->tx_power_next = IWLAGN_TX_POWER_TARGET_POWER_MIN; - ret = iwl_init_channel_map(priv); if (ret) { IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); @@ -3905,28 +3422,30 @@ struct ieee80211_ops iwlagn_hw_ops = { .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, .offchannel_tx = iwl_mac_offchannel_tx, .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, + CFG80211_TESTMODE_CMD(iwl_testmode_cmd) }; -static void iwl_hw_detect(struct iwl_priv *priv) +static u32 iwl_hw_detect(struct iwl_priv *priv) { - priv->hw_rev = _iwl_read32(priv, CSR_HW_REV); - priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG); - priv->rev_id = priv->pci_dev->revision; - IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); + u8 rev_id; + + pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); + IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); + return iwl_read32(priv, CSR_HW_REV); } static int iwl_set_hw_params(struct iwl_priv *priv) { priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; - if (priv->cfg->mod_params->amsdu_size_8K) + if (iwlagn_mod_params.amsdu_size_8K) priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K); else priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K); priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL; - if (priv->cfg->mod_params->disable_11n) + if (iwlagn_mod_params.disable_11n) priv->cfg->sku &= ~IWL_SKU_N; /* Device-specific setup */ @@ -3955,6 +3474,28 @@ static const u8 iwlagn_pan_ac_to_queue[] = { 7, 6, 5, 4, }; +/* This function both allocates and initializes hw and priv. */ +static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg) +{ + struct iwl_priv *priv; + /* mac80211 allocates memory for this device instance, including + * space for this driver's private structure */ + struct ieee80211_hw *hw; + + hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops); + if (hw == NULL) { + pr_err("%s: Can not allocate network device\n", + cfg->name); + goto out; + } + + priv = hw->priv; + priv->hw = hw; + +out: + return hw; +} + static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0, i; @@ -3963,19 +3504,12 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); unsigned long flags; u16 pci_cmd, num_mac; + u32 hw_rev; /************************ * 1. Allocating HW data ************************/ - /* Disabling hardware scan means that mac80211 will perform scans - * "the hard way", rather than using device's scan. */ - if (cfg->mod_params->disable_hw_scan) { - dev_printk(KERN_DEBUG, &(pdev->dev), - "sw scan support is deprecated\n"); - iwlagn_hw_ops.hw_scan = NULL; - } - hw = iwl_alloc_all(cfg); if (!hw) { err = -ENOMEM; @@ -3984,6 +3518,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv = hw->priv; /* At this point both hw and priv are allocated. */ + priv->ucode_type = UCODE_SUBTYPE_NONE_LOADED; + /* * The default context is always valid, * more may be discovered when firmware @@ -4116,16 +3652,15 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - iwl_hw_detect(priv); + hw_rev = iwl_hw_detect(priv); IWL_INFO(priv, "Detected %s, REV=0x%X\n", - priv->cfg->name, priv->hw_rev); + priv->cfg->name, hw_rev); /* We disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); - iwl_prepare_card_hw(priv); - if (!priv->hw_ready) { + if (iwl_prepare_card_hw(priv)) { IWL_WARN(priv, "Failed, HW not ready\n"); goto out_iounmap; } @@ -4134,7 +3669,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * 4. Read EEPROM *****************/ /* Read the EEPROM */ - err = iwl_eeprom_init(priv); + err = iwl_eeprom_init(priv, hw_rev); if (err) { IWL_ERR(priv, "Unable to init EEPROM\n"); goto out_iounmap; @@ -4186,10 +3721,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_enable_msi(priv->pci_dev); - if (priv->cfg->ops->lib->isr_ops.alloc) - priv->cfg->ops->lib->isr_ops.alloc(priv); + iwl_alloc_isr_ict(priv); - err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr, + err = request_irq(priv->pci_dev->irq, iwl_isr_ict, IRQF_SHARED, DRV_NAME, priv); if (err) { IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); @@ -4198,6 +3732,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_setup_deferred_work(priv); iwl_setup_rx_handlers(priv); + iwl_testmode_init(priv); /********************************************* * 8. Enable interrupts and read RFKILL state @@ -4236,8 +3771,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) destroy_workqueue(priv->workqueue); priv->workqueue = NULL; free_irq(priv->pci_dev->irq, priv); - if (priv->cfg->ops->lib->isr_ops.free) - priv->cfg->ops->lib->isr_ops.free(priv); + iwl_free_isr_ict(priv); out_disable_msi: pci_disable_msi(priv->pci_dev); iwl_uninit_drv(priv); @@ -4283,17 +3817,9 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; - } else { - iwl_down(priv); } - /* - * Make sure device is reset to low power before unloading driver. - * This may be redundant with iwl_down(), but there are paths to - * run iwl_down() without calling apm_ops.stop(), and there are - * paths to avoid running iwl_down() at all before leaving driver. - * This (inexpensive) call *makes sure* device is reset. - */ + /* Reset to low power before unloading driver. */ iwl_apm_stop(priv); iwl_tt_exit(priv); @@ -4335,8 +3861,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_uninit_drv(priv); - if (priv->cfg->ops->lib->isr_ops.free) - priv->cfg->ops->lib->isr_ops.free(priv); + iwl_free_isr_ict(priv); dev_kfree_skb(priv->beacon_skb); @@ -4521,21 +4046,21 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)}, {IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)}, -/* 200 Series */ - {IWL_PCI_DEVICE(0x0894, 0x0022, iwl200_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0895, 0x0222, iwl200_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0894, 0x0422, iwl200_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0894, 0x0026, iwl200_bg_cfg)}, - {IWL_PCI_DEVICE(0x0895, 0x0226, iwl200_bg_cfg)}, - {IWL_PCI_DEVICE(0x0894, 0x0426, iwl200_bg_cfg)}, +/* 105 Series */ + {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)}, + {IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)}, -/* 230 Series */ - {IWL_PCI_DEVICE(0x0892, 0x0062, iwl230_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0893, 0x0262, iwl230_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0892, 0x0462, iwl230_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0892, 0x0066, iwl230_bg_cfg)}, - {IWL_PCI_DEVICE(0x0893, 0x0266, iwl230_bg_cfg)}, - {IWL_PCI_DEVICE(0x0892, 0x0466, iwl230_bg_cfg)}, +/* 135 Series */ + {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0066, iwl135_bg_cfg)}, + {IWL_PCI_DEVICE(0x0893, 0x0266, iwl135_bg_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0466, iwl135_bg_cfg)}, {0} }; @@ -4585,43 +4110,21 @@ module_exit(iwl_exit); module_init(iwl_init); #ifdef CONFIG_IWLWIFI_DEBUG -module_param_named(debug50, iwl_debug_level, uint, S_IRUGO); -MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)"); module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "debug output mask"); #endif -module_param_named(swcrypto50, iwlagn_mod_params.sw_crypto, bool, S_IRUGO); -MODULE_PARM_DESC(swcrypto50, - "using crypto in software (default 0 [hardware]) (deprecated)"); 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(queues_num50, - iwlagn_mod_params.num_of_queues, int, S_IRUGO); -MODULE_PARM_DESC(queues_num50, - "number of hw queues in 50xx series (deprecated)"); module_param_named(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO); MODULE_PARM_DESC(queues_num, "number of hw queues."); -module_param_named(11n_disable50, iwlagn_mod_params.disable_11n, int, S_IRUGO); -MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality (deprecated)"); module_param_named(11n_disable, iwlagn_mod_params.disable_11n, int, S_IRUGO); MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); -module_param_named(amsdu_size_8K50, iwlagn_mod_params.amsdu_size_8K, - int, S_IRUGO); -MODULE_PARM_DESC(amsdu_size_8K50, - "enable 8K amsdu size in 50XX series (deprecated)"); 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_restart50, iwlagn_mod_params.restart_fw, int, S_IRUGO); -MODULE_PARM_DESC(fw_restart50, - "restart firmware in case of error (deprecated)"); 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( - disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO); -MODULE_PARM_DESC(disable_hw_scan, - "disable hardware scanning (default 0) (deprecated)"); module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int, S_IRUGO); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 20f8e4188994..fe33fe8aa418 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,6 @@ #include "iwl-dev.h" /* configuration for the _agn devices */ -extern struct iwl_cfg iwl4965_agn_cfg; extern struct iwl_cfg iwl5300_agn_cfg; extern struct iwl_cfg iwl5100_agn_cfg; extern struct iwl_cfg iwl5350_agn_cfg; @@ -103,10 +102,10 @@ extern struct iwl_cfg iwl2030_2bg_cfg; extern struct iwl_cfg iwl6035_2agn_cfg; extern struct iwl_cfg iwl6035_2abg_cfg; extern struct iwl_cfg iwl6035_2bg_cfg; -extern struct iwl_cfg iwl200_bg_cfg; -extern struct iwl_cfg iwl200_bgn_cfg; -extern struct iwl_cfg iwl230_bg_cfg; -extern struct iwl_cfg iwl230_bgn_cfg; +extern struct iwl_cfg iwl105_bg_cfg; +extern struct iwl_cfg iwl105_bgn_cfg; +extern struct iwl_cfg iwl135_bg_cfg; +extern struct iwl_cfg iwl135_bgn_cfg; extern struct iwl_mod_params iwlagn_mod_params; extern struct iwl_hcmd_ops iwlagn_hcmd; @@ -114,7 +113,6 @@ extern struct iwl_hcmd_ops iwlagn_bt_hcmd; extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils; extern struct ieee80211_ops iwlagn_hw_ops; -extern struct ieee80211_ops iwl4965_hw_ops; int iwl_reset_ict(struct iwl_priv *priv); void iwl_disable_ict(struct iwl_priv *priv); @@ -122,21 +120,25 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv); void iwl_free_isr_ict(struct iwl_priv *priv); irqreturn_t iwl_isr_ict(int irq, void *data); +/* call this function to flush any scheduled tasklet */ +static inline void iwl_synchronize_irq(struct iwl_priv *priv) +{ + /* wait to make sure we flush pending tasklet*/ + synchronize_irq(priv->pci_dev->irq); + tasklet_kill(&priv->irq_tasklet); +} + +int iwl_prepare_card_hw(struct iwl_priv *priv); + +int iwlagn_start_device(struct iwl_priv *priv); +void iwlagn_stop_device(struct iwl_priv *priv); + /* tx queue */ void iwlagn_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index); void iwlagn_tx_queue_set_status(struct iwl_priv *priv, struct iwl_tx_queue *txq, int tx_fifo_id, int scd_retry); -void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - u16 byte_cnt); -void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq); -int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, - int tx_fifo, int sta_id, int tid, u16 ssn_idx); -int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo); void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask); void iwl_free_tfds_in_queue(struct iwl_priv *priv, int sta_id, int tid, int freed); @@ -151,16 +153,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, u32 changes); /* uCode */ -int iwlagn_load_ucode(struct iwl_priv *priv); void iwlagn_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); -void iwlagn_rx_calib_complete(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -void iwlagn_init_alive_start(struct iwl_priv *priv); -int iwlagn_alive_notify(struct iwl_priv *priv); -int iwl_verify_ucode(struct iwl_priv *priv); -void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); +int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); void iwlagn_send_prio_tbl(struct iwl_priv *priv); +int iwlagn_run_init_ucode(struct iwl_priv *priv); +int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, + struct fw_img *image, + int subtype, int alternate_subtype); /* lib */ void iwl_check_abort_status(struct iwl_priv *priv, @@ -179,8 +179,6 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv); int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv); int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); -void iwl_dump_csr(struct iwl_priv *priv); -int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); /* rx */ void iwlagn_rx_queue_restock(struct iwl_priv *priv); @@ -206,6 +204,9 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn); int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); +void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv, + struct ieee80211_sta *sta, + int tid, int frame_limit); int iwlagn_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, @@ -225,6 +226,7 @@ static inline u32 iwl_tx_status_to_mac80211(u32 status) case TX_STATUS_DIRECT_DONE: return IEEE80211_TX_STAT_ACK; case TX_STATUS_FAIL_DEST_PS: + case TX_STATUS_FAIL_PASSIVE_NO_RX: return IEEE80211_TX_STAT_TX_FILTERED; default: return 0; @@ -249,8 +251,6 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, struct ieee80211_vif *vif, bool add); /* hcmd */ -int iwlagn_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx); int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant); int iwlagn_send_beacon_cmd(struct iwl_priv *priv); @@ -311,7 +311,7 @@ static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) { - return le32_to_cpu(rate_n_flags) & 0xFF; + return le32_to_cpu(rate_n_flags) & RATE_MCS_RATE_MSK; } static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) @@ -322,50 +322,39 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) /* eeprom */ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv); void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); -int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); -void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); /* notification wait support */ void __acquires(wait_entry) iwlagn_init_notification_wait(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry, + u8 cmd, void (*fn)(struct iwl_priv *priv, - struct iwl_rx_packet *pkt), - u8 cmd); -signed long __releases(wait_entry) + struct iwl_rx_packet *pkt, + void *data), + void *fn_data); +int __must_check __releases(wait_entry) iwlagn_wait_notification(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry, unsigned long timeout); void __releases(wait_entry) iwlagn_remove_notification(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry); - -/* mac80211 handlers (for 4965) */ -void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -int iwlagn_mac_start(struct ieee80211_hw *hw); -void iwlagn_mac_stop(struct ieee80211_hw *hw); -void iwlagn_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast); -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_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_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_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_channel_switch *ch_switch); -void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop); +extern int iwlagn_init_alive_start(struct iwl_priv *priv); +extern int iwl_alive_start(struct iwl_priv *priv); +/* svtool */ +#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL +extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len); +extern void iwl_testmode_init(struct iwl_priv *priv); +#else +static inline +int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) +{ + return -ENOSYS; +} +static inline +void iwl_testmode_init(struct iwl_priv *priv) +{ +} +#endif #endif /* __iwl_agn_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index ca42ffa63ed7..5fdad6532118 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -103,9 +103,7 @@ enum { REPLY_WEPKEY = 0x20, /* RX, TX, LEDs */ - REPLY_3945_RX = 0x1b, /* 3945 only */ REPLY_TX = 0x1c, - REPLY_RATE_SCALE = 0x47, /* 3945 only */ REPLY_LEDS_CMD = 0x48, REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* for 4965 and up */ @@ -229,7 +227,7 @@ struct iwl_cmd_header { * There is one exception: uCode sets bit 15 when it originates * the response/notification, i.e. when the response/notification * is not a direct response to a command sent by the driver. For - * example, uCode issues REPLY_3945_RX when it sends a received frame + * example, uCode issues REPLY_RX when it sends a received frame * to the driver; it is not a direct response to any driver command. * * The Linux driver uses the following format: @@ -248,36 +246,6 @@ struct iwl_cmd_header { } __packed; -/** - * struct iwl3945_tx_power - * - * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_SCAN_CMD, REPLY_CHANNEL_SWITCH - * - * Each entry contains two values: - * 1) DSP gain (or sometimes called DSP attenuation). This is a fine-grained - * linear value that multiplies the output of the digital signal processor, - * before being sent to the analog radio. - * 2) Radio gain. This sets the analog gain of the radio Tx path. - * It is a coarser setting, and behaves in a logarithmic (dB) fashion. - * - * Driver obtains values from struct iwl3945_tx_power power_gain_table[][]. - */ -struct iwl3945_tx_power { - u8 tx_gain; /* gain for analog radio */ - u8 dsp_atten; /* gain for DSP */ -} __packed; - -/** - * struct iwl3945_power_per_rate - * - * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - */ -struct iwl3945_power_per_rate { - u8 rate; /* plcp */ - struct iwl3945_tx_power tpc; - u8 reserved; -} __packed; - /** * iwlagn rate_n_flags bit fields * @@ -324,6 +292,8 @@ struct iwl3945_power_per_rate { #define RATE_MCS_SPATIAL_MSK 0x18 #define RATE_MCS_HT_DUP_POS 5 #define RATE_MCS_HT_DUP_MSK 0x20 +/* Both legacy and HT use bits 7:0 as the CCK/OFDM rate or HT MCS */ +#define RATE_MCS_RATE_MSK 0xff /* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */ #define RATE_MCS_FLAGS_POS 8 @@ -374,30 +344,6 @@ struct iwl3945_power_per_rate { #define IWL_PWR_NUM_HT_OFDM_ENTRIES 24 #define IWL_PWR_CCK_ENTRIES 2 -/** - * union iwl4965_tx_power_dual_stream - * - * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - * Use __le32 version (struct tx_power_dual_stream) when building command. - * - * Driver provides radio gain and DSP attenuation settings to device in pairs, - * one value for each transmitter chain. The first value is for transmitter A, - * second for transmitter B. - * - * For SISO bit rates, both values in a pair should be identical. - * For MIMO rates, one value may be different from the other, - * in order to balance the Tx output between the two transmitters. - * - * See more details in doc for TXPOWER in iwl-4965-hw.h. - */ -union iwl4965_tx_power_dual_stream { - struct { - u8 radio_tx_gain[2]; - u8 dsp_predis_atten[2]; - } s; - u32 dw; -}; - /** * struct tx_power_dual_stream * @@ -409,15 +355,6 @@ struct tx_power_dual_stream { __le32 dw; } __packed; -/** - * struct iwl4965_tx_power_db - * - * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - */ -struct iwl4965_tx_power_db { - struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; -} __packed; - /** * Command REPLY_TX_POWER_DBM_CMD = 0x98 * struct iwlagn_tx_power_dbm_cmd @@ -449,55 +386,18 @@ struct iwl_tx_ant_config_cmd { *****************************************************************************/ #define UCODE_VALID_OK cpu_to_le32(0x1) -#define INITIALIZE_SUBTYPE (9) -/* - * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command) - * - * uCode issues this "initialize alive" notification once the initialization - * uCode image has completed its work, and is ready to load the runtime image. - * This is the *first* "alive" notification that the driver will receive after - * rebooting uCode; the "initialize" alive is indicated by subtype field == 9. - * - * See comments documenting "BSM" (bootstrap state machine). - * - * For 4965, this notification contains important calibration data for - * calculating txpower settings: - * - * 1) Power supply voltage indication. The voltage sensor outputs higher - * values for lower voltage, and vice verse. - * - * 2) Temperature measurement parameters, for each of two channel widths - * (20 MHz and 40 MHz) supported by the radios. Temperature sensing - * is done via one of the receiver chains, and channel width influences - * the results. - * - * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation, - * for each of 5 frequency ranges. - */ -struct iwl_init_alive_resp { - u8 ucode_minor; - u8 ucode_major; - __le16 reserved1; - u8 sw_rev[8]; - u8 ver_type; - u8 ver_subtype; /* "9" for initialize alive */ - __le16 reserved2; - __le32 log_event_table_ptr; - __le32 error_event_table_ptr; - __le32 timestamp; - __le32 is_valid; - - /* calibration values from "initialize" uCode */ - __le32 voltage; /* signed, higher value is lower voltage */ - __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */ - __le32 therm_r2[2]; /* signed */ - __le32 therm_r3[2]; /* signed */ - __le32 therm_r4[2]; /* signed */ - __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups, - * 2 Tx chains */ -} __packed; +enum iwlagn_ucode_subtype { + UCODE_SUBTYPE_REGULAR = 0, + UCODE_SUBTYPE_REGULAR_NEW = 1, + UCODE_SUBTYPE_INIT = 9, + /* + * Not a valid subtype, the ucode has just a u8, so + * we can use something > 0xff for this value. + */ + UCODE_SUBTYPE_NONE_LOADED = 0x100, +}; /** * REPLY_ALIVE = 0x1 (response only, not a command) @@ -533,49 +433,61 @@ struct iwl_init_alive_resp { * * 2) error_event_table_ptr indicates base of the error log. This contains * information about any uCode error that occurs. For agn, the format - * of the error log is: - * - * __le32 valid; (nonzero) valid, (0) log is empty - * __le32 error_id; type of error - * __le32 pc; program counter - * __le32 blink1; branch link - * __le32 blink2; branch link - * __le32 ilink1; interrupt link - * __le32 ilink2; interrupt link - * __le32 data1; error-specific data - * __le32 data2; error-specific data - * __le32 line; source code line of error - * __le32 bcon_time; beacon timer - * __le32 tsf_low; network timestamp function timer - * __le32 tsf_hi; network timestamp function timer - * __le32 gp1; GP1 timer register - * __le32 gp2; GP2 timer register - * __le32 gp3; GP3 timer register - * __le32 ucode_ver; uCode version - * __le32 hw_ver; HW Silicon version - * __le32 brd_ver; HW board version - * __le32 log_pc; log program counter - * __le32 frame_ptr; frame pointer - * __le32 stack_ptr; stack pointer - * __le32 hcmd; last host command - * __le32 isr0; isr status register LMPM_NIC_ISR0: rxtx_flag - * __le32 isr1; isr status register LMPM_NIC_ISR1: host_flag - * __le32 isr2; isr status register LMPM_NIC_ISR2: enc_flag - * __le32 isr3; isr status register LMPM_NIC_ISR3: time_flag - * __le32 isr4; isr status register LMPM_NIC_ISR4: wico interrupt - * __le32 isr_pref; isr status register LMPM_NIC_PREF_STAT - * __le32 wait_event; wait event() caller address - * __le32 l2p_control; L2pControlField - * __le32 l2p_duration; L2pDurationField - * __le32 l2p_mhvalid; L2pMhValidBits - * __le32 l2p_addr_match; L2pAddrMatchStat - * __le32 lmpm_pmg_sel; indicate which clocks are turned on (LMPM_PMG_SEL) - * __le32 u_timestamp; indicate when the date and time of the compilation - * __le32 reserved; + * of the error log is defined by struct iwl_error_event_table. * * The Linux driver can print both logs to the system log when a uCode error * occurs. */ + +/* + * Note: This structure is read from the device with IO accesses, + * and the reading already does the endian conversion. As it is + * read with u32-sized accesses, any members with a different size + * need to be ordered correctly though! + */ +struct iwl_error_event_table { + u32 valid; /* (nonzero) valid, (0) log is empty */ + u32 error_id; /* type of error */ + u32 pc; /* program counter */ + u32 blink1; /* branch link */ + u32 blink2; /* branch link */ + u32 ilink1; /* interrupt link */ + u32 ilink2; /* interrupt link */ + u32 data1; /* error-specific data */ + u32 data2; /* error-specific data */ + u32 line; /* source code line of error */ + u32 bcon_time; /* beacon timer */ + u32 tsf_low; /* network timestamp function timer */ + u32 tsf_hi; /* network timestamp function timer */ + u32 gp1; /* GP1 timer register */ + u32 gp2; /* GP2 timer register */ + u32 gp3; /* GP3 timer register */ + u32 ucode_ver; /* uCode version */ + u32 hw_ver; /* HW Silicon version */ + u32 brd_ver; /* HW board version */ + u32 log_pc; /* log program counter */ + u32 frame_ptr; /* frame pointer */ + u32 stack_ptr; /* stack pointer */ + u32 hcmd; /* last host command header */ +#if 0 + /* no need to read the remainder, we don't use the values */ + u32 isr0; /* isr status register LMPM_NIC_ISR0: rxtx_flag */ + u32 isr1; /* isr status register LMPM_NIC_ISR1: host_flag */ + u32 isr2; /* isr status register LMPM_NIC_ISR2: enc_flag */ + u32 isr3; /* isr status register LMPM_NIC_ISR3: time_flag */ + u32 isr4; /* isr status register LMPM_NIC_ISR4: wico interrupt */ + u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ + u32 wait_event; /* wait event() caller address */ + u32 l2p_control; /* L2pControlField */ + u32 l2p_duration; /* L2pDurationField */ + u32 l2p_mhvalid; /* L2pMhValidBits */ + u32 l2p_addr_match; /* L2pAddrMatchStat */ + u32 lmpm_pmg_sel; /* indicate which clocks are turned on (LMPM_PMG_SEL) */ + u32 u_timestamp; /* indicate when the date and time of the compilation */ + u32 flow_handler; /* FH read/write pointers, RX credit */ +#endif +} __packed; + struct iwl_alive_resp { u8 ucode_minor; u8 ucode_major; @@ -722,46 +634,6 @@ enum { * regardless of whether RXON_FILTER_ASSOC_MSK is set. */ -struct iwl3945_rxon_cmd { - u8 node_addr[6]; - __le16 reserved1; - u8 bssid_addr[6]; - __le16 reserved2; - u8 wlap_bssid_addr[6]; - __le16 reserved3; - u8 dev_type; - u8 air_propagation; - __le16 reserved4; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 assoc_id; - __le32 flags; - __le32 filter_flags; - __le16 channel; - __le16 reserved5; -} __packed; - -struct iwl4965_rxon_cmd { - u8 node_addr[6]; - __le16 reserved1; - u8 bssid_addr[6]; - __le16 reserved2; - u8 wlap_bssid_addr[6]; - __le16 reserved3; - u8 dev_type; - u8 air_propagation; - __le16 rx_chain; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 assoc_id; - __le32 flags; - __le32 filter_flags; - __le16 channel; - u8 ofdm_ht_single_stream_basic_rates; - u8 ofdm_ht_dual_stream_basic_rates; -} __packed; - -/* 5000 HW just extend this command */ struct iwl_rxon_cmd { u8 node_addr[6]; __le16 reserved1; @@ -789,26 +661,7 @@ struct iwl_rxon_cmd { /* * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) */ -struct iwl3945_rxon_assoc_cmd { - __le32 flags; - __le32 filter_flags; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 reserved; -} __packed; - -struct iwl4965_rxon_assoc_cmd { - __le32 flags; - __le32 filter_flags; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - u8 ofdm_ht_single_stream_basic_rates; - u8 ofdm_ht_dual_stream_basic_rates; - __le16 rx_chain_select_flags; - __le16 reserved; -} __packed; - -struct iwl5000_rxon_assoc_cmd { +struct iwl_rxon_assoc_cmd { __le32 flags; __le32 filter_flags; u8 ofdm_basic_rates; @@ -843,26 +696,6 @@ struct iwl_rxon_time_cmd { /* * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) */ -struct iwl3945_channel_switch_cmd { - u8 band; - u8 expect_beacon; - __le16 channel; - __le32 rxon_flags; - __le32 rxon_filter_flags; - __le32 switch_time; - struct iwl3945_power_per_rate power[IWL_MAX_RATES]; -} __packed; - -struct iwl4965_channel_switch_cmd { - u8 band; - u8 expect_beacon; - __le16 channel; - __le32 rxon_flags; - __le32 rxon_filter_flags; - __le32 switch_time; - struct iwl4965_tx_power_db tx_power; -} __packed; - /** * struct iwl5000_channel_switch_cmd * @band: 0- 5.2GHz, 1- 2.4GHz @@ -976,15 +809,10 @@ struct iwl_qosparam_cmd { #define IWL_AP_ID 0 #define IWL_AP_ID_PAN 1 #define IWL_STA_ID 2 -#define IWL3945_BROADCAST_ID 24 -#define IWL3945_STATION_COUNT 25 -#define IWL4965_BROADCAST_ID 31 -#define IWL4965_STATION_COUNT 32 #define IWLAGN_PAN_BCAST_ID 14 #define IWLAGN_BROADCAST_ID 15 #define IWLAGN_STATION_COUNT 16 -#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) @@ -1032,16 +860,6 @@ struct iwl_qosparam_cmd { * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) -struct iwl4965_keyinfo { - __le16 key_flags; - u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ - u8 reserved1; - __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ - u8 key_offset; - u8 reserved2; - u8 key[16]; /* 16-byte unicast decryption key */ -} __packed; - /* agn */ struct iwl_keyinfo { __le16 key_flags; @@ -1083,7 +901,6 @@ struct sta_id_modify { * with info on security keys, aggregation parameters, and Tx rates for * initial Tx attempt and any retries (agn devices uses * REPLY_TX_LINK_QUALITY_CMD, - * 3945 uses REPLY_RATE_SCALE to set up rate tables). * * REPLY_ADD_STA sets up the table entry for one station, either creating * a new entry, or modifying a pre-existing one. @@ -1103,72 +920,6 @@ struct sta_id_modify { * entries for all STAs in network, starting with index IWL_STA_ID. */ -struct iwl3945_addsta_cmd { - u8 mode; /* 1: modify existing, 0: add new station */ - u8 reserved[3]; - struct sta_id_modify sta; - struct iwl4965_keyinfo key; - __le32 station_flags; /* STA_FLG_* */ - __le32 station_flags_msk; /* STA_FLG_* */ - - /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) - * corresponding to bit (e.g. bit 5 controls TID 5). - * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ - __le16 tid_disable_tx; - - __le16 rate_n_flags; - - /* TID for which to add block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - u8 add_immediate_ba_tid; - - /* TID for which to remove block-ack support. - * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ - u8 remove_immediate_ba_tid; - - /* Starting Sequence Number for added block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - __le16 add_immediate_ba_ssn; -} __packed; - -struct iwl4965_addsta_cmd { - u8 mode; /* 1: modify existing, 0: add new station */ - u8 reserved[3]; - struct sta_id_modify sta; - struct iwl4965_keyinfo key; - __le32 station_flags; /* STA_FLG_* */ - __le32 station_flags_msk; /* STA_FLG_* */ - - /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) - * corresponding to bit (e.g. bit 5 controls TID 5). - * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ - __le16 tid_disable_tx; - - __le16 reserved1; - - /* TID for which to add block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - u8 add_immediate_ba_tid; - - /* TID for which to remove block-ack support. - * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ - u8 remove_immediate_ba_tid; - - /* Starting Sequence Number for added block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - __le16 add_immediate_ba_ssn; - - /* - * Number of packets OK to transmit to station even though - * it is asleep -- used to synchronise PS-poll and u-APSD - * responses while ucode keeps track of STA sleep state. - */ - __le16 sleep_tx_count; - - __le16 reserved2; -} __packed; - -/* agn */ struct iwl_addsta_cmd { u8 mode; /* 1: modify existing, 0: add new station */ u8 reserved[3]; @@ -1337,62 +1088,6 @@ struct iwl_wep_cmd { #define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) -struct iwl3945_rx_frame_stats { - u8 phy_count; - u8 id; - u8 rssi; - u8 agc; - __le16 sig_avg; - __le16 noise_diff; - u8 payload[0]; -} __packed; - -struct iwl3945_rx_frame_hdr { - __le16 channel; - __le16 phy_flags; - u8 reserved1; - u8 rate; - __le16 len; - u8 payload[0]; -} __packed; - -struct iwl3945_rx_frame_end { - __le32 status; - __le64 timestamp; - __le32 beacon_timestamp; -} __packed; - -/* - * REPLY_3945_RX = 0x1b (response only, not a command) - * - * NOTE: DO NOT dereference from casts to this structure - * It is provided only for calculating minimum data set size. - * The actual offsets of the hdr and end are dynamic based on - * stats.phy_count - */ -struct iwl3945_rx_frame { - struct iwl3945_rx_frame_stats stats; - struct iwl3945_rx_frame_hdr hdr; - struct iwl3945_rx_frame_end end; -} __packed; - -#define IWL39_RX_FRAME_SIZE (4 + sizeof(struct iwl3945_rx_frame)) - -/* Fixed (non-configurable) rx data from phy */ - -#define IWL49_RX_RES_PHY_CNT 14 -#define IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET (4) -#define IWL49_RX_PHY_FLAGS_ANTENNAE_MASK (0x70) -#define IWL49_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ -#define IWL49_AGC_DB_POS (7) -struct iwl4965_rx_non_cfg_phy { - __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ - __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ - u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ - u8 pad[0]; -} __packed; - - #define IWLAGN_RX_RES_PHY_CNT 8 #define IWLAGN_RX_RES_AGC_IDX 1 #define IWLAGN_RX_RES_RSSI_AB_IDX 2 @@ -1576,80 +1271,6 @@ struct iwl_rx_mpdu_res_start { * REPLY_TX = 0x1c (command) */ -struct iwl3945_tx_cmd { - /* - * MPDU byte count: - * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, - * + 8 byte IV for CCM or TKIP (not used for WEP) - * + Data payload - * + 8-byte MIC (not used for CCM/WEP) - * NOTE: Does not include Tx command bytes, post-MAC pad bytes, - * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i - * Range: 14-2342 bytes. - */ - __le16 len; - - /* - * MPDU or MSDU byte count for next frame. - * Used for fragmentation and bursting, but not 11n aggregation. - * Same as "len", but for next frame. Set to 0 if not applicable. - */ - __le16 next_frame_len; - - __le32 tx_flags; /* TX_CMD_FLG_* */ - - u8 rate; - - /* Index of recipient station in uCode's station table */ - u8 sta_id; - u8 tid_tspec; - u8 sec_ctl; - u8 key[16]; - union { - u8 byte[8]; - __le16 word[4]; - __le32 dw[2]; - } tkip_mic; - __le32 next_frame_info; - union { - __le32 life_time; - __le32 attempt; - } stop_time; - u8 supp_rates[2]; - u8 rts_retry_limit; /*byte 50 */ - u8 data_retry_limit; /*byte 51 */ - union { - __le16 pm_frame_timeout; - __le16 attempt_duration; - } timeout; - - /* - * Duration of EDCA burst Tx Opportunity, in 32-usec units. - * Set this if txop time is not specified by HCCA protocol (e.g. by AP). - */ - __le16 driver_txop; - - /* - * MAC header goes here, followed by 2 bytes padding if MAC header - * length is 26 or 30 bytes, followed by payload data - */ - u8 payload[0]; - struct ieee80211_hdr hdr[0]; -} __packed; - -/* - * REPLY_TX = 0x1c (response) - */ -struct iwl3945_tx_resp { - u8 failure_rts; - u8 failure_frame; - u8 bt_kill_count; - u8 rate; - __le32 wireless_media_time; - __le32 status; /* TX status */ -} __packed; - - /* * 4965 uCode updates these Tx attempt count values in host DRAM. * Used for managing Tx retries when expecting block-acks. @@ -1740,54 +1361,6 @@ struct iwl_tx_cmd { struct ieee80211_hdr hdr[0]; } __packed; -/* TX command response is sent after *3945* transmission attempts. - * - * NOTES: - * - * TX_STATUS_FAIL_NEXT_FRAG - * - * If the fragment flag in the MAC header for the frame being transmitted - * is set and there is insufficient time to transmit the next frame, the - * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'. - * - * TX_STATUS_FIFO_UNDERRUN - * - * Indicates the host did not provide bytes to the FIFO fast enough while - * a TX was in progress. - * - * TX_STATUS_FAIL_MGMNT_ABORT - * - * This status is only possible if the ABORT ON MGMT RX parameter was - * set to true with the TX command. - * - * If the MSB of the status parameter is set then an abort sequence is - * required. This sequence consists of the host activating the TX Abort - * control line, and then waiting for the TX Abort command response. This - * indicates that a the device is no longer in a transmit state, and that the - * command FIFO has been cleared. The host must then deactivate the TX Abort - * control line. Receiving is still allowed in this case. - */ -enum { - TX_3945_STATUS_SUCCESS = 0x01, - TX_3945_STATUS_DIRECT_DONE = 0x02, - TX_3945_STATUS_FAIL_SHORT_LIMIT = 0x82, - TX_3945_STATUS_FAIL_LONG_LIMIT = 0x83, - TX_3945_STATUS_FAIL_FIFO_UNDERRUN = 0x84, - TX_3945_STATUS_FAIL_MGMNT_ABORT = 0x85, - TX_3945_STATUS_FAIL_NEXT_FRAG = 0x86, - TX_3945_STATUS_FAIL_LIFE_EXPIRE = 0x87, - TX_3945_STATUS_FAIL_DEST_PS = 0x88, - TX_3945_STATUS_FAIL_ABORTED = 0x89, - TX_3945_STATUS_FAIL_BT_RETRY = 0x8a, - TX_3945_STATUS_FAIL_STA_INVALID = 0x8b, - TX_3945_STATUS_FAIL_FRAG_DROPPED = 0x8c, - TX_3945_STATUS_FAIL_TID_DISABLE = 0x8d, - TX_3945_STATUS_FAIL_FRAME_FLUSHED = 0x8e, - TX_3945_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f, - TX_3945_STATUS_FAIL_TX_LOCKED = 0x90, - TX_3945_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91, -}; - /* * TX command response is sent after *agn* transmission attempts. * @@ -1905,43 +1478,6 @@ struct agg_tx_status { __le16 sequence; } __packed; -struct iwl4965_tx_resp { - u8 frame_count; /* 1 no aggregation, >1 aggregation */ - u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ - u8 failure_rts; /* # failures due to unsuccessful RTS */ - u8 failure_frame; /* # failures due to no ACK (unused for agg) */ - - /* For non-agg: Rate at which frame was successful. - * For agg: Rate at which all frames were transmitted. */ - __le32 rate_n_flags; /* RATE_MCS_* */ - - /* For non-agg: RTS + CTS + frame tx attempts time + ACK. - * For agg: RTS + CTS + aggregation tx time + block-ack time. */ - __le16 wireless_media_time; /* uSecs */ - - __le16 reserved; - __le32 pa_power1; /* RF power amplifier measurement (not used) */ - __le32 pa_power2; - - /* - * For non-agg: frame status TX_STATUS_* - * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status - * fields follow this one, up to frame_count. - * Bit fields: - * 11- 0: AGG_TX_STATE_* status code - * 15-12: Retry count for 1st frame in aggregation (retries - * occur if tx failed for this frame when it was a - * member of a previous aggregation block). If rate - * scaling is used, retry count indicates the rate - * table entry used for all frames in the new agg. - * 31-16: Sequence # for this frame's Tx cmd (not SSN!) - */ - union { - __le32 status; - struct agg_tx_status agg_status[0]; /* for each agg frame */ - } u; -} __packed; - /* * definitions for initial rate index field * bits [3:0] initial rate index @@ -2030,52 +1566,8 @@ struct iwl_compressed_ba_resp { /* * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) * - * See details under "TXPOWER" in iwl-4965-hw.h. */ -struct iwl3945_txpowertable_cmd { - u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ - u8 reserved; - __le16 channel; - struct iwl3945_power_per_rate power[IWL_MAX_RATES]; -} __packed; - -struct iwl4965_txpowertable_cmd { - u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ - u8 reserved; - __le16 channel; - struct iwl4965_tx_power_db tx_power; -} __packed; - - -/** - * struct iwl3945_rate_scaling_cmd - Rate Scaling Command & Response - * - * REPLY_RATE_SCALE = 0x47 (command, has simple generic response) - * - * NOTE: The table of rates passed to the uCode via the - * RATE_SCALE command sets up the corresponding order of - * rates used for all related commands, including rate - * masks, etc. - * - * For example, if you set 9MB (PLCP 0x0f) as the first - * rate in the rate table, the bit mask for that rate - * when passed through ofdm_basic_rates on the REPLY_RXON - * command would be bit 0 (1 << 0) - */ -struct iwl3945_rate_scaling_info { - __le16 rate_n_flags; - u8 try_cnt; - u8 next_rate_index; -} __packed; - -struct iwl3945_rate_scaling_cmd { - u8 table_id; - u8 reserved[3]; - struct iwl3945_rate_scaling_info table[IWL_MAX_RATES]; -} __packed; - - /*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ #define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1 << 0) @@ -2130,7 +1622,7 @@ struct iwl_link_qual_general_params { #define LINK_QUAL_AGG_DISABLE_START_MAX (255) #define LINK_QUAL_AGG_DISABLE_START_MIN (0) -#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31) +#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) @@ -2696,14 +2188,6 @@ struct iwl_spectrum_notification { #define IWL_POWER_BT_SCO_ENA cpu_to_le16(BIT(8)) #define IWL_POWER_ADVANCE_PM_ENA_MSK cpu_to_le16(BIT(9)) -struct iwl3945_powertable_cmd { - __le16 flags; - u8 reserved[2]; - __le32 rx_data_timeout; - __le32 tx_data_timeout; - __le32 sleep_interval[IWL_POWER_VEC_SIZE]; -} __packed; - struct iwl_powertable_cmd { __le16 flags; u8 keep_alive_seconds; /* 3945 reserved */ @@ -2806,25 +2290,6 @@ struct iwl_ct_kill_throttling_config { * active_dwell < max_out_time */ -/* FIXME: rename to AP1, remove tpc */ -struct iwl3945_scan_channel { - /* - * type is defined as: - * 0:0 1 = active, 0 = passive - * 1:4 SSID direct bit map; if a bit is set, then corresponding - * SSID IE is transmitted in probe request. - * 5:7 reserved - */ - u8 type; - u8 channel; /* band is selected by iwl3945_scan_cmd "flags" field */ - struct iwl3945_tx_power tpc; - __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */ - __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */ -} __packed; - -/* set number of direct probes u8 type */ -#define IWL39_SCAN_PROBE_MASK(n) ((BIT(n) | (BIT(n) - BIT(1)))) - struct iwl_scan_channel { /* * type is defined as: @@ -2920,50 +2385,6 @@ struct iwl_ssid_ie { * struct iwl_scan_channel. */ -struct iwl3945_scan_cmd { - __le16 len; - u8 reserved0; - u8 channel_count; /* # channels in channel list */ - __le16 quiet_time; /* dwell only this # millisecs on quiet channel - * (only for active scan) */ - __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ - __le16 good_CRC_th; /* passive -> active promotion threshold */ - __le16 reserved1; - __le32 max_out_time; /* max usec to be away from associated (service) - * channel */ - __le32 suspend_time; /* pause scan this long (in "extended beacon - * format") when returning to service channel: - * 3945; 31:24 # beacons, 19:0 additional usec, - * 4965; 31:22 # beacons, 21:0 additional usec. - */ - __le32 flags; /* RXON_FLG_* */ - __le32 filter_flags; /* RXON_FILTER_* */ - - /* For active scans (set to all-0s for passive scans). - * Does not include payload. Must specify Tx rate; no rate scaling. */ - struct iwl3945_tx_cmd tx_cmd; - - /* For directed active scans (set to all-0s otherwise) */ - struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_3945]; - - /* - * Probe request frame, followed by channel list. - * - * Size of probe request frame is specified by byte count in tx_cmd. - * Channel list follows immediately after probe request frame. - * Number of channels in list is specified by channel_count. - * Each channel in list is of type: - * - * struct iwl3945_scan_channel channels[0]; - * - * NOTE: Only one band of channels can be scanned per pass. You - * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait - * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) - * before requesting another scan. - */ - u8 data[0]; -} __packed; - enum iwl_scan_flags { /* BIT(0) currently unused */ IWL_SCAN_FLAGS_ACTION_FRAME_TX = BIT(1), @@ -3090,20 +2511,6 @@ enum iwl_ibss_manager { * BEACON_NOTIFICATION = 0x90 (notification only, not a command) */ -struct iwl3945_beacon_notif { - struct iwl3945_tx_resp beacon_notify_hdr; - __le32 low_tsf; - __le32 high_tsf; - __le32 ibss_mgr_status; -} __packed; - -struct iwl4965_beacon_notif { - struct iwl4965_tx_resp beacon_notify_hdr; - __le32 low_tsf; - __le32 high_tsf; - __le32 ibss_mgr_status; -} __packed; - struct iwlagn_beacon_notif { struct iwlagn_tx_resp beacon_notify_hdr; __le32 low_tsf; @@ -3115,14 +2522,6 @@ struct iwlagn_beacon_notif { * REPLY_TX_BEACON = 0x91 (command, has simple generic response) */ -struct iwl3945_tx_beacon_cmd { - struct iwl3945_tx_cmd tx; - __le16 tim_idx; - u8 tim_size; - u8 reserved1; - struct ieee80211_hdr frame[0]; /* beacon frame */ -} __packed; - struct iwl_tx_beacon_cmd { struct iwl_tx_cmd tx; __le16 tim_idx; @@ -3159,53 +2558,6 @@ struct rate_histogram { /* statistics command response */ -struct iwl39_statistics_rx_phy { - __le32 ina_cnt; - __le32 fina_cnt; - __le32 plcp_err; - __le32 crc32_err; - __le32 overrun_err; - __le32 early_overrun_err; - __le32 crc32_good; - __le32 false_alarm_cnt; - __le32 fina_sync_err_cnt; - __le32 sfd_timeout; - __le32 fina_timeout; - __le32 unresponded_rts; - __le32 rxe_frame_limit_overrun; - __le32 sent_ack_cnt; - __le32 sent_cts_cnt; -} __packed; - -struct iwl39_statistics_rx_non_phy { - __le32 bogus_cts; /* CTS received when not expecting CTS */ - __le32 bogus_ack; /* ACK received when not expecting ACK */ - __le32 non_bssid_frames; /* number of frames with BSSID that - * doesn't belong to the STA BSSID */ - __le32 filtered_frames; /* count frames that were dumped in the - * filtering process */ - __le32 non_channel_beacons; /* beacons with our bss id but not on - * our serving channel */ -} __packed; - -struct iwl39_statistics_rx { - struct iwl39_statistics_rx_phy ofdm; - struct iwl39_statistics_rx_phy cck; - struct iwl39_statistics_rx_non_phy general; -} __packed; - -struct iwl39_statistics_tx { - __le32 preamble_cnt; - __le32 rx_detected_cnt; - __le32 bt_prio_defer_cnt; - __le32 bt_prio_kill_cnt; - __le32 few_bytes_cnt; - __le32 cts_timeout; - __le32 ack_timeout; - __le32 expected_ack_cnt; - __le32 actual_ack_cnt; -} __packed; - struct statistics_dbg { __le32 burst_check; __le32 burst_count; @@ -3213,23 +2565,6 @@ struct statistics_dbg { __le32 reserved[3]; } __packed; -struct iwl39_statistics_div { - __le32 tx_on_a; - __le32 tx_on_b; - __le32 exec_time; - __le32 probe_time; -} __packed; - -struct iwl39_statistics_general { - __le32 temperature; - struct statistics_dbg dbg; - __le32 sleep_time; - __le32 slots_out; - __le32 slots_idle; - __le32 ttl_timestamp; - struct iwl39_statistics_div div; -} __packed; - struct statistics_rx_phy { __le32 ina_cnt; __le32 fina_cnt; @@ -3471,13 +2806,6 @@ struct iwl_statistics_cmd { #define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) #define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8) -struct iwl3945_notif_statistics { - __le32 flag; - struct iwl39_statistics_rx rx; - struct iwl39_statistics_tx tx; - struct iwl39_statistics_general general; -} __packed; - struct iwl_notif_statistics { __le32 flag; struct statistics_rx rx; @@ -4451,10 +3779,6 @@ struct iwl_rx_packet { __le32 len_n_flags; struct iwl_cmd_header hdr; union { - struct iwl3945_rx_frame rx_frame; - struct iwl3945_tx_resp tx_resp; - struct iwl3945_beacon_notif beacon_status; - struct iwl_alive_resp alive_frame; struct iwl_spectrum_notification spectrum_notif; struct iwl_csa_notification csa_notif; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index bafbe57c9602..4653deada05b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -41,6 +41,7 @@ #include "iwl-power.h" #include "iwl-sta.h" #include "iwl-helpers.h" +#include "iwl-agn.h" /* @@ -67,30 +68,6 @@ u32 iwl_debug_level; const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - -/* This function both allocates and initializes hw and priv. */ -struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg) -{ - struct iwl_priv *priv; - /* mac80211 allocates memory for this device instance, including - * space for this driver's private structure */ - struct ieee80211_hw *hw; - - hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), - cfg->ops->ieee80211_ops); - if (hw == NULL) { - pr_err("%s: Can not allocate network device\n", - cfg->name); - goto out; - } - - priv = hw->priv; - priv->hw = hw; - -out: - return hw; -} - #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, @@ -118,7 +95,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, max_bit_rate = MAX_BIT_RATE_40_MHZ; } - if (priv->cfg->mod_params->amsdu_size_8K) + 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; @@ -159,6 +136,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) 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) { @@ -232,8 +210,8 @@ int iwlcore_init_geos(struct iwl_priv *priv) geo_ch->flags |= ch->ht40_extension_channel; - if (ch->max_power_avg > priv->tx_power_device_lmt) - priv->tx_power_device_lmt = ch->max_power_avg; + if (ch->max_power_avg > max_tx_power) + max_tx_power = ch->max_power_avg; } else { geo_ch->flags |= IEEE80211_CHAN_DISABLED; } @@ -246,6 +224,10 @@ int iwlcore_init_geos(struct iwl_priv *priv) 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->cfg->sku & IWL_SKU_A) { IWL_INFO(priv, "Incorrectly detected BG card as ABG. " @@ -434,72 +416,72 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { struct iwl_rxon_cmd *rxon = &ctx->staging; - bool error = false; + 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"); - error = true; + errors |= BIT(0); } if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) { IWL_WARN(priv, "check 2.4G: wrong radar\n"); - error = true; + errors |= BIT(1); } } else { if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) { IWL_WARN(priv, "check 5.2G: not short slot!\n"); - error = true; + errors |= BIT(2); } if (rxon->flags & RXON_FLG_CCK_MSK) { IWL_WARN(priv, "check 5.2G: CCK!\n"); - error = true; + errors |= BIT(3); } } if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) { IWL_WARN(priv, "mac/bssid mcast!\n"); - error = true; + 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"); - error = true; + errors |= BIT(5); } if (le16_to_cpu(rxon->assoc_id) > 2007) { IWL_WARN(priv, "aid > 2007\n"); - error = true; + 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"); - error = true; + 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"); - error = true; + 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"); - error = true; + errors |= BIT(9); } - if (error) - IWL_WARN(priv, "Tuning to channel %d\n", - le16_to_cpu(rxon->channel)); - - if (error) { - IWL_ERR(priv, "Invalid RXON\n"); - return -EINVAL; + if (rxon->channel == 0) { + IWL_WARN(priv, "zero channel is invalid\n"); + errors |= BIT(10); } - return 0; + + WARN(errors, "Invalid RXON (%#x), channel %d", + errors, le16_to_cpu(rxon->channel)); + + return errors ? -EINVAL : 0; } /** @@ -890,10 +872,21 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv, IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif -/** - * iwl_irq_handle_error - called for HW or SW error interrupt from card - */ -void iwl_irq_handle_error(struct iwl_priv *priv) + +static void iwlagn_abort_notification_waits(struct iwl_priv *priv) +{ + unsigned long flags; + struct iwl_notification_wait *wait_entry; + + spin_lock_irqsave(&priv->_agn.notif_wait_lock, flags); + list_for_each_entry(wait_entry, &priv->_agn.notif_waits, list) + wait_entry->aborted = true; + spin_unlock_irqrestore(&priv->_agn.notif_wait_lock, flags); + + wake_up_all(&priv->_agn.notif_waitq); +} + +void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) { unsigned int reload_msec; unsigned long reload_jiffies; @@ -904,18 +897,64 @@ void iwl_irq_handle_error(struct iwl_priv *priv) /* Cancel currently queued command. */ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + iwlagn_abort_notification_waits(priv); + + /* Keep the restart process from trying to send host + * commands by clearing the ready bit */ + clear_bit(STATUS_READY, &priv->status); + + wake_up_interruptible(&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(priv, IWL_DL_FW_ERRORS, + "Restarting adapter due to uCode error.\n"); + queue_work(priv->workqueue, &priv->restart); + } else + IWL_DEBUG(priv, IWL_DL_FW_ERRORS, + "Detected FW error, but not restarting\n"); + } +} + +/** + * iwl_irq_handle_error - called for HW or SW error interrupt from card + */ +void iwl_irq_handle_error(struct iwl_priv *priv) +{ /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ if (priv->cfg->internal_wimax_coex && (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) & APMS_CLK_VAL_MRB_FUNC_MODE) || (iwl_read_prph(priv, APMG_PS_CTRL_REG) & APMG_PS_CTRL_VAL_RESET_REQ))) { - wake_up_interruptible(&priv->wait_command_queue); /* - *Keep the restart process from trying to send host - * commands by clearing the INIT status bit + * Keep the restart process from trying to send host + * commands by clearing the ready bit. */ clear_bit(STATUS_READY, &priv->status); + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); IWL_ERR(priv, "RF is used by WiMAX\n"); return; } @@ -923,50 +962,17 @@ void iwl_irq_handle_error(struct iwl_priv *priv) IWL_ERR(priv, "Loaded firmware version: %s\n", priv->hw->wiphy->fw_version); - priv->cfg->ops->lib->dump_nic_error_log(priv); - if (priv->cfg->ops->lib->dump_csr) - priv->cfg->ops->lib->dump_csr(priv); - if (priv->cfg->ops->lib->dump_fh) - priv->cfg->ops->lib->dump_fh(priv, NULL, false); - priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false); + iwl_dump_nic_error_log(priv); + iwl_dump_csr(priv); + iwl_dump_fh(priv, NULL, false); + iwl_dump_nic_event_log(priv, false, NULL, false); #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) iwl_print_rx_config_cmd(priv, &priv->contexts[IWL_RXON_CTX_BSS]); #endif - wake_up_interruptible(&priv->wait_command_queue); - - /* Keep the restart process from trying to send host - * commands by clearing the INIT status bit */ - clear_bit(STATUS_READY, &priv->status); - - /* - * 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)) { - IWL_DEBUG(priv, IWL_DL_FW_ERRORS, - "Restarting adapter due to uCode error.\n"); - - if (priv->cfg->mod_params->restart_fw) - queue_work(priv->workqueue, &priv->restart); - } + iwlagn_fw_error(priv, false); } static int iwl_apm_stop_master(struct iwl_priv *priv) @@ -990,6 +996,8 @@ void iwl_apm_stop(struct iwl_priv *priv) { IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n"); + clear_bit(STATUS_DEVICE_ENABLED, &priv->status); + /* Stop device's DMA activity */ iwl_apm_stop_master(priv); @@ -1040,7 +1048,6 @@ int iwl_apm_init(struct iwl_priv *priv) /* * Enable HAP INTA (interrupt from management bus) to * wake device's PCI Express link L1a -> L0s - * NOTE: This is no-op for 3945 (non-existent bit) */ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); @@ -1053,20 +1060,18 @@ int iwl_apm_init(struct iwl_priv *priv) * If not (unlikely), enable L0S, so there is at least some * power savings, even without L1. */ - if (priv->cfg->base_params->set_l0s) { - lctl = iwl_pcie_link_ctl(priv); - if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == - PCI_CFG_LINK_CTRL_VAL_L1_EN) { - /* L1-ASPM enabled; disable(!) L0S */ - iwl_set_bit(priv, CSR_GIO_REG, - CSR_GIO_REG_VAL_L0S_ENABLED); - IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n"); - } else { - /* L1-ASPM disabled; enable(!) L0S */ - iwl_clear_bit(priv, CSR_GIO_REG, - CSR_GIO_REG_VAL_L0S_ENABLED); - IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n"); - } + lctl = iwl_pcie_link_ctl(priv); + if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == + PCI_CFG_LINK_CTRL_VAL_L1_EN) { + /* L1-ASPM enabled; disable(!) L0S */ + iwl_set_bit(priv, CSR_GIO_REG, + CSR_GIO_REG_VAL_L0S_ENABLED); + IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n"); + } else { + /* L1-ASPM disabled; enable(!) L0S */ + iwl_clear_bit(priv, CSR_GIO_REG, + CSR_GIO_REG_VAL_L0S_ENABLED); + IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n"); } /* Configure analog phase-lock-loop before activating to D0A */ @@ -1094,27 +1099,21 @@ int iwl_apm_init(struct iwl_priv *priv) } /* - * Enable DMA and BSM (if used) clocks, wait for them to stabilize. - * BSM (Boostrap State Machine) is only in 3945 and 4965; - * later devices (i.e. 5000 and later) have non-volatile SRAM, - * and don't need BSM to restore data after power-saving sleep. + * Enable DMA clock and wait for it to stabilize. * * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits * do not disable clocks. This preserves any hardware bits already * set by default in "CLK_CTRL_REG" after reset. */ - if (priv->cfg->base_params->use_bsm) - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); - else - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT); + iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); udelay(20); /* Disable L1-Active */ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + set_bit(STATUS_DEVICE_ENABLED, &priv->status); + out: return ret; } @@ -1430,7 +1429,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, iwl_teardown_interface(priv, vif, false); - memset(priv->bssid, 0, ETH_ALEN); mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); @@ -1750,21 +1748,13 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) * detect failure), then fw_restart module parameter * need to be check before performing firmware reload */ - if (!external && !priv->cfg->mod_params->restart_fw) { + 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"); - /* Set the FW error flag -- cleared on iwl_down */ - set_bit(STATUS_FW_ERROR, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); - /* - * Keep the restart process from trying to send host - * commands by clearing the INIT status bit - */ - clear_bit(STATUS_READY, &priv->status); - queue_work(priv->workqueue, &priv->restart); + iwlagn_fw_error(priv, true); break; } return 0; @@ -1775,6 +1765,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct iwl_priv *priv = hw->priv; struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_rxon_context *tmp; u32 interface_modes; int err; @@ -1783,6 +1774,15 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&priv->mutex); + if (!ctx->vif || !iwl_is_ready_rf(priv)) { + /* + * Huh? But wait ... this can maybe happen when + * we're in the middle of a firmware restart! + */ + err = -EBUSY; + goto out; + } + interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; if (!(interface_modes & BIT(newtype))) { @@ -1790,6 +1790,19 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto out; } + /* + * Refuse a change that should be done by moving from the PAN + * context to the BSS context instead, if the BSS context is + * available and can support the new interface type. + */ + if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif && + (bss_ctx->interface_modes & BIT(newtype) || + bss_ctx->exclusive_interface_modes & BIT(newtype))) { + BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); + err = -EBUSY; + goto out; + } + if (ctx->exclusive_interface_modes & BIT(newtype)) { for_each_context(priv, tmp) { if (ctx == tmp) @@ -1810,6 +1823,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* success */ iwl_teardown_interface(priv, vif, true); vif->type = newtype; + vif->p2p = newp2p; err = iwl_setup_interface(priv, ctx); WARN_ON(err); /* diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b316d833d9a2..5b5b0cce4a54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,7 +73,7 @@ struct iwl_cmd; #define IWLWIFI_VERSION "in-tree:" -#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation" #define DRV_AUTHOR "" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ @@ -90,7 +90,6 @@ struct iwl_cmd; #define IWL_CMD(x) case x: return #x struct iwl_hcmd_ops { - int (*rxon_assoc)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); void (*set_rxon_chain)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); @@ -100,7 +99,6 @@ struct iwl_hcmd_ops { }; struct iwl_hcmd_utils_ops { - u16 (*get_hcmd_size)(u8 cmd_id, u16 len); u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); void (*gain_computation)(struct iwl_priv *priv, u32 *average_noise, @@ -122,46 +120,14 @@ struct iwl_apm_ops { void (*config)(struct iwl_priv *priv); }; -struct iwl_isr_ops { - irqreturn_t (*isr) (int irq, void *data); - void (*free)(struct iwl_priv *priv); - int (*alloc)(struct iwl_priv *priv); - int (*reset)(struct iwl_priv *priv); - void (*disable)(struct iwl_priv *priv); -}; - -struct iwl_debugfs_ops { - ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*tx_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*general_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*bt_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*reply_tx_error)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -}; - struct iwl_temp_ops { void (*temperature)(struct iwl_priv *priv); }; -struct iwl_tt_ops { - bool (*lower_power_detection)(struct iwl_priv *priv); - u8 (*tt_power_mode)(struct iwl_priv *priv); - bool (*ct_kill_check)(struct iwl_priv *priv); -}; - struct iwl_lib_ops { /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); /* Handling TX */ - void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - u16 byte_cnt); - void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv, - struct iwl_tx_queue *txq); void (*txq_set_sched)(struct iwl_priv *priv, u32 mask); int (*txq_attach_buf_to_tfd)(struct iwl_priv *priv, struct iwl_tx_queue *txq, @@ -171,30 +137,14 @@ struct iwl_lib_ops { struct iwl_tx_queue *txq); int (*txq_init)(struct iwl_priv *priv, struct iwl_tx_queue *txq); - /* aggregations */ - int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo, - int sta_id, int tid, u16 ssn_idx); - int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, - u8 tx_fifo); /* setup Rx handler */ void (*rx_handler_setup)(struct iwl_priv *priv); /* setup deferred work */ void (*setup_deferred_work)(struct iwl_priv *priv); /* cancel deferred work */ void (*cancel_deferred_work)(struct iwl_priv *priv); - /* alive notification after init uCode load */ - void (*init_alive_start)(struct iwl_priv *priv); - /* alive notification */ - int (*alive_notify)(struct iwl_priv *priv); /* check validity of rtc data address */ int (*is_valid_rtc_data_addr)(u32 addr); - /* 1st ucode load */ - int (*load_ucode)(struct iwl_priv *priv); - int (*dump_nic_event_log)(struct iwl_priv *priv, - bool full_log, char **buf, bool display); - void (*dump_nic_error_log)(struct iwl_priv *priv); - void (*dump_csr)(struct iwl_priv *priv); - int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display); int (*set_channel_switch)(struct iwl_priv *priv, struct ieee80211_channel_switch *ch_switch); /* power management */ @@ -204,9 +154,6 @@ struct iwl_lib_ops { int (*send_tx_power) (struct iwl_priv *priv); void (*update_chain_flags)(struct iwl_priv *priv); - /* isr */ - struct iwl_isr_ops isr_ops; - /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; @@ -216,14 +163,6 @@ struct iwl_lib_ops { int (*txfifo_flush)(struct iwl_priv *priv, u16 flush_control); void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control); - struct iwl_debugfs_ops debugfs_ops; - - /* thermal throttling */ - struct iwl_tt_ops tt_ops; -}; - -struct iwl_led_ops { - int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd); }; /* NIC specific ops */ @@ -231,28 +170,15 @@ struct iwl_nic_ops { void (*additional_nic_config)(struct iwl_priv *priv); }; -struct iwl_legacy_ops { - void (*post_associate)(struct iwl_priv *priv); - void (*config_ap)(struct iwl_priv *priv); - /* station management */ - int (*update_bcast_stations)(struct iwl_priv *priv); - int (*manage_ibss_station)(struct iwl_priv *priv, - struct ieee80211_vif *vif, bool add); -}; - struct iwl_ops { const struct iwl_lib_ops *lib; const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; - const struct iwl_led_ops *led; const struct iwl_nic_ops *nic; - const struct iwl_legacy_ops *legacy; - const struct ieee80211_ops *ieee80211_ops; }; struct iwl_mod_params { int sw_crypto; /* def: 0 = using hardware encryption */ - int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int disable_11n; /* def: 0 = 11n capabilities enabled */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ @@ -278,16 +204,7 @@ struct iwl_mod_params { * @wd_timeout: TX queues watchdog timeout * @temperature_kelvin: temperature report by uCode in kelvin * @max_event_log_size: size of event log buffer size for ucode event logging - * @tx_power_by_driver: tx power calibration performed by driver - * instead of uCode - * @ucode_tracing: support ucode continuous tracing - * @sensitivity_calib_by_driver: driver has the capability to perform - * sensitivity calibration operation - * @chain_noise_calib_by_driver: driver has the capability to perform - * chain noise calibration operation * @shadow_reg_enable: HW shadhow register bit - * @no_agg_framecnt_info: uCode do not provide aggregation frame count - * information */ struct iwl_base_params { int eeprom_size; @@ -295,14 +212,10 @@ struct iwl_base_params { int num_of_ampdu_queues;/* def: HW dependent */ /* for iwl_apm_init() */ u32 pll_cfg_val; - bool set_l0s; - bool use_bsm; - bool use_isr_legacy; const u16 max_ll_items; const bool shadow_ram_support; u16 led_compensation; - const bool broken_powersave; int chain_noise_num_beacons; bool adv_thermal_throttle; bool support_ct_kill_exit; @@ -312,18 +225,12 @@ struct iwl_base_params { unsigned int wd_timeout; bool temperature_kelvin; u32 max_event_log_size; - const bool tx_power_by_driver; - const bool ucode_tracing; - const bool sensitivity_calib_by_driver; - const bool chain_noise_calib_by_driver; const bool shadow_reg_enable; - const bool no_agg_framecnt_info; }; /* * @advanced_bt_coexist: support advanced bt coexist * @bt_init_traffic_load: specify initial bt traffic load * @bt_prio_boost: default bt priority boost value - * @bt_statistics: use BT version of statistics notification * @agg_time_limit: maximum number of uSec in aggregation * @ampdu_factor: Maximum A-MPDU length factor * @ampdu_density: Minimum A-MPDU spacing @@ -333,7 +240,6 @@ struct iwl_bt_params { bool advanced_bt_coexist; u8 bt_init_traffic_load; u8 bt_prio_boost; - const bool bt_statistics; u16 agg_time_limit; u8 ampdu_factor; u8 ampdu_density; @@ -364,6 +270,7 @@ struct iwl_ht_params { * @rx_with_siso_diversity: 1x1 device with rx antenna diversity * @internal_wimax_coex: internal wifi/wimax combo device * @iq_invert: I/Q inversion + * @disable_otp_refresh: disable OTP refresh current limit * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -398,8 +305,6 @@ struct iwl_cfg { u16 eeprom_ver; u16 eeprom_calib_ver; const struct iwl_ops *ops; - /* module based parameters which can be set from modprobe cmd */ - const struct iwl_mod_params *mod_params; /* params not likely to change within a device family */ struct iwl_base_params *base_params; /* params likely to change within a device family */ @@ -414,13 +319,13 @@ struct iwl_cfg { const bool rx_with_siso_diversity; const bool internal_wimax_coex; const bool iq_invert; + const bool disable_otp_refresh; }; /*************************** * L i b * ***************************/ -struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg); int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); @@ -625,6 +530,8 @@ extern const struct dev_pm_ops iwl_pm_ops; void iwl_dump_nic_error_log(struct iwl_priv *priv); int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, char **buf, bool display); +void iwl_dump_csr(struct iwl_priv *priv); +int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_print_rx_config_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); @@ -662,6 +569,7 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_SCAN_HW 15 #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 +#define STATUS_DEVICE_ENABLED 18 static inline int iwl_is_ready(struct iwl_priv *priv) @@ -714,11 +622,6 @@ void iwl_apm_stop(struct iwl_priv *priv); int iwl_apm_init(struct iwl_priv *priv); int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -static inline int iwl_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - return priv->cfg->ops->hcmd->rxon_assoc(priv, ctx); -} static inline int iwlcore_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { @@ -736,12 +639,10 @@ static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) priv->cfg->bt_params->advanced_bt_coexist; } -static inline bool iwl_bt_statistics(struct iwl_priv *priv) -{ - return priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics; -} - extern bool bt_coex_active; extern bool bt_siso_mode; + +void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); + #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index f52bc040bcbf..5ab90ba7a024 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -155,18 +155,10 @@ #define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250) /* Bits for CSR_HW_IF_CONFIG_REG */ -#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) -#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100) -#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200) -#define CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) -#define CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) -#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) -#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) - #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ @@ -186,7 +178,7 @@ #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ #define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ #define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ -#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ +#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses */ #define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ #define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ @@ -202,29 +194,17 @@ /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ #define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ #define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ -#define CSR39_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */ #define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ #define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ -#define CSR39_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */ #define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ #define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ -#define CSR39_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ - CSR39_FH_INT_BIT_RX_CHNL2 | \ - CSR_FH_INT_BIT_RX_CHNL1 | \ - CSR_FH_INT_BIT_RX_CHNL0) +#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ + CSR_FH_INT_BIT_RX_CHNL1 | \ + CSR_FH_INT_BIT_RX_CHNL0) - -#define CSR39_FH_INT_TX_MASK (CSR39_FH_INT_BIT_TX_CHNL6 | \ - CSR_FH_INT_BIT_TX_CHNL1 | \ - CSR_FH_INT_BIT_TX_CHNL0) - -#define CSR49_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ - CSR_FH_INT_BIT_RX_CHNL1 | \ - CSR_FH_INT_BIT_RX_CHNL0) - -#define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ - CSR_FH_INT_BIT_TX_CHNL0) +#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ + CSR_FH_INT_BIT_TX_CHNL0) /* GPIO */ #define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) @@ -268,7 +248,7 @@ * Indicates MAC (ucode processor, etc.) is powered up and can run. * Internal resources are accessible. * NOTE: This does not indicate that the processor is actually running. - * NOTE: This does not indicate that 4965 or 3945 has completed + * NOTE: This does not indicate that device has completed * init or post-power-down restore of internal SRAM memory. * Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that * SRAM is restored and uCode is in normal operation mode. @@ -291,8 +271,6 @@ /* HW REV */ #define CSR_HW_REV_TYPE_MSK (0x00001F0) -#define CSR_HW_REV_TYPE_3945 (0x00000D0) -#define CSR_HW_REV_TYPE_4965 (0x0000000) #define CSR_HW_REV_TYPE_5300 (0x0000020) #define CSR_HW_REV_TYPE_5350 (0x0000030) #define CSR_HW_REV_TYPE_5100 (0x0000050) @@ -363,7 +341,7 @@ * 0: MAC_SLEEP * uCode sets this when preparing a power-saving power-down. * uCode resets this when power-up is complete and SRAM is sane. - * NOTE: 3945/4965 saves internal SRAM data to host when powering down, + * NOTE: device saves internal SRAM data to host when powering down, * and must restore this data after powering back up. * MAC_SLEEP is the best indication that restore is complete. * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and @@ -394,7 +372,6 @@ #define CSR_LED_REG_TRUN_OFF (0x38) /* ANA_PLL */ -#define CSR39_ANA_PLL_CFG_VAL (0x01000000) #define CSR50_ANA_PLL_CFG_VAL (0x00880300) /* HPET MEM debug */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index ebdea3be3ef9..2824ccbcc1fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -146,7 +146,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DL_RX (1 << 24) #define IWL_DL_ISR (1 << 25) #define IWL_DL_HT (1 << 26) -#define IWL_DL_IO (1 << 27) /* 0xF0000000 - 0x10000000 */ #define IWL_DL_11H (1 << 28) #define IWL_DL_STATS (1 << 29) @@ -174,7 +173,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a) #define IWL_DEBUG_AP(p, f, a...) IWL_DEBUG(p, IWL_DL_AP, f, ## a) #define IWL_DEBUG_TXPOWER(p, f, a...) IWL_DEBUG(p, IWL_DL_TXPOWER, f, ## a) -#define IWL_DEBUG_IO(p, f, a...) IWL_DEBUG(p, IWL_DL_IO, f, ## a) #define IWL_DEBUG_RATE(p, f, a...) IWL_DEBUG(p, IWL_DL_RATE, f, ## a) #define IWL_DEBUG_RATE_LIMIT(p, f, a...) \ IWL_DEBUG_LIMIT(p, IWL_DL_RATE, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 8842411f1cf3..0e6a04b739ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -39,6 +39,7 @@ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" +#include "iwl-agn.h" /* create and remove of files */ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ @@ -226,10 +227,10 @@ 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_type == UCODE_INIT) - priv->dbgfs_sram_len = priv->ucode_init_data.len; + if (priv->ucode_type == UCODE_SUBTYPE_INIT) + priv->dbgfs_sram_len = priv->ucode_init.data.len; else - priv->dbgfs_sram_len = priv->ucode_data.len; + priv->dbgfs_sram_len = priv->ucode_rt.data.len; } len = priv->dbgfs_sram_len; @@ -437,8 +438,7 @@ static ssize_t iwl_dbgfs_log_event_read(struct file *file, int pos = 0; ssize_t ret = -ENOMEM; - ret = pos = priv->cfg->ops->lib->dump_nic_event_log( - priv, true, &buf, true); + 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); @@ -462,8 +462,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, if (sscanf(buf, "%d", &event_log_flag) != 1) return -EFAULT; if (event_log_flag == 1) - priv->cfg->ops->lib->dump_nic_event_log(priv, true, - NULL, false); + iwl_dump_nic_event_log(priv, true, NULL, false); return count; } @@ -1039,13 +1038,463 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +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"; +static const char *fmt_header = + "%-32s current cumulative delta max\n"; + +static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) +{ + int p = 0; + u32 flag; + + flag = le32_to_cpu(priv->statistics.flag); + + p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag); + if (flag & UCODE_STATISTICS_CLEAR_MSK) + p += scnprintf(buf + p, bufsz - p, + "\tStatistics have been cleared\n"); + p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", + (flag & UCODE_STATISTICS_FREQUENCY_MSK) + ? "2.4 GHz" : "5.2 GHz"); + p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", + (flag & UCODE_STATISTICS_NARROW_BAND_MSK) + ? "enabled" : "disabled"); + + return p; +} + static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file, - user_buf, count, ppos); + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_rx_phy) * 40 + + sizeof(struct statistics_rx_non_phy) * 40 + + sizeof(struct statistics_rx_ht_phy) * 40 + 400; + ssize_t ret; + struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; + struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; + struct statistics_rx_non_phy *general, *accum_general; + struct statistics_rx_non_phy *delta_general, *max_general; + struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* + * the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + ofdm = &priv->statistics.rx_ofdm; + cck = &priv->statistics.rx_cck; + general = &priv->statistics.rx_non_phy; + ht = &priv->statistics.rx_ofdm_ht; + accum_ofdm = &priv->accum_stats.rx_ofdm; + accum_cck = &priv->accum_stats.rx_cck; + accum_general = &priv->accum_stats.rx_non_phy; + accum_ht = &priv->accum_stats.rx_ofdm_ht; + delta_ofdm = &priv->delta_stats.rx_ofdm; + delta_cck = &priv->delta_stats.rx_cck; + delta_general = &priv->delta_stats.rx_non_phy; + delta_ht = &priv->delta_stats.rx_ofdm_ht; + max_ofdm = &priv->max_delta_stats.rx_ofdm; + max_cck = &priv->max_delta_stats.rx_cck; + max_general = &priv->max_delta_stats.rx_non_phy; + max_ht = &priv->max_delta_stats.rx_ofdm_ht; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - OFDM:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ina_cnt:", + le32_to_cpu(ofdm->ina_cnt), + accum_ofdm->ina_cnt, + delta_ofdm->ina_cnt, max_ofdm->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_cnt:", + le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, + delta_ofdm->fina_cnt, max_ofdm->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "plcp_err:", + le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, + delta_ofdm->plcp_err, max_ofdm->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_err:", + le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, + delta_ofdm->crc32_err, max_ofdm->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "overrun_err:", + le32_to_cpu(ofdm->overrun_err), + accum_ofdm->overrun_err, delta_ofdm->overrun_err, + max_ofdm->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "early_overrun_err:", + le32_to_cpu(ofdm->early_overrun_err), + accum_ofdm->early_overrun_err, + delta_ofdm->early_overrun_err, + max_ofdm->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_good:", + le32_to_cpu(ofdm->crc32_good), + accum_ofdm->crc32_good, delta_ofdm->crc32_good, + max_ofdm->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "false_alarm_cnt:", + le32_to_cpu(ofdm->false_alarm_cnt), + accum_ofdm->false_alarm_cnt, + delta_ofdm->false_alarm_cnt, + max_ofdm->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_sync_err_cnt:", + le32_to_cpu(ofdm->fina_sync_err_cnt), + accum_ofdm->fina_sync_err_cnt, + delta_ofdm->fina_sync_err_cnt, + max_ofdm->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sfd_timeout:", + le32_to_cpu(ofdm->sfd_timeout), + accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout, + max_ofdm->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_timeout:", + le32_to_cpu(ofdm->fina_timeout), + accum_ofdm->fina_timeout, delta_ofdm->fina_timeout, + max_ofdm->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "unresponded_rts:", + le32_to_cpu(ofdm->unresponded_rts), + accum_ofdm->unresponded_rts, + delta_ofdm->unresponded_rts, + max_ofdm->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rxe_frame_lmt_ovrun:", + le32_to_cpu(ofdm->rxe_frame_limit_overrun), + accum_ofdm->rxe_frame_limit_overrun, + delta_ofdm->rxe_frame_limit_overrun, + max_ofdm->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ack_cnt:", + le32_to_cpu(ofdm->sent_ack_cnt), + accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt, + max_ofdm->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_cts_cnt:", + le32_to_cpu(ofdm->sent_cts_cnt), + accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt, + max_ofdm->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ba_rsp_cnt:", + le32_to_cpu(ofdm->sent_ba_rsp_cnt), + accum_ofdm->sent_ba_rsp_cnt, + delta_ofdm->sent_ba_rsp_cnt, + max_ofdm->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dsp_self_kill:", + le32_to_cpu(ofdm->dsp_self_kill), + accum_ofdm->dsp_self_kill, + delta_ofdm->dsp_self_kill, + max_ofdm->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "mh_format_err:", + le32_to_cpu(ofdm->mh_format_err), + accum_ofdm->mh_format_err, + delta_ofdm->mh_format_err, + max_ofdm->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "re_acq_main_rssi_sum:", + le32_to_cpu(ofdm->re_acq_main_rssi_sum), + accum_ofdm->re_acq_main_rssi_sum, + delta_ofdm->re_acq_main_rssi_sum, + max_ofdm->re_acq_main_rssi_sum); + + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - CCK:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ina_cnt:", + le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, + delta_cck->ina_cnt, max_cck->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_cnt:", + le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, + delta_cck->fina_cnt, max_cck->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "plcp_err:", + le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, + delta_cck->plcp_err, max_cck->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_err:", + le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, + delta_cck->crc32_err, max_cck->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "overrun_err:", + le32_to_cpu(cck->overrun_err), + accum_cck->overrun_err, delta_cck->overrun_err, + max_cck->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "early_overrun_err:", + le32_to_cpu(cck->early_overrun_err), + accum_cck->early_overrun_err, + delta_cck->early_overrun_err, + max_cck->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_good:", + le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, + delta_cck->crc32_good, max_cck->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "false_alarm_cnt:", + le32_to_cpu(cck->false_alarm_cnt), + accum_cck->false_alarm_cnt, + delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_sync_err_cnt:", + le32_to_cpu(cck->fina_sync_err_cnt), + accum_cck->fina_sync_err_cnt, + delta_cck->fina_sync_err_cnt, + max_cck->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sfd_timeout:", + le32_to_cpu(cck->sfd_timeout), + accum_cck->sfd_timeout, delta_cck->sfd_timeout, + max_cck->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_timeout:", + le32_to_cpu(cck->fina_timeout), + accum_cck->fina_timeout, delta_cck->fina_timeout, + max_cck->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "unresponded_rts:", + le32_to_cpu(cck->unresponded_rts), + accum_cck->unresponded_rts, delta_cck->unresponded_rts, + max_cck->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rxe_frame_lmt_ovrun:", + le32_to_cpu(cck->rxe_frame_limit_overrun), + accum_cck->rxe_frame_limit_overrun, + delta_cck->rxe_frame_limit_overrun, + max_cck->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ack_cnt:", + le32_to_cpu(cck->sent_ack_cnt), + accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt, + max_cck->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_cts_cnt:", + le32_to_cpu(cck->sent_cts_cnt), + accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt, + max_cck->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ba_rsp_cnt:", + le32_to_cpu(cck->sent_ba_rsp_cnt), + accum_cck->sent_ba_rsp_cnt, + delta_cck->sent_ba_rsp_cnt, + max_cck->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dsp_self_kill:", + le32_to_cpu(cck->dsp_self_kill), + accum_cck->dsp_self_kill, delta_cck->dsp_self_kill, + max_cck->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "mh_format_err:", + le32_to_cpu(cck->mh_format_err), + accum_cck->mh_format_err, delta_cck->mh_format_err, + max_cck->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "re_acq_main_rssi_sum:", + le32_to_cpu(cck->re_acq_main_rssi_sum), + accum_cck->re_acq_main_rssi_sum, + delta_cck->re_acq_main_rssi_sum, + max_cck->re_acq_main_rssi_sum); + + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - GENERAL:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bogus_cts:", + le32_to_cpu(general->bogus_cts), + accum_general->bogus_cts, delta_general->bogus_cts, + max_general->bogus_cts); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bogus_ack:", + le32_to_cpu(general->bogus_ack), + accum_general->bogus_ack, delta_general->bogus_ack, + max_general->bogus_ack); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "non_bssid_frames:", + le32_to_cpu(general->non_bssid_frames), + accum_general->non_bssid_frames, + delta_general->non_bssid_frames, + max_general->non_bssid_frames); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "filtered_frames:", + le32_to_cpu(general->filtered_frames), + accum_general->filtered_frames, + delta_general->filtered_frames, + max_general->filtered_frames); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "non_channel_beacons:", + le32_to_cpu(general->non_channel_beacons), + accum_general->non_channel_beacons, + delta_general->non_channel_beacons, + max_general->non_channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "channel_beacons:", + le32_to_cpu(general->channel_beacons), + accum_general->channel_beacons, + delta_general->channel_beacons, + max_general->channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "num_missed_bcon:", + le32_to_cpu(general->num_missed_bcon), + accum_general->num_missed_bcon, + delta_general->num_missed_bcon, + max_general->num_missed_bcon); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "adc_rx_saturation_time:", + le32_to_cpu(general->adc_rx_saturation_time), + accum_general->adc_rx_saturation_time, + delta_general->adc_rx_saturation_time, + max_general->adc_rx_saturation_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ina_detect_search_tm:", + le32_to_cpu(general->ina_detection_search_time), + accum_general->ina_detection_search_time, + delta_general->ina_detection_search_time, + max_general->ina_detection_search_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_silence_rssi_a:", + le32_to_cpu(general->beacon_silence_rssi_a), + accum_general->beacon_silence_rssi_a, + delta_general->beacon_silence_rssi_a, + max_general->beacon_silence_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_silence_rssi_b:", + le32_to_cpu(general->beacon_silence_rssi_b), + accum_general->beacon_silence_rssi_b, + delta_general->beacon_silence_rssi_b, + max_general->beacon_silence_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_silence_rssi_c:", + le32_to_cpu(general->beacon_silence_rssi_c), + accum_general->beacon_silence_rssi_c, + delta_general->beacon_silence_rssi_c, + max_general->beacon_silence_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "interference_data_flag:", + le32_to_cpu(general->interference_data_flag), + accum_general->interference_data_flag, + delta_general->interference_data_flag, + max_general->interference_data_flag); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "channel_load:", + le32_to_cpu(general->channel_load), + accum_general->channel_load, + delta_general->channel_load, + max_general->channel_load); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dsp_false_alarms:", + le32_to_cpu(general->dsp_false_alarms), + accum_general->dsp_false_alarms, + delta_general->dsp_false_alarms, + max_general->dsp_false_alarms); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_rssi_a:", + le32_to_cpu(general->beacon_rssi_a), + accum_general->beacon_rssi_a, + delta_general->beacon_rssi_a, + max_general->beacon_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_rssi_b:", + le32_to_cpu(general->beacon_rssi_b), + accum_general->beacon_rssi_b, + delta_general->beacon_rssi_b, + max_general->beacon_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_rssi_c:", + le32_to_cpu(general->beacon_rssi_c), + accum_general->beacon_rssi_c, + delta_general->beacon_rssi_c, + max_general->beacon_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_energy_a:", + le32_to_cpu(general->beacon_energy_a), + accum_general->beacon_energy_a, + delta_general->beacon_energy_a, + max_general->beacon_energy_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_energy_b:", + le32_to_cpu(general->beacon_energy_b), + accum_general->beacon_energy_b, + delta_general->beacon_energy_b, + max_general->beacon_energy_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_energy_c:", + le32_to_cpu(general->beacon_energy_c), + accum_general->beacon_energy_c, + delta_general->beacon_energy_c, + max_general->beacon_energy_c); + + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - OFDM_HT:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "plcp_err:", + le32_to_cpu(ht->plcp_err), accum_ht->plcp_err, + delta_ht->plcp_err, max_ht->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "overrun_err:", + le32_to_cpu(ht->overrun_err), accum_ht->overrun_err, + delta_ht->overrun_err, max_ht->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "early_overrun_err:", + le32_to_cpu(ht->early_overrun_err), + accum_ht->early_overrun_err, + delta_ht->early_overrun_err, + max_ht->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_good:", + le32_to_cpu(ht->crc32_good), accum_ht->crc32_good, + delta_ht->crc32_good, max_ht->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_err:", + le32_to_cpu(ht->crc32_err), accum_ht->crc32_err, + delta_ht->crc32_err, max_ht->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "mh_format_err:", + le32_to_cpu(ht->mh_format_err), + accum_ht->mh_format_err, + delta_ht->mh_format_err, max_ht->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg_crc32_good:", + le32_to_cpu(ht->agg_crc32_good), + accum_ht->agg_crc32_good, + delta_ht->agg_crc32_good, max_ht->agg_crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg_mpdu_cnt:", + le32_to_cpu(ht->agg_mpdu_cnt), + accum_ht->agg_mpdu_cnt, + delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg_cnt:", + le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt, + delta_ht->agg_cnt, max_ht->agg_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "unsupport_mcs:", + le32_to_cpu(ht->unsupport_mcs), + accum_ht->unsupport_mcs, + delta_ht->unsupport_mcs, max_ht->unsupport_mcs); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; } static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, @@ -1053,8 +1502,190 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file, - user_buf, count, ppos); + int pos = 0; + char *buf; + int bufsz = (sizeof(struct statistics_tx) * 48) + 250; + ssize_t ret; + struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + tx = &priv->statistics.tx; + accum_tx = &priv->accum_stats.tx; + delta_tx = &priv->delta_stats.tx; + max_tx = &priv->max_delta_stats.tx; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Tx:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "preamble:", + le32_to_cpu(tx->preamble_cnt), + accum_tx->preamble_cnt, + delta_tx->preamble_cnt, max_tx->preamble_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rx_detected_cnt:", + le32_to_cpu(tx->rx_detected_cnt), + accum_tx->rx_detected_cnt, + delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bt_prio_defer_cnt:", + le32_to_cpu(tx->bt_prio_defer_cnt), + accum_tx->bt_prio_defer_cnt, + delta_tx->bt_prio_defer_cnt, + max_tx->bt_prio_defer_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bt_prio_kill_cnt:", + le32_to_cpu(tx->bt_prio_kill_cnt), + accum_tx->bt_prio_kill_cnt, + delta_tx->bt_prio_kill_cnt, + max_tx->bt_prio_kill_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "few_bytes_cnt:", + le32_to_cpu(tx->few_bytes_cnt), + accum_tx->few_bytes_cnt, + delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "cts_timeout:", + le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, + delta_tx->cts_timeout, max_tx->cts_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ack_timeout:", + le32_to_cpu(tx->ack_timeout), + accum_tx->ack_timeout, + delta_tx->ack_timeout, max_tx->ack_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "expected_ack_cnt:", + le32_to_cpu(tx->expected_ack_cnt), + accum_tx->expected_ack_cnt, + delta_tx->expected_ack_cnt, + max_tx->expected_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "actual_ack_cnt:", + le32_to_cpu(tx->actual_ack_cnt), + accum_tx->actual_ack_cnt, + delta_tx->actual_ack_cnt, + max_tx->actual_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dump_msdu_cnt:", + le32_to_cpu(tx->dump_msdu_cnt), + accum_tx->dump_msdu_cnt, + delta_tx->dump_msdu_cnt, + max_tx->dump_msdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "abort_nxt_frame_mismatch:", + le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), + accum_tx->burst_abort_next_frame_mismatch_cnt, + delta_tx->burst_abort_next_frame_mismatch_cnt, + max_tx->burst_abort_next_frame_mismatch_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "abort_missing_nxt_frame:", + le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), + accum_tx->burst_abort_missing_next_frame_cnt, + delta_tx->burst_abort_missing_next_frame_cnt, + max_tx->burst_abort_missing_next_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "cts_timeout_collision:", + le32_to_cpu(tx->cts_timeout_collision), + accum_tx->cts_timeout_collision, + delta_tx->cts_timeout_collision, + max_tx->cts_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ack_ba_timeout_collision:", + le32_to_cpu(tx->ack_or_ba_timeout_collision), + accum_tx->ack_or_ba_timeout_collision, + delta_tx->ack_or_ba_timeout_collision, + max_tx->ack_or_ba_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg ba_timeout:", + le32_to_cpu(tx->agg.ba_timeout), + accum_tx->agg.ba_timeout, + delta_tx->agg.ba_timeout, + max_tx->agg.ba_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg ba_resched_frames:", + le32_to_cpu(tx->agg.ba_reschedule_frames), + accum_tx->agg.ba_reschedule_frames, + delta_tx->agg.ba_reschedule_frames, + max_tx->agg.ba_reschedule_frames); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_agg_frame:", + le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), + accum_tx->agg.scd_query_agg_frame_cnt, + delta_tx->agg.scd_query_agg_frame_cnt, + max_tx->agg.scd_query_agg_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_no_agg:", + le32_to_cpu(tx->agg.scd_query_no_agg), + accum_tx->agg.scd_query_no_agg, + delta_tx->agg.scd_query_no_agg, + max_tx->agg.scd_query_no_agg); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_agg:", + le32_to_cpu(tx->agg.scd_query_agg), + accum_tx->agg.scd_query_agg, + delta_tx->agg.scd_query_agg, + max_tx->agg.scd_query_agg); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_mismatch:", + le32_to_cpu(tx->agg.scd_query_mismatch), + accum_tx->agg.scd_query_mismatch, + delta_tx->agg.scd_query_mismatch, + max_tx->agg.scd_query_mismatch); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg frame_not_ready:", + le32_to_cpu(tx->agg.frame_not_ready), + accum_tx->agg.frame_not_ready, + delta_tx->agg.frame_not_ready, + max_tx->agg.frame_not_ready); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg underrun:", + le32_to_cpu(tx->agg.underrun), + accum_tx->agg.underrun, + delta_tx->agg.underrun, max_tx->agg.underrun); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg bt_prio_kill:", + le32_to_cpu(tx->agg.bt_prio_kill), + accum_tx->agg.bt_prio_kill, + delta_tx->agg.bt_prio_kill, + max_tx->agg.bt_prio_kill); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg rx_ba_rsp_cnt:", + le32_to_cpu(tx->agg.rx_ba_rsp_cnt), + accum_tx->agg.rx_ba_rsp_cnt, + delta_tx->agg.rx_ba_rsp_cnt, + max_tx->agg.rx_ba_rsp_cnt); + + if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) { + pos += scnprintf(buf + pos, bufsz - pos, + "tx power: (1/2 dB step)\n"); + if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a) + pos += scnprintf(buf + pos, bufsz - pos, + fmt_hex, "antenna A:", + tx->tx_power.ant_a); + if ((priv->cfg->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 ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c) + pos += scnprintf(buf + pos, bufsz - pos, + fmt_hex, "antenna C:", + tx->tx_power.ant_c); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; } static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, @@ -1062,8 +1693,347 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file, - user_buf, count, ppos); + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_general) * 10 + 300; + ssize_t ret; + struct statistics_general_common *general, *accum_general; + struct statistics_general_common *delta_general, *max_general; + struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; + struct statistics_div *div, *accum_div, *delta_div, *max_div; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + general = &priv->statistics.common; + dbg = &priv->statistics.common.dbg; + div = &priv->statistics.common.div; + accum_general = &priv->accum_stats.common; + accum_dbg = &priv->accum_stats.common.dbg; + accum_div = &priv->accum_stats.common.div; + delta_general = &priv->delta_stats.common; + max_general = &priv->max_delta_stats.common; + delta_dbg = &priv->delta_stats.common.dbg; + max_dbg = &priv->max_delta_stats.common.dbg; + delta_div = &priv->delta_stats.common.div; + max_div = &priv->max_delta_stats.common.div; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_General:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_value, "temperature:", + le32_to_cpu(general->temperature)); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_value, "temperature_m:", + le32_to_cpu(general->temperature_m)); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_value, "ttl_timestamp:", + le32_to_cpu(general->ttl_timestamp)); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "burst_check:", + le32_to_cpu(dbg->burst_check), + accum_dbg->burst_check, + delta_dbg->burst_check, max_dbg->burst_check); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "burst_count:", + le32_to_cpu(dbg->burst_count), + accum_dbg->burst_count, + delta_dbg->burst_count, max_dbg->burst_count); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "wait_for_silence_timeout_count:", + le32_to_cpu(dbg->wait_for_silence_timeout_cnt), + accum_dbg->wait_for_silence_timeout_cnt, + delta_dbg->wait_for_silence_timeout_cnt, + max_dbg->wait_for_silence_timeout_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sleep_time:", + le32_to_cpu(general->sleep_time), + accum_general->sleep_time, + delta_general->sleep_time, max_general->sleep_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "slots_out:", + le32_to_cpu(general->slots_out), + accum_general->slots_out, + delta_general->slots_out, max_general->slots_out); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "slots_idle:", + le32_to_cpu(general->slots_idle), + accum_general->slots_idle, + delta_general->slots_idle, max_general->slots_idle); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "tx_on_a:", + le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, + delta_div->tx_on_a, max_div->tx_on_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "tx_on_b:", + le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, + delta_div->tx_on_b, max_div->tx_on_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "exec_time:", + le32_to_cpu(div->exec_time), accum_div->exec_time, + delta_div->exec_time, max_div->exec_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "probe_time:", + le32_to_cpu(div->probe_time), accum_div->probe_time, + delta_div->probe_time, max_div->probe_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rx_enable_counter:", + le32_to_cpu(general->rx_enable_counter), + accum_general->rx_enable_counter, + delta_general->rx_enable_counter, + max_general->rx_enable_counter); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "num_of_sos_states:", + le32_to_cpu(general->num_of_sos_states), + accum_general->num_of_sos_states, + delta_general->num_of_sos_states, + max_general->num_of_sos_states); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200; + ssize_t ret; + struct statistics_bt_activity *bt, *accum_bt; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + if (!priv->bt_enable_flag) + return -EINVAL; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + 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); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* + * the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + bt = &priv->statistics.bt_activity; + accum_bt = &priv->accum_stats.bt_activity; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_tx_req_cnt), + accum_bt->hi_priority_tx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_tx_denied_cnt), + accum_bt->hi_priority_tx_denied_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_tx_req_cnt), + accum_bt->lo_priority_tx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_tx_denied_cnt), + accum_bt->lo_priority_tx_denied_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_rx_req_cnt), + accum_bt->hi_priority_rx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_rx_denied_cnt), + accum_bt->hi_priority_rx_denied_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_rx_req_cnt), + accum_bt->lo_priority_rx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_rx_denied_cnt), + accum_bt->lo_priority_rx_denied_cnt); + + pos += scnprintf(buf + pos, bufsz - pos, + "(rx)num_bt_kills:\t\t%u\t\t\t%u\n", + le32_to_cpu(priv->statistics.num_bt_kills), + priv->statistics.accum_num_bt_kills); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) + + (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200; + ssize_t ret; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + 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", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY), + priv->_agn.reply_tx_stats.pp_delay); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES), + priv->_agn.reply_tx_stats.pp_few_bytes); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO), + priv->_agn.reply_tx_stats.pp_bt_prio); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD), + priv->_agn.reply_tx_stats.pp_quiet_period); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK), + priv->_agn.reply_tx_stats.pp_calc_ttak); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_tx_fail_reason( + TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY), + priv->_agn.reply_tx_stats.int_crossed_retry); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT), + priv->_agn.reply_tx_stats.short_limit); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT), + priv->_agn.reply_tx_stats.long_limit); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN), + priv->_agn.reply_tx_stats.fifo_underrun); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW), + priv->_agn.reply_tx_stats.drain_flow); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH), + priv->_agn.reply_tx_stats.rfkill_flush); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE), + priv->_agn.reply_tx_stats.life_expire); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS), + priv->_agn.reply_tx_stats.dest_ps); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED), + priv->_agn.reply_tx_stats.host_abort); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY), + priv->_agn.reply_tx_stats.pp_delay); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID), + priv->_agn.reply_tx_stats.sta_invalid); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED), + priv->_agn.reply_tx_stats.frag_drop); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE), + priv->_agn.reply_tx_stats.tid_disable); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED), + priv->_agn.reply_tx_stats.fifo_flush); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_tx_fail_reason( + TX_STATUS_FAIL_INSUFFICIENT_CF_POLL), + priv->_agn.reply_tx_stats.insuff_cf_poll); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX), + priv->_agn.reply_tx_stats.fail_hw_drop); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_tx_fail_reason( + TX_STATUS_FAIL_NO_BEACON_ON_RADAR), + priv->_agn.reply_tx_stats.sta_color_mismatch); + pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", + priv->_agn.reply_tx_stats.unknown); + + pos += scnprintf(buf + pos, bufsz - pos, + "\nStatistics_Agg_TX_Error:\n"); + + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK), + priv->_agn.reply_agg_tx_stats.underrun); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK), + priv->_agn.reply_agg_tx_stats.bt_prio); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK), + priv->_agn.reply_agg_tx_stats.few_bytes); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK), + priv->_agn.reply_agg_tx_stats.abort); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_LAST_SENT_TTL_MSK), + priv->_agn.reply_agg_tx_stats.last_sent_ttl); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK), + priv->_agn.reply_agg_tx_stats.last_sent_try); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK), + priv->_agn.reply_agg_tx_stats.last_sent_bt_kill); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK), + priv->_agn.reply_agg_tx_stats.scd_query); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_TEST_BAD_CRC32_MSK), + priv->_agn.reply_agg_tx_stats.bad_crc32); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK), + priv->_agn.reply_agg_tx_stats.response); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK), + priv->_agn.reply_agg_tx_stats.dump_tx); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK), + priv->_agn.reply_agg_tx_stats.delay_tx); + pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", + priv->_agn.reply_agg_tx_stats.unknown); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; } static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, @@ -1268,8 +2238,7 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file, if (sscanf(buf, "%d", &csr) != 1) return -EFAULT; - if (priv->cfg->ops->lib->dump_csr) - priv->cfg->ops->lib->dump_csr(priv); + iwl_dump_csr(priv); return count; } @@ -1359,13 +2328,11 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, int pos = 0; ssize_t ret = -EFAULT; - if (priv->cfg->ops->lib->dump_fh) { - ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true); - if (buf) { - ret = simple_read_from_buffer(user_buf, - count, ppos, buf, pos); - kfree(buf); - } + ret = pos = iwl_dump_fh(priv, &buf, true); + if (buf) { + ret = simple_read_from_buffer(user_buf, + count, ppos, buf, pos); + kfree(buf); } return ret; @@ -1531,16 +2498,6 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - - return priv->cfg->ops->lib->debugfs_ops.bt_stats_read(file, - user_buf, count, ppos); -} - static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { @@ -1572,12 +2529,10 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, int pos = 0; char buf[200]; const size_t bufsz = sizeof(buf); - ssize_t ret; if (!priv->bt_enable_flag) { pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n"); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n", priv->bt_enable_flag); @@ -1608,8 +2563,7 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, break; } - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } static ssize_t iwl_dbgfs_protection_mode_read(struct file *file, @@ -1658,18 +2612,6 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - - if (priv->cfg->ops->lib->debugfs_ops.reply_tx_error) - return priv->cfg->ops->lib->debugfs_ops.reply_tx_error( - file, user_buf, count, ppos); - else - return -ENODATA; -} DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -1731,11 +2673,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR); - if (!priv->cfg->base_params->broken_powersave) { - DEBUGFS_ADD_FILE(sleep_level_override, dir_data, - S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); - } + DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR); @@ -1758,29 +2697,20 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR); - if (priv->cfg->base_params->sensitivity_calib_by_driver) - DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); - if (priv->cfg->base_params->chain_noise_calib_by_driver) - DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); - if (priv->cfg->base_params->ucode_tracing) - DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); - if (iwl_bt_statistics(priv)) - DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR); 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); if (iwl_advanced_bt_coexist(priv)) DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR); - if (priv->cfg->base_params->sensitivity_calib_by_driver) - DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, - &priv->disable_sens_cal); - if (priv->cfg->base_params->chain_noise_calib_by_driver) - DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, - &priv->disable_chain_noise_cal); - if (priv->cfg->base_params->tx_power_by_driver) - DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf, - &priv->disable_tx_power_cal); + DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, + &priv->disable_sens_cal); + DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, + &priv->disable_chain_noise_cal); return 0; err: diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 68b953f2bdc7..214e4658c495 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 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 @@ -26,7 +26,6 @@ /* * Please use this file (iwl-dev.h) for driver implementation definitions. * Please use iwl-commands.h for uCode API definitions. - * Please use iwl-4965-hw.h for hardware-related definitions. */ #ifndef __iwl_dev_h__ @@ -179,53 +178,12 @@ struct iwl_tx_queue { #define IWL_NUM_SCAN_RATES (2) -struct iwl4965_channel_tgd_info { - u8 type; - s8 max_power; -}; - -struct iwl4965_channel_tgh_info { - s64 last_radar_time; -}; - -#define IWL4965_MAX_RATE (33) - -struct iwl3945_clip_group { - /* maximum power level to prevent clipping for each rate, derived by - * us from this band's saturation power in EEPROM */ - const s8 clip_powers[IWL_MAX_RATES]; -}; - -/* current Tx power values to use, one for each rate for each channel. - * requested power is limited by: - * -- regulatory EEPROM limits for this channel - * -- hardware capabilities (clip-powers) - * -- spectrum management - * -- user preference (e.g. iwconfig) - * when requested power is set, base power index must also be set. */ -struct iwl3945_channel_power_info { - struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 base_power_index; /* gain index for power at factory temp. */ - s8 requested_power; /* power (dBm) requested for this chnl/rate */ -}; - -/* current scan Tx power values to use, one for each scan rate for each - * channel. */ -struct iwl3945_scan_power_info { - struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ -}; - /* * One for each channel, holds all channel setup data * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant * with one another! */ struct iwl_channel_info { - struct iwl4965_channel_tgd_info tgd; - struct iwl4965_channel_tgh_info tgh; struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for * HT40 channel */ @@ -245,14 +203,6 @@ struct iwl_channel_info { s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ u8 ht40_flags; /* flags copied from EEPROM */ u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ - - /* Radio/DSP gain settings for each "normal" data Tx rate. - * These include, in addition to RF and DSP gain, a few fields for - * remembering/modifying gain settings (indexes). */ - struct iwl3945_channel_power_info power_info[IWL4965_MAX_RATE]; - - /* Radio/DSP gain settings for each scan rate, for directed scans. */ - struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; }; #define IWL_TX_FIFO_BK 0 /* shared */ @@ -288,15 +238,6 @@ struct iwl_channel_info { #define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) #define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) -struct iwl_frame { - union { - struct ieee80211_hdr frame; - struct iwl_tx_beacon_cmd beacon; - u8 raw[IEEE80211_FRAME_LEN]; - u8 cmd[360]; - } u; - struct list_head list; -}; #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) @@ -309,6 +250,7 @@ enum { CMD_SIZE_HUGE = (1 << 0), CMD_ASYNC = (1 << 1), CMD_WANT_SKB = (1 << 2), + CMD_MAPPED = (1 << 3), }; #define DEF_CMD_PAYLOAD_SIZE 320 @@ -416,6 +358,7 @@ struct iwl_ht_agg { #define IWL_EMPTYING_HW_QUEUE_ADDBA 2 #define IWL_EMPTYING_HW_QUEUE_DELBA 3 u8 state; + u8 tx_fifo; }; @@ -499,9 +442,6 @@ struct iwl_station_priv_common { * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is places in that * space. - * - * The common struct MUST be first because it is shared between - * 3945 and agn! */ struct iwl_station_priv { struct iwl_station_priv_common common; @@ -530,6 +470,10 @@ struct fw_desc { u32 len; /* bytes */ }; +struct fw_img { + struct fw_desc code, data; +}; + /* v1/v2 uCode file layout */ struct iwl_ucode_header { __le32 ver; /* major/minor/API/serial */ @@ -586,6 +530,22 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, + /* 16 and 17 reserved for future use */ + IWL_UCODE_TLV_FLAGS = 18, +}; + +/** + * enum iwl_ucode_tlv_flag - ucode API flags + * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously + * was a separate TLV but moved here to save space. + * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, + * treats good CRC threshold as a boolean + * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). + */ +enum iwl_ucode_tlv_flag { + IWL_UCODE_TLV_FLAGS_PAN = BIT(0), + IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), + IWL_UCODE_TLV_FLAGS_MFP = BIT(2), }; struct iwl_ucode_tlv { @@ -619,14 +579,6 @@ struct iwl_tlv_ucode_header { u8 data[0]; }; -struct iwl4965_ibss_seq { - u8 mac[ETH_ALEN]; - u16 seq_num; - u16 frag_num; - unsigned long packet_time; - struct list_head list; -}; - struct iwl_sensitivity_ranges { u16 min_nrg_cck; u16 max_nrg_cck; @@ -700,7 +652,6 @@ struct iwl_hw_params { u8 max_beacon_itrvl; /* in 1024 ms */ u32 max_inst_size; u32 max_data_size; - u32 max_bsm_size; u32 ct_kill_threshold; /* value in hw-dependent units */ u32 ct_kill_exit_threshold; /* value in hw-dependent units */ /* for 1000, 6000 series and up */ @@ -722,8 +673,6 @@ struct iwl_hw_params { * Naming convention -- * iwl_ <-- Is part of iwlwifi * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) - * iwl4965_bg_ <-- Called from work queue context - * iwl4965_mac_ <-- mac80211 callback * ****************************************************************************/ extern void iwl_update_chain_flags(struct iwl_priv *priv); @@ -772,7 +721,6 @@ struct iwl_dma_ptr { /* Sensitivity and chain noise calibration */ #define INITIALIZATION_VALUE 0xFFFF -#define IWL4965_CAL_NUM_BEACONS 20 #define IWL_CAL_NUM_BEACONS 16 #define MAXIMUM_ALLOWED_PATHLOSS 15 @@ -806,24 +754,19 @@ struct iwl_dma_ptr { #define NRG_NUM_PREV_STAT_L 20 #define NUM_RX_CHAINS 3 -enum iwl4965_false_alarm_state { +enum iwlagn_false_alarm_state { IWL_FA_TOO_MANY = 0, IWL_FA_TOO_FEW = 1, IWL_FA_GOOD_RANGE = 2, }; -enum iwl4965_chain_noise_state { +enum iwlagn_chain_noise_state { IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ IWL_CHAIN_NOISE_ACCUMULATE, IWL_CHAIN_NOISE_CALIBRATED, IWL_CHAIN_NOISE_DONE, }; -enum iwl4965_calib_enabled_state { - IWL_CALIB_DISABLED = 0, /* must be 0 */ - IWL_CALIB_ENABLED = 1, -}; - /* * enum iwl_calib @@ -847,12 +790,6 @@ struct iwl_calib_result { size_t buf_len; }; -enum ucode_type { - UCODE_NONE = 0, - UCODE_INIT, - UCODE_RT -}; - /* Sensitivity calib data */ struct iwl_sensitivity_data { u32 auto_corr_ofdm; @@ -1130,12 +1067,6 @@ struct iwl_force_reset { }; /* extend beacon time format bit shifting */ -/* - * for _3945 devices - * bits 31:24 - extended - * bits 23:0 - interval - */ -#define IWL3945_EXT_BEACON_TIME_POS 24 /* * for _agn devices * bits 31:22 - extended @@ -1164,10 +1095,12 @@ struct iwl_force_reset { struct iwl_notification_wait { struct list_head list; - void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt); + void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt, + void *data); + void *fn_data; u8 cmd; - bool triggered; + bool triggered, aborted; }; enum iwl_rxon_context_id { @@ -1228,6 +1161,8 @@ struct iwl_rxon_context { bool enabled, is_40mhz; u8 extension_chan_offset; } ht; + + bool last_tx_rejected; }; enum iwl_scan_type { @@ -1244,13 +1179,10 @@ struct iwl_priv { struct ieee80211_rate *ieee_rates; struct iwl_cfg *cfg; - /* temporary frame storage list */ - struct list_head free_frames; - int frames_count; - enum ieee80211_band band; - int alloc_rxb_page; + void (*pre_rx_handler)(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); @@ -1305,16 +1237,12 @@ struct iwl_priv { spinlock_t hcmd_lock; /* protect hcmd */ spinlock_t reg_lock; /* protect hw register access */ struct mutex mutex; - struct mutex sync_cmd_mutex; /* enable serialization of sync commands */ /* basic pci-network driver stuff */ struct pci_dev *pci_dev; /* pci hardware address support */ void __iomem *hw_base; - u32 hw_rev; - u32 hw_wa_rev; - u8 rev_id; /* microcode/device supports multiple contexts */ u8 valid_contexts; @@ -1325,6 +1253,8 @@ struct iwl_priv { /* max number of station keys */ u8 sta_key_max_num; + bool new_scan_threshold_behaviour; + /* EEPROM MAC addresses */ struct mac_address addresses[2]; @@ -1332,13 +1262,10 @@ struct iwl_priv { int fw_index; /* firmware we're trying to load */ u32 ucode_ver; /* version of ucode, copy of iwl_ucode.ver */ - struct fw_desc ucode_code; /* runtime inst */ - struct fw_desc ucode_data; /* runtime data original */ - struct fw_desc ucode_data_backup; /* runtime data save/restore */ - struct fw_desc ucode_init; /* initialization inst */ - struct fw_desc ucode_init_data; /* initialization data */ - struct fw_desc ucode_boot; /* bootstrap inst */ - enum ucode_type ucode_type; + struct fw_img ucode_rt; + struct fw_img ucode_init; + + enum iwlagn_ucode_subtype ucode_type; u8 ucode_write_complete; /* the image write is complete */ char firmware_name[25]; @@ -1346,10 +1273,10 @@ struct iwl_priv { struct iwl_switch_rxon switch_rxon; - /* 1st responses from initialize and runtime uCode images. - * _agn's initialize alive response contains some calibration data. */ - struct iwl_init_alive_resp card_alive_init; - struct iwl_alive_resp card_alive; + struct { + u32 error_event_table; + u32 log_event_table; + } device_pointers; u16 active_rate; @@ -1390,15 +1317,12 @@ struct iwl_priv { struct iwl_power_mgr power_data; struct iwl_tt_mgmt thermal_throttle; - /* context information */ - u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */ - /* station table variables */ /* Note: if lock and sta_lock are needed, lock must be acquired first */ spinlock_t sta_lock; int num_stations; - struct iwl_station_entry stations[IWL_STATION_COUNT]; + struct iwl_station_entry stations[IWLAGN_STATION_COUNT]; unsigned long ucode_key_table; /* queue refcounts */ @@ -1422,101 +1346,81 @@ struct iwl_priv { /* Last Rx'd beacon timestamp */ u64 timestamp; - union { -#if defined(CONFIG_IWL3945) || defined(CONFIG_IWL3945_MODULE) - struct { - void *shared_virt; - dma_addr_t shared_phys; - - struct delayed_work thermal_periodic; - struct delayed_work rfkill_poll; - - struct iwl3945_notif_statistics statistics; + struct { + __le32 flag; + struct statistics_general_common common; + struct statistics_rx_non_phy rx_non_phy; + struct statistics_rx_phy rx_ofdm; + struct statistics_rx_ht_phy rx_ofdm_ht; + struct statistics_rx_phy rx_cck; + struct statistics_tx tx; #ifdef CONFIG_IWLWIFI_DEBUGFS - struct iwl3945_notif_statistics accum_statistics; - struct iwl3945_notif_statistics delta_statistics; - struct iwl3945_notif_statistics max_delta; + struct statistics_bt_activity bt_activity; + __le32 num_bt_kills, accum_num_bt_kills; #endif - - u32 sta_supp_rates; - int last_rx_rssi; /* From Rx packet statistics */ - - /* Rx'd packet timing information */ - u32 last_beacon_time; - u64 last_tsf; - - /* - * each calibration channel group in the - * EEPROM has a derived clip setting for - * each rate. - */ - const struct iwl3945_clip_group clip_groups[5]; - - } _3945; -#endif -#if defined(CONFIG_IWLAGN) || defined(CONFIG_IWLAGN_MODULE) - struct { - /* INT ICT Table */ - __le32 *ict_tbl; - void *ict_tbl_vir; - dma_addr_t ict_tbl_dma; - dma_addr_t aligned_ict_tbl_dma; - int ict_index; - u32 inta; - bool use_ict; - /* - * reporting the number of tids has AGG on. 0 means - * no AGGREGATION - */ - u8 agg_tids_count; - - struct iwl_rx_phy_res last_phy_res; - bool last_phy_res_valid; - - struct completion firmware_loading_complete; - - u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; - u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; - - /* - * chain noise reset and gain commands are the - * two extra calibration commands follows the standard - * phy calibration commands - */ - u8 phy_calib_chain_noise_reset_cmd; - u8 phy_calib_chain_noise_gain_cmd; - - struct iwl_notif_statistics statistics; - struct iwl_bt_notif_statistics statistics_bt; - /* counts reply_tx error */ - struct reply_tx_error_statistics reply_tx_stats; - struct reply_agg_tx_error_statistics reply_agg_tx_stats; + } statistics; #ifdef CONFIG_IWLWIFI_DEBUGFS - struct iwl_notif_statistics accum_statistics; - struct iwl_notif_statistics delta_statistics; - struct iwl_notif_statistics max_delta; - struct iwl_bt_notif_statistics accum_statistics_bt; - struct iwl_bt_notif_statistics delta_statistics_bt; - struct iwl_bt_notif_statistics max_delta_bt; + struct { + struct statistics_general_common common; + struct statistics_rx_non_phy rx_non_phy; + struct statistics_rx_phy rx_ofdm; + struct statistics_rx_ht_phy rx_ofdm_ht; + struct statistics_rx_phy rx_cck; + struct statistics_tx tx; + struct statistics_bt_activity bt_activity; + } accum_stats, delta_stats, max_delta_stats; #endif - /* notification wait support */ - struct list_head notif_waits; - spinlock_t notif_wait_lock; - wait_queue_head_t notif_waitq; + struct { + /* INT ICT Table */ + __le32 *ict_tbl; + void *ict_tbl_vir; + dma_addr_t ict_tbl_dma; + dma_addr_t aligned_ict_tbl_dma; + int ict_index; + u32 inta; + bool use_ict; + /* + * reporting the number of tids has AGG on. 0 means + * no AGGREGATION + */ + u8 agg_tids_count; - /* remain-on-channel offload support */ - struct ieee80211_channel *hw_roc_channel; - struct delayed_work hw_roc_work; - enum nl80211_channel_type hw_roc_chantype; - int hw_roc_duration; + struct iwl_rx_phy_res last_phy_res; + bool last_phy_res_valid; - struct sk_buff *offchan_tx_skb; - int offchan_tx_timeout; - struct ieee80211_channel *offchan_tx_chan; - } _agn; -#endif - }; + struct completion firmware_loading_complete; + + u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; + u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; + + /* + * chain noise reset and gain commands are the + * two extra calibration commands follows the standard + * phy calibration commands + */ + u8 phy_calib_chain_noise_reset_cmd; + u8 phy_calib_chain_noise_gain_cmd; + + /* counts reply_tx error */ + struct reply_tx_error_statistics reply_tx_stats; + struct reply_agg_tx_error_statistics reply_agg_tx_stats; + /* notification wait support */ + struct list_head notif_waits; + spinlock_t notif_wait_lock; + wait_queue_head_t notif_waitq; + + /* remain-on-channel offload support */ + struct ieee80211_channel *hw_roc_channel; + struct delayed_work hw_roc_work; + enum nl80211_channel_type hw_roc_chantype; + int hw_roc_duration; + bool hw_roc_setup; + + struct sk_buff *offchan_tx_skb; + int offchan_tx_timeout; + struct ieee80211_channel *offchan_tx_chan; + } _agn; /* bt coex */ u8 bt_enable_flag; @@ -1559,8 +1463,6 @@ struct iwl_priv { struct tasklet_struct irq_tasklet; - struct delayed_work init_alive_start; - struct delayed_work alive_start; struct delayed_work scan_check; /* TX Power */ @@ -1589,12 +1491,10 @@ struct iwl_priv { struct work_struct txpower_work; u32 disable_sens_cal; u32 disable_chain_noise_cal; - u32 disable_tx_power_cal; struct work_struct run_time_calib_work; struct timer_list statistics_periodic; struct timer_list ucode_trace; struct timer_list watchdog; - bool hw_ready; struct iwl_event_log event_log; @@ -1658,21 +1558,24 @@ iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif) ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++) \ if (priv->valid_contexts & BIT(ctx->ctxid)) +static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx) +{ + return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; +} + static inline int iwl_is_associated(struct iwl_priv *priv, enum iwl_rxon_context_id ctxid) { - return (priv->contexts[ctxid].active.filter_flags & - RXON_FILTER_ASSOC_MSK) ? 1 : 0; + return iwl_is_associated_ctx(&priv->contexts[ctxid]); } static inline int iwl_is_any_associated(struct iwl_priv *priv) { - return iwl_is_associated(priv, IWL_RXON_CTX_BSS); -} - -static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx) -{ - return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; + struct iwl_rxon_context *ctx; + for_each_context(priv, ctx) + if (iwl_is_associated_ctx(ctx)) + return true; + return false; } static inline int is_channel_valid(const struct iwl_channel_info *ch_info) @@ -1710,12 +1613,10 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) static inline void __iwl_free_pages(struct iwl_priv *priv, struct page *page) { __free_pages(page, priv->hw_params.rx_page_order); - priv->alloc_rxb_page--; } static inline void iwl_free_pages(struct iwl_priv *priv, unsigned long page) { free_pages(page, priv->hw_params.rx_page_order); - priv->alloc_rxb_page--; } #endif /* __iwl_dev_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 4a487639d932..a635a7e75447 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2011 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 diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 4cf864c664ee..f00172cb8a6d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2011 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 diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 833194a2c639..c8397962632c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -142,6 +142,45 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ * ******************************************************************************/ +/* + * The device's EEPROM semaphore prevents conflicts between driver and uCode + * when accessing the EEPROM; each access is a series of pulses to/from the + * EEPROM chip, not a single event, so even reads could conflict if they + * weren't arbitrated by the semaphore. + */ +static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv) +{ + u16 count; + int ret; + + for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { + /* Request semaphore */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + + /* See if we got it */ + ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + EEPROM_SEM_TIMEOUT); + if (ret >= 0) { + IWL_DEBUG_EEPROM(priv, + "Acquired semaphore after %d tries.\n", + count+1); + return ret; + } + } + + return ret; +} + +static void iwl_eeprom_release_semaphore(struct iwl_priv *priv) +{ + iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + +} + static int iwl_eeprom_verify_signature(struct iwl_priv *priv) { u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; @@ -188,18 +227,16 @@ static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) CSR_OTP_GP_REG_OTP_ACCESS_MODE); } -static int iwlcore_get_nvm_type(struct iwl_priv *priv) +static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) { u32 otpgp; int nvm_type; /* OTP only valid for CP/PP and after */ - switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + switch (hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_NONE: IWL_ERR(priv, "Unknown hardware type\n"); return -ENOENT; - case CSR_HW_REV_TYPE_3945: - case CSR_HW_REV_TYPE_4965: case CSR_HW_REV_TYPE_5300: case CSR_HW_REV_TYPE_5350: case CSR_HW_REV_TYPE_5100: @@ -217,26 +254,20 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv) return nvm_type; } -const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) -{ - BUG_ON(offset >= priv->cfg->base_params->eeprom_size); - return &priv->eeprom[offset]; -} - static int iwl_init_otp_access(struct iwl_priv *priv) { int ret; /* Enable 40MHz radio clock */ - _iwl_write32(priv, CSR_GP_CNTRL, - _iwl_read32(priv, CSR_GP_CNTRL) | - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_write32(priv, CSR_GP_CNTRL, + iwl_read32(priv, CSR_GP_CNTRL) | + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock to be ready */ ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - 25000); + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + 25000); if (ret < 0) IWL_ERR(priv, "Time out access OTP\n"); else { @@ -263,17 +294,17 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat u32 r; u32 otpgp; - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); ret = iwl_poll_bit(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); + CSR_EEPROM_REG_READ_VALID_MSK, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); return ret; } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + r = iwl_read32(priv, CSR_EEPROM_REG); /* check for ECC errors: */ otpgp = iwl_read32(priv, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { @@ -396,7 +427,7 @@ u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) * * NOTE: This routine uses the non-debug IO access functions. */ -int iwl_eeprom_init(struct iwl_priv *priv) +int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) { __le16 *e; u32 gp = iwl_read32(priv, CSR_EEPROM_GP); @@ -406,7 +437,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) u16 validblockaddr = 0; u16 cache_addr = 0; - priv->nvm_device_type = iwlcore_get_nvm_type(priv); + priv->nvm_device_type = iwlcore_get_nvm_type(priv, hw_rev); if (priv->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ @@ -429,7 +460,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv); + ret = iwl_eeprom_acquire_semaphore(priv); if (ret < 0) { IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n"); ret = -ENOENT; @@ -444,9 +475,9 @@ int iwl_eeprom_init(struct iwl_priv *priv) ret = -ENOENT; goto done; } - _iwl_write32(priv, CSR_EEPROM_GP, - iwl_read32(priv, CSR_EEPROM_GP) & - ~CSR_EEPROM_GP_IF_OWNER_MSK); + iwl_write32(priv, CSR_EEPROM_GP, + iwl_read32(priv, CSR_EEPROM_GP) & + ~CSR_EEPROM_GP_IF_OWNER_MSK); iwl_set_bit(priv, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | @@ -473,8 +504,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) for (addr = 0; addr < sz; addr += sizeof(u16)) { u32 r; - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); ret = iwl_poll_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_READ_VALID_MSK, @@ -484,7 +515,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); goto done; } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + r = iwl_read32(priv, CSR_EEPROM_REG); e[addr / 2] = cpu_to_le16(r >> 16); } } @@ -496,7 +527,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) ret = 0; done: - priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); + iwl_eeprom_release_semaphore(priv); err: if (ret) @@ -719,13 +750,6 @@ int iwl_init_channel_map(struct iwl_priv *priv) flags & EEPROM_CHANNEL_RADAR)) ? "" : "not "); - /* Set the tx_power_user_lmt to the highest power - * supported by any channel */ - if (eeprom_ch_info[ch].max_power_avg > - priv->tx_power_user_lmt) - priv->tx_power_user_lmt = - eeprom_ch_info[ch].max_power_avg; - ch_info++; } } diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 20b66469d68f..c960c6fa009b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -110,10 +110,6 @@ enum { }; /* SKU Capabilities */ -/* 3945 only */ -#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) -#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) - /* 5000 and up */ #define EEPROM_SKU_CAP_BAND_POS (4) #define EEPROM_SKU_CAP_BAND_SELECTION \ @@ -168,28 +164,6 @@ struct iwl_eeprom_enhanced_txpwr { s8 mimo3_max; } __packed; -/* 3945 Specific */ -#define EEPROM_3945_EEPROM_VERSION (0x2f) - -/* 4965 has two radio transmitters (and 3 radio receivers) */ -#define EEPROM_TX_POWER_TX_CHAINS (2) - -/* 4965 has room for up to 8 sets of txpower calibration data */ -#define EEPROM_TX_POWER_BANDS (8) - -/* 4965 factory calibration measures txpower gain settings for - * each of 3 target output levels */ -#define EEPROM_TX_POWER_MEASUREMENTS (3) - -/* 4965 Specific */ -/* 4965 driver does not work with txpower calibration version < 5 */ -#define EEPROM_4965_TX_POWER_VERSION (5) -#define EEPROM_4965_EEPROM_VERSION (0x2f) -#define EEPROM_4965_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ -#define EEPROM_4965_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ -#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ -#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ - /* 5000 Specific */ #define EEPROM_5000_TX_POWER_VERSION (4) #define EEPROM_5000_EEPROM_VERSION (0x11A) @@ -282,90 +256,6 @@ struct iwl_eeprom_enhanced_txpwr { /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; -/* - * factory calibration data for one txpower level, on one channel, - * measured on one of the 2 tx chains (radio transmitter and associated - * antenna). EEPROM contains: - * - * 1) Temperature (degrees Celsius) of device when measurement was made. - * - * 2) Gain table index used to achieve the target measurement power. - * This refers to the "well-known" gain tables (see iwl-4965-hw.h). - * - * 3) Actual measured output power, in half-dBm ("34" = 17 dBm). - * - * 4) RF power amplifier detector level measurement (not used). - */ -struct iwl_eeprom_calib_measure { - u8 temperature; /* Device temperature (Celsius) */ - u8 gain_idx; /* Index into gain table */ - u8 actual_pow; /* Measured RF output power, half-dBm */ - s8 pa_det; /* Power amp detector level (not used) */ -} __packed; - - -/* - * measurement set for one channel. EEPROM contains: - * - * 1) Channel number measured - * - * 2) Measurements for each of 3 power levels for each of 2 radio transmitters - * (a.k.a. "tx chains") (6 measurements altogether) - */ -struct iwl_eeprom_calib_ch_info { - u8 ch_num; - struct iwl_eeprom_calib_measure - measurements[EEPROM_TX_POWER_TX_CHAINS] - [EEPROM_TX_POWER_MEASUREMENTS]; -} __packed; - -/* - * txpower subband info. - * - * For each frequency subband, EEPROM contains the following: - * - * 1) First and last channels within range of the subband. "0" values - * indicate that this sample set is not being used. - * - * 2) Sample measurement sets for 2 channels close to the range endpoints. - */ -struct iwl_eeprom_calib_subband_info { - u8 ch_from; /* channel number of lowest channel in subband */ - u8 ch_to; /* channel number of highest channel in subband */ - struct iwl_eeprom_calib_ch_info ch1; - struct iwl_eeprom_calib_ch_info ch2; -} __packed; - - -/* - * txpower calibration info. EEPROM contains: - * - * 1) Factory-measured saturation power levels (maximum levels at which - * tx power amplifier can output a signal without too much distortion). - * There is one level for 2.4 GHz band and one for 5 GHz band. These - * values apply to all channels within each of the bands. - * - * 2) Factory-measured power supply voltage level. This is assumed to be - * constant (i.e. same value applies to all channels/bands) while the - * factory measurements are being made. - * - * 3) Up to 8 sets of factory-measured txpower calibration values. - * These are for different frequency ranges, since txpower gain - * characteristics of the analog radio circuitry vary with frequency. - * - * Not all sets need to be filled with data; - * struct iwl_eeprom_calib_subband_info contains range of channels - * (0 if unused) for each set of data. - */ -struct iwl_eeprom_calib_info { - u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ - u8 saturation_power52; /* half-dBm */ - __le16 voltage; /* signed */ - struct iwl_eeprom_calib_subband_info - band_info[EEPROM_TX_POWER_BANDS]; -} __packed; - - #define ADDRESS_MSK 0x0000FFFF #define INDIRECT_TYPE_MSK 0x000F0000 #define INDIRECT_HOST 0x00010000 @@ -398,103 +288,24 @@ struct iwl_eeprom_calib_info { #define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ #define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ -#define EEPROM_3945_RF_CFG_TYPE_MAX 0x0 -#define EEPROM_4965_RF_CFG_TYPE_MAX 0x1 - -/* Radio Config for 5000 and up */ -#define EEPROM_RF_CONFIG_TYPE_R3x3 0x0 -#define EEPROM_RF_CONFIG_TYPE_R2x2 0x1 -#define EEPROM_RF_CONFIG_TYPE_R1x2 0x2 #define EEPROM_RF_CONFIG_TYPE_MAX 0x3 -/* - * Per-channel regulatory data. - * - * Each channel that *might* be supported by iwl has a fixed location - * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory - * txpower (MSB). - * - * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) - * channels (only for 4965, not supported by 3945) appear later in the EEPROM. - * - * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - */ -#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ -#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ - -/* - * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, - * 5.0 GHz channels 7, 8, 11, 12, 16 - * (4915-5080MHz) (none of these is ever supported) - */ -#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ - -/* - * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 - * (5170-5320MHz) - */ -#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ - -/* - * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 - * (5500-5700MHz) - */ -#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ - -/* - * 5.7 GHz channels 145, 149, 153, 157, 161, 165 - * (5725-5825MHz) - */ -#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ - -/* - * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) - * - * The channel listed is the center of the lower 20 MHz half of the channel. - * The overall center frequency is actually 2 channels (10 MHz) above that, - * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away - * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5, - * and the overall HT40 channel width centers on channel 3. - * - * NOTE: The RXON command uses 20 MHz channel numbers to specify the - * control channel to which to tune. RXON also specifies whether the - * control channel is the upper or lower half of a HT40 channel. - * - * NOTE: 4965 does not support HT40 channels on 2.4 GHz. - */ -#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */ - -/* - * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64), - * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) - */ -#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */ - #define EEPROM_REGULATORY_BAND_NO_HT40 (0) struct iwl_eeprom_ops { const u32 regulatory_bands[7]; - int (*acquire_semaphore) (struct iwl_priv *priv); - void (*release_semaphore) (struct iwl_priv *priv); - u16 (*calib_version) (struct iwl_priv *priv); const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); void (*update_enhanced_txpower) (struct iwl_priv *priv); }; -int iwl_eeprom_init(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_check_sku(struct iwl_priv *priv); const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset); -const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); 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/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 474009a244d4..6dfa806aefec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -77,14 +77,14 @@ /** * Keep-Warm (KW) buffer base address. * - * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the + * Driver must allocate a 4KByte buffer that is for keeping the * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency - * DRAM access when 4965 is Txing or Rxing. The dummy accesses prevent host + * DRAM access when doing Txing or Rxing. The dummy accesses prevent host * from going into a power-savings mode that would cause higher DRAM latency, * and possible data over/under-runs, before all Tx/Rx is complete. * * Driver loads FH_KW_MEM_ADDR_REG with the physical address (bits 35:4) - * of the buffer, which must be 4K aligned. Once this is set up, the 4965 + * of the buffer, which must be 4K aligned. Once this is set up, the device * automatically invokes keep-warm accesses when normal accesses might not * be sufficient to maintain fast DRAM response. * @@ -97,7 +97,7 @@ /** * TFD Circular Buffers Base (CBBC) addresses * - * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident + * Device has 16 base pointer registers, one for each of 16 host-DRAM-resident * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs) * (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04 * bytes from one another. Each TFD circular buffer in DRAM must be 256-byte @@ -116,16 +116,16 @@ /** * Rx SRAM Control and Status Registers (RSCSR) * - * These registers provide handshake between driver and 4965 for the Rx queue + * These registers provide handshake between driver and device for the Rx queue * (this queue handles *all* command responses, notifications, Rx data, etc. - * sent from 4965 uCode to host driver). Unlike Tx, there is only one Rx + * sent from uCode to host driver). Unlike Tx, there is only one Rx * queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1 * mapping between RBDs and RBs. * * Driver must allocate host DRAM memory for the following, and set the - * physical address of each into 4965 registers: + * physical address of each into device registers: * * 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256 * entries (although any power of 2, up to 4096, is selectable by driver). @@ -140,20 +140,20 @@ * Driver sets physical address [35:8] of base of RBD circular buffer * into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0]. * - * 2) Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers + * 2) Rx status buffer, 8 bytes, in which uCode indicates which Rx Buffers * (RBs) have been filled, via a "write pointer", actually the index of * the RB's corresponding RBD within the circular buffer. Driver sets * physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0]. * * Bit fields in lower dword of Rx status buffer (upper dword not used - * by driver; see struct iwl4965_shared, val0): + * by driver: * 31-12: Not used by driver * 11- 0: Index of last filled Rx buffer descriptor - * (4965 writes, driver reads this value) + * (device writes, driver reads this value) * - * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must + * As the driver prepares Receive Buffers (RBs) for device to fill, driver must * enter pointers to these RBs into contiguous RBD circular buffer entries, - * and update the 4965's "write" index register, + * and update the device's "write" index register, * FH_RSCSR_CHNL0_RBDCB_WPTR_REG. * * This "write" index corresponds to the *next* RBD that the driver will make @@ -162,12 +162,12 @@ * RBs), should be 8 after preparing the first 8 RBs (for example), and must * wrap back to 0 at the end of the circular buffer (but don't wrap before * "read" index has advanced past 1! See below). - * NOTE: 4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. + * NOTE: DEVICE EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. * - * As the 4965 fills RBs (referenced from contiguous RBDs within the circular + * As the device fills RBs (referenced from contiguous RBDs within the circular * buffer), it updates the Rx status buffer in host DRAM, 2) described above, * to tell the driver the index of the latest filled RBD. The driver must - * read this "read" index from DRAM after receiving an Rx interrupt from 4965. + * read this "read" index from DRAM after receiving an Rx interrupt from device * * The driver must also internally keep track of a third index, which is the * next RBD to process. When receiving an Rx interrupt, driver should process @@ -176,7 +176,7 @@ * driver may process the RB pointed to by RBD 0. Depending on volume of * traffic, there may be many RBs to process. * - * If read index == write index, 4965 thinks there is no room to put new data. + * If read index == write index, device thinks there is no room to put new data. * Due to this, the maximum number of filled RBs is 255, instead of 256. To * be safe, make sure that there is a gap of at least 2 RBDs between "write" * and "read" indexes; that is, make sure that there are no more than 254 @@ -303,7 +303,7 @@ /** * Transmit DMA Channel Control/Status Registers (TCSR) * - * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels + * Device has one configuration register for each of 8 Tx DMA/FIFO channels * supported in hardware (don't confuse these with the 16 Tx queues in DRAM, * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes. * @@ -326,7 +326,6 @@ #define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) /* Find Control/Status reg for given Tx DMA/FIFO channel */ -#define FH49_TCSR_CHNL_NUM (7) #define FH50_TCSR_CHNL_NUM (8) /* TCSR: tx_config register values */ @@ -424,7 +423,6 @@ #define RX_LOW_WATERMARK 8 /* Size of one Rx buffer in host DRAM */ -#define IWL_RX_BUF_SIZE_3K (3 * 1000) /* 3945 only */ #define IWL_RX_BUF_SIZE_4K (4 * 1024) #define IWL_RX_BUF_SIZE_8K (8 * 1024) @@ -443,7 +441,7 @@ struct iwl_rb_status { __le16 closed_fr_num; __le16 finished_rb_num; __le16 finished_fr_nam; - __le32 __unused; /* 3945 only */ + __le32 __unused; } __packed; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 02499f684683..8f0beb992ccf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 @@ -51,9 +51,7 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_REMOVE_ALL_STA); IWL_CMD(REPLY_TXFIFO_FLUSH); IWL_CMD(REPLY_WEPKEY); - IWL_CMD(REPLY_3945_RX); IWL_CMD(REPLY_TX); - IWL_CMD(REPLY_RATE_SCALE); IWL_CMD(REPLY_LEDS_CMD); IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); IWL_CMD(COEX_PRIORITY_TABLE_CMD); @@ -145,10 +143,12 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { int ret; - BUG_ON(!(cmd->flags & CMD_ASYNC)); + if (WARN_ON(!(cmd->flags & CMD_ASYNC))) + return -EINVAL; /* An asynchronous command can not expect an SKB to be set. */ - BUG_ON(cmd->flags & CMD_WANT_SKB); + if (WARN_ON(cmd->flags & CMD_WANT_SKB)) + return -EINVAL; /* Assign a generic callback if one is not provided */ if (!cmd->callback) @@ -171,14 +171,15 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int cmd_idx; int ret; - BUG_ON(cmd->flags & CMD_ASYNC); + if (WARN_ON(cmd->flags & CMD_ASYNC)) + return -EINVAL; /* A synchronous command can not have a callback set. */ - BUG_ON(cmd->callback); + if (WARN_ON(cmd->callback)) + return -EINVAL; IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", get_cmd_string(cmd->id)); - mutex_lock(&priv->sync_cmd_mutex); set_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", @@ -189,7 +190,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) ret = cmd_idx; IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); - goto out; + return ret; } ret = wait_event_interruptible_timeout(priv->wait_command_queue, @@ -229,8 +230,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) goto cancel; } - ret = 0; - goto out; + return 0; cancel: if (cmd->flags & CMD_WANT_SKB) { @@ -248,8 +248,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) iwl_free_pages(priv, cmd->reply_page); cmd->reply_page = 0; } -out: - mutex_unlock(&priv->sync_cmd_mutex); + return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 8821f088ba7f..41207a3645b8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -64,30 +64,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd) return --index & (n_bd - 1); } -/* TODO: Move fw_desc functions to iwl-pci.ko */ -static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, - struct fw_desc *desc) -{ - if (desc->v_addr) - dma_free_coherent(&pci_dev->dev, desc->len, - desc->v_addr, desc->p_addr); - desc->v_addr = NULL; - desc->len = 0; -} - -static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev, - struct fw_desc *desc) -{ - if (!desc->len) { - desc->v_addr = NULL; - return -EINVAL; - } - - desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len, - &desc->p_addr, GFP_KERNEL); - return (desc->v_addr != NULL) ? 0 : -ENOMEM; -} - /* * we have 8 bits used like this: * @@ -131,6 +107,19 @@ static inline void iwl_stop_queue(struct iwl_priv *priv, ieee80211_stop_queue(priv->hw, ac); } +static inline void iwl_wake_any_queue(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + u8 ac; + + for (ac = 0; ac < AC_NUM; ac++) { + IWL_DEBUG_INFO(priv, "Queue Status: Q[%d] %s\n", + ac, (atomic_read(&priv->queue_stop_count[ac]) > 0) + ? "stopped" : "awake"); + iwl_wake_queue(priv, &priv->txq[ctx->ac_to_queue[ac]]); + } +} + #define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue #define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c new file mode 100644 index 000000000000..aa4a90674452 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -0,0 +1,294 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * + * 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 + * + *****************************************************************************/ + +#include "iwl-io.h" + +#define IWL_POLL_INTERVAL 10 /* microseconds */ + +static inline void __iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + iwl_write32(priv, reg, iwl_read32(priv, reg) | mask); +} + +static inline void __iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + iwl_write32(priv, reg, iwl_read32(priv, reg) & ~mask); +} + +void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + __iwl_set_bit(priv, reg, mask); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + __iwl_clear_bit(priv, reg, mask); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +int iwl_poll_bit(struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int t = 0; + + do { + if ((iwl_read32(priv, addr) & mask) == (bits & mask)) + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + +int iwl_grab_nic_access_silent(struct iwl_priv *priv) +{ + int ret; + + lockdep_assert_held(&priv->reg_lock); + + /* this bit wakes up the NIC */ + __iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* + * These bits say the device is running, and should keep running for + * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), + * but they do not indicate that embedded SRAM is restored yet; + * 3945 and 4965 have volatile SRAM, and must save/restore contents + * to/from host DRAM when sleeping/waking for power-saving. + * Each direction takes approximately 1/4 millisecond; with this + * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a + * series of register accesses are expected (e.g. reading Event Log), + * to keep device from sleeping. + * + * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that + * SRAM is okay/restored. We don't check that here because this call + * is just for hardware register access; but GP1 MAC_SLEEP check is a + * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). + * + * 5000 series and later (including 1000 series) have non-volatile SRAM, + * and do not save/restore SRAM when power cycling. + */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, + (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); + if (ret < 0) { + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); + return -EIO; + } + + return 0; +} + +int iwl_grab_nic_access(struct iwl_priv *priv) +{ + int ret = iwl_grab_nic_access_silent(priv); + if (ret) { + u32 val = iwl_read32(priv, CSR_GP_CNTRL); + IWL_ERR(priv, + "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); + } + + return ret; +} + +void iwl_release_nic_access(struct iwl_priv *priv) +{ + lockdep_assert_held(&priv->reg_lock); + __iwl_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +} + +u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) +{ + u32 value; + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + value = iwl_read32(priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); + + return value; +} + +void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) { + iwl_write32(priv, reg, value); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, + int timeout) +{ + int t = 0; + + do { + if ((iwl_read_direct32(priv, addr) & mask) == mask) + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + +static inline u32 __iwl_read_prph(struct iwl_priv *priv, u32 reg) +{ + iwl_write32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + rmb(); + return iwl_read32(priv, HBUS_TARG_PRPH_RDAT); +} + +static inline void __iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) +{ + iwl_write32(priv, HBUS_TARG_PRPH_WADDR, + ((addr & 0x0000FFFF) | (3 << 24))); + wmb(); + iwl_write32(priv, HBUS_TARG_PRPH_WDAT, val); +} + +u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + val = __iwl_read_prph(priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); + return val; +} + +void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) { + __iwl_write_prph(priv, addr, val); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + __iwl_write_prph(priv, reg, __iwl_read_prph(priv, reg) | mask); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, + u32 bits, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + __iwl_write_prph(priv, reg, + (__iwl_read_prph(priv, reg) & mask) | bits); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + val = __iwl_read_prph(priv, reg); + __iwl_write_prph(priv, reg, (val & ~mask)); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr, + void *buf, int words) +{ + unsigned long flags; + int offs; + u32 *vals = buf; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + + iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr); + rmb(); + + for (offs = 0; offs < words; offs++) + vals[offs] = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) +{ + u32 value; + + _iwl_read_targ_mem_words(priv, addr, &value, 1); + + return value; +} + +void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) { + iwl_write32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); + iwl_write32(priv, HBUS_TARG_MEM_WDAT, val); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, flags); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 0203a3bbf872..869edc580ec6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -35,494 +35,58 @@ #include "iwl-debug.h" #include "iwl-devtrace.h" -/* - * IO, register, and NIC memory access functions - * - * NOTE on naming convention and macro usage for these - * - * A single _ prefix before a an access function means that no state - * check or debug information is printed when that function is called. - * - * A double __ prefix before an access function means that state is checked - * and the current line number and caller function name are printed in addition - * to any other debug output. - * - * The non-prefixed name is the #define that maps the caller into a - * #define that provides the caller's name and __LINE__ to the double - * prefix version. - * - * If you wish to call the function without any debug or state checking, - * you should use the single _ prefix version (as is used by dependent IO - * routines, for example _iwl_read_direct32 calls the non-check version of - * _iwl_read32.) - * - * These declarations are *extremely* useful in quickly isolating code deltas - * which result in misconfiguration of the hardware I/O. In combination with - * git-bisect and the IO debug level you can quickly determine the specific - * commit which breaks the IO sequence to the hardware. - * - */ - -static inline void _iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) +static inline void iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) { trace_iwlwifi_dev_iowrite8(priv, ofs, val); iowrite8(val, priv->hw_base + ofs); } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_write8(const char *f, u32 l, struct iwl_priv *priv, - u32 ofs, u8 val) -{ - IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l); - _iwl_write8(priv, ofs, val); -} -#define iwl_write8(priv, ofs, val) \ - __iwl_write8(__FILE__, __LINE__, priv, ofs, val) -#else -#define iwl_write8(priv, ofs, val) _iwl_write8(priv, ofs, val) -#endif - - -static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) +static inline void iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) { trace_iwlwifi_dev_iowrite32(priv, ofs, val); iowrite32(val, priv->hw_base + ofs); } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, - u32 ofs, u32 val) -{ - IWL_DEBUG_IO(priv, "write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l); - _iwl_write32(priv, ofs, val); -} -#define iwl_write32(priv, ofs, val) \ - __iwl_write32(__FILE__, __LINE__, priv, ofs, val) -#else -#define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val) -#endif - -static inline u32 _iwl_read32(struct iwl_priv *priv, u32 ofs) +static inline u32 iwl_read32(struct iwl_priv *priv, u32 ofs) { u32 val = ioread32(priv->hw_base + ofs); trace_iwlwifi_dev_ioread32(priv, ofs, val); return val; } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) -{ - IWL_DEBUG_IO(priv, "read_direct32(0x%08X) - %s %d\n", ofs, f, l); - return _iwl_read32(priv, ofs); -} -#define iwl_read32(priv, ofs) __iwl_read32(__FILE__, __LINE__, priv, ofs) -#else -#define iwl_read32(p, o) _iwl_read32(p, o) -#endif - -#define IWL_POLL_INTERVAL 10 /* microseconds */ -static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int t = 0; - - do { - if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) - return t; - udelay(IWL_POLL_INTERVAL); - t += IWL_POLL_INTERVAL; - } while (t < timeout); - - return -ETIMEDOUT; -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_poll_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout); - IWL_DEBUG_IO(priv, "poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", - addr, bits, mask, - unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l); - return ret; -} -#define iwl_poll_bit(priv, addr, bits, mask, timeout) \ - __iwl_poll_bit(__FILE__, __LINE__, priv, addr, bits, mask, timeout) -#else -#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t) -#endif - -static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) -{ - _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_set_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 reg, u32 mask) -{ - u32 val = _iwl_read32(priv, reg) | mask; - IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); - _iwl_write32(priv, reg, val); -} -static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - __iwl_set_bit(__FILE__, __LINE__, p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#else -static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - _iwl_set_bit(p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#endif - -static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) -{ - _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_clear_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 reg, u32 mask) -{ - u32 val = _iwl_read32(priv, reg) & ~mask; - IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); - _iwl_write32(priv, reg, val); -} -static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - __iwl_clear_bit(__FILE__, __LINE__, p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#else -static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - _iwl_clear_bit(p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#endif - -static inline int _iwl_grab_nic_access(struct iwl_priv *priv) -{ - int ret; - u32 val; - - /* this bit wakes up the NIC */ - _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - /* - * These bits say the device is running, and should keep running for - * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), - * but they do not indicate that embedded SRAM is restored yet; - * 3945 and 4965 have volatile SRAM, and must save/restore contents - * to/from host DRAM when sleeping/waking for power-saving. - * Each direction takes approximately 1/4 millisecond; with this - * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a - * series of register accesses are expected (e.g. reading Event Log), - * to keep device from sleeping. - * - * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that - * SRAM is okay/restored. We don't check that here because this call - * is just for hardware register access; but GP1 MAC_SLEEP check is a - * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). - * - * 5000 series and later (including 1000 series) have non-volatile SRAM, - * and do not save/restore SRAM when power cycling. - */ - ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, - (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | - CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); - if (ret < 0) { - val = _iwl_read32(priv, CSR_GP_CNTRL); - IWL_ERR(priv, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); - _iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); - return -EIO; - } - - return 0; -} - -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_grab_nic_access(const char *f, u32 l, - struct iwl_priv *priv) -{ - IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l); - return _iwl_grab_nic_access(priv); -} -#define iwl_grab_nic_access(priv) \ - __iwl_grab_nic_access(__FILE__, __LINE__, priv) -#else -#define iwl_grab_nic_access(priv) \ - _iwl_grab_nic_access(priv) -#endif - -static inline void _iwl_release_nic_access(struct iwl_priv *priv) -{ - _iwl_clear_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_release_nic_access(const char *f, u32 l, - struct iwl_priv *priv) -{ - - IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l); - _iwl_release_nic_access(priv); -} -#define iwl_release_nic_access(priv) \ - __iwl_release_nic_access(__FILE__, __LINE__, priv) -#else -#define iwl_release_nic_access(priv) \ - _iwl_release_nic_access(priv) -#endif - -static inline u32 _iwl_read_direct32(struct iwl_priv *priv, u32 reg) -{ - return _iwl_read32(priv, reg); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read_direct32(const char *f, u32 l, - struct iwl_priv *priv, u32 reg) -{ - u32 value = _iwl_read_direct32(priv, reg); - IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d\n", reg, value, - f, l); - return value; -} -static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) -{ - u32 value; - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return value; -} - -#else -static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) -{ - u32 value; - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - value = _iwl_read_direct32(priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return value; - -} -#endif - -static inline void _iwl_write_direct32(struct iwl_priv *priv, - u32 reg, u32 value) -{ - _iwl_write32(priv, reg, value); -} -static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_direct32(priv, reg, value); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline void iwl_write_reg_buf(struct iwl_priv *priv, - u32 reg, u32 len, u32 *values) -{ - u32 count = sizeof(u32); - - if ((priv != NULL) && (values != NULL)) { - for (; 0 < len; len -= count, reg += count, values++) - iwl_write_direct32(priv, reg, *values); - } -} - -static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, - u32 mask, int timeout) -{ - int t = 0; - - do { - if ((iwl_read_direct32(priv, addr) & mask) == mask) - return t; - udelay(IWL_POLL_INTERVAL); - t += IWL_POLL_INTERVAL; - } while (t < timeout); - - return -ETIMEDOUT; -} - -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_poll_direct_bit(const char *f, u32 l, - struct iwl_priv *priv, - u32 addr, u32 mask, int timeout) -{ - int ret = _iwl_poll_direct_bit(priv, addr, mask, timeout); - - if (unlikely(ret == -ETIMEDOUT)) - IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) - " - "timedout - %s %d\n", addr, mask, f, l); - else - IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) = 0x%08X " - "- %s %d\n", addr, mask, ret, f, l); - return ret; -} -#define iwl_poll_direct_bit(priv, addr, mask, timeout) \ - __iwl_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout) -#else -#define iwl_poll_direct_bit _iwl_poll_direct_bit -#endif - -static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) -{ - _iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); - rmb(); - return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); -} -static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) -{ - unsigned long reg_flags; - u32 val; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - val = _iwl_read_prph(priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return val; -} - -static inline void _iwl_write_prph(struct iwl_priv *priv, - u32 addr, u32 val) -{ - _iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR, - ((addr & 0x0000FFFF) | (3 << 24))); - wmb(); - _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); -} - -static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_prph(priv, addr, val); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -#define _iwl_set_bits_prph(priv, reg, mask) \ - _iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask)) - -static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - _iwl_set_bits_prph(priv, reg, mask); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -#define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \ - _iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits)) - -static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, - u32 bits, u32 mask) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - _iwl_set_bits_mask_prph(priv, reg, bits, mask); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline void iwl_clear_bits_prph(struct iwl_priv - *priv, u32 reg, u32 mask) -{ - unsigned long reg_flags; - u32 val; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - val = _iwl_read_prph(priv, reg); - _iwl_write_prph(priv, reg, (val & ~mask)); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) -{ - unsigned long reg_flags; - u32 value; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); - rmb(); - value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return value; -} - -static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - wmb(); - _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, - u32 len, u32 *values) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - wmb(); - for (; 0 < len; len -= sizeof(u32), values++) - _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); - - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} +void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask); +void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask); + +int iwl_poll_bit(struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout); +int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, + int timeout); + +int iwl_grab_nic_access_silent(struct iwl_priv *priv); +int iwl_grab_nic_access(struct iwl_priv *priv); +void iwl_release_nic_access(struct iwl_priv *priv); + +u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg); +void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value); + + +u32 iwl_read_prph(struct iwl_priv *priv, u32 reg); +void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val); +void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); +void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, + u32 bits, u32 mask); +void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); + +void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr, + void *buf, int words); + +#define iwl_read_targ_mem_words(priv, addr, buf, bufsize) \ + do { \ + BUILD_BUG_ON((bufsize) % sizeof(u32)); \ + _iwl_read_targ_mem_words(priv, addr, buf, \ + (bufsize) / sizeof(u32));\ + } while (0) + +u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr); +void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index d7f2a0bb32c9..439187f903c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 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 @@ -48,8 +48,21 @@ module_param(led_mode, int, S_IRUGO); MODULE_PARM_DESC(led_mode, "0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking"); +/* Throughput OFF time(ms) ON time (ms) + * >300 25 25 + * >200 to 300 40 40 + * >100 to 200 55 55 + * >70 to 100 65 65 + * >50 to 70 75 75 + * >20 to 50 85 85 + * >10 to 20 95 95 + * >5 to 10 110 110 + * >1 to 5 130 130 + * >0 to 1 167 167 + * <=0 SOLID ON + */ static const struct ieee80211_tpt_blink iwl_blink[] = { - { .throughput = 0 * 1024 - 1, .blink_time = 334 }, + { .throughput = 0, .blink_time = 334 }, { .throughput = 1 * 1024 - 1, .blink_time = 260 }, { .throughput = 5 * 1024 - 1, .blink_time = 220 }, { .throughput = 10 * 1024 - 1, .blink_time = 190 }, @@ -61,10 +74,16 @@ static const struct ieee80211_tpt_blink iwl_blink[] = { { .throughput = 300 * 1024 - 1, .blink_time = 50 }, }; +/* Set led register off */ +void iwlagn_led_enable(struct iwl_priv *priv) +{ + iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); +} + /* * Adjust led blink rate to compensate on a MAC Clock difference on every HW - * Led blink rate analysis showed an average deviation of 0% on 3945, - * 5% on 4965 HW and 20% on 5000 series and up. + * Led blink rate analysis showed an average deviation of 20% on 5000 series + * and up. * Need to compensate on the led on/off time per HW according to the deviation * to achieve the desired led frequency * The calculation is: (100-averageDeviation)/100 * blinkTime @@ -84,6 +103,24 @@ static inline u8 iwl_blink_compensation(struct iwl_priv *priv, return (u8)((time * compensation) >> 6); } +static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl_led_cmd), + .data = led_cmd, + .flags = CMD_ASYNC, + .callback = NULL, + }; + u32 reg; + + reg = iwl_read32(priv, CSR_LED_REG); + if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) + iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); + + return iwl_send_cmd(priv, &cmd); +} + /* Set led pattern command */ static int iwl_led_cmd(struct iwl_priv *priv, unsigned long on, @@ -101,6 +138,11 @@ static int iwl_led_cmd(struct iwl_priv *priv, if (priv->blink_on == on && priv->blink_off == off) return 0; + if (off == 0) { + /* led is SOLID_ON */ + on = IWL_LED_SOLID; + } + IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n", priv->cfg->base_params->led_compensation); led_cmd.on = iwl_blink_compensation(priv, on, @@ -108,7 +150,7 @@ static int iwl_led_cmd(struct iwl_priv *priv, led_cmd.off = iwl_blink_compensation(priv, off, priv->cfg->base_params->led_compensation); - ret = priv->cfg->ops->led->cmd(priv, &led_cmd); + ret = iwl_send_led_cmd(priv, &led_cmd); if (!ret) { priv->blink_on = on; priv->blink_off = off; diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 101eef12b3bb..1c93dfef6933 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 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 @@ -50,6 +50,7 @@ enum iwl_led_mode { IWL_LED_BLINK, }; +void iwlagn_led_enable(struct iwl_priv *priv); void iwl_leds_init(struct iwl_priv *priv); void iwl_leds_exit(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 576795e2c75b..595c930b28ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -188,9 +188,10 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, table = range_0; } - BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); - - *cmd = table[lvl].cmd; + if (WARN_ON(lvl < 0 || lvl >= IWL_POWER_NUM)) + memset(cmd, 0, sizeof(*cmd)); + else + *cmd = table[lvl].cmd; if (period == 0) { skip = 0; @@ -354,16 +355,12 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, dtimper = priv->hw->conf.ps_dtim_period ?: 1; - if (priv->cfg->base_params->broken_powersave) - iwl_power_sleep_cam_cmd(priv, cmd); - else if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) + if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); - else if (priv->cfg->ops->lib->tt_ops.lower_power_detection && - priv->cfg->ops->lib->tt_ops.tt_power_mode && - priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) { + else if (iwl_tt_is_low_power_state(priv)) { /* in thermal throttling low power state */ iwl_static_sleep_cmd(priv, cmd, - priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper); + iwl_tt_current_power_mode(priv), dtimper); } else if (!enabled) iwl_power_sleep_cam_cmd(priv, cmd); else if (priv->power_data.debug_sleep_level_override >= 0) diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index fe012032c28c..59635d784e27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 86f5123bccda..f00d188b2cfc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -91,159 +91,12 @@ #define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) #define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) -#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */ #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) #define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ #define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) -/** - * BSM (Bootstrap State Machine) - * - * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program - * in special SRAM that does not power down when the embedded control - * processor is sleeping (e.g. for periodic power-saving shutdowns of radio). - * - * When powering back up after sleeps (or during initial uCode load), the BSM - * internally loads the short bootstrap program from the special SRAM into the - * embedded processor's instruction SRAM, and starts the processor so it runs - * the bootstrap program. - * - * This bootstrap program loads (via PCI busmaster DMA) instructions and data - * images for a uCode program from host DRAM locations. The host driver - * indicates DRAM locations and sizes for instruction and data images via the - * four BSM_DRAM_* registers. Once the bootstrap program loads the new program, - * the new program starts automatically. - * - * The uCode used for open-source drivers includes two programs: - * - * 1) Initialization -- performs hardware calibration and sets up some - * internal data, then notifies host via "initialize alive" notification - * (struct iwl_init_alive_resp) that it has completed all of its work. - * After signal from host, it then loads and starts the runtime program. - * The initialization program must be used when initially setting up the - * NIC after loading the driver. - * - * 2) Runtime/Protocol -- performs all normal runtime operations. This - * notifies host via "alive" notification (struct iwl_alive_resp) that it - * is ready to be used. - * - * When initializing the NIC, the host driver does the following procedure: - * - * 1) Load bootstrap program (instructions only, no data image for bootstrap) - * into bootstrap memory. Use dword writes starting at BSM_SRAM_LOWER_BOUND - * - * 2) Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction - * images in host DRAM. - * - * 3) Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked: - * BSM_WR_MEM_SRC_REG = 0 - * BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND - * BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image - * - * 4) Load bootstrap into instruction SRAM: - * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START - * - * 5) Wait for load completion: - * Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0 - * - * 6) Enable future boot loads whenever NIC's power management triggers it: - * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN - * - * 7) Start the NIC by removing all reset bits: - * CSR_RESET = 0 - * - * The bootstrap uCode (already in instruction SRAM) loads initialization - * uCode. Initialization uCode performs data initialization, sends - * "initialize alive" notification to host, and waits for a signal from - * host to load runtime code. - * - * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction - * images in host DRAM. The last register loaded must be the instruction - * byte count register ("1" in MSbit tells initialization uCode to load - * the runtime uCode): - * BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD - * - * 5) Wait for "alive" notification, then issue normal runtime commands. - * - * Data caching during power-downs: - * - * Just before the embedded controller powers down (e.g for automatic - * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA) - * a current snapshot of the embedded processor's data SRAM into host DRAM. - * This caches the data while the embedded processor's memory is powered down. - * Location and size are controlled by BSM_DRAM_DATA_* registers. - * - * NOTE: Instruction SRAM does not need to be saved, since that doesn't - * change during operation; the original image (from uCode distribution - * file) can be used for reload. - * - * When powering back up, the BSM loads the bootstrap program. Bootstrap looks - * at the BSM_DRAM_* registers, which now point to the runtime instruction - * image and the cached (modified) runtime data (*not* the initialization - * uCode). Bootstrap reloads these runtime images into SRAM, and restarts the - * uCode from where it left off before the power-down. - * - * NOTE: Initialization uCode does *not* run as part of the save/restore - * procedure. - * - * This save/restore method is mostly for autonomous power management during - * normal operation (result of POWER_TABLE_CMD). Platform suspend/resume and - * RFKILL should use complete restarts (with total re-initialization) of uCode, - * allowing total shutdown (including BSM memory). - * - * Note that, during normal operation, the host DRAM that held the initial - * startup data for the runtime code is now being used as a backup data cache - * for modified data! If you need to completely re-initialize the NIC, make - * sure that you use the runtime data image from the uCode distribution file, - * not the modified/saved runtime data. You may want to store a separate - * "clean" runtime data image in DRAM to avoid disk reads of distribution file. - */ - -/* BSM bit fields */ -#define BSM_WR_CTRL_REG_BIT_START (0x80000000) /* start boot load now */ -#define BSM_WR_CTRL_REG_BIT_START_EN (0x40000000) /* enable boot after pwrup*/ -#define BSM_DRAM_INST_LOAD (0x80000000) /* start program load now */ - -/* BSM addresses */ -#define BSM_BASE (PRPH_BASE + 0x3400) -#define BSM_END (PRPH_BASE + 0x3800) - -#define BSM_WR_CTRL_REG (BSM_BASE + 0x000) /* ctl and status */ -#define BSM_WR_MEM_SRC_REG (BSM_BASE + 0x004) /* source in BSM mem */ -#define BSM_WR_MEM_DST_REG (BSM_BASE + 0x008) /* dest in SRAM mem */ -#define BSM_WR_DWCOUNT_REG (BSM_BASE + 0x00C) /* bytes */ -#define BSM_WR_STATUS_REG (BSM_BASE + 0x010) /* bit 0: 1 == done */ - -/* - * Pointers and size regs for bootstrap load and data SRAM save/restore. - * NOTE: 3945 pointers use bits 31:0 of DRAM address. - * 4965 pointers use bits 35:4 of DRAM address. - */ -#define BSM_DRAM_INST_PTR_REG (BSM_BASE + 0x090) -#define BSM_DRAM_INST_BYTECOUNT_REG (BSM_BASE + 0x094) -#define BSM_DRAM_DATA_PTR_REG (BSM_BASE + 0x098) -#define BSM_DRAM_DATA_BYTECOUNT_REG (BSM_BASE + 0x09C) - -/* - * BSM special memory, stays powered on during power-save sleeps. - * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1) - */ -#define BSM_SRAM_LOWER_BOUND (PRPH_BASE + 0x3800) -#define BSM_SRAM_SIZE (1024) /* bytes */ - - -/* 3945 Tx scheduler registers */ -#define ALM_SCD_BASE (PRPH_BASE + 0x2E00) -#define ALM_SCD_MODE_REG (ALM_SCD_BASE + 0x000) -#define ALM_SCD_ARASTAT_REG (ALM_SCD_BASE + 0x004) -#define ALM_SCD_TXFACT_REG (ALM_SCD_BASE + 0x010) -#define ALM_SCD_TXF4MF_REG (ALM_SCD_BASE + 0x014) -#define ALM_SCD_TXF5MF_REG (ALM_SCD_BASE + 0x020) -#define ALM_SCD_SBYP_MODE_1_REG (ALM_SCD_BASE + 0x02C) -#define ALM_SCD_SBYP_MODE_2_REG (ALM_SCD_BASE + 0x030) - /** * Tx Scheduler * @@ -254,17 +107,7 @@ * device. A queue maps to only one (selectable by driver) Tx DMA channel, * but one DMA channel may take input from several queues. * - * Tx DMA FIFOs have dedicated purposes. For 4965, they are used as follows - * (cf. default_queue_to_tx_fifo in iwl-4965.c): - * - * 0 -- EDCA BK (background) frames, lowest priority - * 1 -- EDCA BE (best effort) frames, normal priority - * 2 -- EDCA VI (video) frames, higher priority - * 3 -- EDCA VO (voice) and management frames, highest priority - * 4 -- Commands (e.g. RXON, etc.) - * 5 -- unused (HCCA) - * 6 -- unused (HCCA) - * 7 -- not used by driver (device-internal only) + * Tx DMA FIFOs have dedicated purposes. * * For 5000 series and up, they are used differently * (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c): @@ -298,7 +141,7 @@ * Tx completion may end up being out-of-order). * * The driver must maintain the queue's Byte Count table in host DRAM - * (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode. + * for this mode. * This mode does not support fragmentation. * * 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order. @@ -311,7 +154,7 @@ * * Driver controls scheduler operation via 3 means: * 1) Scheduler registers - * 2) Shared scheduler data base in internal 4956 SRAM + * 2) Shared scheduler data base in internal SRAM * 3) Shared data in host DRAM * * Initialization: @@ -330,201 +173,10 @@ * Max Tx window size is the max number of contiguous TFDs that the scheduler * can keep track of at one time when creating block-ack chains of frames. * Note that "64" matches the number of ack bits in a block-ack packet. - * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize - * IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) values. */ #define SCD_WIN_SIZE 64 #define SCD_FRAME_LIMIT 64 -/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */ -#define IWL49_SCD_START_OFFSET 0xa02c00 - -/* - * 4965 tells driver SRAM address for internal scheduler structs via this reg. - * Value is valid only after "Alive" response from uCode. - */ -#define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x0) - -/* - * Driver may need to update queue-empty bits after changing queue's - * write and read pointers (indexes) during (re-)initialization (i.e. when - * scheduler is not tracking what's happening). - * Bit fields: - * 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit - * 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty - * NOTE: This register is not used by Linux driver. - */ -#define IWL49_SCD_EMPTY_BITS (IWL49_SCD_START_OFFSET + 0x4) - -/* - * Physical base address of array of byte count (BC) circular buffers (CBs). - * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode. - * This register points to BC CB for queue 0, must be on 1024-byte boundary. - * Others are spaced by 1024 bytes. - * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad. - * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff). - * Bit fields: - * 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned. - */ -#define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x10) - -/* - * Enables any/all Tx DMA/FIFO channels. - * Scheduler generates requests for only the active channels. - * Set this to 0xff to enable all 8 channels (normal usage). - * Bit fields: - * 7- 0: Enable (1), disable (0), one bit for each channel 0-7 - */ -#define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c) -/* - * Queue (x) Write Pointers (indexes, really!), one for each Tx queue. - * Initialized and updated by driver as new TFDs are added to queue. - * NOTE: If using Block Ack, index must correspond to frame's - * Start Sequence Number; index = (SSN & 0xff) - * NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses? - */ -#define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_START_OFFSET + 0x24 + (x) * 4) - -/* - * Queue (x) Read Pointers (indexes, really!), one for each Tx queue. - * For FIFO mode, index indicates next frame to transmit. - * For Scheduler-ACK mode, index indicates first frame in Tx window. - * Initialized by driver, updated by scheduler. - */ -#define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_START_OFFSET + 0x64 + (x) * 4) - -/* - * Select which queues work in chain mode (1) vs. not (0). - * Use chain mode to build chains of aggregated frames. - * Bit fields: - * 31-16: Reserved - * 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time - * NOTE: If driver sets up queue for chain mode, it should be also set up - * Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x). - */ -#define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_START_OFFSET + 0xd0) - -/* - * Select which queues interrupt driver when scheduler increments - * a queue's read pointer (index). - * Bit fields: - * 31-16: Reserved - * 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled - * NOTE: This functionality is apparently a no-op; driver relies on interrupts - * from Rx queue to read Tx command responses and update Tx queues. - */ -#define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_START_OFFSET + 0xe4) - -/* - * Queue search status registers. One for each queue. - * Sets up queue mode and assigns queue to Tx DMA channel. - * Bit fields: - * 19-10: Write mask/enable bits for bits 0-9 - * 9: Driver should init to "0" - * 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0). - * Driver should init to "1" for aggregation mode, or "0" otherwise. - * 7-6: Driver should init to "0" - * 5: Window Size Left; indicates whether scheduler can request - * another TFD, based on window size, etc. Driver should init - * this bit to "1" for aggregation mode, or "0" for non-agg. - * 4-1: Tx FIFO to use (range 0-7). - * 0: Queue is active (1), not active (0). - * Other bits should be written as "0" - * - * NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled - * via SCD_QUEUECHAIN_SEL. - */ -#define IWL49_SCD_QUEUE_STATUS_BITS(x)\ - (IWL49_SCD_START_OFFSET + 0x104 + (x) * 4) - -/* Bit field positions */ -#define IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE (0) -#define IWL49_SCD_QUEUE_STTS_REG_POS_TXF (1) -#define IWL49_SCD_QUEUE_STTS_REG_POS_WSL (5) -#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) - -/* Write masks */ -#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) -#define IWL49_SCD_QUEUE_STTS_REG_MSK (0x0007FC00) - -/** - * 4965 internal SRAM structures for scheduler, shared with driver ... - * - * Driver should clear and initialize the following areas after receiving - * "Alive" response from 4965 uCode, i.e. after initial - * uCode load, or after a uCode load done for error recovery: - * - * SCD_CONTEXT_DATA_OFFSET (size 128 bytes) - * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes) - * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes) - * - * Driver accesses SRAM via HBUS_TARG_MEM_* registers. - * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR. - * All OFFSET values must be added to this base address. - */ - -/* - * Queue context. One 8-byte entry for each of 16 queues. - * - * Driver should clear this entire area (size 0x80) to 0 after receiving - * "Alive" notification from uCode. Additionally, driver should init - * each queue's entry as follows: - * - * LS Dword bit fields: - * 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64. - * - * MS Dword bit fields: - * 16-22: Frame limit. Driver should init to 10 (0xa). - * - * Driver should init all other bits to 0. - * - * Init must be done after driver receives "Alive" response from 4965 uCode, - * and when setting up queue for aggregation. - */ -#define IWL49_SCD_CONTEXT_DATA_OFFSET 0x380 -#define IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) \ - (IWL49_SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) - -#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) -#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) -#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) -#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) - -/* - * Tx Status Bitmap - * - * Driver should clear this entire area (size 0x100) to 0 after receiving - * "Alive" notification from uCode. Area is used only by device itself; - * no other support (besides clearing) is required from driver. - */ -#define IWL49_SCD_TX_STTS_BITMAP_OFFSET 0x400 - -/* - * RAxTID to queue translation mapping. - * - * When queue is in Scheduler-ACK mode, frames placed in a that queue must be - * for only one combination of receiver address (RA) and traffic ID (TID), i.e. - * one QOS priority level destined for one station (for this wireless link, - * not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit - * mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK - * mode, the device ignores the mapping value. - * - * Bit fields, for each 16-bit map: - * 15-9: Reserved, set to 0 - * 8-4: Index into device's station table for recipient station - * 3-0: Traffic ID (tid), range 0-15 - * - * Driver should clear this entire area (size 32 bytes) to 0 after receiving - * "Alive" notification from uCode. To update a 16-bit map value, driver - * must read a dword-aligned value from device SRAM, replace the 16-bit map - * value of interest, and write the dword value back into device SRAM. - */ -#define IWL49_SCD_TRANSLATE_TBL_OFFSET 0x500 - -/* Find translation table dword to read/write for given queue */ -#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ - ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) - #define IWL_SCD_TXFIFO_POS_TID (0) #define IWL_SCD_TXFIFO_POS_RA (4) #define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 6f9a2fa04763..0053e9ea9021 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -225,55 +225,6 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) * ******************************************************************************/ -static void iwl_rx_reply_alive(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_alive_resp *palive; - struct delayed_work *pwork; - - palive = &pkt->u.alive_frame; - - IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " - "0x%01X 0x%01X\n", - palive->is_valid, palive->ver_type, - palive->ver_subtype); - - if (palive->ver_subtype == INITIALIZE_SUBTYPE) { - IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - memcpy(&priv->card_alive_init, - &pkt->u.alive_frame, - sizeof(struct iwl_init_alive_resp)); - pwork = &priv->init_alive_start; - } else { - IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - memcpy(&priv->card_alive, &pkt->u.alive_frame, - sizeof(struct iwl_alive_resp)); - pwork = &priv->alive_start; - } - - /* We delay the ALIVE response by 5ms to - * give the HW RF Kill time to activate... */ - if (palive->is_valid == UCODE_VALID_OK) - queue_delayed_work(priv->workqueue, pwork, - msecs_to_jiffies(5)); - else { - IWL_WARN(priv, "%s uCode did not respond OK.\n", - (palive->ver_subtype == INITIALIZE_SUBTYPE) ? - "init" : "runtime"); - /* - * If fail to load init uCode, - * let's try to load the init uCode again. - * We should not get into this situation, but if it - * does happen, we should not move on and loading "runtime" - * without proper calibrate the device. - */ - if (palive->ver_subtype == INITIALIZE_SUBTYPE) - priv->ucode_type = UCODE_NONE; - queue_work(priv->workqueue, &priv->restart); - } -} - static void iwl_rx_reply_error(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -390,21 +341,16 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv, * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal * operation state. */ -static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt) +static bool iwl_good_ack_health(struct iwl_priv *priv, + struct statistics_tx *cur) { int actual_delta, expected_delta, ba_timeout_delta; - struct statistics_tx *cur, *old; + struct statistics_tx *old; if (priv->_agn.agg_tids_count) return true; - if (iwl_bt_statistics(priv)) { - cur = &pkt->u.stats_bt.tx; - old = &priv->_agn.statistics_bt.tx; - } else { - cur = &pkt->u.stats.tx; - old = &priv->_agn.statistics.tx; - } + old = &priv->statistics.tx; actual_delta = le32_to_cpu(cur->actual_ack_cnt) - le32_to_cpu(old->actual_ack_cnt); @@ -430,10 +376,10 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt * DEBUG is not, these will just compile out. */ IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n", - priv->_agn.delta_statistics.tx.rx_detected_cnt); + priv->delta_stats.tx.rx_detected_cnt); IWL_DEBUG_RADIO(priv, "ack_or_ba_timeout_collision delta %d\n", - priv->_agn.delta_statistics.tx.ack_or_ba_timeout_collision); + priv->delta_stats.tx.ack_or_ba_timeout_collision); #endif if (ba_timeout_delta >= BA_TIMEOUT_MAX) @@ -450,7 +396,9 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt * to improve the throughput. */ static bool iwl_good_plcp_health(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, unsigned int msecs) + struct statistics_rx_phy *cur_ofdm, + struct statistics_rx_ht_phy *cur_ofdm_ht, + unsigned int msecs) { int delta; int threshold = priv->cfg->base_params->plcp_delta_threshold; @@ -460,29 +408,12 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv, return true; } - if (iwl_bt_statistics(priv)) { - struct statistics_rx_bt *cur, *old; + delta = le32_to_cpu(cur_ofdm->plcp_err) - + le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) + + le32_to_cpu(cur_ofdm_ht->plcp_err) - + le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err); - cur = &pkt->u.stats_bt.rx; - old = &priv->_agn.statistics_bt.rx; - - delta = le32_to_cpu(cur->ofdm.plcp_err) - - le32_to_cpu(old->ofdm.plcp_err) + - le32_to_cpu(cur->ofdm_ht.plcp_err) - - le32_to_cpu(old->ofdm_ht.plcp_err); - } else { - struct statistics_rx *cur, *old; - - cur = &pkt->u.stats.rx; - old = &priv->_agn.statistics.rx; - - delta = le32_to_cpu(cur->ofdm.plcp_err) - - le32_to_cpu(old->ofdm.plcp_err) + - le32_to_cpu(cur->ofdm_ht.plcp_err) - - le32_to_cpu(old->ofdm_ht.plcp_err); - } - - /* Can be negative if firmware reseted statistics */ + /* Can be negative if firmware reset statistics */ if (delta <= 0) return true; @@ -497,44 +428,35 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv, } static void iwl_recover_from_statistics(struct iwl_priv *priv, - struct iwl_rx_packet *pkt) + struct statistics_rx_phy *cur_ofdm, + struct statistics_rx_ht_phy *cur_ofdm_ht, + struct statistics_tx *tx, + unsigned long stamp) { - const struct iwl_mod_params *mod_params = priv->cfg->mod_params; unsigned int msecs; - unsigned long stamp; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - stamp = jiffies; msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies); /* Only gather statistics and update time stamp when not associated */ if (!iwl_is_any_associated(priv)) - goto out; + return; /* Do not check/recover when do not have enough statistics data */ if (msecs < 99) return; - if (mod_params->ack_check && !iwl_good_ack_health(priv, pkt)) { + if (iwlagn_mod_params.ack_check && !iwl_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 (mod_params->plcp_check && !iwl_good_plcp_health(priv, pkt, msecs)) + if (iwlagn_mod_params.plcp_check && + !iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs)) iwl_force_reset(priv, IWL_RF_RESET, false); - -out: - if (iwl_bt_statistics(priv)) - memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt, - sizeof(priv->_agn.statistics_bt)); - else - memcpy(&priv->_agn.statistics, &pkt->u.stats, - sizeof(priv->_agn.statistics)); - - priv->rx_statistics_jiffies = stamp; } /* Calculate noise level, based on measurements during network silence just @@ -548,10 +470,8 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv) int bcn_silence_a, bcn_silence_b, bcn_silence_c; int last_rx_noise; - if (iwl_bt_statistics(priv)) - rx_info = &(priv->_agn.statistics_bt.rx.general.common); - else - rx_info = &(priv->_agn.statistics.rx.general); + rx_info = &priv->statistics.rx_non_phy; + bcn_silence_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; bcn_silence_b = @@ -583,105 +503,153 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv) last_rx_noise); } +#ifdef CONFIG_IWLWIFI_DEBUGFS /* * based on the assumption of all statistics counter are in DWORD * FIXME: This function is for debugging, do not deal with * the case of counters roll-over. */ -static void iwl_accumulative_statistics(struct iwl_priv *priv, - __le32 *stats) +static void accum_stats(__le32 *prev, __le32 *cur, __le32 *delta, + __le32 *max_delta, __le32 *accum, int size) { -#ifdef CONFIG_IWLWIFI_DEBUGFS - int i, size; - __le32 *prev_stats; - u32 *accum_stats; - u32 *delta, *max_delta; - struct statistics_general_common *general, *accum_general; - struct statistics_tx *tx, *accum_tx; + int i; - if (iwl_bt_statistics(priv)) { - prev_stats = (__le32 *)&priv->_agn.statistics_bt; - accum_stats = (u32 *)&priv->_agn.accum_statistics_bt; - size = sizeof(struct iwl_bt_notif_statistics); - general = &priv->_agn.statistics_bt.general.common; - accum_general = &priv->_agn.accum_statistics_bt.general.common; - tx = &priv->_agn.statistics_bt.tx; - accum_tx = &priv->_agn.accum_statistics_bt.tx; - delta = (u32 *)&priv->_agn.delta_statistics_bt; - max_delta = (u32 *)&priv->_agn.max_delta_bt; - } else { - prev_stats = (__le32 *)&priv->_agn.statistics; - accum_stats = (u32 *)&priv->_agn.accum_statistics; - size = sizeof(struct iwl_notif_statistics); - general = &priv->_agn.statistics.general.common; - accum_general = &priv->_agn.accum_statistics.general.common; - tx = &priv->_agn.statistics.tx; - accum_tx = &priv->_agn.accum_statistics.tx; - delta = (u32 *)&priv->_agn.delta_statistics; - max_delta = (u32 *)&priv->_agn.max_delta; - } - for (i = sizeof(__le32); i < size; - i += sizeof(__le32), stats++, prev_stats++, delta++, - max_delta++, accum_stats++) { - if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) { - *delta = (le32_to_cpu(*stats) - - le32_to_cpu(*prev_stats)); - *accum_stats += *delta; - if (*delta > *max_delta) + for (i = 0; + i < size / sizeof(__le32); + i++, prev++, cur++, delta++, max_delta++, accum++) { + if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) { + *delta = cpu_to_le32( + le32_to_cpu(*cur) - le32_to_cpu(*prev)); + le32_add_cpu(accum, le32_to_cpu(*delta)); + if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta)) *max_delta = *delta; } } - - /* reset accumulative statistics for "no-counter" type statistics */ - accum_general->temperature = general->temperature; - accum_general->temperature_m = general->temperature_m; - accum_general->ttl_timestamp = general->ttl_timestamp; - accum_tx->tx_power.ant_a = tx->tx_power.ant_a; - accum_tx->tx_power.ant_b = tx->tx_power.ant_b; - accum_tx->tx_power.ant_c = tx->tx_power.ant_c; -#endif } +static void +iwl_accumulative_statistics(struct iwl_priv *priv, + struct statistics_general_common *common, + struct statistics_rx_non_phy *rx_non_phy, + struct statistics_rx_phy *rx_ofdm, + struct statistics_rx_ht_phy *rx_ofdm_ht, + struct statistics_rx_phy *rx_cck, + struct statistics_tx *tx, + struct statistics_bt_activity *bt_activity) +{ +#define ACCUM(_name) \ + accum_stats((__le32 *)&priv->statistics._name, \ + (__le32 *)_name, \ + (__le32 *)&priv->delta_stats._name, \ + (__le32 *)&priv->max_delta_stats._name, \ + (__le32 *)&priv->accum_stats._name, \ + sizeof(*_name)); + + ACCUM(common); + ACCUM(rx_non_phy); + ACCUM(rx_ofdm); + ACCUM(rx_ofdm_ht); + ACCUM(rx_cck); + ACCUM(tx); + if (bt_activity) + ACCUM(bt_activity); +#undef ACCUM +} +#else +static inline void +iwl_accumulative_statistics(struct iwl_priv *priv, + struct statistics_general_common *common, + struct statistics_rx_non_phy *rx_non_phy, + struct statistics_rx_phy *rx_ofdm, + struct statistics_rx_ht_phy *rx_ofdm_ht, + struct statistics_rx_phy *rx_cck, + struct statistics_tx *tx, + struct statistics_bt_activity *bt_activity) +{ +} +#endif + static void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { + unsigned long stamp = jiffies; const int reg_recalib_period = 60; int change; struct iwl_rx_packet *pkt = rxb_addr(rxb); + u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + __le32 *flag; + struct statistics_general_common *common; + struct statistics_rx_non_phy *rx_non_phy; + struct statistics_rx_phy *rx_ofdm; + struct statistics_rx_ht_phy *rx_ofdm_ht; + struct statistics_rx_phy *rx_cck; + struct statistics_tx *tx; + struct statistics_bt_activity *bt_activity; - if (iwl_bt_statistics(priv)) { - IWL_DEBUG_RX(priv, - "Statistics notification received (%d vs %d).\n", - (int)sizeof(struct iwl_bt_notif_statistics), - le32_to_cpu(pkt->len_n_flags) & - FH_RSCSR_FRAME_SIZE_MSK); + len -= sizeof(struct iwl_cmd_header); /* skip header */ - change = ((priv->_agn.statistics_bt.general.common.temperature != - pkt->u.stats_bt.general.common.temperature) || - ((priv->_agn.statistics_bt.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK) != - (pkt->u.stats_bt.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK))); + IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n", + len); - iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt); + if (len == sizeof(struct iwl_bt_notif_statistics)) { + struct iwl_bt_notif_statistics *stats; + stats = &pkt->u.stats_bt; + flag = &stats->flag; + common = &stats->general.common; + rx_non_phy = &stats->rx.general.common; + rx_ofdm = &stats->rx.ofdm; + rx_ofdm_ht = &stats->rx.ofdm_ht; + rx_cck = &stats->rx.cck; + tx = &stats->tx; + bt_activity = &stats->general.activity; + +#ifdef CONFIG_IWLWIFI_DEBUGFS + /* handle this exception directly */ + priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills; + le32_add_cpu(&priv->statistics.accum_num_bt_kills, + le32_to_cpu(stats->rx.general.num_bt_kills)); +#endif + } else if (len == sizeof(struct iwl_notif_statistics)) { + struct iwl_notif_statistics *stats; + stats = &pkt->u.stats; + flag = &stats->flag; + common = &stats->general.common; + rx_non_phy = &stats->rx.general; + rx_ofdm = &stats->rx.ofdm; + rx_ofdm_ht = &stats->rx.ofdm_ht; + rx_cck = &stats->rx.cck; + tx = &stats->tx; + bt_activity = NULL; } else { - IWL_DEBUG_RX(priv, - "Statistics notification received (%d vs %d).\n", - (int)sizeof(struct iwl_notif_statistics), - le32_to_cpu(pkt->len_n_flags) & - FH_RSCSR_FRAME_SIZE_MSK); - - change = ((priv->_agn.statistics.general.common.temperature != - pkt->u.stats.general.common.temperature) || - ((priv->_agn.statistics.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK) != - (pkt->u.stats.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK))); - - iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); + WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n", + len, sizeof(struct iwl_bt_notif_statistics), + sizeof(struct iwl_notif_statistics)); + return; } - iwl_recover_from_statistics(priv, pkt); + change = common->temperature != priv->statistics.common.temperature || + (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) != + (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK); + + iwl_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm, + rx_ofdm_ht, rx_cck, tx, bt_activity); + + iwl_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp); + + priv->statistics.flag = *flag; + memcpy(&priv->statistics.common, common, sizeof(*common)); + memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy)); + memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm)); + memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht)); + memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck)); + memcpy(&priv->statistics.tx, tx, sizeof(*tx)); +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (bt_activity) + memcpy(&priv->statistics.bt_activity, bt_activity, + sizeof(*bt_activity)); +#endif + + priv->rx_statistics_jiffies = stamp; set_bit(STATUS_STATISTICS, &priv->status); @@ -708,18 +676,12 @@ static void iwl_rx_reply_statistics(struct iwl_priv *priv, if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { #ifdef CONFIG_IWLWIFI_DEBUGFS - memset(&priv->_agn.accum_statistics, 0, - sizeof(struct iwl_notif_statistics)); - memset(&priv->_agn.delta_statistics, 0, - sizeof(struct iwl_notif_statistics)); - memset(&priv->_agn.max_delta, 0, - sizeof(struct iwl_notif_statistics)); - memset(&priv->_agn.accum_statistics_bt, 0, - sizeof(struct iwl_bt_notif_statistics)); - memset(&priv->_agn.delta_statistics_bt, 0, - sizeof(struct iwl_bt_notif_statistics)); - memset(&priv->_agn.max_delta_bt, 0, - sizeof(struct iwl_bt_notif_statistics)); + memset(&priv->accum_stats, 0, + sizeof(priv->accum_stats)); + memset(&priv->delta_stats, 0, + sizeof(priv->delta_stats)); + memset(&priv->max_delta_stats, 0, + sizeof(priv->max_delta_stats)); #endif IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); } @@ -873,6 +835,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, { struct sk_buff *skb; __le16 fc = hdr->frame_control; + struct iwl_rxon_context *ctx; /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { @@ -882,7 +845,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, } /* In case of HW accelerated crypto and bad decryption, drop */ - if (!priv->cfg->mod_params->sw_crypto && + if (!iwlagn_mod_params.sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; @@ -895,10 +858,29 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); iwl_update_stats(priv, false, fc, len); + + /* + * Wake any queues that were stopped due to a passive channel tx + * failure. This can happen because the regulatory enforcement in + * the device waits for a beacon before allowing transmission, + * sometimes even after already having transmitted frames for the + * association because the new RXON may reset the information. + */ + if (unlikely(ieee80211_is_beacon(fc))) { + for_each_context(priv, ctx) { + if (!ctx->last_tx_rejected) + continue; + if (compare_ether_addr(hdr->addr3, + ctx->active.bssid_addr)) + continue; + ctx->last_tx_rejected = false; + iwl_wake_any_queue(priv, ctx); + } + } + memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); ieee80211_rx(priv->hw, skb); - priv->alloc_rxb_page--; rxb->page = NULL; } @@ -1093,7 +1075,6 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) handlers = priv->rx_handlers; - handlers[REPLY_ALIVE] = iwl_rx_reply_alive; handlers[REPLY_ERROR] = iwl_rx_reply_error; handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; handlers[SPECTRUM_MEASURE_NOTIFICATION] = iwl_rx_spectrum_measure_notif; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 914c77e44588..d60d630cb93a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 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 diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h deleted file mode 100644 index c4ca0b5d77da..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ /dev/null @@ -1,92 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ieee80211 subsystem header files. - * - * 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 - * - *****************************************************************************/ - -#ifndef __iwl_spectrum_h__ -#define __iwl_spectrum_h__ -enum { /* ieee80211_basic_report.map */ - IEEE80211_BASIC_MAP_BSS = (1 << 0), - IEEE80211_BASIC_MAP_OFDM = (1 << 1), - IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2), - IEEE80211_BASIC_MAP_RADAR = (1 << 3), - IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4), - /* Bits 5-7 are reserved */ - -}; -struct ieee80211_basic_report { - u8 channel; - __le64 start_time; - __le16 duration; - u8 map; -} __packed; - -enum { /* ieee80211_measurement_request.mode */ - /* Bit 0 is reserved */ - IEEE80211_MEASUREMENT_ENABLE = (1 << 1), - IEEE80211_MEASUREMENT_REQUEST = (1 << 2), - IEEE80211_MEASUREMENT_REPORT = (1 << 3), - /* Bits 4-7 are reserved */ -}; - -enum { - IEEE80211_REPORT_BASIC = 0, /* required */ - IEEE80211_REPORT_CCA = 1, /* optional */ - IEEE80211_REPORT_RPI = 2, /* optional */ - /* 3-255 reserved */ -}; - -struct ieee80211_measurement_params { - u8 channel; - __le64 start_time; - __le16 duration; -} __packed; - -struct ieee80211_info_element { - u8 id; - u8 len; - u8 data[0]; -} __packed; - -struct ieee80211_measurement_request { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - struct ieee80211_measurement_params params[0]; -} __packed; - -struct ieee80211_measurement_report { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - union { - struct ieee80211_basic_report basic[0]; - } u; -} __packed; - -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index bc90a12408a3..3c8cebde16cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -233,7 +233,6 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct iwl_station_entry *station; int i; u8 sta_id = IWL_INVALID_STATION; - u16 rate; if (is_ap) sta_id = ctx->ap_sta_id; @@ -306,12 +305,6 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, */ iwl_set_ht_add_station(priv, sta_id, sta, ctx); - /* 3945 only */ - rate = (priv->band == IEEE80211_BAND_5GHZ) ? - IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP; - /* Turn on both antennas for the station... */ - station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); - return sta_id; } @@ -501,7 +494,8 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, priv->num_stations--; - BUG_ON(priv->num_stations < 0); + if (WARN_ON(priv->num_stations < 0)) + priv->num_stations = 0; spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -686,7 +680,8 @@ void iwl_dealloc_bcast_stations(struct iwl_priv *priv) priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; priv->num_stations--; - BUG_ON(priv->num_stations < 0); + if (WARN_ON(priv->num_stations < 0)) + priv->num_stations = 0; kfree(priv->stations[i].lq); priv->stations[i].lq = NULL; } @@ -782,7 +777,8 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, spin_unlock_irqrestore(&priv->sta_lock, flags_spin); iwl_dump_lq_cmd(priv, lq); - BUG_ON(init && (cmd.flags & CMD_ASYNC)); + if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) + return -EINVAL; if (is_lq_table_valid(priv, ctx, lq)) ret = iwl_send_cmd(priv, &cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 206f1e1a0caf..ff64027ff4cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-sv-open.c new file mode 100644 index 000000000000..89b6696622c1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-sv-open.c @@ -0,0 +1,469 @@ +/****************************************************************************** + * + * 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) 2010 - 2011 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) 2010 - 2011 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 +#include +#include +#include +#include +#include + + +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-debug.h" +#include "iwl-fh.h" +#include "iwl-io.h" +#include "iwl-agn.h" +#include "iwl-testmode.h" + + +/* The TLVs used in the gnl message policy between the kernel module and + * user space application. iwl_testmode_gnl_msg_policy is to be carried + * through the NL80211_CMD_TESTMODE channel regulated by nl80211. + * See iwl-testmode.h + */ +static +struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = { + [IWL_TM_ATTR_COMMAND] = { .type = NLA_U32, }, + + [IWL_TM_ATTR_UCODE_CMD_ID] = { .type = NLA_U8, }, + [IWL_TM_ATTR_UCODE_CMD_DATA] = { .type = NLA_UNSPEC, }, + + [IWL_TM_ATTR_REG_OFFSET] = { .type = NLA_U32, }, + [IWL_TM_ATTR_REG_VALUE8] = { .type = NLA_U8, }, + [IWL_TM_ATTR_REG_VALUE32] = { .type = NLA_U32, }, + + [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, }, + [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, }, +}; + +/* + * See the struct iwl_rx_packet in iwl-commands.h for the format of the + * received events from the device + */ +static inline int get_event_length(struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + if (pkt) + return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + else + return 0; +} + + +/* + * This function multicasts the spontaneous messages from the device to the + * user space. It is invoked whenever there is a received messages + * from the device. This function is called within the ISR of the rx handlers + * in iwlagn driver. + * + * The parsing of the message content is left to the user space application, + * The message content is treated as unattacked raw data and is encapsulated + * with IWL_TM_ATTR_UCODE_RX_PKT multicasting to the user space. + * + * @priv: the instance of iwlwifi device + * @rxb: pointer to rx data content received by the ISR + * + * See the message policies and TLVs in iwl_testmode_gnl_msg_policy[]. + * For the messages multicasting to the user application, the mandatory + * TLV fields are : + * IWL_TM_ATTR_COMMAND must be IWL_TM_CMD_DEV2APP_UCODE_RX_PKT + * IWL_TM_ATTR_UCODE_RX_PKT for carrying the message content + */ + +static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct ieee80211_hw *hw = priv->hw; + struct sk_buff *skb; + void *data; + int length; + + data = (void *)rxb_addr(rxb); + length = get_event_length(rxb); + + if (!data || length == 0) + return; + + skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length, + GFP_ATOMIC); + if (skb == NULL) { + IWL_DEBUG_INFO(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); + NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, length, data); + cfg80211_testmode_event(skb, GFP_ATOMIC); + return; + +nla_put_failure: + kfree_skb(skb); + IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n"); +} + +void iwl_testmode_init(struct iwl_priv *priv) +{ + priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt; +} + +/* + * This function handles the user application commands to the ucode. + * + * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_CMD_ID and + * IWL_TM_ATTR_UCODE_CMD_DATA and calls to the handler to send the + * host command to the ucode. + * + * If any mandatory field is missing, -ENOMSG is replied to the user space + * application; otherwise, the actual execution result of the host command to + * ucode is replied. + * + * @hw: ieee80211_hw object that represents the device + * @tb: gnl message fields from the user space + */ +static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_host_cmd cmd; + + memset(&cmd, 0, sizeof(struct iwl_host_cmd)); + + if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] || + !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) { + IWL_DEBUG_INFO(priv, + "Error finding ucode command mandatory fields\n"); + return -ENOMSG; + } + + cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]); + cmd.data = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); + cmd.len = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); + IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," + " len %d\n", cmd.id, cmd.flags, cmd.len); + /* ok, let's submit the command to ucode */ + return iwl_send_cmd(priv, &cmd); +} + + +/* + * This function handles the user application commands for register access. + * + * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the + * handlers respectively. + * + * If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the + * mandatory fields(IWL_TM_ATTR_REG_OFFSET,IWL_TM_ATTR_REG_VALUE32, + * IWL_TM_ATTR_REG_VALUE8) are missing; Otherwise 0 is replied indicating + * the success of the command execution. + * + * If IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_READ32, the register read + * value is returned with IWL_TM_ATTR_REG_VALUE32. + * + * @hw: ieee80211_hw object that represents the device + * @tb: gnl message fields from the user space + */ +static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) +{ + struct iwl_priv *priv = hw->priv; + u32 ofs, val32; + u8 val8; + struct sk_buff *skb; + int status = 0; + + if (!tb[IWL_TM_ATTR_REG_OFFSET]) { + IWL_DEBUG_INFO(priv, "Error finding register offset\n"); + return -ENOMSG; + } + ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]); + IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs); + + switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { + case IWL_TM_CMD_APP2DEV_REG_READ32: + val32 = iwl_read32(priv, ofs); + IWL_INFO(priv, "32bit value to read 0x%x\n", val32); + + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); + if (!skb) { + IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + return -ENOMEM; + } + NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32); + status = cfg80211_testmode_reply(skb); + if (status < 0) + IWL_DEBUG_INFO(priv, + "Error sending msg : %d\n", status); + break; + case IWL_TM_CMD_APP2DEV_REG_WRITE32: + if (!tb[IWL_TM_ATTR_REG_VALUE32]) { + IWL_DEBUG_INFO(priv, + "Error finding value to write\n"); + return -ENOMSG; + } else { + val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); + IWL_INFO(priv, "32bit value to write 0x%x\n", val32); + iwl_write32(priv, ofs, val32); + } + break; + case IWL_TM_CMD_APP2DEV_REG_WRITE8: + if (!tb[IWL_TM_ATTR_REG_VALUE8]) { + IWL_DEBUG_INFO(priv, "Error finding value to write\n"); + return -ENOMSG; + } else { + val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]); + IWL_INFO(priv, "8bit value to write 0x%x\n", val8); + iwl_write8(priv, ofs, val8); + } + break; + default: + IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n"); + return -ENOSYS; + } + + return status; + +nla_put_failure: + kfree_skb(skb); + return -EMSGSIZE; +} + + +static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv) +{ + struct iwl_notification_wait calib_wait; + int ret; + + iwlagn_init_notification_wait(priv, &calib_wait, + CALIBRATION_COMPLETE_NOTIFICATION, + NULL, NULL); + ret = iwlagn_init_alive_start(priv); + if (ret) { + IWL_DEBUG_INFO(priv, + "Error configuring init calibration: %d\n", ret); + goto cfg_init_calib_error; + } + + ret = iwlagn_wait_notification(priv, &calib_wait, 2 * HZ); + if (ret) + IWL_DEBUG_INFO(priv, "Error detecting" + " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret); + return ret; + +cfg_init_calib_error: + iwlagn_remove_notification(priv, &calib_wait); + return ret; +} + +/* + * This function handles the user application commands for driver. + * + * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the + * handlers respectively. + * + * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned + * value of the actual command execution is replied to the user application. + * + * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP + * is used for carry the message while IWL_TM_ATTR_COMMAND must set to + * IWL_TM_CMD_DEV2APP_SYNC_RSP. + * + * @hw: ieee80211_hw object that represents the device + * @tb: gnl message fields from the user space + */ +static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) +{ + struct iwl_priv *priv = hw->priv; + struct sk_buff *skb; + unsigned char *rsp_data_ptr = NULL; + int status = 0, rsp_data_len = 0; + + switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { + case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: + 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_DEBUG_INFO(priv, + "Error allocating memory\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); + status = cfg80211_testmode_reply(skb); + if (status < 0) + IWL_DEBUG_INFO(priv, "Error sending msg : %d\n", + status); + break; + + case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: + status = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init, + UCODE_SUBTYPE_INIT, -1); + if (status) + IWL_DEBUG_INFO(priv, + "Error loading init ucode: %d\n", status); + break; + + case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: + iwl_testmode_cfg_init_calib(priv); + iwlagn_stop_device(priv); + break; + + case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: + status = iwlagn_load_ucode_wait_alive(priv, + &priv->ucode_rt, + UCODE_SUBTYPE_REGULAR, + UCODE_SUBTYPE_REGULAR_NEW); + if (status) { + IWL_DEBUG_INFO(priv, + "Error loading runtime ucode: %d\n", status); + break; + } + status = iwl_alive_start(priv); + if (status) + IWL_DEBUG_INFO(priv, + "Error starting the device: %d\n", status); + break; + + default: + IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n"); + return -ENOSYS; + } + return status; + +nla_put_failure: + kfree_skb(skb); + return -EMSGSIZE; +} + +/* The testmode gnl message handler that takes the gnl message from the + * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then + * invoke the corresponding handlers. + * + * This function is invoked when there is user space application sending + * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated + * by nl80211. + * + * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before + * dispatching it to the corresponding handler. + * + * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application; + * -ENOSYS is replied to the user application if the command is unknown; + * Otherwise, the command is dispatched to the respective handler. + * + * @hw: ieee80211_hw object that represents the device + * @data: pointer to user space message + * @len: length in byte of @data + */ +int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) +{ + struct nlattr *tb[IWL_TM_ATTR_MAX - 1]; + struct iwl_priv *priv = hw->priv; + int result; + + result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len, + iwl_testmode_gnl_msg_policy); + if (result != 0) { + IWL_DEBUG_INFO(priv, + "Error parsing the gnl message : %d\n", result); + return result; + } + + /* IWL_TM_ATTR_COMMAND is absolutely mandatory */ + if (!tb[IWL_TM_ATTR_COMMAND]) { + IWL_DEBUG_INFO(priv, "Error finding testmode command type\n"); + return -ENOMSG; + } + /* in case multiple accesses to the device happens */ + mutex_lock(&priv->mutex); + + switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { + case IWL_TM_CMD_APP2DEV_UCODE: + IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n"); + result = iwl_testmode_ucode(hw, tb); + break; + case IWL_TM_CMD_APP2DEV_REG_READ32: + case IWL_TM_CMD_APP2DEV_REG_WRITE32: + case IWL_TM_CMD_APP2DEV_REG_WRITE8: + IWL_DEBUG_INFO(priv, "testmode cmd to register\n"); + result = iwl_testmode_reg(hw, tb); + break; + case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: + case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: + case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: + case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: + IWL_DEBUG_INFO(priv, "testmode cmd to driver\n"); + result = iwl_testmode_driver(hw, tb); + break; + default: + IWL_DEBUG_INFO(priv, "Unknown testmode command\n"); + result = -ENOSYS; + break; + } + + mutex_unlock(&priv->mutex); + return result; +} diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h new file mode 100644 index 000000000000..31f8949f2801 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * 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) 2010 - 2011 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) 2010 - 2011 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_TESTMODE_H__ +#define __IWL_TESTMODE_H__ + +#include + + +/* Commands from user space to kernel space(IWL_TM_CMD_ID_APP2DEV_XX) and + * from and kernel space to user space(IWL_TM_CMD_ID_DEV2APP_XX). + * The command ID is carried with IWL_TM_ATTR_COMMAND. There are three types of + * of command from user space and two types of command from kernel space. + * See below. + */ +enum iwl_tm_cmd_t { + /* commands from user application to the uCode, + * the actual uCode host command ID is carried with + * IWL_TM_ATTR_UCODE_CMD_ID */ + IWL_TM_CMD_APP2DEV_UCODE = 1, + + /* commands from user applicaiton to access register */ + IWL_TM_CMD_APP2DEV_REG_READ32, + IWL_TM_CMD_APP2DEV_REG_WRITE32, + IWL_TM_CMD_APP2DEV_REG_WRITE8, + + /* commands fom user space for pure driver level operations */ + IWL_TM_CMD_APP2DEV_GET_DEVICENAME, + IWL_TM_CMD_APP2DEV_LOAD_INIT_FW, + IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB, + IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW, + /* if there is other new command for the driver layer operation, + * append them here */ + + + /* commands from kernel space to carry the synchronous response + * to user application */ + IWL_TM_CMD_DEV2APP_SYNC_RSP, + + /* commands from kernel space to multicast the spontaneous messages + * to user application */ + IWL_TM_CMD_DEV2APP_UCODE_RX_PKT, + IWL_TM_CMD_MAX, +}; + +enum iwl_tm_attr_t { + IWL_TM_ATTR_NOT_APPLICABLE = 0, + + /* From user space to kernel space: + * the command either destines to ucode, driver, or register; + * See enum iwl_tm_cmd_t. + * + * From kernel space to user space: + * the command either carries synchronous response, + * or the spontaneous message multicast from the device; + * See enum iwl_tm_cmd_t. */ + IWL_TM_ATTR_COMMAND, + + /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE, + * The mandatory fields are : + * IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID; + * IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands; + * The optional fields are: + * IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload + * to the ucode */ + IWL_TM_ATTR_UCODE_CMD_ID, + IWL_TM_ATTR_UCODE_CMD_DATA, + + /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_XXX, + * The mandatory fields are: + * IWL_TM_ATTR_REG_OFFSET for the offset of the target register; + * IWL_TM_ATTR_REG_VALUE8 or IWL_TM_ATTR_REG_VALUE32 for value */ + IWL_TM_ATTR_REG_OFFSET, + IWL_TM_ATTR_REG_VALUE8, + IWL_TM_ATTR_REG_VALUE32, + + /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_SYNC_RSP, + * The mandatory fields are: + * IWL_TM_ATTR_SYNC_RSP for the data content responding to the user + * application command */ + IWL_TM_ATTR_SYNC_RSP, + /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_UCODE_RX_PKT, + * The mandatory fields are: + * IWL_TM_ATTR_UCODE_RX_PKT for the data content multicast to the user + * application */ + IWL_TM_ATTR_UCODE_RX_PKT, + + IWL_TM_ATTR_MAX, +}; + + +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 277c9175dcf6..e69597ea43e2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -149,32 +149,31 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv) struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; struct iwl_queue *q = &txq->q; int i; - bool huge = false; if (q->n_bd == 0) return; while (q->read_ptr != q->write_ptr) { - /* we have no way to tell if it is a huge cmd ATM */ i = get_cmd_index(q, q->read_ptr, 0); - if (txq->meta[i].flags & CMD_SIZE_HUGE) - huge = true; - else + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; + } - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); } - if (huge) { - i = q->n_window; + i = q->n_window; + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; } } @@ -233,7 +232,6 @@ void iwl_cmd_queue_free(struct iwl_priv *priv) * reclaiming packets (on 'tx done IRQ), if free space become > high mark, * Tx queue resumed. * - * See more detailed info in iwl-4965-hw.h. ***************************************************/ int iwl_queue_space(const struct iwl_queue *q) @@ -265,11 +263,13 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, /* count must be power-of-two size, otherwise iwl_queue_inc_wrap * and iwl_queue_dec_wrap are broken. */ - BUG_ON(!is_power_of_2(count)); + if (WARN_ON(!is_power_of_2(count))) + return -EINVAL; /* slots_num must be power-of-two size, otherwise * get_cmd_index is broken. */ - BUG_ON(!is_power_of_2(slots_num)); + if (WARN_ON(!is_power_of_2(slots_num))) + return -EINVAL; q->low_mark = q->n_window / 4; if (q->low_mark < 4) @@ -386,7 +386,9 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); /* Initialize queue's high/low-water marks, and head/tail indexes */ - iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + if (ret) + return ret; /* Tell device where to find queue */ priv->cfg->ops->lib->txq_init(priv, txq); @@ -440,22 +442,25 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) struct iwl_cmd_meta *out_meta; dma_addr_t phys_addr; unsigned long flags; - int len; u32 idx; u16 fix_size; bool is_ct_kill = false; - cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); - /* If any of the command structures end up being larger than + /* + * If any of the command structures end up being larger than * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then * we will need to increase the size of the TFD entries * Also, check to see if command buffer should not exceed the size - * of device_cmd and max_cmd_size. */ - BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && - !(cmd->flags & CMD_SIZE_HUGE)); - BUG_ON(fix_size > IWL_MAX_CMD_SIZE); + * of device_cmd and max_cmd_size. + */ + if (WARN_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && + !(cmd->flags & CMD_SIZE_HUGE))) + return -EINVAL; + + if (WARN_ON(fix_size > IWL_MAX_CMD_SIZE)) + return -EINVAL; if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) { IWL_WARN(priv, "Not sending command - %s KILL\n", @@ -463,35 +468,38 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } - if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { - IWL_ERR(priv, "No space in command queue\n"); - if (priv->cfg->ops->lib->tt_ops.ct_kill_check) { - is_ct_kill = - priv->cfg->ops->lib->tt_ops.ct_kill_check(priv); - } - if (!is_ct_kill) { - IWL_ERR(priv, "Restarting adapter due to queue full\n"); - queue_work(priv->workqueue, &priv->restart); - } - return -ENOSPC; - } + /* + * As we only have a single huge buffer, check that the command + * is synchronous (otherwise buffers could end up being reused). + */ + + if (WARN_ON((cmd->flags & CMD_ASYNC) && (cmd->flags & CMD_SIZE_HUGE))) + return -EINVAL; spin_lock_irqsave(&priv->hcmd_lock, flags); - /* If this is a huge cmd, mark the huge flag also on the meta.flags - * of the _original_ cmd. This is used for DMA mapping clean up. - */ - if (cmd->flags & CMD_SIZE_HUGE) { - idx = get_cmd_index(q, q->write_ptr, 0); - txq->meta[idx].flags = CMD_SIZE_HUGE; + if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + + IWL_ERR(priv, "No space in command queue\n"); + is_ct_kill = iwl_check_for_ct_kill(priv); + if (!is_ct_kill) { + IWL_ERR(priv, "Restarting adapter due to queue full\n"); + iwlagn_fw_error(priv, false); + } + return -ENOSPC; } idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); out_cmd = txq->cmd[idx]; out_meta = &txq->meta[idx]; + if (WARN_ON(out_meta->flags & CMD_MAPPED)) { + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return -ENOSPC; + } + memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ - out_meta->flags = cmd->flags; if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; if (cmd->flags & CMD_ASYNC) @@ -508,9 +516,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) INDEX_TO_SEQ(q->write_ptr)); if (cmd->flags & CMD_SIZE_HUGE) out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; - len = sizeof(struct iwl_device_cmd); - if (idx == TFD_CMD_SLOTS) - len = IWL_MAX_CMD_SIZE; #ifdef CONFIG_IWLWIFI_DEBUG switch (out_cmd->hdr.cmd) { @@ -532,17 +537,20 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) q->write_ptr, idx, priv->cmd_queue); } #endif - txq->need_update = 1; - - if (priv->cfg->ops->lib->txq_update_byte_cnt_tbl) - /* Set up entry in queue's byte count circular buffer */ - priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0); - phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr, fix_size, PCI_DMA_BIDIRECTIONAL); + if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) { + idx = -ENOMEM; + goto out; + } + dma_unmap_addr_set(out_meta, mapping, phys_addr); dma_unmap_len_set(out_meta, len, fix_size); + out_meta->flags = cmd->flags | CMD_MAPPED; + + txq->need_update = 1; + trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags); priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, @@ -553,6 +561,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); iwl_txq_update_write_ptr(priv, txq); + out: spin_unlock_irqrestore(&priv->hcmd_lock, flags); return idx; } @@ -584,7 +593,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, if (nfreed++ > 0) { IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx, q->write_ptr, q->read_ptr); - queue_work(priv->workqueue, &priv->restart); + iwlagn_fw_error(priv, false); } } @@ -609,6 +618,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_device_cmd *cmd; struct iwl_cmd_meta *meta; struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; + unsigned long flags; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -622,14 +632,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) return; } - /* If this is a huge cmd, clear the huge flag on the meta.flags - * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap - * the DMA buffer for the scan (huge) command. - */ - if (huge) { - cmd_index = get_cmd_index(&txq->q, index, 0); - txq->meta[cmd_index].flags = 0; - } cmd_index = get_cmd_index(&txq->q, index, huge); cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; @@ -646,6 +648,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) } else if (meta->callback) meta->callback(priv, cmd, pkt); + spin_lock_irqsave(&priv->hcmd_lock, flags); + iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); if (!(meta->flags & CMD_ASYNC)) { @@ -654,5 +658,9 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) get_cmd_string(cmd->hdr.cmd)); wake_up_interruptible(&priv->wait_command_queue); } + + /* Mark as unmapped */ meta->flags = 0; + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); } diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 9a57cf6a488f..5665a1a9b99e 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1576,7 +1576,8 @@ static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb) IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len); __skb_queue_head_init(&list); - ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0); + ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0, + true); while ((frame = __skb_dequeue(&list))) { ndev->stats.rx_packets++; diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 5caa2ac14d61..5d637af2d7c3 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -6,6 +6,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -122,8 +124,10 @@ static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type) } -/* Various firmware commands need the list of supported rates, but with - the hight-bit set for basic rates */ +/* + * Various firmware commands need the list of supported rates, but with + * the hight-bit set for basic rates + */ static int lbs_add_rates(u8 *rates) { size_t i; @@ -425,7 +429,7 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len) return ie_len + 2; } -/*************************************************************************** +/* * Set Channel */ @@ -452,7 +456,7 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy, -/*************************************************************************** +/* * Scanning */ @@ -538,8 +542,10 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, goto done; } - /* Validity check: the TLV holds TSF values with 8 bytes each, so - * the size in the TLV must match the nr_sets value */ + /* + * Validity check: the TLV holds TSF values with 8 bytes each, so + * the size in the TLV must match the nr_sets value + */ i = get_unaligned_le16(tsfdesc); tsfdesc += 2; if (i / 8 != scanresp->nr_sets) { @@ -581,8 +587,10 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, /* To find out the channel, we must parse the IEs */ ie = pos; - /* 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon - interval, capabilities */ + /* + * 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon + * interval, capabilities + */ ielen = left = len - (6 + 1 + 8 + 2 + 2); while (left >= 2) { u8 id, elen; @@ -790,7 +798,7 @@ static int lbs_cfg_scan(struct wiphy *wiphy, -/*************************************************************************** +/* * Events */ @@ -825,7 +833,7 @@ void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event) -/*************************************************************************** +/* * Connect/disconnect */ @@ -950,8 +958,10 @@ static int lbs_enable_rsn(struct lbs_private *priv, int enable) * Set WPA/WPA key material */ -/* like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we - * get rid of WEXT, this should go into host.h */ +/* + * like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we + * get rid of WEXT, this should go into host.h + */ struct cmd_key_material { struct cmd_header hdr; @@ -1314,8 +1324,8 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, sme->ssid, sme->ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); if (!bss) { - lbs_pr_err("assoc: bss %pM not in scan results\n", - sme->bssid); + wiphy_err(wiphy, "assoc: bss %pM not in scan results\n", + sme->bssid); ret = -ENOENT; goto done; } @@ -1372,8 +1382,8 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, lbs_enable_rsn(priv, sme->crypto.cipher_group != 0); break; default: - lbs_pr_err("unsupported cipher group 0x%x\n", - sme->crypto.cipher_group); + wiphy_err(wiphy, "unsupported cipher group 0x%x\n", + sme->crypto.cipher_group); ret = -ENOTSUPP; goto done; } @@ -1491,7 +1501,7 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev, params->key, params->key_len); break; default: - lbs_pr_err("unhandled cipher 0x%x\n", params->cipher); + wiphy_err(wiphy, "unhandled cipher 0x%x\n", params->cipher); ret = -ENOTSUPP; break; } @@ -1536,7 +1546,7 @@ static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev, } -/*************************************************************************** +/* * Get station */ @@ -1581,7 +1591,7 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, -/*************************************************************************** +/* * "Site survey", here just current channel and noise level */ @@ -1614,7 +1624,7 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev, -/*************************************************************************** +/* * Change interface */ @@ -1656,11 +1666,12 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev, -/*************************************************************************** +/* * IBSS (Ad-Hoc) */ -/* The firmware needs the following bits masked out of the beacon-derived +/* + * The firmware needs the following bits masked out of the beacon-derived * capability field when associating/joining to a BSS: * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused) */ @@ -1999,7 +2010,7 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) -/*************************************************************************** +/* * Initialization */ @@ -2118,13 +2129,13 @@ int lbs_cfg_register(struct lbs_private *priv) ret = wiphy_register(wdev->wiphy); if (ret < 0) - lbs_pr_err("cannot register wiphy device\n"); + pr_err("cannot register wiphy device\n"); priv->wiphy_registered = true; ret = register_netdev(priv->dev); if (ret) - lbs_pr_err("cannot register network device\n"); + pr_err("cannot register network device\n"); INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 7e8a658b7670..84566db486d2 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1,7 +1,7 @@ -/** - * This file contains the handling of command. - * It prepares command and sends it to firmware when it is ready. - */ +/* + * This file contains the handling of command. + * It prepares command and sends it to firmware when it is ready. + */ #include #include @@ -16,14 +16,14 @@ #define CAL_RSSI(snr, nf) ((s32)((s32)(snr) + CAL_NF(nf))) /** - * @brief Simple callback that copies response back into command + * lbs_cmd_copyback - Simple callback that copies response back into command * - * @param priv A pointer to struct lbs_private structure - * @param extra A pointer to the original command structure for which - * 'resp' is a response - * @param resp A pointer to the command response + * @priv: A pointer to &struct lbs_private structure + * @extra: A pointer to the original command structure for which + * 'resp' is a response + * @resp: A pointer to the command response * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, struct cmd_header *resp) @@ -38,15 +38,15 @@ int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, EXPORT_SYMBOL_GPL(lbs_cmd_copyback); /** - * @brief Simple callback that ignores the result. Use this if - * you just want to send a command to the hardware, but don't + * lbs_cmd_async_callback - Simple callback that ignores the result. + * Use this if you just want to send a command to the hardware, but don't * care for the result. * - * @param priv ignored - * @param extra ignored - * @param resp ignored + * @priv: ignored + * @extra: ignored + * @resp: ignored * - * @return 0 for success + * returns: 0 for success */ static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra, struct cmd_header *resp) @@ -56,10 +56,11 @@ static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra, /** - * @brief Checks whether a command is allowed in Power Save mode + * is_command_allowed_in_ps - tests if a command is allowed in Power Save mode * - * @param command the command ID - * @return 1 if allowed, 0 if not allowed + * @cmd: the command ID + * + * returns: 1 if allowed, 0 if not allowed */ static u8 is_command_allowed_in_ps(u16 cmd) { @@ -75,11 +76,12 @@ static u8 is_command_allowed_in_ps(u16 cmd) } /** - * @brief Updates the hardware details like MAC address and regulatory region + * lbs_update_hw_spec - Updates the hardware details like MAC address + * and regulatory region * - * @param priv A pointer to struct lbs_private structure + * @priv: A pointer to &struct lbs_private structure * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_update_hw_spec(struct lbs_private *priv) { @@ -108,7 +110,7 @@ int lbs_update_hw_spec(struct lbs_private *priv) * CF card firmware 5.0.16p0: cap 0x00000303 * USB dongle firmware 5.110.17p2: cap 0x00000303 */ - lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n", + netdev_info(priv->dev, "%pM, fw %u.%u.%up%u, cap 0x%08x\n", cmd.permanentaddr, priv->fwrelease >> 24 & 0xff, priv->fwrelease >> 16 & 0xff, @@ -139,7 +141,8 @@ int lbs_update_hw_spec(struct lbs_private *priv) /* if it's unidentified region code, use the default (USA) */ if (i >= MRVDRV_MAX_REGION_CODE) { priv->regioncode = 0x10; - lbs_pr_info("unidentified region code; using the default (USA)\n"); + netdev_info(priv->dev, + "unidentified region code; using the default (USA)\n"); } if (priv->current_addr[0] == 0xff) @@ -209,7 +212,7 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, (uint8_t *)&cmd_config.wol_conf, sizeof(struct wol_config)); } else { - lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret); + netdev_info(priv->dev, "HOST_SLEEP_CFG failed %d\n", ret); } return ret; @@ -217,14 +220,14 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg); /** - * @brief Sets the Power Save mode + * lbs_set_ps_mode - Sets the Power Save mode * - * @param priv A pointer to struct lbs_private structure - * @param cmd_action The Power Save operation (PS_MODE_ACTION_ENTER_PS or + * @priv: A pointer to &struct lbs_private structure + * @cmd_action: The Power Save operation (PS_MODE_ACTION_ENTER_PS or * PS_MODE_ACTION_EXIT_PS) - * @param block Whether to block on a response or not + * @block: Whether to block on a response or not * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block) { @@ -312,7 +315,7 @@ static int lbs_wait_for_ds_awake(struct lbs_private *priv) if (priv->is_deep_sleep) { if (!wait_event_interruptible_timeout(priv->ds_awake_q, !priv->is_deep_sleep, (10 * HZ))) { - lbs_pr_err("ds_awake_q: timer expired\n"); + netdev_err(priv->dev, "ds_awake_q: timer expired\n"); ret = -1; } } @@ -337,7 +340,7 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) netif_carrier_off(priv->dev); } } else { - lbs_pr_err("deep sleep: already enabled\n"); + netdev_err(priv->dev, "deep sleep: already enabled\n"); } } else { if (priv->is_deep_sleep) { @@ -347,8 +350,8 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) if (!ret) { ret = lbs_wait_for_ds_awake(priv); if (ret) - lbs_pr_err("deep sleep: wakeup" - "failed\n"); + netdev_err(priv->dev, + "deep sleep: wakeup failed\n"); } } } @@ -382,8 +385,9 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep) ret = lbs_host_sleep_cfg(priv, priv->wol_criteria, (struct wol_config *)NULL); if (ret) { - lbs_pr_info("Host sleep configuration failed: " - "%d\n", ret); + netdev_info(priv->dev, + "Host sleep configuration failed: %d\n", + ret); return ret; } if (priv->psstate == PS_STATE_FULL_POWER) { @@ -393,19 +397,21 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep) sizeof(cmd), lbs_ret_host_sleep_activate, 0); if (ret) - lbs_pr_info("HOST_SLEEP_ACTIVATE " - "failed: %d\n", ret); + netdev_info(priv->dev, + "HOST_SLEEP_ACTIVATE failed: %d\n", + ret); } if (!wait_event_interruptible_timeout( priv->host_sleep_q, priv->is_host_sleep_activated, (10 * HZ))) { - lbs_pr_err("host_sleep_q: timer expired\n"); + netdev_err(priv->dev, + "host_sleep_q: timer expired\n"); ret = -1; } } else { - lbs_pr_err("host sleep: already enabled\n"); + netdev_err(priv->dev, "host sleep: already enabled\n"); } } else { if (priv->is_host_sleep_activated) @@ -417,13 +423,13 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep) } /** - * @brief Set an SNMP MIB value + * lbs_set_snmp_mib - Set an SNMP MIB value * - * @param priv A pointer to struct lbs_private structure - * @param oid The OID to set in the firmware - * @param val Value to set the OID to + * @priv: A pointer to &struct lbs_private structure + * @oid: The OID to set in the firmware + * @val: Value to set the OID to * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val) { @@ -467,13 +473,13 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val) } /** - * @brief Get an SNMP MIB value + * lbs_get_snmp_mib - Get an SNMP MIB value * - * @param priv A pointer to struct lbs_private structure - * @param oid The OID to retrieve from the firmware - * @param out_val Location for the returned value + * @priv: A pointer to &struct lbs_private structure + * @oid: The OID to retrieve from the firmware + * @out_val: Location for the returned value * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val) { @@ -510,14 +516,14 @@ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val) } /** - * @brief Get the min, max, and current TX power + * lbs_get_tx_power - Get the min, max, and current TX power * - * @param priv A pointer to struct lbs_private structure - * @param curlevel Current power level in dBm - * @param minlevel Minimum supported power level in dBm (optional) - * @param maxlevel Maximum supported power level in dBm (optional) + * @priv: A pointer to &struct lbs_private structure + * @curlevel: Current power level in dBm + * @minlevel: Minimum supported power level in dBm (optional) + * @maxlevel: Maximum supported power level in dBm (optional) * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, s16 *maxlevel) @@ -545,12 +551,12 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, } /** - * @brief Set the TX power + * lbs_set_tx_power - Set the TX power * - * @param priv A pointer to struct lbs_private structure - * @param dbm The desired power level in dBm + * @priv: A pointer to &struct lbs_private structure + * @dbm: The desired power level in dBm * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) { @@ -573,12 +579,13 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) } /** - * @brief Enable or disable monitor mode (only implemented on OLPC usb8388 FW) + * lbs_set_monitor_mode - Enable or disable monitor mode + * (only implemented on OLPC usb8388 FW) * - * @param priv A pointer to struct lbs_private structure - * @param enable 1 to enable monitor mode, 0 to disable + * @priv: A pointer to &struct lbs_private structure + * @enable: 1 to enable monitor mode, 0 to disable * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_monitor_mode(struct lbs_private *priv, int enable) { @@ -604,11 +611,11 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable) } /** - * @brief Get the radio channel + * lbs_get_channel - Get the radio channel * - * @param priv A pointer to struct lbs_private structure + * @priv: A pointer to &struct lbs_private structure * - * @return The channel on success, error on failure + * returns: The channel on success, error on failure */ static int lbs_get_channel(struct lbs_private *priv) { @@ -650,12 +657,12 @@ int lbs_update_channel(struct lbs_private *priv) } /** - * @brief Set the radio channel + * lbs_set_channel - Set the radio channel * - * @param priv A pointer to struct lbs_private structure - * @param channel The desired channel, or 0 to clear a locked channel + * @priv: A pointer to &struct lbs_private structure + * @channel: The desired channel, or 0 to clear a locked channel * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_channel(struct lbs_private *priv, u8 channel) { @@ -686,12 +693,13 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel) } /** - * @brief Get current RSSI and noise floor + * lbs_get_rssi - Get current RSSI and noise floor * - * @param priv A pointer to struct lbs_private structure - * @param rssi On successful return, signal level in mBm + * @priv: A pointer to &struct lbs_private structure + * @rssi: On successful return, signal level in mBm + * @nf: On successful return, Noise floor * - * @return The channel on success, error on failure + * returns: The channel on success, error on failure */ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf) { @@ -719,13 +727,14 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf) } /** - * @brief Send regulatory and 802.11d domain information to the firmware + * lbs_set_11d_domain_info - Send regulatory and 802.11d domain information + * to the firmware * - * @param priv pointer to struct lbs_private - * @param request cfg80211 regulatory request structure - * @param bands the device's supported bands and channels + * @priv: pointer to &struct lbs_private + * @request: cfg80211 regulatory request structure + * @bands: the device's supported bands and channels * - * @return 0 on success, error code on failure + * returns: 0 on success, error code on failure */ int lbs_set_11d_domain_info(struct lbs_private *priv, struct regulatory_request *request, @@ -842,15 +851,15 @@ int lbs_set_11d_domain_info(struct lbs_private *priv, } /** - * @brief Read a MAC, Baseband, or RF register + * lbs_get_reg - Read a MAC, Baseband, or RF register * - * @param priv pointer to struct lbs_private - * @param cmd register command, one of CMD_MAC_REG_ACCESS, - * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS - * @param offset byte offset of the register to get - * @param value on success, the value of the register at 'offset' + * @priv: pointer to &struct lbs_private + * @reg: register command, one of CMD_MAC_REG_ACCESS, + * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS + * @offset: byte offset of the register to get + * @value: on success, the value of the register at 'offset' * - * @return 0 on success, error code on failure + * returns: 0 on success, error code on failure */ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value) { @@ -886,15 +895,15 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value) } /** - * @brief Write a MAC, Baseband, or RF register + * lbs_set_reg - Write a MAC, Baseband, or RF register * - * @param priv pointer to struct lbs_private - * @param cmd register command, one of CMD_MAC_REG_ACCESS, - * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS - * @param offset byte offset of the register to set - * @param value the value to write to the register at 'offset' + * @priv: pointer to &struct lbs_private + * @reg: register command, one of CMD_MAC_REG_ACCESS, + * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS + * @offset: byte offset of the register to set + * @value: the value to write to the register at 'offset' * - * @return 0 on success, error code on failure + * returns: 0 on success, error code on failure */ int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value) { @@ -1002,7 +1011,8 @@ static void lbs_submit_command(struct lbs_private *priv, ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize); if (ret) { - lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret); + netdev_info(priv->dev, "DNLD_CMD: hw_host_to_card failed: %d\n", + ret); /* Let the timer kick in and retry, and potentially reset the whole thing if the condition persists */ timeo = HZ/4; @@ -1023,7 +1033,7 @@ static void lbs_submit_command(struct lbs_private *priv, lbs_deb_leave(LBS_DEB_HOST); } -/** +/* * This function inserts command node to cmdfreeq * after cleans it. Requires priv->driver_lock held. */ @@ -1125,11 +1135,12 @@ void lbs_set_mac_control(struct lbs_private *priv) } /** - * @brief This function allocates the command buffer and link - * it to command free queue. + * lbs_allocate_cmd_buffer - allocates the command buffer and links + * it to command free queue * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private structure + * + * returns: 0 for success or -1 on error */ int lbs_allocate_cmd_buffer(struct lbs_private *priv) { @@ -1171,10 +1182,11 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv) } /** - * @brief This function frees the command buffer. + * lbs_free_cmd_buffer - free the command buffer * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private structure + * + * returns: 0 for success */ int lbs_free_cmd_buffer(struct lbs_private *priv) { @@ -1211,11 +1223,13 @@ int lbs_free_cmd_buffer(struct lbs_private *priv) } /** - * @brief This function gets a free command node if available in - * command free queue. + * lbs_get_free_cmd_node - gets a free command node if available in + * command free queue * - * @param priv A pointer to struct lbs_private structure - * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL + * @priv: A pointer to &struct lbs_private structure + * + * returns: A pointer to &cmd_ctrl_node structure on success + * or %NULL on error */ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv) { @@ -1245,12 +1259,12 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv) } /** - * @brief This function executes next command in command - * pending queue. It will put firmware back to PS mode - * if applicable. + * lbs_execute_next_command - execute next command in command + * pending queue. Will put firmware back to PS mode if applicable. * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private structure + * + * returns: 0 on success or -1 on error */ int lbs_execute_next_command(struct lbs_private *priv) { @@ -1267,7 +1281,8 @@ int lbs_execute_next_command(struct lbs_private *priv) spin_lock_irqsave(&priv->driver_lock, flags); if (priv->cur_cmd) { - lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n"); + netdev_alert(priv->dev, + "EXEC_NEXT_CMD: already processing command!\n"); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; @@ -1339,8 +1354,8 @@ int lbs_execute_next_command(struct lbs_private *priv) cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) { lbs_deb_host( "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n"); - list_del(&cmdnode->list); spin_lock_irqsave(&priv->driver_lock, flags); + list_del(&cmdnode->list); lbs_complete_command(priv, cmdnode, 0); spin_unlock_irqrestore(&priv->driver_lock, flags); @@ -1352,8 +1367,8 @@ int lbs_execute_next_command(struct lbs_private *priv) (priv->psstate == PS_STATE_PRE_SLEEP)) { lbs_deb_host( "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n"); - list_del(&cmdnode->list); spin_lock_irqsave(&priv->driver_lock, flags); + list_del(&cmdnode->list); lbs_complete_command(priv, cmdnode, 0); spin_unlock_irqrestore(&priv->driver_lock, flags); priv->needtowakeup = 1; @@ -1366,7 +1381,9 @@ int lbs_execute_next_command(struct lbs_private *priv) "EXEC_NEXT_CMD: sending EXIT_PS\n"); } } + spin_lock_irqsave(&priv->driver_lock, flags); list_del(&cmdnode->list); + spin_unlock_irqrestore(&priv->driver_lock, flags); lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n", le16_to_cpu(cmd->command)); lbs_submit_command(priv, cmdnode); @@ -1429,7 +1446,7 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep, sizeof(confirm_sleep)); if (ret) { - lbs_pr_alert("confirm_sleep failed\n"); + netdev_alert(priv->dev, "confirm_sleep failed\n"); goto out; } @@ -1454,12 +1471,12 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) } /** - * @brief This function checks condition and prepares to - * send sleep confirm command to firmware if ok. + * lbs_ps_confirm_sleep - checks condition and prepares to + * send sleep confirm command to firmware if ok * - * @param priv A pointer to struct lbs_private structure - * @param psmode Power Saving mode - * @return n/a + * @priv: A pointer to &struct lbs_private structure + * + * returns: n/a */ void lbs_ps_confirm_sleep(struct lbs_private *priv) { @@ -1499,16 +1516,16 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) /** - * @brief Configures the transmission power control functionality. + * lbs_set_tpc_cfg - Configures the transmission power control functionality * - * @param priv A pointer to struct lbs_private structure - * @param enable Transmission power control enable - * @param p0 Power level when link quality is good (dBm). - * @param p1 Power level when link quality is fair (dBm). - * @param p2 Power level when link quality is poor (dBm). - * @param usesnr Use Signal to Noise Ratio in TPC + * @priv: A pointer to &struct lbs_private structure + * @enable: Transmission power control enable + * @p0: Power level when link quality is good (dBm). + * @p1: Power level when link quality is fair (dBm). + * @p2: Power level when link quality is poor (dBm). + * @usesnr: Use Signal to Noise Ratio in TPC * - * @return 0 on success + * returns: 0 on success */ int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, int8_t p2, int usesnr) @@ -1531,15 +1548,15 @@ int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, } /** - * @brief Configures the power adaptation settings. + * lbs_set_power_adapt_cfg - Configures the power adaptation settings * - * @param priv A pointer to struct lbs_private structure - * @param enable Power adaptation enable - * @param p0 Power level for 1, 2, 5.5 and 11 Mbps (dBm). - * @param p1 Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm). - * @param p2 Power level for 48 and 54 Mbps (dBm). + * @priv: A pointer to &struct lbs_private structure + * @enable: Power adaptation enable + * @p0: Power level for 1, 2, 5.5 and 11 Mbps (dBm). + * @p1: Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm). + * @p2: Power level for 48 and 54 Mbps (dBm). * - * @return 0 on Success + * returns: 0 on Success */ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, @@ -1655,7 +1672,7 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command, spin_lock_irqsave(&priv->driver_lock, flags); ret = cmdnode->result; if (ret) - lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n", + netdev_info(priv->dev, "PREP_CMD: command 0x%04x failed: %d\n", command, ret); __lbs_cleanup_and_insert_cmd(priv, cmdnode); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 5e95da9dcc2e..207fc361db84 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -1,7 +1,8 @@ -/** - * This file contains the handling of command - * responses as well as events generated by firmware. - */ +/* + * This file contains the handling of command + * responses as well as events generated by firmware. + */ + #include #include #include @@ -12,12 +13,13 @@ #include "cmd.h" /** - * @brief This function handles disconnect event. it - * reports disconnect to upper layer, clean tx/rx packets, - * reset link state etc. + * lbs_mac_event_disconnected - handles disconnect event. It + * reports disconnect to upper layer, clean tx/rx packets, + * reset link state etc. * - * @param priv A pointer to struct lbs_private structure - * @return n/a + * @priv: A pointer to struct lbs_private structure + * + * returns: n/a */ void lbs_mac_event_disconnected(struct lbs_private *priv) { @@ -84,15 +86,18 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len); if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) { - lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n", - le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum)); + netdev_info(priv->dev, + "Received CMD_RESP with invalid sequence %d (expected %d)\n", + le16_to_cpu(resp->seqnum), + le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum)); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } if (respcmd != CMD_RET(curcmd) && respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) { - lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd); + netdev_info(priv->dev, "Invalid CMD_RESP %x to command %x!\n", + respcmd, curcmd); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; @@ -101,7 +106,8 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) if (resp->result == cpu_to_le16(0x0004)) { /* 0x0004 means -EAGAIN. Drop the response, let it time out and be resubmitted */ - lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n", + netdev_info(priv->dev, + "Firmware returns DEFER to command %x. Will let it time out...\n", le16_to_cpu(resp->command)); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; @@ -313,28 +319,28 @@ int lbs_process_event(struct lbs_private *priv, u32 event) lbs_deb_cmd("EVENT: ADHOC beacon lost\n"); break; case MACREG_INT_CODE_RSSI_LOW: - lbs_pr_alert("EVENT: rssi low\n"); + netdev_alert(priv->dev, "EVENT: rssi low\n"); break; case MACREG_INT_CODE_SNR_LOW: - lbs_pr_alert("EVENT: snr low\n"); + netdev_alert(priv->dev, "EVENT: snr low\n"); break; case MACREG_INT_CODE_MAX_FAIL: - lbs_pr_alert("EVENT: max fail\n"); + netdev_alert(priv->dev, "EVENT: max fail\n"); break; case MACREG_INT_CODE_RSSI_HIGH: - lbs_pr_alert("EVENT: rssi high\n"); + netdev_alert(priv->dev, "EVENT: rssi high\n"); break; case MACREG_INT_CODE_SNR_HIGH: - lbs_pr_alert("EVENT: snr high\n"); + netdev_alert(priv->dev, "EVENT: snr high\n"); break; case MACREG_INT_CODE_MESH_AUTO_STARTED: /* Ignore spurious autostart events */ - lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); + netdev_info(priv->dev, "EVENT: MESH_AUTO_STARTED (ignoring)\n"); break; default: - lbs_pr_alert("EVENT: unknown event id %d\n", event); + netdev_alert(priv->dev, "EVENT: unknown event id %d\n", event); break; } diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index fbf3b0332bb7..23250f621761 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -151,13 +151,14 @@ static ssize_t lbs_host_sleep_write(struct file *file, ret = lbs_set_host_sleep(priv, 0); else if (host_sleep == 1) { if (priv->wol_criteria == EHS_REMOVE_WAKEUP) { - lbs_pr_info("wake parameters not configured"); + netdev_info(priv->dev, + "wake parameters not configured\n"); ret = -EINVAL; goto out_unlock; } ret = lbs_set_host_sleep(priv, 1); } else { - lbs_pr_err("invalid option\n"); + netdev_err(priv->dev, "invalid option\n"); ret = -EINVAL; } @@ -849,15 +850,14 @@ static struct debug_data items[] = { static int num_of_items = ARRAY_SIZE(items); /** - * @brief proc read function + * lbs_debugfs_read - proc read function * - * @param page pointer to buffer - * @param s read data starting position - * @param off offset - * @param cnt counter - * @param eof end of file flag - * @param data data to output - * @return number of output data + * @file: file to read + * @userbuf: pointer to buffer + * @count: number of bytes to read + * @ppos: read data starting position + * + * returns: amount of data read or negative error code */ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) @@ -897,13 +897,14 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, } /** - * @brief proc write function + * lbs_debugfs_write - proc write function * - * @param f file pointer - * @param buf pointer to data buffer - * @param cnt data number to write - * @param data data to write - * @return number of data + * @f: file pointer + * @buf: pointer to data buffer + * @cnt: data number to write + * @ppos: file position + * + * returns: amount of data written */ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf, size_t cnt, loff_t *ppos) @@ -966,11 +967,11 @@ static const struct file_operations lbs_debug_fops = { }; /** - * @brief create debug proc file + * lbs_debug_init - create debug proc file * - * @param priv pointer struct lbs_private - * @param dev pointer net_device - * @return N/A + * @priv: pointer to &struct lbs_private + * + * returns: N/A */ static void lbs_debug_init(struct lbs_private *priv) { diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 2ae752d10065..da0b05bb89fe 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -1,8 +1,8 @@ -/** - * This file contains declaration referring to - * functions defined in other source files - */ +/* + * This file contains declaration referring to + * functions defined in other source files + */ #ifndef _LBS_DECL_H_ #define _LBS_DECL_H_ diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index d00c728cec47..ab966f08024a 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -1,7 +1,7 @@ -/** - * This header file contains global constant/enum definitions, - * global variable declaration. - */ +/* + * This header file contains global constant/enum definitions, + * global variable declaration. + */ #ifndef _LBS_DEFS_H_ #define _LBS_DEFS_H_ @@ -89,13 +89,6 @@ do { if ((lbs_debug & (grp)) == (grp)) \ #define lbs_deb_spi(fmt, args...) LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args) #define lbs_deb_cfg80211(fmt, args...) LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args) -#define lbs_pr_info(format, args...) \ - printk(KERN_INFO DRV_NAME": " format, ## args) -#define lbs_pr_err(format, args...) \ - printk(KERN_ERR DRV_NAME": " format, ## args) -#define lbs_pr_alert(format, args...) \ - printk(KERN_ALERT DRV_NAME": " format, ## args) - #ifdef DEBUG static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len) { @@ -123,19 +116,19 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in -/** Buffer Constants */ +/* Buffer Constants */ /* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical -* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas -* driver has more local TxPDs. Each TxPD on the host memory is associated -* with a Tx control node. The driver maintains 8 RxPD descriptors for -* station firmware to store Rx packet information. -* -* Current version of MAC has a 32x6 multicast address buffer. -* -* 802.11b can have up to 14 channels, the driver keeps the -* BSSID(MAC address) of each APs or Ad hoc stations it has sensed. -*/ + * addresses of TxPD buffers. Station has only 8 TxPD available, Whereas + * driver has more local TxPDs. Each TxPD on the host memory is associated + * with a Tx control node. The driver maintains 8 RxPD descriptors for + * station firmware to store Rx packet information. + * + * Current version of MAC has a 32x6 multicast address buffer. + * + * 802.11b can have up to 14 channels, the driver keeps the + * BSSID(MAC address) of each APs or Ad hoc stations it has sensed. + */ #define MRVDRV_MAX_MULTICAST_LIST_SIZE 32 #define LBS_NUM_CMD_BUFFERS 10 @@ -166,7 +159,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define WOL_RESULT_NOSPC_ERR 1 #define WOL_RESULT_EEXIST_ERR 2 -/** Misc constants */ +/* Misc constants */ /* This section defines 802.11 specific contants */ #define MRVDRV_MAX_BSS_DESCRIPTS 16 @@ -183,7 +176,8 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MARVELL_MESH_IE_LENGTH 9 -/* Values used to populate the struct mrvl_mesh_ie. The only time you need this +/* + * Values used to populate the struct mrvl_mesh_ie. The only time you need this * is when enabling the mesh using CMD_MESH_CONFIG. */ #define MARVELL_MESH_IE_TYPE 4 @@ -193,7 +187,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MARVELL_MESH_METRIC_ID 0 #define MARVELL_MESH_CAPABILITY 0 -/** INT status Bit Definition*/ +/* INT status Bit Definition */ #define MRVDRV_TX_DNLD_RDY 0x0001 #define MRVDRV_RX_UPLD_RDY 0x0002 #define MRVDRV_CMD_DNLD_RDY 0x0004 @@ -208,59 +202,63 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define TPC_DEFAULT_P1 10 #define TPC_DEFAULT_P2 13 -/** TxPD status */ +/* TxPD status */ -/* Station firmware use TxPD status field to report final Tx transmit -* result, Bit masks are used to present combined situations. -*/ +/* + * Station firmware use TxPD status field to report final Tx transmit + * result, Bit masks are used to present combined situations. + */ #define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01 #define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08 -/** Tx mesh flag */ -/* Currently we are using normal WDS flag as mesh flag. +/* Tx mesh flag */ +/* + * Currently we are using normal WDS flag as mesh flag. * TODO: change to proper mesh flag when MAC understands it. */ #define TxPD_CONTROL_WDS_FRAME (1<<17) #define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME -/** Mesh interface ID */ +/* Mesh interface ID */ #define MESH_IFACE_ID 0x0001 -/** Mesh id should be in bits 14-13-12 */ +/* Mesh id should be in bits 14-13-12 */ #define MESH_IFACE_BIT_OFFSET 0x000c -/** Mesh enable bit in FW capability */ +/* Mesh enable bit in FW capability */ #define MESH_CAPINFO_ENABLE_MASK (1<<16) -/** FW definition from Marvell v4 */ +/* FW definition from Marvell v4 */ #define MRVL_FW_V4 (0x04) -/** FW definition from Marvell v5 */ +/* FW definition from Marvell v5 */ #define MRVL_FW_V5 (0x05) -/** FW definition from Marvell v10 */ +/* FW definition from Marvell v10 */ #define MRVL_FW_V10 (0x0a) -/** FW major revision definition */ +/* FW major revision definition */ #define MRVL_FW_MAJOR_REV(x) ((x)>>24) -/** RxPD status */ +/* RxPD status */ #define MRVDRV_RXPD_STATUS_OK 0x0001 -/** RxPD status - Received packet types */ -/** Rx mesh flag */ -/* Currently we are using normal WDS flag as mesh flag. +/* RxPD status - Received packet types */ +/* Rx mesh flag */ +/* + * Currently we are using normal WDS flag as mesh flag. * TODO: change to proper mesh flag when MAC understands it. */ #define RxPD_CONTROL_WDS_FRAME (0x40) #define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME -/** RSSI-related defines */ -/* RSSI constants are used to implement 802.11 RSSI threshold -* indication. if the Rx packet signal got too weak for 5 consecutive -* times, miniport driver (driver) will report this event to wrapper -*/ +/* RSSI-related defines */ +/* + * RSSI constants are used to implement 802.11 RSSI threshold + * indication. if the Rx packet signal got too weak for 5 consecutive + * times, miniport driver (driver) will report this event to wrapper + */ #define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96) -/** RTS/FRAG related defines */ +/* RTS/FRAG related defines */ #define MRVDRV_RTS_MIN_VALUE 0 #define MRVDRV_RTS_MAX_VALUE 2347 #define MRVDRV_FRAG_MIN_VALUE 256 @@ -300,36 +298,36 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MAX_LEDS 8 -/** Global Variable Declaration */ +/* Global Variable Declaration */ extern const char lbs_driver_version[]; extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE]; -/** ENUM definition*/ -/** SNRNF_TYPE */ +/* ENUM definition */ +/* SNRNF_TYPE */ enum SNRNF_TYPE { TYPE_BEACON = 0, TYPE_RXPD, MAX_TYPE_B }; -/** SNRNF_DATA*/ +/* SNRNF_DATA */ enum SNRNF_DATA { TYPE_NOAVG = 0, TYPE_AVG, MAX_TYPE_AVG }; -/** LBS_802_11_POWER_MODE */ +/* LBS_802_11_POWER_MODE */ enum LBS_802_11_POWER_MODE { LBS802_11POWERMODECAM, LBS802_11POWERMODEMAX_PSP, LBS802_11POWERMODEFAST_PSP, - /*not a real mode, defined as an upper bound */ + /* not a real mode, defined as an upper bound */ LBS802_11POWEMODEMAX }; -/** PS_STATE */ +/* PS_STATE */ enum PS_STATE { PS_STATE_FULL_POWER, PS_STATE_AWAKE, @@ -337,7 +335,7 @@ enum PS_STATE { PS_STATE_SLEEP }; -/** DNLD_STATE */ +/* DNLD_STATE */ enum DNLD_STATE { DNLD_RES_RECEIVED, DNLD_DATA_SENT, @@ -345,19 +343,19 @@ enum DNLD_STATE { DNLD_BOOTCMD_SENT, }; -/** LBS_MEDIA_STATE */ +/* LBS_MEDIA_STATE */ enum LBS_MEDIA_STATE { LBS_CONNECTED, LBS_DISCONNECTED }; -/** LBS_802_11_PRIVACY_FILTER */ +/* LBS_802_11_PRIVACY_FILTER */ enum LBS_802_11_PRIVACY_FILTER { LBS802_11PRIVFILTERACCEPTALL, LBS802_11PRIVFILTER8021XWEP }; -/** mv_ms_type */ +/* mv_ms_type */ enum mv_ms_type { MVMS_DAT = 0, MVMS_CMD = 1, @@ -365,14 +363,14 @@ enum mv_ms_type { MVMS_EVENT }; -/** KEY_TYPE_ID */ +/* KEY_TYPE_ID */ enum KEY_TYPE_ID { KEY_TYPE_ID_WEP = 0, KEY_TYPE_ID_TKIP, KEY_TYPE_ID_AES }; -/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */ +/* KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */ enum KEY_INFO_WPA { KEY_INFO_WPA_MCAST = 0x01, KEY_INFO_WPA_UNICAST = 0x02, diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index bc461eb39660..76d018beebf4 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -1,8 +1,8 @@ -/** - * This file contains definitions and data structures specific - * to Marvell 802.11 NIC. It contains the Device Information - * structure struct lbs_private.. - */ +/* + * This file contains definitions and data structures specific + * to Marvell 802.11 NIC. It contains the Device Information + * structure struct lbs_private.. + */ #ifndef _LBS_DEV_H_ #define _LBS_DEV_H_ @@ -12,7 +12,7 @@ #include -/** sleep_params */ +/* sleep_params */ struct sleep_params { uint16_t sp_error; uint16_t sp_offset; @@ -23,7 +23,7 @@ struct sleep_params { }; -/** Private structure for the MV device */ +/* Private structure for the MV device */ struct lbs_private { /* Basic networking */ @@ -125,12 +125,12 @@ struct lbs_private { /* Events sent from hardware to driver */ struct kfifo event_fifo; - /** thread to service interrupts */ + /* thread to service interrupts */ struct task_struct *main_thread; wait_queue_head_t waitq; struct workqueue_struct *work_thread; - /** Encryption stuff */ + /* Encryption stuff */ u8 authtype_auto; u8 wep_tx_key; u8 wep_key[4][WLAN_KEY_LEN_WEP104]; @@ -162,7 +162,7 @@ struct lbs_private { s16 txpower_min; s16 txpower_max; - /** Scanning */ + /* Scanning */ struct delayed_work scan_work; int scan_channel; /* Queue of things waiting for scan completion */ diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 50193aac679e..29dbce4a9f86 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -20,7 +20,8 @@ static void lbs_ethtool_get_drvinfo(struct net_device *dev, strcpy(info->version, lbs_driver_version); } -/* All 8388 parts have 16KiB EEPROM size at the time of writing. +/* + * All 8388 parts have 16KiB EEPROM size at the time of writing. * In case that changes this needs fixing. */ #define LBS_EEPROM_LEN 16384 diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 6cb6935ee4a3..2e2dbfa2ee50 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -1,7 +1,7 @@ -/** - * This file function prototypes, data structure - * and definitions for all the host/station commands - */ +/* + * This file function prototypes, data structure + * and definitions for all the host/station commands + */ #ifndef _LBS_HOST_H_ #define _LBS_HOST_H_ @@ -13,9 +13,10 @@ #define CMD_OPTION_WAITFORRSP 0x0002 -/** Host command IDs */ +/* Host command IDs */ -/* Return command are almost always the same as the host command, but with +/* + * Return command are almost always the same as the host command, but with * bit 15 set high. There are a few exceptions, though... */ #define CMD_RET(cmd) (0x8000 | cmd) @@ -251,7 +252,7 @@ enum cmd_mesh_config_types { CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */ }; -/** Card Event definition */ +/* Card Event definition */ #define MACREG_INT_CODE_TX_PPA_FREE 0 #define MACREG_INT_CODE_TX_DMA_DONE 1 #define MACREG_INT_CODE_LINK_LOST_W_SCAN 2 @@ -624,12 +625,14 @@ struct cmd_ds_802_11_rf_channel { struct cmd_ds_802_11_rssi { struct cmd_header hdr; - /* request: number of beacons (N) to average the SNR and NF over + /* + * request: number of beacons (N) to average the SNR and NF over * response: SNR of most recent beacon */ __le16 n_or_snr; - /* The following fields are only set in the response. + /* + * The following fields are only set in the response. * In the request these are reserved and should be set to 0. */ __le16 nf; /* most recent beacon noise floor */ @@ -680,14 +683,16 @@ struct cmd_ds_802_11_ps_mode { __le16 action; - /* Interval for keepalive in PS mode: + /* + * Interval for keepalive in PS mode: * 0x0000 = don't change * 0x001E = firmware default * 0xFFFF = disable */ __le16 nullpktinterval; - /* Number of DTIM intervals to wake up for: + /* + * Number of DTIM intervals to wake up for: * 0 = don't change * 1 = firmware default * 5 = max @@ -697,7 +702,8 @@ struct cmd_ds_802_11_ps_mode { __le16 reserved; __le16 locallisteninterval; - /* AdHoc awake period (FW v9+ only): + /* + * AdHoc awake period (FW v9+ only): * 0 = don't change * 1 = always awake (IEEE standard behavior) * 2 - 31 = sleep for (n - 1) periods and awake for 1 period @@ -771,7 +777,8 @@ struct adhoc_bssdesc { __le16 capability; u8 rates[MAX_RATES]; - /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the + /* + * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the * Adhoc join command and will cause a binary layout mismatch with * the firmware */ diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 8712cb213f2f..63ed5798365c 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -21,6 +21,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -312,7 +314,8 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r #define CF8385_MANFID 0x02df #define CF8385_CARDID 0x8103 -/* FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when +/* + * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when * that gets fixed. Currently there's no way to access it from the probe hook. */ static inline u32 get_model(u16 manf_id, u16 card_id) @@ -361,7 +364,7 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) if (status & IF_CS_BIT_COMMAND) break; if (++loops > 100) { - lbs_pr_err("card not ready for commands\n"); + netdev_err(priv->dev, "card not ready for commands\n"); goto done; } mdelay(1); @@ -431,14 +434,16 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) /* is hardware ready? */ status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); if ((status & IF_CS_BIT_RESP) == 0) { - lbs_pr_err("no cmd response in card\n"); + netdev_err(priv->dev, "no cmd response in card\n"); *len = 0; goto out; } *len = if_cs_read16(priv->card, IF_CS_RESP_LEN); if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) { - lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len); + netdev_err(priv->dev, + "card cmd buffer has invalid # of bytes (%d)\n", + *len); goto out; } @@ -472,7 +477,9 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) len = if_cs_read16(priv->card, IF_CS_READ_LEN); if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { - lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len); + netdev_err(priv->dev, + "card data buffer has invalid # of bytes (%d)\n", + len); priv->dev->stats.rx_dropped++; goto dat_err; } @@ -621,8 +628,10 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) if (remain < count) count = remain; - /* "write the number of bytes to be sent to the I/O Command - * write length register" */ + /* + * "write the number of bytes to be sent to the I/O Command + * write length register" + */ if_cs_write16(card, IF_CS_CMD_LEN, count); /* "write this to I/O Command port register as 16 bit writes */ @@ -631,21 +640,27 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) &fw->data[sent], count >> 1); - /* "Assert the download over interrupt command in the Host - * status register" */ + /* + * "Assert the download over interrupt command in the Host + * status register" + */ if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - /* "Assert the download over interrupt command in the Card - * interrupt case register" */ + /* + * "Assert the download over interrupt command in the Card + * interrupt case register" + */ if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - /* "The host polls the Card Status register ... for 50 ms before - declaring a failure */ + /* + * "The host polls the Card Status register ... for 50 ms before + * declaring a failure" + */ ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, IF_CS_BIT_COMMAND); if (ret < 0) { - lbs_pr_err("can't download helper at 0x%x, ret %d\n", - sent, ret); + pr_err("can't download helper at 0x%x, ret %d\n", + sent, ret); goto done; } @@ -675,7 +690,7 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW, IF_CS_SQ_HELPER_OK); if (ret < 0) { - lbs_pr_err("helper firmware doesn't answer\n"); + pr_err("helper firmware doesn't answer\n"); goto done; } @@ -683,13 +698,13 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) len = if_cs_read16(card, IF_CS_SQ_READ_LOW); if (len & 1) { retry++; - lbs_pr_info("odd, need to retry this firmware block\n"); + pr_info("odd, need to retry this firmware block\n"); } else { retry = 0; } if (retry > 20) { - lbs_pr_err("could not download firmware\n"); + pr_err("could not download firmware\n"); ret = -ENODEV; goto done; } @@ -709,14 +724,14 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, IF_CS_BIT_COMMAND); if (ret < 0) { - lbs_pr_err("can't download firmware at 0x%x\n", sent); + pr_err("can't download firmware at 0x%x\n", sent); goto done; } } ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a); if (ret < 0) - lbs_pr_err("firmware download failed\n"); + pr_err("firmware download failed\n"); done: lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); @@ -750,7 +765,8 @@ static int if_cs_host_to_card(struct lbs_private *priv, ret = if_cs_send_cmd(priv, buf, nb); break; default: - lbs_pr_err("%s: unsupported type %d\n", __func__, type); + netdev_err(priv->dev, "%s: unsupported type %d\n", + __func__, type); } lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); @@ -779,7 +795,7 @@ static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data) p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; if (p_dev->resource[1]->end) { - lbs_pr_err("wrong CIS (check number of IO windows)\n"); + pr_err("wrong CIS (check number of IO windows)\n"); return -ENODEV; } @@ -800,7 +816,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL); if (!card) { - lbs_pr_err("error in kzalloc\n"); + pr_err("error in kzalloc\n"); goto out; } card->p_dev = p_dev; @@ -809,7 +825,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) { - lbs_pr_err("error in pcmcia_loop_config\n"); + pr_err("error in pcmcia_loop_config\n"); goto out1; } @@ -825,14 +841,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev) card->iobase = ioport_map(p_dev->resource[0]->start, resource_size(p_dev->resource[0])); if (!card->iobase) { - lbs_pr_err("error in ioport_map\n"); + pr_err("error in ioport_map\n"); ret = -EIO; goto out1; } ret = pcmcia_enable_device(p_dev); if (ret) { - lbs_pr_err("error in pcmcia_enable_device\n"); + pr_err("error in pcmcia_enable_device\n"); goto out2; } @@ -841,14 +857,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev) /* * Most of the libertas cards can do unaligned register access, but some - * weird ones can not. That's especially true for the CF8305 card. + * weird ones cannot. That's especially true for the CF8305 card. */ card->align_regs = 0; card->model = get_model(p_dev->manf_id, p_dev->card_id); if (card->model == MODEL_UNKNOWN) { - lbs_pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n", - p_dev->manf_id, p_dev->card_id); + pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n", + p_dev->manf_id, p_dev->card_id); goto out2; } @@ -857,20 +873,20 @@ static int if_cs_probe(struct pcmcia_device *p_dev) if (card->model == MODEL_8305) { card->align_regs = 1; if (prod_id < IF_CS_CF8305_B1_REV) { - lbs_pr_err("8305 rev B0 and older are not supported\n"); + pr_err("8305 rev B0 and older are not supported\n"); ret = -ENODEV; goto out2; } } if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) { - lbs_pr_err("8381 rev B2 and older are not supported\n"); + pr_err("8381 rev B2 and older are not supported\n"); ret = -ENODEV; goto out2; } if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) { - lbs_pr_err("8385 rev B0 and older are not supported\n"); + pr_err("8385 rev B0 and older are not supported\n"); ret = -ENODEV; goto out2; } @@ -878,7 +894,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model, &fw_table[0], &helper, &mainfw); if (ret) { - lbs_pr_err("failed to find firmware (%d)\n", ret); + pr_err("failed to find firmware (%d)\n", ret); goto out2; } @@ -909,18 +925,20 @@ static int if_cs_probe(struct pcmcia_device *p_dev) ret = request_irq(p_dev->irq, if_cs_interrupt, IRQF_SHARED, DRV_NAME, card); if (ret) { - lbs_pr_err("error in request_irq\n"); + pr_err("error in request_irq\n"); goto out3; } - /* Clear any interrupt cause that happened while sending - * firmware/initializing card */ + /* + * 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) { - lbs_pr_err("could not activate card\n"); + pr_err("could not activate card\n"); goto out3; } diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index b4de0ca10feb..a7b5cb0c2753 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -26,6 +26,8 @@ * if_sdio_card_to_host() to pad the data. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -409,7 +411,7 @@ static int if_sdio_card_to_host(struct if_sdio_card *card) out: if (ret) - lbs_pr_err("problem fetching packet from firmware\n"); + pr_err("problem fetching packet from firmware\n"); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); @@ -446,7 +448,7 @@ static void if_sdio_host_to_card_worker(struct work_struct *work) } if (ret) - lbs_pr_err("error %d sending packet to firmware\n", ret); + pr_err("error %d sending packet to firmware\n", ret); sdio_release_host(card->func); @@ -555,7 +557,7 @@ static int if_sdio_prog_helper(struct if_sdio_card *card, out: if (ret) - lbs_pr_err("failed to load helper firmware\n"); + pr_err("failed to load helper firmware\n"); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; @@ -669,7 +671,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card, out: if (ret) - lbs_pr_err("failed to load firmware\n"); + pr_err("failed to load firmware\n"); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; @@ -723,7 +725,7 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name, card->model, &fw_table[0], &helper, &mainfw); if (ret) { - lbs_pr_err("failed to find firmware (%d)\n", ret); + pr_err("failed to find firmware (%d)\n", ret); goto out; } @@ -849,7 +851,7 @@ static int if_sdio_enter_deep_sleep(struct lbs_private *priv) ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd), lbs_cmd_copyback, (unsigned long) &cmd); if (ret) - lbs_pr_err("DEEP_SLEEP cmd failed\n"); + netdev_err(priv->dev, "DEEP_SLEEP cmd failed\n"); mdelay(200); return ret; @@ -865,7 +867,7 @@ static int if_sdio_exit_deep_sleep(struct lbs_private *priv) sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret); if (ret) - lbs_pr_err("sdio_writeb failed!\n"); + netdev_err(priv->dev, "sdio_writeb failed!\n"); sdio_release_host(card->func); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); @@ -882,7 +884,7 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv) sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret); if (ret) - lbs_pr_err("sdio_writeb failed!\n"); + netdev_err(priv->dev, "sdio_writeb failed!\n"); sdio_release_host(card->func); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); @@ -961,7 +963,7 @@ static int if_sdio_probe(struct sdio_func *func, } if (i == func->card->num_info) { - lbs_pr_err("unable to identify card model\n"); + pr_err("unable to identify card model\n"); return -ENODEV; } @@ -995,7 +997,7 @@ static int if_sdio_probe(struct sdio_func *func, break; } if (i == ARRAY_SIZE(fw_table)) { - lbs_pr_err("unknown card model 0x%x\n", card->model); + pr_err("unknown card model 0x%x\n", card->model); ret = -ENODEV; goto free; } @@ -1101,7 +1103,7 @@ static int if_sdio_probe(struct sdio_func *func, lbs_deb_sdio("send function INIT command\n"); if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), lbs_cmd_copyback, (unsigned long) &cmd)) - lbs_pr_alert("CMD_FUNC_INIT cmd failed\n"); + netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n"); } ret = lbs_start_card(priv); @@ -1163,7 +1165,7 @@ static void if_sdio_remove(struct sdio_func *func) if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN, &cmd, sizeof(cmd), lbs_cmd_copyback, (unsigned long) &cmd)) - lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n"); + pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n"); } @@ -1202,20 +1204,19 @@ static int if_sdio_suspend(struct device *dev) mmc_pm_flag_t flags = sdio_get_host_pm_caps(func); - lbs_pr_info("%s: suspend: PM flags = 0x%x\n", - sdio_func_id(func), flags); + dev_info(dev, "%s: suspend: PM flags = 0x%x\n", + sdio_func_id(func), flags); /* If we aren't being asked to wake on anything, we should bail out * and let the SD stack power down the card. */ if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) { - lbs_pr_info("Suspend without wake params -- " - "powering down card."); + dev_info(dev, "Suspend without wake params -- powering down card\n"); return -ENOSYS; } if (!(flags & MMC_PM_KEEP_POWER)) { - lbs_pr_err("%s: cannot remain alive while host is suspended\n", + dev_err(dev, "%s: cannot remain alive while host is suspended\n", sdio_func_id(func)); return -ENOSYS; } @@ -1237,7 +1238,7 @@ static int if_sdio_resume(struct device *dev) struct if_sdio_card *card = sdio_get_drvdata(func); int ret; - lbs_pr_info("%s: resume: we're back\n", sdio_func_id(func)); + dev_info(dev, "%s: resume: we're back\n", sdio_func_id(func)); ret = lbs_resume(card->priv); diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index f6c2cd665f49..463352c890d7 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -17,6 +17,8 @@ * (at your option) any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -57,6 +59,7 @@ struct if_spi_card { /* Handles all SPI communication (except for FW load) */ struct workqueue_struct *workqueue; struct work_struct packet_work; + struct work_struct resume_work; u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE]; @@ -68,6 +71,9 @@ struct if_spi_card { /* Protects cmd_packet_list and data_packet_list */ spinlock_t buffer_lock; + + /* True is card suspended */ + u8 suspended; }; static void free_if_spi_card(struct if_spi_card *card) @@ -139,8 +145,10 @@ static void spu_transaction_finish(struct if_spi_card *card) card->prev_xfer_time = jiffies; } -/* Write out a byte buffer to an SPI register, - * using a series of 16-bit transfers. */ +/* + * Write out a byte buffer to an SPI register, + * using a series of 16-bit transfers. + */ static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) { int err = 0; @@ -204,8 +212,10 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) struct spi_transfer dummy_trans; struct spi_transfer data_trans; - /* You must take an even number of bytes from the SPU, even if you - * don't care about the last one. */ + /* + * You must take an even number of bytes from the SPU, even if you + * don't care about the last one. + */ BUG_ON(len & 0x1); spu_transaction_init(card); @@ -254,8 +264,10 @@ static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val) return ret; } -/* Read 32 bits from an SPI register. - * The low 16 bits are read first. */ +/* + * Read 32 bits from an SPI register. + * The low 16 bits are read first. + */ static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val) { __le32 buf; @@ -267,13 +279,15 @@ static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val) return err; } -/* Keep reading 16 bits from an SPI register until you get the correct result. +/* + * Keep reading 16 bits from an SPI register until you get the correct result. * * If mask = 0, the correct result is any non-zero number. * If mask != 0, the correct result is any number where * number & target_mask == target * - * Returns -ETIMEDOUT if a second passes without the correct result. */ + * Returns -ETIMEDOUT if a second passes without the correct result. + */ static int spu_wait_for_u16(struct if_spi_card *card, u16 reg, u16 target_mask, u16 target) { @@ -293,16 +307,17 @@ static int spu_wait_for_u16(struct if_spi_card *card, u16 reg, } udelay(100); if (time_after(jiffies, timeout)) { - lbs_pr_err("%s: timeout with val=%02x, " - "target_mask=%02x, target=%02x\n", + pr_err("%s: timeout with val=%02x, target_mask=%02x, target=%02x\n", __func__, val, target_mask, target); return -ETIMEDOUT; } } } -/* Read 16 bits from an SPI register until you receive a specific value. - * Returns -ETIMEDOUT if a 4 tries pass without success. */ +/* + * Read 16 bits from an SPI register until you receive a specific value. + * Returns -ETIMEDOUT if a 4 tries pass without success. + */ static int spu_wait_for_u32(struct if_spi_card *card, u32 reg, u32 target) { int err, try; @@ -324,8 +339,10 @@ static int spu_set_interrupt_mode(struct if_spi_card *card, { int err = 0; - /* We can suppress a host interrupt by clearing the appropriate - * bit in the "host interrupt status mask" register */ + /* + * We can suppress a host interrupt by clearing the appropriate + * bit in the "host interrupt status mask" register + */ if (suppress_host_int) { err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0); if (err) @@ -341,10 +358,12 @@ static int spu_set_interrupt_mode(struct if_spi_card *card, return err; } - /* If auto-interrupts are on, the completion of certain transactions + /* + * If auto-interrupts are on, the completion of certain transactions * will trigger an interrupt automatically. If auto-interrupts * are off, we need to set the "Card Interrupt Cause" register to - * trigger a card interrupt. */ + * trigger a card interrupt. + */ if (auto_int) { err = spu_write_u16(card, IF_SPI_HOST_INT_CTRL_REG, IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO | @@ -387,7 +406,7 @@ static int spu_set_bus_mode(struct if_spi_card *card, u16 mode) if (err) return err; if ((rval & 0xF) != mode) { - lbs_pr_err("Can't read bus mode register.\n"); + pr_err("Can't read bus mode register\n"); return -EIO; } return 0; @@ -398,8 +417,10 @@ static int spu_init(struct if_spi_card *card, int use_dummy_writes) int err = 0; u32 delay; - /* We have to start up in timed delay mode so that we can safely - * read the Delay Read Register. */ + /* + * We have to start up in timed delay mode so that we can safely + * read the Delay Read Register. + */ card->use_dummy_writes = 0; err = spu_set_bus_mode(card, IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING | @@ -455,8 +476,10 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, /* Load helper firmware image */ while (bytes_remaining > 0) { - /* Scratch pad 1 should contain the number of bytes we - * want to download to the firmware */ + /* + * Scratch pad 1 should contain the number of bytes we + * want to download to the firmware + */ err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, HELPER_FW_LOAD_CHUNK_SZ); if (err) @@ -468,8 +491,10 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, if (err) goto out; - /* Feed the data into the command read/write port reg - * in chunks of 64 bytes */ + /* + * Feed the data into the command read/write port reg + * in chunks of 64 bytes + */ memset(temp, 0, sizeof(temp)); memcpy(temp, fw, min(bytes_remaining, HELPER_FW_LOAD_CHUNK_SZ)); @@ -491,9 +516,11 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, fw += HELPER_FW_LOAD_CHUNK_SZ; } - /* Once the helper / single stage firmware download is complete, + /* + * Once the helper / single stage firmware download is complete, * write 0 to scratch pad 1 and interrupt the - * bootloader. This completes the helper download. */ + * bootloader. This completes the helper download. + */ err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK); if (err) goto out; @@ -508,26 +535,30 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, out: if (err) - lbs_pr_err("failed to load helper firmware (err=%d)\n", err); + pr_err("failed to load helper firmware (err=%d)\n", err); lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err); return err; } -/* Returns the length of the next packet the firmware expects us to send - * Sets crc_err if the previous transfer had a CRC error. */ +/* + * Returns the length of the next packet the firmware expects us to send. + * Sets crc_err if the previous transfer had a CRC error. + */ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card, int *crc_err) { u16 len; int err = 0; - /* wait until the host interrupt status register indicates - * that we are ready to download */ + /* + * wait until the host interrupt status register indicates + * that we are ready to download + */ err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG, IF_SPI_HIST_CMD_DOWNLOAD_RDY, IF_SPI_HIST_CMD_DOWNLOAD_RDY); if (err) { - lbs_pr_err("timed out waiting for host_int_status\n"); + pr_err("timed out waiting for host_int_status\n"); return err; } @@ -537,9 +568,8 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card, return err; if (len > IF_SPI_CMD_BUF_SIZE) { - lbs_pr_err("firmware load device requested a larger " - "tranfer than we are prepared to " - "handle. (len = %d)\n", len); + pr_err("firmware load device requested a larger transfer than we are prepared to handle (len = %d)\n", + len); return -EIO; } if (len & 0x1) { @@ -555,6 +585,7 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card, static int if_spi_prog_main_firmware(struct if_spi_card *card, const struct firmware *firmware) { + struct lbs_private *priv = card->priv; int len, prev_len; int bytes, crc_err = 0, err = 0; const u8 *fw; @@ -568,8 +599,9 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0); if (err) { - lbs_pr_err("%s: timed out waiting for initial " - "scratch reg = 0\n", __func__); + netdev_err(priv->dev, + "%s: timed out waiting for initial scratch reg = 0\n", + __func__); goto out; } @@ -583,17 +615,18 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, goto out; } if (bytes < 0) { - /* If there are no more bytes left, we would normally - * expect to have terminated with len = 0 */ - lbs_pr_err("Firmware load wants more bytes " - "than we have to offer.\n"); + /* + * If there are no more bytes left, we would normally + * expect to have terminated with len = 0 + */ + netdev_err(priv->dev, + "Firmware load wants more bytes than we have to offer.\n"); break; } if (crc_err) { /* Previous transfer failed. */ if (++num_crc_errs > MAX_MAIN_FW_LOAD_CRC_ERR) { - lbs_pr_err("Too many CRC errors encountered " - "in firmware load.\n"); + pr_err("Too many CRC errors encountered in firmware load.\n"); err = -EIO; goto out; } @@ -622,21 +655,20 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, prev_len = len; } if (bytes > prev_len) { - lbs_pr_err("firmware load wants fewer bytes than " - "we have to offer.\n"); + pr_err("firmware load wants fewer bytes than we have to offer\n"); } /* Confirm firmware download */ err = spu_wait_for_u32(card, IF_SPI_SCRATCH_4_REG, SUCCESSFUL_FW_DOWNLOAD_MAGIC); if (err) { - lbs_pr_err("failed to confirm the firmware download\n"); + pr_err("failed to confirm the firmware download\n"); goto out; } out: if (err) - lbs_pr_err("failed to load firmware (err=%d)\n", err); + pr_err("failed to load firmware (err=%d)\n", err); lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err); return err; } @@ -656,14 +688,18 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) u16 len; u8 i; - /* We need a buffer big enough to handle whatever people send to - * hw_host_to_card */ + /* + * We need a buffer big enough to handle whatever people send to + * hw_host_to_card + */ BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_CMD_BUFFER_SIZE); BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_UPLD_SIZE); - /* It's just annoying if the buffer size isn't a multiple of 4, because - * then we might have len < IF_SPI_CMD_BUF_SIZE but - * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE */ + /* + * It's just annoying if the buffer size isn't a multiple of 4, because + * then we might have len < IF_SPI_CMD_BUF_SIZE but + * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE + */ BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0); lbs_deb_enter(LBS_DEB_SPI); @@ -673,13 +709,13 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) if (err) goto out; if (!len) { - lbs_pr_err("%s: error: card has no data for host\n", + netdev_err(priv->dev, "%s: error: card has no data for host\n", __func__); err = -EINVAL; goto out; } else if (len > IF_SPI_CMD_BUF_SIZE) { - lbs_pr_err("%s: error: response packet too large: " - "%d bytes, but maximum is %d\n", + netdev_err(priv->dev, + "%s: error: response packet too large: %d bytes, but maximum is %d\n", __func__, len, IF_SPI_CMD_BUF_SIZE); err = -EINVAL; goto out; @@ -701,7 +737,7 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) out: if (err) - lbs_pr_err("%s: err=%d\n", __func__, err); + netdev_err(priv->dev, "%s: err=%d\n", __func__, err); lbs_deb_leave(LBS_DEB_SPI); return err; } @@ -709,6 +745,7 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) /* Move data from the card to the host */ static int if_spi_c2h_data(struct if_spi_card *card) { + struct lbs_private *priv = card->priv; struct sk_buff *skb; char *data; u16 len; @@ -721,13 +758,13 @@ static int if_spi_c2h_data(struct if_spi_card *card) if (err) goto out; if (!len) { - lbs_pr_err("%s: error: card has no data for host\n", + netdev_err(priv->dev, "%s: error: card has no data for host\n", __func__); err = -EINVAL; goto out; } else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { - lbs_pr_err("%s: error: card has %d bytes of data, but " - "our maximum skb size is %zu\n", + netdev_err(priv->dev, + "%s: error: card has %d bytes of data, but our maximum skb size is %zu\n", __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); err = -EINVAL; goto out; @@ -759,7 +796,7 @@ static int if_spi_c2h_data(struct if_spi_card *card) dev_kfree_skb(skb); out: if (err) - lbs_pr_err("%s: err=%d\n", __func__, err); + netdev_err(priv->dev, "%s: err=%d\n", __func__, err); lbs_deb_leave(LBS_DEB_SPI); return err; } @@ -768,6 +805,7 @@ static int if_spi_c2h_data(struct if_spi_card *card) static void if_spi_h2c(struct if_spi_card *card, struct if_spi_packet *packet, int type) { + struct lbs_private *priv = card->priv; int err = 0; u16 int_type, port_reg; @@ -781,7 +819,8 @@ static void if_spi_h2c(struct if_spi_card *card, port_reg = IF_SPI_CMD_RDWRPORT_REG; break; default: - lbs_pr_err("can't transfer buffer of type %d\n", type); + netdev_err(priv->dev, "can't transfer buffer of type %d\n", + type); err = -EINVAL; goto out; } @@ -795,7 +834,7 @@ static void if_spi_h2c(struct if_spi_card *card, kfree(packet); if (err) - lbs_pr_err("%s: error %d\n", __func__, err); + netdev_err(priv->dev, "%s: error %d\n", __func__, err); } /* Inform the host about a card event */ @@ -819,7 +858,7 @@ static void if_spi_e2h(struct if_spi_card *card) lbs_queue_event(priv, cause & 0xff); out: if (err) - lbs_pr_err("%s: error %d\n", __func__, err); + netdev_err(priv->dev, "%s: error %d\n", __func__, err); } static void if_spi_host_to_card_worker(struct work_struct *work) @@ -829,17 +868,21 @@ static void if_spi_host_to_card_worker(struct work_struct *work) u16 hiStatus; unsigned long flags; struct if_spi_packet *packet; + struct lbs_private *priv; card = container_of(work, struct if_spi_card, packet_work); + priv = card->priv; lbs_deb_enter(LBS_DEB_SPI); - /* Read the host interrupt status register to see what we - * can do. */ + /* + * Read the host interrupt status register to see what we + * can do. + */ err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG, &hiStatus); if (err) { - lbs_pr_err("I/O error\n"); + netdev_err(priv->dev, "I/O error\n"); goto err; } @@ -854,12 +897,15 @@ static void if_spi_host_to_card_worker(struct work_struct *work) goto err; } - /* workaround: in PS mode, the card does not set the Command - * Download Ready bit, but it sets TX Download Ready. */ + /* + * workaround: in PS mode, the card does not set the Command + * Download Ready bit, but it sets TX Download Ready. + */ if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY || (card->priv->psstate != PS_STATE_FULL_POWER && (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) { - /* This means two things. First of all, + /* + * This means two things. First of all, * if there was a previous command sent, the card has * successfully received it. * Secondly, it is now ready to download another @@ -867,8 +913,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work) */ lbs_host_to_card_done(card->priv); - /* Do we have any command packets from the host to - * send? */ + /* Do we have any command packets from the host to send? */ packet = NULL; spin_lock_irqsave(&card->buffer_lock, flags); if (!list_empty(&card->cmd_packet_list)) { @@ -882,8 +927,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work) if_spi_h2c(card, packet, MVMS_CMD); } if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) { - /* Do we have any data packets from the host to - * send? */ + /* Do we have any data packets from the host to send? */ packet = NULL; spin_lock_irqsave(&card->buffer_lock, flags); if (!list_empty(&card->data_packet_list)) { @@ -901,7 +945,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work) err: if (err) - lbs_pr_err("%s: got error %d\n", __func__, err); + netdev_err(priv->dev, "%s: got error %d\n", __func__, err); lbs_deb_leave(LBS_DEB_SPI); } @@ -910,7 +954,8 @@ static void if_spi_host_to_card_worker(struct work_struct *work) * Host to Card * * Called from Libertas to transfer some data to the WLAN device - * We can't sleep here. */ + * We can't sleep here. + */ static int if_spi_host_to_card(struct lbs_private *priv, u8 type, u8 *buf, u16 nb) { @@ -923,7 +968,8 @@ static int if_spi_host_to_card(struct lbs_private *priv, lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb); if (nb == 0) { - lbs_pr_err("%s: invalid size requested: %d\n", __func__, nb); + netdev_err(priv->dev, "%s: invalid size requested: %d\n", + __func__, nb); err = -EINVAL; goto out; } @@ -951,7 +997,8 @@ static int if_spi_host_to_card(struct lbs_private *priv, spin_unlock_irqrestore(&card->buffer_lock, flags); break; default: - lbs_pr_err("can't transfer buffer of type %d", type); + netdev_err(priv->dev, "can't transfer buffer of type %d\n", + type); err = -EINVAL; break; } @@ -984,6 +1031,7 @@ static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id) static int if_spi_init_card(struct if_spi_card *card) { + struct lbs_private *priv = card->priv; struct spi_device *spi = card->spi; int err, i; u32 scratch; @@ -1012,8 +1060,8 @@ static int if_spi_init_card(struct if_spi_card *card) break; } if (i == ARRAY_SIZE(fw_table)) { - lbs_pr_err("Unsupported chip_id: 0x%02x\n", - card->card_id); + netdev_err(priv->dev, "Unsupported chip_id: 0x%02x\n", + card->card_id); err = -ENODEV; goto out; } @@ -1022,7 +1070,8 @@ static int if_spi_init_card(struct if_spi_card *card) card->card_id, &fw_table[0], &helper, &mainfw); if (err) { - lbs_pr_err("failed to find firmware (%d)\n", err); + netdev_err(priv->dev, "failed to find firmware (%d)\n", + err); goto out; } @@ -1057,6 +1106,28 @@ static int if_spi_init_card(struct if_spi_card *card) return err; } +static void if_spi_resume_worker(struct work_struct *work) +{ + struct if_spi_card *card; + + card = container_of(work, struct if_spi_card, resume_work); + + if (card->suspended) { + if (card->pdata->setup) + card->pdata->setup(card->spi); + + /* Init card ... */ + if_spi_init_card(card); + + enable_irq(card->spi->irq); + + /* And resume it ... */ + lbs_resume(card->priv); + + card->suspended = 0; + } +} + static int __devinit if_spi_probe(struct spi_device *spi) { struct if_spi_card *card; @@ -1099,14 +1170,17 @@ static int __devinit if_spi_probe(struct spi_device *spi) if (err) goto free_card; - /* Register our card with libertas. - * This will call alloc_etherdev */ + /* + * Register our card with libertas. + * This will call alloc_etherdev. + */ priv = lbs_add_card(card, &spi->dev); if (!priv) { err = -ENOMEM; goto free_card; } card->priv = priv; + priv->setup_fw_on_resume = 1; priv->card = card; priv->hw_host_to_card = if_spi_host_to_card; priv->enter_deep_sleep = NULL; @@ -1117,17 +1191,20 @@ static int __devinit if_spi_probe(struct spi_device *spi) /* Initialize interrupt handling stuff. */ card->workqueue = create_workqueue("libertas_spi"); INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); + INIT_WORK(&card->resume_work, if_spi_resume_worker); err = request_irq(spi->irq, if_spi_host_interrupt, IRQF_TRIGGER_FALLING, "libertas_spi", card); if (err) { - lbs_pr_err("can't get host irq line-- request_irq failed\n"); + pr_err("can't get host irq line-- request_irq failed\n"); goto terminate_workqueue; } - /* Start the card. + /* + * Start the card. * This will call register_netdev, and we'll start - * getting interrupts... */ + * getting interrupts... + */ err = lbs_start_card(priv); if (err) goto release_irq; @@ -1161,6 +1238,8 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) lbs_deb_spi("libertas_spi_remove\n"); lbs_deb_enter(LBS_DEB_SPI); + cancel_work_sync(&card->resume_work); + lbs_stop_card(priv); lbs_remove_card(priv); /* will call free_netdev */ @@ -1174,6 +1253,40 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) return 0; } +static int if_spi_suspend(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct if_spi_card *card = spi_get_drvdata(spi); + + if (!card->suspended) { + lbs_suspend(card->priv); + flush_workqueue(card->workqueue); + disable_irq(spi->irq); + + if (card->pdata->teardown) + card->pdata->teardown(spi); + card->suspended = 1; + } + + return 0; +} + +static int if_spi_resume(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct if_spi_card *card = spi_get_drvdata(spi); + + /* Schedule delayed work */ + schedule_work(&card->resume_work); + + return 0; +} + +static const struct dev_pm_ops if_spi_pm_ops = { + .suspend = if_spi_suspend, + .resume = if_spi_resume, +}; + static struct spi_driver libertas_spi_driver = { .probe = if_spi_probe, .remove = __devexit_p(libertas_spi_remove), @@ -1181,6 +1294,7 @@ static struct spi_driver libertas_spi_driver = { .name = "libertas_spi", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &if_spi_pm_ops, }, }; diff --git a/drivers/net/wireless/libertas/if_spi.h b/drivers/net/wireless/libertas/if_spi.h index d2ac1dcd7e2e..e450e31fd11d 100644 --- a/drivers/net/wireless/libertas/if_spi.h +++ b/drivers/net/wireless/libertas/if_spi.h @@ -86,34 +86,34 @@ #define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dc) (dc & 0x000000ff) /***************** IF_SPI_HOST_INT_CTRL_REG *****************/ -/** Host Interrupt Control bit : Wake up */ +/* Host Interrupt Control bit : Wake up */ #define IF_SPI_HICT_WAKE_UP (1<<0) -/** Host Interrupt Control bit : WLAN ready */ +/* Host Interrupt Control bit : WLAN ready */ #define IF_SPI_HICT_WLAN_READY (1<<1) /*#define IF_SPI_HICT_FIFO_FIRST_HALF_EMPTY (1<<2) */ /*#define IF_SPI_HICT_FIFO_SECOND_HALF_EMPTY (1<<3) */ /*#define IF_SPI_HICT_IRQSRC_WLAN (1<<4) */ -/** Host Interrupt Control bit : Tx auto download */ +/* Host Interrupt Control bit : Tx auto download */ #define IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO (1<<5) -/** Host Interrupt Control bit : Rx auto upload */ +/* Host Interrupt Control bit : Rx auto upload */ #define IF_SPI_HICT_RX_UPLOAD_OVER_AUTO (1<<6) -/** Host Interrupt Control bit : Command auto download */ +/* Host Interrupt Control bit : Command auto download */ #define IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO (1<<7) -/** Host Interrupt Control bit : Command auto upload */ +/* Host Interrupt Control bit : Command auto upload */ #define IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO (1<<8) /***************** IF_SPI_CARD_INT_CAUSE_REG *****************/ -/** Card Interrupt Case bit : Tx download over */ +/* Card Interrupt Case bit : Tx download over */ #define IF_SPI_CIC_TX_DOWNLOAD_OVER (1<<0) -/** Card Interrupt Case bit : Rx upload over */ +/* Card Interrupt Case bit : Rx upload over */ #define IF_SPI_CIC_RX_UPLOAD_OVER (1<<1) -/** Card Interrupt Case bit : Command download over */ +/* Card Interrupt Case bit : Command download over */ #define IF_SPI_CIC_CMD_DOWNLOAD_OVER (1<<2) -/** Card Interrupt Case bit : Host event */ +/* Card Interrupt Case bit : Host event */ #define IF_SPI_CIC_HOST_EVENT (1<<3) -/** Card Interrupt Case bit : Command upload over */ +/* Card Interrupt Case bit : Command upload over */ #define IF_SPI_CIC_CMD_UPLOAD_OVER (1<<4) -/** Card Interrupt Case bit : Power down */ +/* Card Interrupt Case bit : Power down */ #define IF_SPI_CIC_POWER_DOWN (1<<5) /***************** IF_SPI_CARD_INT_STATUS_REG *****************/ @@ -138,51 +138,51 @@ #define IF_SPI_HICU_CMD_RD_FIFO_UNDERFLOW (1<<10) /***************** IF_SPI_HOST_INT_STATUS_REG *****************/ -/** Host Interrupt Status bit : Tx download ready */ +/* Host Interrupt Status bit : Tx download ready */ #define IF_SPI_HIST_TX_DOWNLOAD_RDY (1<<0) -/** Host Interrupt Status bit : Rx upload ready */ +/* Host Interrupt Status bit : Rx upload ready */ #define IF_SPI_HIST_RX_UPLOAD_RDY (1<<1) -/** Host Interrupt Status bit : Command download ready */ +/* Host Interrupt Status bit : Command download ready */ #define IF_SPI_HIST_CMD_DOWNLOAD_RDY (1<<2) -/** Host Interrupt Status bit : Card event */ +/* Host Interrupt Status bit : Card event */ #define IF_SPI_HIST_CARD_EVENT (1<<3) -/** Host Interrupt Status bit : Command upload ready */ +/* Host Interrupt Status bit : Command upload ready */ #define IF_SPI_HIST_CMD_UPLOAD_RDY (1<<4) -/** Host Interrupt Status bit : I/O write FIFO overflow */ +/* Host Interrupt Status bit : I/O write FIFO overflow */ #define IF_SPI_HIST_IO_WR_FIFO_OVERFLOW (1<<5) -/** Host Interrupt Status bit : I/O read FIFO underflow */ +/* Host Interrupt Status bit : I/O read FIFO underflow */ #define IF_SPI_HIST_IO_RD_FIFO_UNDRFLOW (1<<6) -/** Host Interrupt Status bit : Data write FIFO overflow */ +/* Host Interrupt Status bit : Data write FIFO overflow */ #define IF_SPI_HIST_DATA_WR_FIFO_OVERFLOW (1<<7) -/** Host Interrupt Status bit : Data read FIFO underflow */ +/* Host Interrupt Status bit : Data read FIFO underflow */ #define IF_SPI_HIST_DATA_RD_FIFO_UNDERFLOW (1<<8) -/** Host Interrupt Status bit : Command write FIFO overflow */ +/* Host Interrupt Status bit : Command write FIFO overflow */ #define IF_SPI_HIST_CMD_WR_FIFO_OVERFLOW (1<<9) -/** Host Interrupt Status bit : Command read FIFO underflow */ +/* Host Interrupt Status bit : Command read FIFO underflow */ #define IF_SPI_HIST_CMD_RD_FIFO_UNDERFLOW (1<<10) /***************** IF_SPI_HOST_INT_STATUS_MASK_REG *****************/ -/** Host Interrupt Status Mask bit : Tx download ready */ +/* Host Interrupt Status Mask bit : Tx download ready */ #define IF_SPI_HISM_TX_DOWNLOAD_RDY (1<<0) -/** Host Interrupt Status Mask bit : Rx upload ready */ +/* Host Interrupt Status Mask bit : Rx upload ready */ #define IF_SPI_HISM_RX_UPLOAD_RDY (1<<1) -/** Host Interrupt Status Mask bit : Command download ready */ +/* Host Interrupt Status Mask bit : Command download ready */ #define IF_SPI_HISM_CMD_DOWNLOAD_RDY (1<<2) -/** Host Interrupt Status Mask bit : Card event */ +/* Host Interrupt Status Mask bit : Card event */ #define IF_SPI_HISM_CARDEVENT (1<<3) -/** Host Interrupt Status Mask bit : Command upload ready */ +/* Host Interrupt Status Mask bit : Command upload ready */ #define IF_SPI_HISM_CMD_UPLOAD_RDY (1<<4) -/** Host Interrupt Status Mask bit : I/O write FIFO overflow */ +/* Host Interrupt Status Mask bit : I/O write FIFO overflow */ #define IF_SPI_HISM_IO_WR_FIFO_OVERFLOW (1<<5) -/** Host Interrupt Status Mask bit : I/O read FIFO underflow */ +/* Host Interrupt Status Mask bit : I/O read FIFO underflow */ #define IF_SPI_HISM_IO_RD_FIFO_UNDERFLOW (1<<6) -/** Host Interrupt Status Mask bit : Data write FIFO overflow */ +/* Host Interrupt Status Mask bit : Data write FIFO overflow */ #define IF_SPI_HISM_DATA_WR_FIFO_OVERFLOW (1<<7) -/** Host Interrupt Status Mask bit : Data write FIFO underflow */ +/* Host Interrupt Status Mask bit : Data write FIFO underflow */ #define IF_SPI_HISM_DATA_RD_FIFO_UNDERFLOW (1<<8) -/** Host Interrupt Status Mask bit : Command write FIFO overflow */ +/* Host Interrupt Status Mask bit : Command write FIFO overflow */ #define IF_SPI_HISM_CMD_WR_FIFO_OVERFLOW (1<<9) -/** Host Interrupt Status Mask bit : Command write FIFO underflow */ +/* Host Interrupt Status Mask bit : Command write FIFO underflow */ #define IF_SPI_HISM_CMD_RD_FIFO_UNDERFLOW (1<<10) /***************** IF_SPI_SPU_BUS_MODE_REG *****************/ diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 6524c70363d9..b5acc393a65a 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -1,6 +1,9 @@ -/** - * This file contains functions used in USB interface module. - */ +/* + * This file contains functions used in USB interface module. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -66,7 +69,7 @@ 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, @@ -85,7 +88,7 @@ static ssize_t if_usb_firmware_set(struct device *dev, 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: @@ -94,7 +97,14 @@ static ssize_t if_usb_firmware_set(struct device *dev, static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set); /** - * Set function to write firmware to device's persistent memory + * 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) @@ -112,7 +122,7 @@ static ssize_t if_usb_boot2_set(struct device *dev, 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: @@ -121,9 +131,10 @@ static ssize_t if_usb_boot2_set(struct device *dev, static DEVICE_ATTR(lbs_flash_boot2, 0200, NULL, if_usb_boot2_set); /** - * @brief call back function to handle the status of the URB - * @param urb pointer to urb structure - * @return N/A + * if_usb_write_bulk_callback - callback function to handle the status + * of the URB + * @urb: pointer to &urb structure + * returns: N/A */ static void if_usb_write_bulk_callback(struct urb *urb) { @@ -145,14 +156,14 @@ static void if_usb_write_bulk_callback(struct urb *urb) lbs_host_to_card_done(priv); } else { /* print the failure status number for debug */ - lbs_pr_info("URB in failure status: %d\n", urb->status); + pr_info("URB in failure status: %d\n", urb->status); } } /** - * @brief free tx/rx urb, skb and rx buffer - * @param cardp pointer if_usb_card - * @return N/A + * if_usb_free - free tx/rx urb, skb and rx buffer + * @cardp: pointer to &if_usb_card + * returns: N/A */ static void if_usb_free(struct if_usb_card *cardp) { @@ -195,7 +206,7 @@ static void if_usb_setup_firmware(struct lbs_private *priv) wake_method.hdr.size = cpu_to_le16(sizeof(wake_method)); wake_method.action = cpu_to_le16(CMD_ACT_GET); if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) { - lbs_pr_info("Firmware does not seem to support PS mode\n"); + netdev_info(priv->dev, "Firmware does not seem to support PS mode\n"); priv->fwcapinfo &= ~FW_CAPINFO_PS; } else { if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) { @@ -204,7 +215,8 @@ static void if_usb_setup_firmware(struct lbs_private *priv) /* The versions which boot up this way don't seem to work even if we set it to the command interrupt */ priv->fwcapinfo &= ~FW_CAPINFO_PS; - lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n"); + netdev_info(priv->dev, + "Firmware doesn't wake via command interrupt; disabling PS mode\n"); } } } @@ -216,7 +228,7 @@ static void if_usb_fw_timeo(unsigned long priv) if (cardp->fwdnldover) { lbs_deb_usb("Download complete, no event. Assuming success\n"); } else { - lbs_pr_err("Download timed out\n"); + pr_err("Download timed out\n"); cardp->surprise_removed = 1; } wake_up(&cardp->fw_wq); @@ -231,10 +243,10 @@ static void if_usb_reset_olpc_card(struct lbs_private *priv) #endif /** - * @brief sets the configuration values - * @param ifnum interface number - * @param id pointer to usb_device_id - * @return 0 on success, error code on failure + * if_usb_probe - sets the configuration values + * @intf: &usb_interface pointer + * @id: pointer to usb_device_id + * returns: 0 on success, error code on failure */ static int if_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -250,7 +262,7 @@ static int if_usb_probe(struct usb_interface *intf, cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL); if (!cardp) { - lbs_pr_err("Out of memory allocating private data.\n"); + pr_err("Out of memory allocating private data\n"); goto error; } @@ -340,10 +352,12 @@ static int if_usb_probe(struct usb_interface *intf, usb_set_intfdata(intf, cardp); if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_fw)) - lbs_pr_err("cannot register lbs_flash_fw attribute\n"); + netdev_err(priv->dev, + "cannot register lbs_flash_fw attribute\n"); if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2)) - lbs_pr_err("cannot register lbs_flash_boot2 attribute\n"); + netdev_err(priv->dev, + "cannot register lbs_flash_boot2 attribute\n"); /* * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware. @@ -366,9 +380,9 @@ static int if_usb_probe(struct usb_interface *intf, } /** - * @brief free resource and cleanup - * @param intf USB interface structure - * @return N/A + * if_usb_disconnect - free resource and cleanup + * @intf: USB interface structure + * returns: N/A */ static void if_usb_disconnect(struct usb_interface *intf) { @@ -398,9 +412,9 @@ static void if_usb_disconnect(struct usb_interface *intf) } /** - * @brief This function download FW - * @param priv pointer to struct lbs_private - * @return 0 + * if_usb_send_fw_pkt - download FW + * @cardp: pointer to &struct if_usb_card + * returns: 0 */ static int if_usb_send_fw_pkt(struct if_usb_card *cardp) { @@ -486,11 +500,11 @@ static int if_usb_reset_device(struct if_usb_card *cardp) } /** - * @brief This function transfer the data to the device. - * @param priv pointer to struct lbs_private - * @param payload pointer to payload data - * @param nb data length - * @return 0 or -1 + * usb_tx_block - transfer the data to the device + * @cardp: pointer to &struct if_usb_card + * @payload: pointer to payload data + * @nb: data length + * returns: 0 for success or negative error code */ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb) { @@ -528,7 +542,7 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp, int ret = -1; if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) { - lbs_pr_err("No free skb\n"); + pr_err("No free skb\n"); goto rx_ret; } @@ -587,7 +601,7 @@ static void if_usb_receive_fwload(struct urb *urb) if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) && tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) { - lbs_pr_info("Firmware ready event received\n"); + pr_info("Firmware ready event received\n"); wake_up(&cardp->fw_wq); } else { lbs_deb_usb("Waiting for confirmation; got %x %x\n", @@ -614,20 +628,20 @@ static void if_usb_receive_fwload(struct urb *urb) bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) || bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) { if (!cardp->bootcmdresp) - lbs_pr_info("Firmware already seems alive; resetting\n"); + pr_info("Firmware already seems alive; resetting\n"); cardp->bootcmdresp = -1; } else { - lbs_pr_info("boot cmd response wrong magic number (0x%x)\n", + pr_info("boot cmd response wrong magic number (0x%x)\n", le32_to_cpu(bootcmdresp.magic)); } } else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) && (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) && (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) { - lbs_pr_info("boot cmd response cmd_tag error (%d)\n", - bootcmdresp.cmd); + pr_info("boot cmd response cmd_tag error (%d)\n", + bootcmdresp.cmd); } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) { - lbs_pr_info("boot cmd response result error (%d)\n", - bootcmdresp.result); + pr_info("boot cmd response result error (%d)\n", + bootcmdresp.result); } else { cardp->bootcmdresp = 1; lbs_deb_usbd(&cardp->udev->dev, @@ -727,11 +741,11 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, } /** - * @brief This function reads of the packet into the upload buff, - * wake up the main thread and initialise the Rx callack. + * if_usb_receive - read the packet into the upload buffer, + * wake up the main thread and initialise the Rx callack * - * @param urb pointer to struct urb - * @return N/A + * @urb: pointer to &struct urb + * returns: N/A */ static void if_usb_receive(struct urb *urb) { @@ -802,12 +816,12 @@ static void if_usb_receive(struct urb *urb) } /** - * @brief This function downloads data to FW - * @param priv pointer to struct lbs_private structure - * @param type type of data - * @param buf pointer to data buffer - * @param len number of bytes - * @return 0 or -1 + * if_usb_host_to_card - downloads data to FW + * @priv: pointer to &struct lbs_private structure + * @type: type of data + * @payload: pointer to data buffer + * @nb: number of bytes + * returns: 0 for success or negative error code */ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, uint8_t *payload, uint16_t nb) @@ -831,10 +845,11 @@ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, } /** - * @brief This function issues Boot command to the Boot2 code - * @param ivalue 1:Boot from FW by USB-Download - * 2:Boot from FW in EEPROM - * @return 0 + * if_usb_issue_boot_command - issues Boot command to the Boot2 code + * @cardp: pointer to &if_usb_card + * @ivalue: 1:Boot from FW by USB-Download + * 2:Boot from FW in EEPROM + * returns: 0 for success or negative error code */ static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue) { @@ -853,11 +868,11 @@ static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue) /** - * @brief This function checks the validity of Boot2/FW image. + * check_fwfile_format - check the validity of Boot2/FW image * - * @param data pointer to image - * len image length - * @return 0 or -1 + * @data: pointer to image + * @totlen: image length + * returns: 0 (good) or 1 (failure) */ static int check_fwfile_format(const uint8_t *data, uint32_t totlen) { @@ -892,7 +907,7 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen) } while (!exit); if (ret) - lbs_pr_err("firmware file format check FAIL\n"); + pr_err("firmware file format check FAIL\n"); else lbs_deb_fw("firmware file format check PASS\n"); @@ -901,13 +916,13 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen) /** -* @brief This function programs the firmware subject to cmd +* if_usb_prog_firmware - programs the firmware subject to cmd * -* @param 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. -* @return 0 or error code +* @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) @@ -989,7 +1004,7 @@ static int __if_usb_prog_firmware(struct if_usb_card *cardp, ret = get_fw(cardp, fwname); if (ret) { - lbs_pr_err("failed to find firmware (%d)\n", ret); + pr_err("failed to find firmware (%d)\n", ret); goto done; } @@ -1064,13 +1079,13 @@ static int __if_usb_prog_firmware(struct if_usb_card *cardp, usb_kill_urb(cardp->rx_urb); if (!cardp->fwdnldover) { - lbs_pr_info("failed to load fw, resetting device!\n"); + pr_info("failed to load fw, resetting device!\n"); if (--reset_count >= 0) { if_usb_reset_device(cardp); goto restart; } - lbs_pr_info("FW download failure, time = %d ms\n", i * 100); + pr_info("FW download failure, time = %d ms\n", i * 100); ret = -EIO; goto release_fw; } diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index d819e7e3c9aa..6e42eac331de 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -6,9 +6,9 @@ struct lbs_private; -/** - * This file contains definition for USB interface. - */ +/* + * This file contains definition for USB interface. + */ #define CMD_TYPE_REQUEST 0xF00DFACE #define CMD_TYPE_DATA 0xBEADC0DE #define CMD_TYPE_INDICATION 0xBEEFFACE @@ -40,7 +40,7 @@ struct bootcmdresp uint8_t pad[2]; }; -/** USB card description structure*/ +/* USB card description structure*/ struct if_usb_card { struct usb_device *udev; uint32_t model; /* MODEL_* */ @@ -77,7 +77,7 @@ struct if_usb_card { __le16 boot2_version; }; -/** fwheader */ +/* fwheader */ struct fwheader { __le32 dnldcmd; __le32 baseaddr; @@ -86,14 +86,14 @@ struct fwheader { }; #define FW_MAX_DATA_BLK_SIZE 600 -/** FWData */ +/* FWData */ struct fwdata { struct fwheader hdr; __le32 seqnum; uint8_t data[0]; }; -/** fwsyncheader */ +/* fwsyncheader */ struct fwsyncheader { __le32 cmd; __le32 seqnum; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index ca8149cd5bd9..8c40949cb076 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1,8 +1,10 @@ -/** - * This file contains the major functions in WLAN - * driver. It includes init, exit, open, close and main - * thread etc.. - */ +/* + * This file contains the major functions in WLAN + * driver. It includes init, exit, open, close and main + * thread etc.. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -34,19 +36,25 @@ unsigned int lbs_debug; EXPORT_SYMBOL_GPL(lbs_debug); module_param_named(libertas_debug, lbs_debug, int, 0644); +unsigned int lbs_disablemesh; +EXPORT_SYMBOL_GPL(lbs_disablemesh); +module_param_named(libertas_disablemesh, lbs_disablemesh, int, 0644); -/* This global structure is used to send the confirm_sleep command as - * fast as possible down to the firmware. */ + +/* + * This global structure is used to send the confirm_sleep command as + * fast as possible down to the firmware. + */ struct cmd_confirm_sleep confirm_sleep; -/** +/* * the table to keep region code */ u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; -/** +/* * FW rate table. FW refers to rates by their index in this table, not by the * rate value itself. Values of 0x00 are * reserved positions. @@ -57,10 +65,10 @@ static u8 fw_data_rates[MAX_RATES] = }; /** - * @brief use index to get the data rate + * lbs_fw_index_to_data_rate - use index to get the data rate * - * @param idx The index of data rate - * @return data rate or 0 + * @idx: The index of data rate + * returns: data rate or 0 */ u32 lbs_fw_index_to_data_rate(u8 idx) { @@ -70,10 +78,10 @@ u32 lbs_fw_index_to_data_rate(u8 idx) } /** - * @brief use rate to get the index + * lbs_data_rate_to_fw_index - use rate to get the index * - * @param rate data rate - * @return index or 0 + * @rate: data rate + * returns: index or 0 */ u8 lbs_data_rate_to_fw_index(u32 rate) { @@ -91,10 +99,10 @@ u8 lbs_data_rate_to_fw_index(u32 rate) /** - * @brief This function opens the ethX interface + * lbs_dev_open - open the ethX interface * - * @param dev A pointer to net_device structure - * @return 0 or -EBUSY if monitor mode active + * @dev: A pointer to &net_device structure + * returns: 0 or -EBUSY if monitor mode active */ static int lbs_dev_open(struct net_device *dev) { @@ -120,10 +128,10 @@ static int lbs_dev_open(struct net_device *dev) } /** - * @brief This function closes the ethX interface + * lbs_eth_stop - close the ethX interface * - * @param dev A pointer to net_device structure - * @return 0 + * @dev: A pointer to &net_device structure + * returns: 0 */ static int lbs_eth_stop(struct net_device *dev) { @@ -147,28 +155,6 @@ static int lbs_eth_stop(struct net_device *dev) return 0; } -static void lbs_tx_timeout(struct net_device *dev) -{ - struct lbs_private *priv = dev->ml_priv; - - lbs_deb_enter(LBS_DEB_TX); - - lbs_pr_err("tx watch dog timeout\n"); - - dev->trans_start = jiffies; /* prevent tx timeout */ - - if (priv->currenttxskb) - lbs_send_tx_feedback(priv, 0); - - /* XX: Shouldn't we also call into the hw-specific driver - to kick it somehow? */ - lbs_host_to_card_done(priv); - - /* FIXME: reset the card */ - - lbs_deb_leave(LBS_DEB_TX); -} - void lbs_host_to_card_done(struct lbs_private *priv) { unsigned long flags; @@ -336,12 +322,12 @@ void lbs_set_multicast_list(struct net_device *dev) } /** - * @brief This function handles the major jobs in the LBS driver. + * lbs_thread - handles the major jobs in the LBS driver. * It handles all events generated by firmware, RX data received * from firmware and TX data sent from kernel. * - * @param data A pointer to lbs_thread structure - * @return 0 + * @data: A pointer to &lbs_thread structure + * returns: 0 */ static int lbs_thread(void *data) { @@ -462,8 +448,8 @@ static int lbs_thread(void *data) if (priv->cmd_timed_out && priv->cur_cmd) { struct cmd_ctrl_node *cmdnode = priv->cur_cmd; - lbs_pr_info("Timeout submitting command 0x%04x\n", - le16_to_cpu(cmdnode->cmdbuf->command)); + netdev_info(dev, "Timeout submitting command 0x%04x\n", + le16_to_cpu(cmdnode->cmdbuf->command)); lbs_complete_command(priv, cmdnode, -ETIMEDOUT); if (priv->reset_card) priv->reset_card(priv); @@ -490,8 +476,8 @@ static int lbs_thread(void *data) * after firmware fixes it */ priv->psstate = PS_STATE_AWAKE; - lbs_pr_alert("ignore PS_SleepConfirm in " - "non-connected state\n"); + netdev_alert(dev, + "ignore PS_SleepConfirm in non-connected state\n"); } } @@ -540,11 +526,11 @@ static int lbs_thread(void *data) } /** - * @brief This function gets the HW spec from the firmware and sets - * some basic parameters. + * lbs_setup_firmware - gets the HW spec from the firmware and sets + * some basic parameters * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private structure + * returns: 0 or -1 */ static int lbs_setup_firmware(struct lbs_private *priv) { @@ -585,7 +571,8 @@ int lbs_suspend(struct lbs_private *priv) if (priv->is_deep_sleep) { ret = lbs_set_deep_sleep(priv, 0); if (ret) { - lbs_pr_err("deep sleep cancellation failed: %d\n", ret); + netdev_err(priv->dev, + "deep sleep cancellation failed: %d\n", ret); return ret; } priv->deep_sleep_required = 1; @@ -618,7 +605,8 @@ int lbs_resume(struct lbs_private *priv) priv->deep_sleep_required = 0; ret = lbs_set_deep_sleep(priv, 1); if (ret) - lbs_pr_err("deep sleep activation failed: %d\n", ret); + netdev_err(priv->dev, + "deep sleep activation failed: %d\n", ret); } if (priv->setup_fw_on_resume) @@ -630,8 +618,10 @@ int lbs_resume(struct lbs_private *priv) EXPORT_SYMBOL_GPL(lbs_resume); /** - * This function handles the timeout of command sending. - * It will re-send the same command again. + * lbs_cmd_timeout_handler - handles the timeout of command sending. + * It will re-send the same command again. + * + * @data: &struct lbs_private pointer */ static void lbs_cmd_timeout_handler(unsigned long data) { @@ -644,8 +634,8 @@ static void lbs_cmd_timeout_handler(unsigned long data) if (!priv->cur_cmd) goto out; - lbs_pr_info("command 0x%04x timed out\n", - le16_to_cpu(priv->cur_cmd->cmdbuf->command)); + netdev_info(priv->dev, "command 0x%04x timed out\n", + le16_to_cpu(priv->cur_cmd->cmdbuf->command)); priv->cmd_timed_out = 1; wake_up_interruptible(&priv->waitq); @@ -655,8 +645,10 @@ static void lbs_cmd_timeout_handler(unsigned long data) } /** - * This function put the device back to deep sleep mode when timer expires - * and no activity (command, event, data etc.) is detected. + * auto_deepsleep_timer_fn - put the device back to deep sleep mode when + * timer expires and no activity (command, event, data etc.) is detected. + * @data: &struct lbs_private pointer + * returns: N/A */ static void auto_deepsleep_timer_fn(unsigned long data) { @@ -748,7 +740,7 @@ static int lbs_init_adapter(struct lbs_private *priv) /* Allocate the command buffers */ if (lbs_allocate_cmd_buffer(priv)) { - lbs_pr_err("Out of memory allocating command buffers\n"); + pr_err("Out of memory allocating command buffers\n"); ret = -ENOMEM; goto out; } @@ -758,7 +750,7 @@ static int lbs_init_adapter(struct lbs_private *priv) /* Create the event FIFO */ ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL); if (ret) { - lbs_pr_err("Out of memory allocating event FIFO buffer\n"); + pr_err("Out of memory allocating event FIFO buffer\n"); goto out; } @@ -785,18 +777,18 @@ static const struct net_device_ops lbs_netdev_ops = { .ndo_stop = lbs_eth_stop, .ndo_start_xmit = lbs_hard_start_xmit, .ndo_set_mac_address = lbs_set_mac_address, - .ndo_tx_timeout = lbs_tx_timeout, .ndo_set_multicast_list = lbs_set_multicast_list, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, }; /** - * @brief This function adds the card. it will probe the + * lbs_add_card - adds the card. It will probe the * card, allocate the lbs_priv and initialize the device. * - * @param card A pointer to card - * @return A pointer to struct lbs_private structure + * @card: A pointer to card + * @dmdev: A pointer to &struct device + * returns: A pointer to &struct lbs_private structure */ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) { @@ -809,7 +801,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) /* Allocate an Ethernet device and register it */ wdev = lbs_cfg_alloc(dmdev); if (IS_ERR(wdev)) { - lbs_pr_err("cfg80211 init failed\n"); + pr_err("cfg80211 init failed\n"); goto done; } @@ -818,7 +810,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->wdev = wdev; if (lbs_init_adapter(priv)) { - lbs_pr_err("failed to initialize adapter structure.\n"); + pr_err("failed to initialize adapter structure\n"); goto err_wdev; } @@ -950,17 +942,20 @@ int lbs_start_card(struct lbs_private *priv) goto done; if (lbs_cfg_register(priv)) { - lbs_pr_err("cannot register device\n"); + pr_err("cannot register device\n"); goto done; } lbs_update_channel(priv); - lbs_init_mesh(priv); + if (!lbs_disablemesh) + lbs_init_mesh(priv); + else + pr_info("%s: mesh disabled\n", dev->name); lbs_debugfs_init_one(priv, dev); - lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); + netdev_info(dev, "Marvell WLAN 802.11 adapter\n"); ret = 0; @@ -1057,19 +1052,19 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx) EXPORT_SYMBOL_GPL(lbs_notify_command_response); /** - * @brief Retrieves two-stage firmware + * lbs_get_firmware - Retrieves two-stage firmware * - * @param dev A pointer to device structure - * @param user_helper User-defined helper firmware file - * @param user_mainfw User-defined main firmware file - * @param card_model Bus-specific card model ID used to filter firmware table - * elements - * @param fw_table Table of firmware file names and device model numbers - * terminated by an entry with a NULL helper name - * @param helper On success, the helper firmware; caller must free - * @param mainfw On success, the main firmware; caller must free + * @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 * - * @return 0 on success, non-zero on failure + * 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, @@ -1087,16 +1082,16 @@ int lbs_get_firmware(struct device *dev, const char *user_helper, if (user_helper) { ret = request_firmware(helper, user_helper, dev); if (ret) { - lbs_pr_err("couldn't find helper firmware %s", - user_helper); + 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) { - lbs_pr_err("couldn't find main firmware %s", - user_mainfw); + dev_err(dev, "couldn't find main firmware %s\n", + user_mainfw); goto fail; } } diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 9d097b9c8005..24cf06680c6b 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -1,3 +1,5 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -16,12 +18,15 @@ * Mesh sysfs support */ -/** +/* * Attributes exported through sysfs */ /** - * @brief Get function for sysfs attribute anycast_mask + * lbs_anycast_get - Get function for sysfs attribute anycast_mask + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t lbs_anycast_get(struct device *dev, struct device_attribute *attr, char * buf) @@ -40,7 +45,11 @@ static ssize_t lbs_anycast_get(struct device *dev, } /** - * @brief Set function for sysfs attribute anycast_mask + * lbs_anycast_set - Set function for sysfs attribute anycast_mask + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t lbs_anycast_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) @@ -62,7 +71,10 @@ static ssize_t lbs_anycast_set(struct device *dev, } /** - * @brief Get function for sysfs attribute prb_rsp_limit + * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t lbs_prb_rsp_limit_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -85,7 +97,11 @@ static ssize_t lbs_prb_rsp_limit_get(struct device *dev, } /** - * @brief Set function for sysfs attribute prb_rsp_limit + * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t lbs_prb_rsp_limit_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -114,7 +130,10 @@ static ssize_t lbs_prb_rsp_limit_set(struct device *dev, } /** - * Get function for sysfs attribute mesh + * lbs_mesh_get - Get function for sysfs attribute mesh + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t lbs_mesh_get(struct device *dev, struct device_attribute *attr, char * buf) @@ -124,7 +143,11 @@ static ssize_t lbs_mesh_get(struct device *dev, } /** - * Set function for sysfs attribute mesh + * lbs_mesh_set - Set function for sysfs attribute mesh + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t lbs_mesh_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) @@ -151,19 +174,19 @@ static ssize_t lbs_mesh_set(struct device *dev, return count; } -/** +/* * lbs_mesh attribute to be exported per ethX interface * through sysfs (/sys/class/net/ethX/lbs_mesh) */ static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set); -/** +/* * anycast_mask attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/anycast_mask) */ static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set); -/** +/* * prb_rsp_limit attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/prb_rsp_limit) */ @@ -246,7 +269,7 @@ int lbs_init_mesh(struct lbs_private *priv) lbs_add_mesh(priv); if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) - lbs_pr_err("cannot register lbs_mesh attribute\n"); + netdev_err(dev, "cannot register lbs_mesh attribute\n"); ret = 1; } @@ -274,10 +297,10 @@ int lbs_deinit_mesh(struct lbs_private *priv) /** - * @brief This function closes the mshX interface + * lbs_mesh_stop - close the mshX interface * - * @param dev A pointer to net_device structure - * @return 0 + * @dev: A pointer to &net_device structure + * returns: 0 */ static int lbs_mesh_stop(struct net_device *dev) { @@ -301,10 +324,10 @@ static int lbs_mesh_stop(struct net_device *dev) } /** - * @brief This function opens the mshX interface + * lbs_mesh_dev_open - open the mshX interface * - * @param dev A pointer to net_device structure - * @return 0 or -EBUSY if monitor mode active + * @dev: A pointer to &net_device structure + * returns: 0 or -EBUSY if monitor mode active */ static int lbs_mesh_dev_open(struct net_device *dev) { @@ -342,10 +365,10 @@ static const struct net_device_ops mesh_netdev_ops = { }; /** - * @brief This function adds mshX interface + * lbs_add_mesh - add mshX interface * - * @param priv A pointer to the struct lbs_private structure - * @return 0 if successful, -X otherwise + * @priv: A pointer to the &struct lbs_private structure + * returns: 0 if successful, -X otherwise */ int lbs_add_mesh(struct lbs_private *priv) { @@ -374,7 +397,7 @@ int lbs_add_mesh(struct lbs_private *priv) /* Register virtual mesh interface */ ret = register_netdev(mesh_dev); if (ret) { - lbs_pr_err("cannot register mshX virtual interface\n"); + pr_err("cannot register mshX virtual interface\n"); goto err_free; } @@ -456,13 +479,13 @@ void lbs_mesh_set_txpd(struct lbs_private *priv, */ /** - * @brief Add or delete Mesh Blinding Table entries + * lbs_mesh_bt_add_del - Add or delete Mesh Blinding Table entries * - * @param priv A pointer to struct lbs_private structure - * @param add TRUE to add the entry, FALSE to delete it - * @param addr1 Destination address to blind or unblind + * @priv: A pointer to &struct lbs_private structure + * @add: TRUE to add the entry, FALSE to delete it + * @addr1: Destination address to blind or unblind * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1) { @@ -493,11 +516,11 @@ int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1) } /** - * @brief Reset/clear the mesh blinding table + * lbs_mesh_bt_reset - Reset/clear the mesh blinding table * - * @param priv A pointer to struct lbs_private structure + * @priv: A pointer to &struct lbs_private structure * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_reset(struct lbs_private *priv) { @@ -517,17 +540,18 @@ int lbs_mesh_bt_reset(struct lbs_private *priv) } /** - * @brief Gets the inverted status of the mesh blinding table + * lbs_mesh_bt_get_inverted - Gets the inverted status of the mesh + * blinding table * - * Normally the firmware "blinds" or ignores traffic from mesh nodes in the - * table, but an inverted table allows *only* traffic from nodes listed in - * the table. + * Normally the firmware "blinds" or ignores traffic from mesh nodes in the + * table, but an inverted table allows *only* traffic from nodes listed in + * the table. * - * @param priv A pointer to struct lbs_private structure - * @param invert On success, TRUE if the blinding table is inverted, - * FALSE if it is not inverted + * @priv: A pointer to &struct lbs_private structure + * @inverted: On success, TRUE if the blinding table is inverted, + * FALSE if it is not inverted * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted) { @@ -551,18 +575,19 @@ int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted) } /** - * @brief Sets the inverted status of the mesh blinding table + * lbs_mesh_bt_set_inverted - Sets the inverted status of the mesh + * blinding table * - * Normally the firmware "blinds" or ignores traffic from mesh nodes in the - * table, but an inverted table allows *only* traffic from nodes listed in - * the table. + * Normally the firmware "blinds" or ignores traffic from mesh nodes in the + * table, but an inverted table allows *only* traffic from nodes listed in + * the table. * - * @param priv A pointer to struct lbs_private structure - * @param invert TRUE to invert the blinding table (only traffic from - * listed nodes allowed), FALSE to return it - * to normal state (listed nodes ignored) + * @priv: A pointer to &struct lbs_private structure + * @inverted: TRUE to invert the blinding table (only traffic from + * listed nodes allowed), FALSE to return it + * to normal state (listed nodes ignored) * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted) { @@ -583,13 +608,13 @@ int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted) } /** - * @brief List an entry in the mesh blinding table + * lbs_mesh_bt_get_entry - List an entry in the mesh blinding table * - * @param priv A pointer to struct lbs_private structure - * @param id The ID of the entry to list - * @param addr1 MAC address associated with the table entry + * @priv: A pointer to &struct lbs_private structure + * @id: The ID of the entry to list + * @addr1: MAC address associated with the table entry * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1) { @@ -614,14 +639,14 @@ int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1) } /** - * @brief Access the mesh forwarding table + * lbs_cmd_fwt_access - Access the mesh forwarding table * - * @param priv A pointer to struct lbs_private structure - * @param cmd_action The forwarding table action to perform - * @param cmd The pre-filled FWT_ACCESS command + * @priv: A pointer to &struct lbs_private structure + * @cmd_action: The forwarding table action to perform + * @cmd: The pre-filled FWT_ACCESS command * - * @return 0 on success and 'cmd' will be filled with the - * firmware's response + * returns: 0 on success and 'cmd' will be filled with the + * firmware's response */ int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action, struct cmd_ds_fwt_access *cmd) @@ -774,7 +799,10 @@ static int mesh_get_default_parameters(struct device *dev, } /** - * @brief Get function for sysfs attribute bootflag + * bootflag_get - Get function for sysfs attribute bootflag + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t bootflag_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -791,7 +819,11 @@ static ssize_t bootflag_get(struct device *dev, } /** - * @brief Set function for sysfs attribute bootflag + * bootflag_set - Set function for sysfs attribute bootflag + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -817,7 +849,10 @@ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, } /** - * @brief Get function for sysfs attribute boottime + * boottime_get - Get function for sysfs attribute boottime + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t boottime_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -834,7 +869,11 @@ static ssize_t boottime_get(struct device *dev, } /** - * @brief Set function for sysfs attribute boottime + * boottime_set - Set function for sysfs attribute boottime + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t boottime_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -869,7 +908,10 @@ static ssize_t boottime_set(struct device *dev, } /** - * @brief Get function for sysfs attribute channel + * channel_get - Get function for sysfs attribute channel + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t channel_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -886,7 +928,11 @@ static ssize_t channel_get(struct device *dev, } /** - * @brief Set function for sysfs attribute channel + * channel_set - Set function for sysfs attribute channel + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t channel_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -912,7 +958,10 @@ static ssize_t channel_set(struct device *dev, struct device_attribute *attr, } /** - * @brief Get function for sysfs attribute mesh_id + * mesh_id_get - Get function for sysfs attribute mesh_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -926,7 +975,7 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, return ret; if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) { - lbs_pr_err("inconsistent mesh ID length"); + dev_err(dev, "inconsistent mesh ID length\n"); defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN; } @@ -938,7 +987,11 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, } /** - * @brief Set function for sysfs attribute mesh_id + * mesh_id_set - Set function for sysfs attribute mesh_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -980,7 +1033,10 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, } /** - * @brief Get function for sysfs attribute protocol_id + * protocol_id_get - Get function for sysfs attribute protocol_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t protocol_id_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -997,7 +1053,11 @@ static ssize_t protocol_id_get(struct device *dev, } /** - * @brief Set function for sysfs attribute protocol_id + * protocol_id_set - Set function for sysfs attribute protocol_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t protocol_id_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1034,7 +1094,10 @@ static ssize_t protocol_id_set(struct device *dev, } /** - * @brief Get function for sysfs attribute metric_id + * metric_id_get - Get function for sysfs attribute metric_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t metric_id_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -1051,7 +1114,11 @@ static ssize_t metric_id_get(struct device *dev, } /** - * @brief Set function for sysfs attribute metric_id + * metric_id_set - Set function for sysfs attribute metric_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1088,7 +1155,10 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, } /** - * @brief Get function for sysfs attribute capability + * capability_get - Get function for sysfs attribute capability + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t capability_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -1105,7 +1175,11 @@ static ssize_t capability_get(struct device *dev, } /** - * @brief Set function for sysfs attribute capability + * capability_set - Set function for sysfs attribute capability + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t capability_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index afb2e8dead3f..ee95c73ed5f4 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h @@ -1,6 +1,6 @@ -/** - * Contains all definitions needed for the Libertas' MESH implementation. - */ +/* + * Contains all definitions needed for the Libertas' MESH implementation. + */ #ifndef _LBS_MESH_H_ #define _LBS_MESH_H_ diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index a2b1df21d286..fdb0448301a0 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -1,6 +1,9 @@ -/** - * This file contains the handling of RX in wlan driver. - */ +/* + * This file contains the handling of RX in wlan driver. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -40,12 +43,12 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, struct sk_buff *skb); /** - * @brief This function processes received packet and forwards it - * to kernel/upper layer + * lbs_process_rxed_packet - processes received packet and forwards it + * to kernel/upper layer * - * @param priv A pointer to struct lbs_private - * @param skb A pointer to skb which includes the received packet - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private + * @skb: A pointer to skb which includes the received packet + * returns: 0 or -1 */ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) { @@ -156,11 +159,11 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) EXPORT_SYMBOL_GPL(lbs_process_rxed_packet); /** - * @brief This function converts Tx/Rx rates from the Marvell WLAN format - * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) + * convert_mv_rate_to_radiotap - converts Tx/Rx rates from Marvell WLAN format + * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) * - * @param rate Input rate - * @return Output Rate (0 if invalid) + * @rate: Input rate + * returns: Output Rate (0 if invalid) */ static u8 convert_mv_rate_to_radiotap(u8 rate) { @@ -191,17 +194,17 @@ static u8 convert_mv_rate_to_radiotap(u8 rate) case 12: /* 54 Mbps */ return 108; } - lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate); + pr_alert("Invalid Marvell WLAN rate %i\n", rate); return 0; } /** - * @brief This function processes a received 802.11 packet and forwards it - * to kernel/upper layer + * process_rxed_802_11_packet - processes a received 802.11 packet and forwards + * it to kernel/upper layer * - * @param priv A pointer to struct lbs_private - * @param skb A pointer to skb which includes the received packet - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private + * @skb: A pointer to skb which includes the received packet + * returns: 0 or -1 */ static int process_rxed_802_11_packet(struct lbs_private *priv, struct sk_buff *skb) @@ -248,7 +251,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, /* add space for the new radio header */ if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) && pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) { - lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__); + netdev_alert(dev, "%s: couldn't pskb_expand_head\n", __func__); ret = -ENOMEM; kfree_skb(skb); goto done; diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 8000ca6165d0..bbb95f88dc01 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -1,6 +1,6 @@ -/** - * This file contains the handling of TX in wlan driver. - */ +/* + * This file contains the handling of TX in wlan driver. + */ #include #include #include @@ -13,11 +13,11 @@ #include "dev.h" /** - * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE - * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1) + * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE + * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1) * - * @param rate Input rate - * @return Output Rate (0 if invalid) + * @rate: Input rate + * returns: Output Rate (0 if invalid) */ static u32 convert_radiotap_rate_to_mv(u8 rate) { @@ -51,12 +51,12 @@ static u32 convert_radiotap_rate_to_mv(u8 rate) } /** - * @brief This function checks the conditions and sends packet to IF - * layer if everything is ok. + * lbs_hard_start_xmit - checks the conditions and sends packet to IF + * layer if everything is ok * - * @param priv A pointer to struct lbs_private structure - * @param skb A pointer to skb which includes TX packet - * @return 0 or -1 + * @skb: A pointer to skb which includes TX packet + * @dev: A pointer to the &struct net_device + * returns: 0 or -1 */ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -168,13 +168,13 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } /** - * @brief This function sends to the host the last transmitted packet, - * filling the radiotap headers with transmission information. + * lbs_send_tx_feedback - sends to the host the last transmitted packet, + * filling the radiotap headers with transmission information. * - * @param priv A pointer to struct lbs_private structure - * @param status A 32 bit value containing transmission status. + * @priv: A pointer to &struct lbs_private structure + * @try_count: A 32-bit value containing transmission retry status. * - * @returns void + * returns: void */ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count) { diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 462fbb4cb743..cf1d9b047ee6 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -1,6 +1,6 @@ -/** - * This header file contains definition for global types - */ +/* + * This header file contains definition for global types + */ #ifndef _LBS_TYPES_H_ #define _LBS_TYPES_H_ @@ -54,7 +54,7 @@ union ieee_phy_param_set { struct ieee_ie_ds_param_set ds; } __packed; -/** TLV type ID definition */ +/* TLV type ID definition */ #define PROPRIETARY_TLV_BASE_ID 0x0100 /* Terminating TLV type */ @@ -96,7 +96,7 @@ union ieee_phy_param_set { #define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37) #define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291) -/** TLV related data structures*/ +/* TLV related data structures */ struct mrvl_ie_header { __le16 type; __le16 len; @@ -177,7 +177,7 @@ struct mrvl_ie_auth_type { __le16 auth; } __packed; -/** Local Power capability */ +/* Local Power capability */ struct mrvl_ie_power_capability { struct mrvl_ie_header header; s8 minpower; @@ -235,9 +235,11 @@ struct mrvl_ie_ledbhv { struct led_bhv ledbhv[1]; } __packed; -/* Meant to be packed as the value member of a struct ieee80211_info_element. +/* + * Meant to be packed as the value member of a struct ieee80211_info_element. * Note that the len member of the ieee80211_info_element varies depending on - * the mesh_id_len */ + * the mesh_id_len + */ struct mrvl_meshie_val { uint8_t oui[3]; uint8_t type; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index f4f4257a9d67..9d4a40ee16c4 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1515,19 +1515,10 @@ static int __init init_mac80211_hwsim(void) if (hwsim_mon == NULL) goto failed; - rtnl_lock(); - - err = dev_alloc_name(hwsim_mon, hwsim_mon->name); + err = register_netdev(hwsim_mon); if (err < 0) goto failed_mon; - - err = register_netdevice(hwsim_mon); - if (err < 0) - goto failed_mon; - - rtnl_unlock(); - return 0; failed_mon: diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c new file mode 100644 index 000000000000..916183d39009 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n.c @@ -0,0 +1,744 @@ +/* + * Marvell Wireless LAN device driver: 802.11n + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * Fills HT capability information field, AMPDU Parameters field, HT extended + * capability field, and supported MCS set fields. + * + * HT capability information field, AMPDU Parameters field, supported MCS set + * fields are retrieved from cfg80211 stack + * + * RD responder bit to set to clear in the extended capability header. + */ +void +mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type, + struct mwifiex_ie_types_htcap *ht_cap) +{ + uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info); + struct ieee80211_supported_band *sband = + priv->wdev->wiphy->bands[radio_type]; + + ht_cap->ht_cap.ampdu_params_info = + (sband->ht_cap.ampdu_factor & + IEEE80211_HT_AMPDU_PARM_FACTOR)| + ((sband->ht_cap.ampdu_density << + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT) & + IEEE80211_HT_AMPDU_PARM_DENSITY); + + memcpy((u8 *) &ht_cap->ht_cap.mcs, &sband->ht_cap.mcs, + sizeof(sband->ht_cap.mcs)); + + if (priv->bss_mode == NL80211_IFTYPE_STATION || + (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ + SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); + + /* Clear RD responder bit */ + ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER; + + ht_cap->ht_cap.cap_info = cpu_to_le16(sband->ht_cap.cap); + ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap); +} + +/* + * This function returns the pointer to an entry in BA Stream + * table which matches the requested BA status. + */ +static struct mwifiex_tx_ba_stream_tbl * +mwifiex_11n_get_tx_ba_stream_status(struct mwifiex_private *priv, + enum mwifiex_ba_status ba_status) +{ + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (tx_ba_tsr_tbl->ba_status == ba_status) { + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, + flags); + return tx_ba_tsr_tbl; + } + } + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + return NULL; +} + +/* + * This function handles the command response of delete a block + * ack request. + * + * The function checks the response success status and takes action + * accordingly (send an add BA request in case of success, or recreate + * the deleted stream in case of failure, if the add BA was also + * initiated by us). + */ +int mwifiex_ret_11n_delba(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + int tid; + struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; + struct host_cmd_ds_11n_delba *del_ba = + (struct host_cmd_ds_11n_delba *) &resp->params.del_ba; + uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set); + + tid = del_ba_param_set >> DELBA_TID_POS; + if (del_ba->del_result == BA_RESULT_SUCCESS) { + mwifiex_11n_delete_ba_stream_tbl(priv, tid, + del_ba->peer_mac_addr, TYPE_DELBA_SENT, + INITIATOR_BIT(del_ba_param_set)); + + tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv, + BA_STREAM_SETUP_INPROGRESS); + if (tx_ba_tbl) + mwifiex_send_addba(priv, tx_ba_tbl->tid, + tx_ba_tbl->ra); + } else { /* + * In case of failure, recreate the deleted stream in case + * we initiated the ADDBA + */ + if (INITIATOR_BIT(del_ba_param_set)) { + mwifiex_11n_create_tx_ba_stream_tbl(priv, + del_ba->peer_mac_addr, tid, + BA_STREAM_SETUP_INPROGRESS); + + tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv, + BA_STREAM_SETUP_INPROGRESS); + if (tx_ba_tbl) + mwifiex_11n_delete_ba_stream_tbl(priv, + tx_ba_tbl->tid, tx_ba_tbl->ra, + TYPE_DELBA_SENT, true); + } + } + + return 0; +} + +/* + * This function handles the command response of add a block + * ack request. + * + * Handling includes changing the header fields to CPU formats, checking + * the response success status and taking actions accordingly (delete the + * BA stream table in case of failure). + */ +int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + int tid; + struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = + (struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp; + struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; + + add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) + & SSN_MASK); + + tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set) + & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; + if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { + tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, + add_ba_rsp->peer_mac_addr); + if (tx_ba_tbl) { + dev_dbg(priv->adapter->dev, "info: BA stream complete\n"); + tx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE; + } else { + dev_err(priv->adapter->dev, "BA stream not created\n"); + } + } else { + mwifiex_11n_delete_ba_stream_tbl(priv, tid, + add_ba_rsp->peer_mac_addr, + TYPE_DELBA_SENT, true); + if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) + priv->aggr_prio_tbl[tid].ampdu_ap = + BA_STREAM_NOT_ALLOWED; + } + + return 0; +} + +/* + * This function handles the command response of 11n configuration request. + * + * Handling includes changing the header fields into CPU format. + */ +int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, void *data_buf) +{ + struct mwifiex_ds_11n_tx_cfg *tx_cfg; + struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg; + + if (data_buf) { + tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf; + tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap); + tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info); + } + return 0; +} + +/* + * This function prepares command of reconfigure Tx buffer. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting Tx buffer size (for SET only) + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, int cmd_action, + void *data_buf) +{ + struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf; + u16 action = (u16) cmd_action; + u16 buf_size = *((u16 *) data_buf); + + cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN); + tx_buf->action = cpu_to_le16(action); + switch (action) { + case HostCmd_ACT_GEN_SET: + dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size); + tx_buf->buff_size = cpu_to_le16(buf_size); + break; + case HostCmd_ACT_GEN_GET: + default: + tx_buf->buff_size = 0; + break; + } + return 0; +} + +/* + * This function prepares command of AMSDU aggregation control. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting AMSDU control parameters (for SET only) + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, + int cmd_action, void *data_buf) +{ + struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = + &cmd->params.amsdu_aggr_ctrl; + u16 action = (u16) cmd_action; + struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl = + (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; + + cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl) + + S_DS_GEN); + amsdu_ctrl->action = cpu_to_le16(action); + switch (action) { + case HostCmd_ACT_GEN_SET: + amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable); + amsdu_ctrl->curr_buf_size = 0; + break; + case HostCmd_ACT_GEN_GET: + default: + amsdu_ctrl->curr_buf_size = 0; + break; + } + return 0; +} + +/* + * This function handles the command response of AMSDU aggregation + * control request. + * + * Handling includes changing the header fields into CPU format. + */ +int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl; + struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = + &resp->params.amsdu_aggr_ctrl; + + if (data_buf) { + amsdu_aggr_ctrl = + (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; + amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable); + amsdu_aggr_ctrl->curr_buf_size = + le16_to_cpu(amsdu_ctrl->curr_buf_size); + } + return 0; +} + +/* + * This function prepares 11n configuration command. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting HT Tx capability and HT Tx information fields + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; + struct mwifiex_ds_11n_tx_cfg *txcfg = + (struct mwifiex_ds_11n_tx_cfg *) data_buf; + + cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN); + htcfg->action = cpu_to_le16(cmd_action); + htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap); + htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo); + return 0; +} + +/* + * This function appends an 11n TLV to a buffer. + * + * Buffer allocation is responsibility of the calling + * function. No size validation is made here. + * + * The function fills up the following sections, if applicable - + * - HT capability IE + * - HT information IE (with channel list) + * - 20/40 BSS Coexistence IE + * - HT Extended Capabilities IE + */ +int +mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + u8 **buffer) +{ + struct mwifiex_ie_types_htcap *ht_cap; + struct mwifiex_ie_types_htinfo *ht_info; + struct mwifiex_ie_types_chan_list_param_set *chan_list; + struct mwifiex_ie_types_2040bssco *bss_co_2040; + struct mwifiex_ie_types_extcap *ext_cap; + int ret_len = 0; + struct ieee80211_supported_band *sband; + u8 radio_type; + + if (!buffer || !*buffer) + return ret_len; + + radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); + sband = priv->wdev->wiphy->bands[radio_type]; + + if (bss_desc->bcn_ht_cap) { + ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; + memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); + ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); + ht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header), + (u8 *) bss_desc->bcn_ht_cap + + sizeof(struct ieee_types_header), + le16_to_cpu(ht_cap->header.len)); + + mwifiex_fill_cap_info(priv, radio_type, ht_cap); + + *buffer += sizeof(struct mwifiex_ie_types_htcap); + ret_len += sizeof(struct mwifiex_ie_types_htcap); + } + + if (bss_desc->bcn_ht_info) { + 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); + ht_info->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_info)); + + memcpy((u8 *) ht_info + + sizeof(struct mwifiex_ie_types_header), + (u8 *) bss_desc->bcn_ht_info + + 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 &= + ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY | + IEEE80211_HT_PARAM_CHA_SEC_OFFSET); + + *buffer += sizeof(struct mwifiex_ie_types_htinfo); + ret_len += sizeof(struct mwifiex_ie_types_htinfo); + } + + chan_list = + (struct mwifiex_ie_types_chan_list_param_set *) *buffer; + memset(chan_list, 0, + sizeof(struct mwifiex_ie_types_chan_list_param_set)); + chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_list->header.len = cpu_to_le16( + 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; + 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 & + IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) + SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. + radio_type, + (bss_desc->bcn_ht_info->ht_param & + IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); + + *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); + ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set); + } + + if (bss_desc->bcn_bss_co_2040) { + bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer; + memset(bss_co_2040, 0, + sizeof(struct mwifiex_ie_types_2040bssco)); + bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040); + bss_co_2040->header.len = + cpu_to_le16(sizeof(bss_co_2040->bss_co_2040)); + + memcpy((u8 *) bss_co_2040 + + sizeof(struct mwifiex_ie_types_header), + (u8 *) bss_desc->bcn_bss_co_2040 + + sizeof(struct ieee_types_header), + le16_to_cpu(bss_co_2040->header.len)); + + *buffer += sizeof(struct mwifiex_ie_types_2040bssco); + ret_len += sizeof(struct mwifiex_ie_types_2040bssco); + } + + if (bss_desc->bcn_ext_cap) { + ext_cap = (struct mwifiex_ie_types_extcap *) *buffer; + memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap)); + ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY); + ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap)); + + memcpy((u8 *) ext_cap + + sizeof(struct mwifiex_ie_types_header), + (u8 *) bss_desc->bcn_ext_cap + + sizeof(struct ieee_types_header), + le16_to_cpu(ext_cap->header.len)); + + *buffer += sizeof(struct mwifiex_ie_types_extcap); + ret_len += sizeof(struct mwifiex_ie_types_extcap); + } + + return ret_len; +} + +/* + * This function reconfigures the Tx buffer size in firmware. + * + * This function prepares a firmware command and issues it, if + * the current Tx buffer size is different from the one requested. + * Maximum configurable Tx buffer size is limited by the HT capability + * field value. + */ +void +mwifiex_cfg_tx_buf(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K; + u16 tx_buf, curr_tx_buf_size = 0; + + if (bss_desc->bcn_ht_cap) { + if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) & + IEEE80211_HT_CAP_MAX_AMSDU) + max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K; + else + max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K; + } + + tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu); + + dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n", + max_amsdu, priv->adapter->max_tx_buf_size); + + if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K) + curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K) + curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; + else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K) + curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K; + if (curr_tx_buf_size != tx_buf) + mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, + HostCmd_ACT_GEN_SET, 0, &tx_buf); +} + +/* + * This function checks if the given pointer is valid entry of + * Tx BA Stream table. + */ +static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv, + struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr) +{ + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; + + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (tx_ba_tsr_tbl == tx_tbl_ptr) + return true; + } + + return false; +} + +/* + * This function deletes the given entry in Tx BA Stream table. + * + * The function also performs a validity check on the supplied + * pointer before trying to delete. + */ +void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl) +{ + if (!tx_ba_tsr_tbl && + mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl)) + return; + + dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl); + + list_del(&tx_ba_tsr_tbl->list); + + kfree(tx_ba_tsr_tbl); +} + +/* + * This function deletes all the entries in Tx BA Stream table. + */ +void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv) +{ + int i; + struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry_safe(del_tbl_ptr, tmp_node, + &priv->tx_ba_stream_tbl_ptr, list) + mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr); + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + + INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); + + for (i = 0; i < MAX_NUM_TID; ++i) + priv->aggr_prio_tbl[i].ampdu_ap = + priv->aggr_prio_tbl[i].ampdu_user; +} + +/* + * This function returns the pointer to an entry in BA Stream + * table which matches the given RA/TID pair. + */ +struct mwifiex_tx_ba_stream_tbl * +mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv, + int tid, u8 *ra) +{ + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN)) + && (tx_ba_tsr_tbl->tid == tid)) { + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, + flags); + return tx_ba_tsr_tbl; + } + } + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + return NULL; +} + +/* + * This function creates an entry in Tx BA stream table for the + * given RA/TID pair. + */ +void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, + u8 *ra, int tid, + enum mwifiex_ba_status ba_status) +{ + struct mwifiex_tx_ba_stream_tbl *new_node; + unsigned long flags; + + if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) { + new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl), + GFP_ATOMIC); + if (!new_node) { + dev_err(priv->adapter->dev, + "%s: failed to alloc new_node\n", __func__); + return; + } + + INIT_LIST_HEAD(&new_node->list); + + new_node->tid = tid; + new_node->ba_status = ba_status; + memcpy(new_node->ra, ra, ETH_ALEN); + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr); + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + } +} + +/* + * This function sends an add BA request to the given TID/RA pair. + */ +int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) +{ + struct host_cmd_ds_11n_addba_req add_ba_req; + static u8 dialog_tok; + int ret; + + dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid); + + add_ba_req.block_ack_param_set = cpu_to_le16( + (u16) ((tid << BLOCKACKPARAM_TID_POS) | + (priv->add_ba_param. + tx_win_size << BLOCKACKPARAM_WINSIZE_POS) | + IMMEDIATE_BLOCK_ACK)); + add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout); + + ++dialog_tok; + + if (dialog_tok == 0) + dialog_tok = 1; + + add_ba_req.dialog_token = dialog_tok; + memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN); + + /* We don't wait for the response of this command */ + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ, + 0, 0, &add_ba_req); + + return ret; +} + +/* + * This function sends a delete BA request to the given TID/RA pair. + */ +int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, + int initiator) +{ + struct host_cmd_ds_11n_delba delba; + int ret; + uint16_t del_ba_param_set; + + memset(&delba, 0, sizeof(delba)); + delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS); + + del_ba_param_set = le16_to_cpu(delba.del_ba_param_set); + if (initiator) + del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK; + else + del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK; + + memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); + + /* We don't wait for the response of this command */ + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, + HostCmd_ACT_GEN_SET, 0, &delba); + + return ret; +} + +/* + * This function handles the command response of a delete BA request. + */ +void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba) +{ + struct host_cmd_ds_11n_delba *cmd_del_ba = + (struct host_cmd_ds_11n_delba *) del_ba; + uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set); + int tid; + + tid = del_ba_param_set >> DELBA_TID_POS; + + mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr, + TYPE_DELBA_RECEIVE, + INITIATOR_BIT(del_ba_param_set)); +} + +/* + * This function retrieves the Rx reordering table. + */ +int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, + struct mwifiex_ds_rx_reorder_tbl *buf) +{ + int i; + struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf; + struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr; + int count = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr, + list) { + rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid; + memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN); + rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win; + rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size; + for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) { + if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) + rx_reo_tbl->buffer[i] = true; + else + rx_reo_tbl->buffer[i] = false; + } + rx_reo_tbl++; + count++; + + if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED) + break; + } + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + return count; +} + +/* + * This function retrieves the Tx BA stream table. + */ +int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, + struct mwifiex_ds_tx_ba_stream_tbl *buf) +{ + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; + struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf; + int count = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid; + dev_dbg(priv->adapter->dev, "data: %s tid=%d\n", + __func__, rx_reo_tbl->tid); + memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN); + rx_reo_tbl++; + count++; + if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) + break; + } + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + + return count; +} diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h new file mode 100644 index 000000000000..a4390a1a2a9f --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n.h @@ -0,0 +1,161 @@ +/* + * Marvell Wireless LAN device driver: 802.11n + * + * Copyright (C) 2011, 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_11N_H_ +#define _MWIFIEX_11N_H_ + +#include "11n_aggr.h" +#include "11n_rxreorder.h" +#include "wmm.h" + +int mwifiex_ret_11n_delba(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, + void *data_buf); +int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf); + +int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + u8 **buffer); +void mwifiex_cfg_tx_buf(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc); +void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type, + struct mwifiex_ie_types_htcap *); +int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv, + u16 action, int *htcap_cfg); +void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, + struct mwifiex_tx_ba_stream_tbl + *tx_tbl); +void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv); +struct mwifiex_tx_ba_stream_tbl *mwifiex_11n_get_tx_ba_stream_tbl(struct + mwifiex_private + *priv, int tid, + u8 *ra); +void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, u8 *ra, + int tid, + enum mwifiex_ba_status ba_status); +int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac); +int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, + int initiator); +void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba); +int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, + struct mwifiex_ds_rx_reorder_tbl *buf); +int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, + struct mwifiex_ds_tx_ba_stream_tbl *buf); +int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp, + void *data_buf); +int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + int cmd_action, void *data_buf); +int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, + int cmd_action, void *data_buf); + +/* + * This function checks whether AMPDU is allowed or not for a particular TID. + */ +static inline u8 +mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, int tid) +{ + return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED) + ? true : false); +} + +/* + * This function checks whether AMSDU is allowed or not for a particular TID. + */ +static inline u8 +mwifiex_is_amsdu_allowed(struct mwifiex_private *priv, int tid) +{ + return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED) + && ((priv->is_data_rate_auto) + || !((priv->bitmap_rates[2]) & 0x03))) + ? true : false); +} + +/* + * This function checks whether a space is available for new BA stream or not. + */ +static inline u8 mwifiex_space_avail_for_new_ba_stream( + struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv; + u8 i; + u32 ba_stream_num = 0; + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv) + ba_stream_num += mwifiex_wmm_list_len( + (struct list_head *) + &priv->tx_ba_stream_tbl_ptr); + } + + return ((ba_stream_num < + MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false); +} + +/* + * This function finds the correct Tx BA stream to delete. + * + * Upon successfully locating, both the TID and the RA are returned. + */ +static inline u8 +mwifiex_find_stream_to_delete(struct mwifiex_private *priv, int ptr_tid, + int *ptid, u8 *ra) +{ + int tid; + u8 ret = false; + struct mwifiex_tx_ba_stream_tbl *tx_tbl; + unsigned long flags; + + tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) { + tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user; + *ptid = tx_tbl->tid; + memcpy(ra, tx_tbl->ra, ETH_ALEN); + ret = true; + } + } + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + + return ret; +} + +/* + * This function checks whether BA stream is set up or not. + */ +static inline int +mwifiex_is_ba_stream_setup(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int tid) +{ + struct mwifiex_tx_ba_stream_tbl *tx_tbl; + + tx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ptr->ra); + if (tx_tbl && IS_BASTREAM_SETUP(tx_tbl)) + return true; + + return false; +} +#endif /* !_MWIFIEX_11N_H_ */ diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c new file mode 100644 index 000000000000..d3d5e0853c45 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -0,0 +1,298 @@ +/* + * Marvell Wireless LAN device driver: 802.11n Aggregation + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "11n_aggr.h" + +/* + * Creates an AMSDU subframe for aggregation into one AMSDU packet. + * + * The resultant AMSDU subframe format is - + * + * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+ + * | DA | SA | Length | SNAP header | MSDU | + * | data[0..5] | data[6..11] | | | data[14..] | + * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+ + * <--6-bytes--> <--6-bytes--> <--2-bytes--><--8-bytes--> <--n-bytes--> + * + * This function also computes the amount of padding required to make the + * buffer length multiple of 4 bytes. + * + * Data => |DA|SA|SNAP-TYPE|........ .| + * MSDU => |DA|SA|Length|SNAP|...... ..| + */ +static int +mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr, + struct sk_buff *skb_src, int *pad) + +{ + int dt_offset; + struct rfc_1042_hdr snap = { + 0xaa, /* LLC DSAP */ + 0xaa, /* LLC SSAP */ + 0x03, /* LLC CTRL */ + {0x00, 0x00, 0x00}, /* SNAP OUI */ + 0x0000 /* SNAP type */ + /* + * This field will be overwritten + * later with ethertype + */ + }; + struct tx_packet_hdr *tx_header; + + skb_put(skb_aggr, sizeof(*tx_header)); + + tx_header = (struct tx_packet_hdr *) skb_aggr->data; + + /* Copy DA and SA */ + dt_offset = 2 * ETH_ALEN; + memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset); + + /* Copy SNAP header */ + snap.snap_type = *(u16 *) ((u8 *)skb_src->data + dt_offset); + dt_offset += sizeof(u16); + + memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr)); + + skb_pull(skb_src, dt_offset); + + /* Update Length field */ + tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN); + + /* Add payload */ + skb_put(skb_aggr, skb_src->len); + memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data, + skb_src->len); + *pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len + + LLC_SNAP_LEN)) & 3)) : 0; + skb_put(skb_aggr, *pad); + + return skb_aggr->len + *pad; +} + +/* + * Adds TxPD to AMSDU header. + * + * Each AMSDU packet will contain one TxPD at the beginning, + * followed by multiple AMSDU subframes. + */ +static void +mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct txpd *local_tx_pd; + + skb_push(skb, sizeof(*local_tx_pd)); + + local_tx_pd = (struct txpd *) skb->data; + memset(local_tx_pd, 0, sizeof(struct txpd)); + + /* Original priority has been overwritten */ + local_tx_pd->priority = (u8) skb->priority; + local_tx_pd->pkt_delay_2ms = + mwifiex_wmm_compute_drv_pkt_delay(priv, skb); + local_tx_pd->bss_num = priv->bss_num; + local_tx_pd->bss_type = priv->bss_type; + /* Always zero as the data is followed by struct txpd */ + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU); + local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len - + sizeof(*local_tx_pd)); + + if (local_tx_pd->tx_control == 0) + /* TxCtrl set by user or default */ + local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); + + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && + (priv->adapter->pps_uapsd_mode)) { + if (true == mwifiex_check_last_packet_indication(priv)) { + priv->adapter->tx_lock_flag = true; + local_tx_pd->flags = + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; + } + } +} + +/* + * Create aggregated packet. + * + * This function creates an aggregated MSDU packet, by combining buffers + * from the RA list. Each individual buffer is encapsulated as an AMSDU + * subframe and all such subframes are concatenated together to form the + * AMSDU packet. + * + * A TxPD is also added to the front of the resultant AMSDU packets for + * transmission. The resultant packets format is - + * + * +---- ~ ----+------ ~ ------+------ ~ ------+-..-+------ ~ ------+ + * | TxPD |AMSDU sub-frame|AMSDU sub-frame| .. |AMSDU sub-frame| + * | | 1 | 2 | .. | n | + * +---- ~ ----+------ ~ ------+------ ~ ------+ .. +------ ~ ------+ + */ +int +mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *pra_list, int headroom, + int ptrindex, unsigned long ra_list_flags) + __releases(&priv->wmm.ra_list_spinlock) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct sk_buff *skb_aggr, *skb_src; + struct mwifiex_txinfo *tx_info_aggr, *tx_info_src; + int pad = 0, ret; + struct mwifiex_tx_param tx_param; + struct txpd *ptx_pd = NULL; + + if (skb_queue_empty(&pra_list->skb_head)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + return 0; + } + skb_src = skb_peek(&pra_list->skb_head); + tx_info_src = MWIFIEX_SKB_TXCB(skb_src); + skb_aggr = dev_alloc_skb(adapter->tx_buf_size); + if (!skb_aggr) { + dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + return -1; + } + skb_reserve(skb_aggr, headroom + sizeof(struct txpd)); + tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr); + + tx_info_aggr->bss_index = tx_info_src->bss_index; + skb_aggr->priority = skb_src->priority; + + while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len + + LLC_SNAP_LEN) + <= adapter->tx_buf_size)) { + + if (!skb_queue_empty(&pra_list->skb_head)) + skb_src = skb_dequeue(&pra_list->skb_head); + else + skb_src = NULL; + + if (skb_src) + pra_list->total_pkts_size -= skb_src->len; + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad); + + mwifiex_write_data_complete(adapter, skb_src, 0); + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + return -1; + } + + if (!skb_queue_empty(&pra_list->skb_head)) + skb_src = skb_peek(&pra_list->skb_head); + else + skb_src = NULL; + } + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); + + /* Last AMSDU packet does not need padding */ + skb_trim(skb_aggr, skb_aggr->len - pad); + + /* Form AMSDU */ + mwifiex_11n_form_amsdu_txpd(priv, skb_aggr); + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) + ptx_pd = (struct txpd *)skb_aggr->data; + + skb_push(skb_aggr, headroom); + + tx_param.next_pkt_len = ((pra_list->total_pkts_size) ? + (((pra_list->total_pkts_size) > + adapter->tx_buf_size) ? adapter-> + tx_buf_size : pra_list->total_pkts_size + + LLC_SNAP_LEN + sizeof(struct txpd)) : 0); + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, + skb_aggr->data, + skb_aggr->len, &tx_param); + switch (ret) { + case -EBUSY: + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + mwifiex_write_data_complete(adapter, skb_aggr, -1); + return -1; + } + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && + (adapter->pps_uapsd_mode) && + (adapter->tx_lock_flag)) { + priv->adapter->tx_lock_flag = false; + if (ptx_pd) + ptx_pd->flags = 0; + } + + skb_queue_tail(&pra_list->skb_head, skb_aggr); + + pra_list->total_pkts_size += skb_aggr->len; + + tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); + break; + case -1: + adapter->data_sent = false; + dev_err(adapter->dev, "%s: host_to_card failed: %#x\n", + __func__, ret); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb_aggr, ret); + return 0; + case -EINPROGRESS: + adapter->data_sent = false; + break; + case 0: + mwifiex_write_data_complete(adapter, skb_aggr, ret); + break; + default: + break; + } + if (ret != -EBUSY) { + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + if (mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + priv->wmm.packets_out[ptrindex]++; + priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list; + } + /* Now bss_prio_cur pointer points to next node */ + adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = + list_first_entry( + &adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_cur->list, + struct mwifiex_bss_prio_node, list); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + } + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/11n_aggr.h b/drivers/net/wireless/mwifiex/11n_aggr.h new file mode 100644 index 000000000000..9c6dca7ab02c --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_aggr.h @@ -0,0 +1,32 @@ +/* + * Marvell Wireless LAN device driver: 802.11n Aggregation + * + * Copyright (C) 2011, 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_11N_AGGR_H_ +#define _MWIFIEX_11N_AGGR_H_ + +#define PKT_TYPE_AMSDU 0xE6 + +int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, + struct sk_buff *skb); +int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int headroom, + int ptr_index, unsigned long flags) + __releases(&priv->wmm.ra_list_spinlock); + +#endif /* !_MWIFIEX_11N_AGGR_H_ */ diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c new file mode 100644 index 000000000000..e5dfdc39a921 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -0,0 +1,616 @@ +/* + * Marvell Wireless LAN device driver: 802.11n RX Re-ordering + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "11n_rxreorder.h" + +/* + * This function dispatches all packets in the Rx reorder table. + * + * There could be holes in the buffer, which are skipped by the function. + * Since the buffer is linear, the function uses rotation to simulate + * circular buffer. + */ +static int +mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, + struct mwifiex_rx_reorder_tbl + *rx_reor_tbl_ptr, int start_win) +{ + int no_pkt_to_send, i; + void *rx_tmp_ptr; + unsigned long flags; + + no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ? + min((start_win - rx_reor_tbl_ptr->start_win), + rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size; + + for (i = 0; i < no_pkt_to_send; ++i) { + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + rx_tmp_ptr = NULL; + if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) { + rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; + rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; + } + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + if (rx_tmp_ptr) + mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr); + } + + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + /* + * We don't have a circular buffer, hence use rotation to simulate + * circular buffer + */ + for (i = 0; i < rx_reor_tbl_ptr->win_size - no_pkt_to_send; ++i) { + rx_reor_tbl_ptr->rx_reorder_ptr[i] = + rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i]; + rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL; + } + + rx_reor_tbl_ptr->start_win = start_win; + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + + return 0; +} + +/* + * This function dispatches all packets in the Rx reorder table until + * a hole is found. + * + * The start window is adjusted automatically when a hole is located. + * Since the buffer is linear, the function uses rotation to simulate + * circular buffer. + */ +static int +mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr) +{ + int i, j, xchg; + void *rx_tmp_ptr; + unsigned long flags; + + for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) { + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) { + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + break; + } + rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; + rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr); + } + + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + /* + * We don't have a circular buffer, hence use rotation to simulate + * circular buffer + */ + if (i > 0) { + xchg = rx_reor_tbl_ptr->win_size - i; + for (j = 0; j < xchg; ++j) { + rx_reor_tbl_ptr->rx_reorder_ptr[j] = + rx_reor_tbl_ptr->rx_reorder_ptr[i + j]; + rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL; + } + } + rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i) + &(MAX_TID_VALUE - 1); + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + return 0; +} + +/* + * This function deletes the Rx reorder table and frees the memory. + * + * The function stops the associated timer and dispatches all the + * pending packets in the Rx reorder table before deletion. + */ +static void +mwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv, + struct mwifiex_rx_reorder_tbl + *rx_reor_tbl_ptr) +{ + unsigned long flags; + + if (!rx_reor_tbl_ptr) + return; + + mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, + (rx_reor_tbl_ptr->start_win + + rx_reor_tbl_ptr->win_size) + &(MAX_TID_VALUE - 1)); + + del_timer(&rx_reor_tbl_ptr->timer_context.timer); + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_del(&rx_reor_tbl_ptr->list); + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + kfree(rx_reor_tbl_ptr->rx_reorder_ptr); + kfree(rx_reor_tbl_ptr); +} + +/* + * This function returns the pointer to an entry in Rx reordering + * table which matches the given TA/TID pair. + */ +static struct mwifiex_rx_reorder_tbl * +mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta) +{ + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + unsigned long flags; + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { + if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN)) + && (rx_reor_tbl_ptr->tid == tid)) { + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, + flags); + return rx_reor_tbl_ptr; + } + } + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + return NULL; +} + +/* + * This function finds the last sequence number used in the packets + * buffered in Rx reordering table. + */ +static int +mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr) +{ + int i; + + for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) + if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) + return i; + + return -1; +} + +/* + * This function flushes all the packets in Rx reordering table. + * + * The function checks if any packets are currently buffered in the + * table or not. In case there are packets available, it dispatches + * them and then dumps the Rx reordering table. + */ +static void +mwifiex_flush_data(unsigned long context) +{ + struct reorder_tmr_cnxt *reorder_cnxt = + (struct reorder_tmr_cnxt *) context; + int start_win; + + start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr); + if (start_win >= 0) { + dev_dbg(reorder_cnxt->priv->adapter->dev, + "info: flush data %d\n", start_win); + mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv, + reorder_cnxt->ptr, + ((reorder_cnxt->ptr->start_win + + start_win + 1) & (MAX_TID_VALUE - 1))); + } +} + +/* + * This function creates an entry in Rx reordering table for the + * given TA/TID. + * + * The function also initializes the entry with sequence number, window + * size as well as initializes the timer. + * + * If the received TA/TID pair is already present, all the packets are + * dispatched and the window size is moved until the SSN. + */ +static void +mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, + int tid, int win_size, int seq_num) +{ + int i; + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node; + u16 last_seq = 0; + unsigned long flags; + + /* + * If we get a TID, ta pair which is already present dispatch all the + * the packets and move the window size until the ssn + */ + rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); + if (rx_reor_tbl_ptr) { + mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, + seq_num); + return; + } + /* if !rx_reor_tbl_ptr then create one */ + new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL); + if (!new_node) { + dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n", + __func__); + return; + } + + INIT_LIST_HEAD(&new_node->list); + new_node->tid = tid; + memcpy(new_node->ta, ta, ETH_ALEN); + new_node->start_win = seq_num; + if (mwifiex_queuing_ra_based(priv)) + /* TODO for adhoc */ + dev_dbg(priv->adapter->dev, + "info: ADHOC:last_seq=%d start_win=%d\n", + last_seq, new_node->start_win); + else + last_seq = priv->rx_seq[tid]; + + if (last_seq >= new_node->start_win) + new_node->start_win = last_seq + 1; + + new_node->win_size = win_size; + + new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size, + GFP_KERNEL); + if (!new_node->rx_reorder_ptr) { + kfree((u8 *) new_node); + dev_err(priv->adapter->dev, + "%s: failed to alloc reorder_ptr\n", __func__); + return; + } + + new_node->timer_context.ptr = new_node; + new_node->timer_context.priv = priv; + + init_timer(&new_node->timer_context.timer); + new_node->timer_context.timer.function = mwifiex_flush_data; + new_node->timer_context.timer.data = + (unsigned long) &new_node->timer_context; + + for (i = 0; i < win_size; ++i) + new_node->rx_reorder_ptr[i] = NULL; + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr); + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); +} + +/* + * This function prepares command for adding a BA request. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting add BA request buffer + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct host_cmd_ds_11n_addba_req *add_ba_req = + (struct host_cmd_ds_11n_addba_req *) + &cmd->params.add_ba_req; + + cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ); + cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN); + memcpy(add_ba_req, data_buf, sizeof(*add_ba_req)); + + return 0; +} + +/* + * This function prepares command for adding a BA response. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting add BA response buffer + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = + (struct host_cmd_ds_11n_addba_rsp *) + &cmd->params.add_ba_rsp; + struct host_cmd_ds_11n_addba_req *cmd_addba_req = + (struct host_cmd_ds_11n_addba_req *) data_buf; + u8 tid; + int win_size; + uint16_t block_ack_param_set; + + cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP); + cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN); + + memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr, + ETH_ALEN); + add_ba_rsp->dialog_token = cmd_addba_req->dialog_token; + add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo; + add_ba_rsp->ssn = cmd_addba_req->ssn; + + block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set); + tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; + add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT); + block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; + /* We donot support AMSDU inside AMPDU, hence reset the bit */ + block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK; + block_ack_param_set |= (priv->add_ba_param.rx_win_size << + BLOCKACKPARAM_WINSIZE_POS); + add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set); + win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set) + & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) + >> BLOCKACKPARAM_WINSIZE_POS; + cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set); + + mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr, + tid, win_size, le16_to_cpu(cmd_addba_req->ssn)); + return 0; +} + +/* + * This function prepares command for deleting a BA request. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting del BA request buffer + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *) + &cmd->params.del_ba; + + cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA); + cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN); + memcpy(del_ba, data_buf, sizeof(*del_ba)); + + return 0; +} + +/* + * This function identifies if Rx reordering is needed for a received packet. + * + * In case reordering is required, the function will do the reordering + * before sending it to kernel. + * + * The Rx reorder table is checked first with the received TID/TA pair. If + * not found, the received packet is dispatched immediately. But if found, + * the packet is reordered and all the packets in the updated Rx reordering + * table is dispatched until a hole is found. + * + * For sequence number less than the starting window, the packet is dropped. + */ +int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, + u16 seq_num, u16 tid, + u8 *ta, u8 pkt_type, void *payload) +{ + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + int start_win, end_win, win_size, ret; + u16 pkt_index; + + rx_reor_tbl_ptr = + mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv, + tid, ta); + if (!rx_reor_tbl_ptr) { + if (pkt_type != PKT_TYPE_BAR) + mwifiex_process_rx_packet(priv->adapter, payload); + return 0; + } + start_win = rx_reor_tbl_ptr->start_win; + win_size = rx_reor_tbl_ptr->win_size; + end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); + del_timer(&rx_reor_tbl_ptr->timer_context.timer); + mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies + + (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000); + + /* + * If seq_num is less then starting win then ignore and drop the + * packet + */ + if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */ + if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1)) + && (seq_num < start_win)) + return -1; + } else if ((seq_num < start_win) + || (seq_num > (start_win + (TWOPOW11)))) { + return -1; + } + + /* + * If this packet is a BAR we adjust seq_num as + * WinStart = seq_num + */ + if (pkt_type == PKT_TYPE_BAR) + seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1); + + if (((end_win < start_win) + && (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win))) + && (seq_num > end_win)) || ((end_win > start_win) + && ((seq_num > end_win) || (seq_num < start_win)))) { + end_win = seq_num; + if (((seq_num - win_size) + 1) >= 0) + start_win = (end_win - win_size) + 1; + else + start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1; + ret = mwifiex_11n_dispatch_pkt_until_start_win(priv, + rx_reor_tbl_ptr, start_win); + + if (ret) + return ret; + } + + if (pkt_type != PKT_TYPE_BAR) { + if (seq_num >= start_win) + pkt_index = seq_num - start_win; + else + pkt_index = (seq_num+MAX_TID_VALUE) - start_win; + + if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index]) + return -1; + + rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload; + } + + /* + * Dispatch all packets sequentially from start_win until a + * hole is found and adjust the start_win appropriately + */ + ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr); + + return ret; +} + +/* + * This function deletes an entry for a given TID/TA pair. + * + * The TID/TA are taken from del BA event body. + */ +void +mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int tid, + u8 *peer_mac, u8 type, int initiator) +{ + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + struct mwifiex_tx_ba_stream_tbl *ptx_tbl; + u8 cleanup_rx_reorder_tbl; + unsigned long flags; + + if (type == TYPE_DELBA_RECEIVE) + cleanup_rx_reorder_tbl = (initiator) ? true : false; + else + cleanup_rx_reorder_tbl = (initiator) ? false : true; + + dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, " + "initiator=%d\n", peer_mac, tid, initiator); + + if (cleanup_rx_reorder_tbl) { + rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, + peer_mac); + if (!rx_reor_tbl_ptr) { + dev_dbg(priv->adapter->dev, + "event: TID, TA not found in table\n"); + return; + } + mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr); + } else { + ptx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, peer_mac); + if (!ptx_tbl) { + dev_dbg(priv->adapter->dev, + "event: TID, RA not found in table\n"); + return; + } + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl); + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + } +} + +/* + * This function handles the command response of an add BA response. + * + * Handling includes changing the header fields into CPU format and + * creating the stream, provided the add BA is accepted. + */ +int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = + (struct host_cmd_ds_11n_addba_rsp *) + &resp->params.add_ba_rsp; + int tid, win_size; + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + uint16_t block_ack_param_set; + + block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); + + tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; + /* + * Check if we had rejected the ADDBA, if yes then do not create + * the stream + */ + if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { + win_size = (block_ack_param_set & + IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) + >> BLOCKACKPARAM_WINSIZE_POS; + + dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM" + " tid=%d ssn=%d win_size=%d\n", + add_ba_rsp->peer_mac_addr, + tid, add_ba_rsp->ssn, win_size); + } else { + dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n", + add_ba_rsp->peer_mac_addr, tid); + + rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, + tid, add_ba_rsp->peer_mac_addr); + if (rx_reor_tbl_ptr) + mwifiex_11n_delete_rx_reorder_tbl_entry(priv, + rx_reor_tbl_ptr); + } + + return 0; +} + +/* + * This function handles BA stream timeout event by preparing and sending + * a command to the firmware. + */ +void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, + struct host_cmd_ds_11n_batimeout *event) +{ + struct host_cmd_ds_11n_delba delba; + + memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba)); + memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN); + + delba.del_ba_param_set |= + cpu_to_le16((u16) event->tid << DELBA_TID_POS); + delba.del_ba_param_set |= cpu_to_le16( + (u16) event->origninator << DELBA_INITIATOR_POS); + delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); + mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba); +} + +/* + * This function cleans up the Rx reorder table by deleting all the entries + * and re-initializing. + */ +void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv) +{ + struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node; + unsigned long flags; + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_for_each_entry_safe(del_tbl_ptr, tmp_node, + &priv->rx_reorder_tbl_ptr, list) { + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + mwifiex_11n_delete_rx_reorder_tbl_entry(priv, del_tbl_ptr); + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + } + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); + memset(priv->rx_seq, 0, sizeof(priv->rx_seq)); +} diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h new file mode 100644 index 000000000000..f3ca8c8c18f9 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h @@ -0,0 +1,65 @@ +/* + * Marvell Wireless LAN device driver: 802.11n RX Re-ordering + * + * Copyright (C) 2011, 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_11N_RXREORDER_H_ +#define _MWIFIEX_11N_RXREORDER_H_ + +#define MIN_FLUSH_TIMER_MS 50 + +#define PKT_TYPE_BAR 0xE7 +#define MAX_TID_VALUE (2 << 11) +#define TWOPOW11 (2 << 10) + +#define BLOCKACKPARAM_TID_POS 2 +#define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1 +#define BLOCKACKPARAM_WINSIZE_POS 6 +#define DELBA_TID_POS 12 +#define DELBA_INITIATOR_POS 11 +#define TYPE_DELBA_SENT 1 +#define TYPE_DELBA_RECEIVE 2 +#define IMMEDIATE_BLOCK_ACK 0x2 + +#define ADDBA_RSP_STATUS_ACCEPT 0 + +int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *, + u16 seqNum, + u16 tid, u8 *ta, + u8 pkttype, void *payload); +void mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int Tid, + u8 *PeerMACAddr, u8 type, + int initiator); +void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, + struct host_cmd_ds_11n_batimeout *event); +int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, + struct host_cmd_ds_command + *resp); +int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, + void *data_buf); +int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, + struct host_cmd_ds_command + *cmd, void *data_buf); +int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, + void *data_buf); +void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv); +struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct + mwifiex_private + *priv, int tid, + u8 *ta); + +#endif /* _MWIFIEX_11N_RXREORDER_H_ */ diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig new file mode 100644 index 000000000000..86962920cef3 --- /dev/null +++ b/drivers/net/wireless/mwifiex/Kconfig @@ -0,0 +1,21 @@ +config MWIFIEX + tristate "Marvell WiFi-Ex Driver" + depends on CFG80211 + select LIB80211 + ---help--- + This adds support for wireless adapters based on Marvell + 802.11n chipsets. + + If you choose to build it as a module, it will be called + mwifiex. + +config MWIFIEX_SDIO + tristate "Marvell WiFi-Ex Driver for SD8787" + depends on MWIFIEX && MMC + select FW_LOADER + ---help--- + This adds support for wireless adapters based on Marvell + 8787 chipset with SDIO interface. + + If you choose to build it as a module, it will be called + mwifiex_sdio. diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile new file mode 100644 index 000000000000..42cb733ea33a --- /dev/null +++ b/drivers/net/wireless/mwifiex/Makefile @@ -0,0 +1,41 @@ +# +# Copyright (C) 2011, 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. + + +mwifiex-y += main.o +mwifiex-y += init.o +mwifiex-y += cfp.o +mwifiex-y += cmdevt.o +mwifiex-y += util.o +mwifiex-y += txrx.o +mwifiex-y += wmm.o +mwifiex-y += 11n.o +mwifiex-y += 11n_aggr.o +mwifiex-y += 11n_rxreorder.o +mwifiex-y += scan.o +mwifiex-y += join.o +mwifiex-y += sta_ioctl.o +mwifiex-y += sta_cmd.o +mwifiex-y += sta_cmdresp.o +mwifiex-y += sta_event.o +mwifiex-y += sta_tx.o +mwifiex-y += sta_rx.o +mwifiex-y += cfg80211.o +mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o +obj-$(CONFIG_MWIFIEX) += mwifiex.o + +mwifiex_sdio-y += sdio.o +obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README new file mode 100644 index 000000000000..b55badef4660 --- /dev/null +++ b/drivers/net/wireless/mwifiex/README @@ -0,0 +1,204 @@ +# Copyright (C) 2011, 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. + + +=============================================================================== + U S E R M A N U A L + +1) FOR DRIVER INSTALL + + a) Copy sd8787.bin to /lib/firmware/mrvl/ directory, + create the directory if it doesn't exist. + b) Install WLAN driver, + insmod mwifiex.ko + c) Uninstall WLAN driver, + ifconfig mlanX down + rmmod mwifiex + + +2) FOR DRIVER CONFIGURATION AND INFO + The configurations can be done either using the 'iw' user space + utility or debugfs. + + a) 'iw' utility commands + + Following are some useful iw commands:- + +iw dev mlan0 scan + + This command will trigger a scan. + The command will then display the scan table entries + +iw dev mlan0 connect -w [] [] [key 0:abcde d:1123456789a] + The above command can be used to connect to an AP with a particular SSID. + Ap's operating frequency can be specified or even the bssid. If the AP is using + WEP encryption, wep keys can be specified in the command. + Note: Every time before connecting to an AP scan command (iw dev mlan0 scan) should be used by user. + +iw dev mlan0 disconnect + This command will be used to disconnect from an AP. + + +iw dev mlan0 ibss join [fixed-freq] [fixed-bssid] [key 0:abcde] + The command will be used to join or create an ibss. Optionally, operating frequency, + bssid and the security related parameters can be specified while joining/creating + and ibss. + +iw dev mlan0 ibss leave + The command will be used to leave an ibss network. + +iw dev mlan0 link + The command will be used to get the connection status. The command will return parameters + such as SSID, operating frequency, rx/tx packets, signal strength, tx bitrate. + + Apart from the iw utility all standard configurations using the 'iwconfig' utility are also supported. + + b) Debugfs interface + + The debugfs interface can be used for configurations and for getting + some useful information from the driver. + The section below explains the configurations that can be + done. + + Mount debugfs to /debugfs mount point: + + mkdir /debugfs + mount -t debugfs debugfs /debugfs + + The information is provided in /debugfs/mwifiex/mlanX/: + +iw reg set + The command will be used to change the regulatory domain. + +iw reg get + The command will be used to get current regulatory domain. + +info + This command is used to get driver info. + + Usage: + cat info + + driver_name = "mwifiex" + driver_version = + interface_name = "mlanX" + bss_mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown" + media_state = "Disconnected" | "Connected" + mac_address = <6-byte adapter MAC address> + multicase_count = + essid = + bssid = + channel = + region_code = + multicasr_address[n] = + num_tx_bytes = + num_rx_bytes = + num_tx_pkts = + num_rx_pkts = + num_tx_pkts_dropped = + num_rx_pkts_dropped = + num_tx_pkts_err = + num_rx_pkts_err = + carrier "on" | "off" + tx queue "stopped" | "started" + + The following debug info are provided in /debugfs/mwifiex/mlanX/debug: + + int_counter = + wmm_ac_vo = + wmm_ac_vi = + wmm_ac_be = + wmm_ac_bk = + max_tx_buf_size = + tx_buf_size = + curr_tx_buf_size = + ps_mode = <0/1, CAM mode/PS mode> + ps_state = <0/1/2/3, full power state/awake state/pre-sleep state/sleep state> + is_deep_sleep = <0/1, not deep sleep state/deep sleep state> + wakeup_dev_req = <0/1, wakeup device not required/required> + wakeup_tries = + hs_configured = <0/1, host sleep not configured/configured> + hs_activated = <0/1, extended host sleep not activated/activated> + num_tx_timeout = + num_cmd_timeout = + timeout_cmd_id = + timeout_cmd_act = + last_cmd_id = + last_cmd_act = + last_cmd_index = <0 based last command index> + last_cmd_resp_id = + last_cmd_resp_index = <0 based last command response index> + last_event = + last_event_index = <0 based last event index> + num_cmd_h2c_fail = + num_cmd_sleep_cfm_fail = + num_tx_h2c_fail = + num_evt_deauth = + num_evt_disassoc = + num_evt_link_lost = + num_cmd_deauth = + num_cmd_assoc_ok = + num_cmd_assoc_fail = + cmd_sent = <0/1, send command resources available/sending command to device> + data_sent = <0/1, send data resources available/sending data to device> + mp_rd_bitmap = + mp_wr_bitmap = + cmd_resp_received = <0/1, no cmd response to process/response received and yet to process> + event_received = <0/1, no event to process/event received and yet to process> + cmd_pending = + tx_pending = + rx_pending = + + +3) FOR DRIVER CONFIGURATION + +regrdwr + This command is used to read/write the adapter register. + + Usage: + echo " [value]" > regrdwr + cat regrdwr + + where the parameters are, + : 1:MAC/SOC, 2:BBP, 3:RF, 4:PMIC, 5:CAU + : offset of register + [value]: value to be written + + Examples: + echo "1 0xa060" > regrdwr : Read the MAC register + echo "1 0xa060 0x12" > regrdwr : Write the MAC register + echo "1 0xa794 0x80000000" > regrdwr + : Write 0x80000000 to MAC register +rdeeprom + This command is used to read the EEPROM contents of the card. + + Usage: + echo " " > rdeeprom + cat rdeeprom + + where the parameters are, + : multiples of 4 + : 4-20, multiples of 4 + + Example: + echo "0 20" > rdeeprom : Read 20 bytes of EEPROM data from offset 0 + +getlog + This command is used to get the statistics available in the station. + Usage: + + cat getlog + +=============================================================================== diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c new file mode 100644 index 000000000000..660831ce293c --- /dev/null +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -0,0 +1,1417 @@ +/* + * Marvell Wireless LAN device driver: CFG80211 + * + * Copyright (C) 2011, 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 "cfg80211.h" +#include "main.h" + +/* + * This function maps the nl802.11 channel type into driver channel type. + * + * The mapping is as follows - + * NL80211_CHAN_NO_HT -> NO_SEC_CHANNEL + * NL80211_CHAN_HT20 -> NO_SEC_CHANNEL + * NL80211_CHAN_HT40PLUS -> SEC_CHANNEL_ABOVE + * NL80211_CHAN_HT40MINUS -> SEC_CHANNEL_BELOW + * Others -> NO_SEC_CHANNEL + */ +static int +mwifiex_cfg80211_channel_type_to_mwifiex_channels(enum nl80211_channel_type + channel_type) +{ + switch (channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + return NO_SEC_CHANNEL; + case NL80211_CHAN_HT40PLUS: + return SEC_CHANNEL_ABOVE; + case NL80211_CHAN_HT40MINUS: + return SEC_CHANNEL_BELOW; + default: + return NO_SEC_CHANNEL; + } +} + +/* + * This function maps the driver channel type into nl802.11 channel type. + * + * The mapping is as follows - + * NO_SEC_CHANNEL -> NL80211_CHAN_HT20 + * SEC_CHANNEL_ABOVE -> NL80211_CHAN_HT40PLUS + * SEC_CHANNEL_BELOW -> NL80211_CHAN_HT40MINUS + * Others -> NL80211_CHAN_HT20 + */ +static enum nl80211_channel_type +mwifiex_channels_to_cfg80211_channel_type(int channel_type) +{ + switch (channel_type) { + case NO_SEC_CHANNEL: + return NL80211_CHAN_HT20; + case SEC_CHANNEL_ABOVE: + return NL80211_CHAN_HT40PLUS; + case SEC_CHANNEL_BELOW: + return NL80211_CHAN_HT40MINUS; + default: + return NL80211_CHAN_HT20; + } +} + +/* + * This function checks whether WEP is set. + */ +static int +mwifiex_is_alg_wep(u32 cipher) +{ + switch (cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + return 1; + default: + break; + } + + return 0; +} + +/* + * This function retrieves the private structure from kernel wiphy structure. + */ +static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy) +{ + return (void *) (*(unsigned long *) wiphy_priv(wiphy)); +} + +/* + * CFG802.11 operation handler to delete a network key. + */ +static int +mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool pairwise, const u8 *mac_addr) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + if (mwifiex_set_encode(priv, NULL, 0, key_index, 1)) { + wiphy_err(wiphy, "deleting the crypto keys\n"); + return -EFAULT; + } + + wiphy_dbg(wiphy, "info: crypto keys deleted\n"); + return 0; +} + +/* + * CFG802.11 operation handler to set Tx power. + */ +static int +mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, + int dbm) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + struct mwifiex_power_cfg power_cfg; + + if (type == NL80211_TX_POWER_FIXED) { + power_cfg.is_power_auto = 0; + power_cfg.power_level = dbm; + } else { + power_cfg.is_power_auto = 1; + } + + return mwifiex_set_tx_power(priv, &power_cfg); +} + +/* + * CFG802.11 operation handler to set Power Save option. + * + * The timeout value, if provided, is currently ignored. + */ +static int +mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool enabled, int timeout) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + u32 ps_mode; + + if (timeout) + wiphy_dbg(wiphy, + "info: ignoring the timeout value" + " for IEEE power save\n"); + + ps_mode = enabled; + + return mwifiex_drv_set_power(priv, &ps_mode); +} + +/* + * CFG802.11 operation handler to set the default network key. + */ +static int +mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool unicast, + bool multicast) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + /* Return if WEP key not configured */ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED) + return 0; + + if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) { + wiphy_err(wiphy, "set default Tx key index\n"); + return -EFAULT; + } + + return 0; +} + +/* + * CFG802.11 operation handler to add a network key. + */ +static int +mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + if (mwifiex_set_encode(priv, params->key, params->key_len, + key_index, 0)) { + wiphy_err(wiphy, "crypto keys added\n"); + return -EFAULT; + } + + return 0; +} + +/* + * This function sends domain information to the firmware. + * + * The following information are passed to the firmware - + * - Country codes + * - Sub bands (first channel, number of channels, maximum Tx power) + */ +static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) +{ + u8 no_of_triplet = 0; + struct ieee80211_country_ie_triplet *t; + u8 no_of_parsed_chan = 0; + u8 first_chan = 0, next_chan = 0, max_pwr = 0; + u8 i, flag = 0; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg; + + /* Set country code */ + domain_info->country_code[0] = priv->country_code[0]; + domain_info->country_code[1] = priv->country_code[1]; + domain_info->country_code[2] = ' '; + + band = mwifiex_band_to_radio_type(adapter->config_bands); + if (!wiphy->bands[band]) { + wiphy_err(wiphy, "11D: setting domain info in FW\n"); + return -1; + } + + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels ; i++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (!flag) { + flag = 1; + first_chan = (u32) ch->hw_value; + next_chan = first_chan; + max_pwr = ch->max_power; + no_of_parsed_chan = 1; + continue; + } + + if (ch->hw_value == next_chan + 1 && + ch->max_power == max_pwr) { + next_chan++; + no_of_parsed_chan++; + } else { + t = &domain_info->triplet[no_of_triplet]; + t->chans.first_channel = first_chan; + t->chans.num_channels = no_of_parsed_chan; + t->chans.max_power = max_pwr; + no_of_triplet++; + first_chan = (u32) ch->hw_value; + next_chan = first_chan; + max_pwr = ch->max_power; + no_of_parsed_chan = 1; + } + } + + if (flag) { + t = &domain_info->triplet[no_of_triplet]; + t->chans.first_channel = first_chan; + t->chans.num_channels = no_of_parsed_chan; + t->chans.max_power = max_pwr; + no_of_triplet++; + } + + domain_info->no_of_triplet = no_of_triplet; + + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, + HostCmd_ACT_GEN_SET, 0, NULL)) { + wiphy_err(wiphy, "11D: setting domain info in FW\n"); + return -1; + } + + return 0; +} + +/* + * CFG802.11 regulatory domain callback function. + * + * This function is called when the regulatory domain is changed due to the + * following reasons - + * - Set by driver + * - Set by system core + * - Set by user + * - Set bt Country IE + */ +static int mwifiex_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain" + " %c%c\n", request->alpha2[0], request->alpha2[1]); + + memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2)); + + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_USER: + break; + /* Todo: apply driver specific changes in channel flags based + on the request initiator if necessary. */ + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + break; + } + mwifiex_send_domain_info_cmd_fw(wiphy); + + return 0; +} + +/* + * This function sets the RF channel. + * + * This function creates multiple IOCTL requests, populates them accordingly + * and issues them to set the band/channel and frequency. + */ +static int +mwifiex_set_rf_channel(struct mwifiex_private *priv, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct mwifiex_chan_freq_power cfp; + struct mwifiex_ds_band_cfg band_cfg; + u32 config_bands = 0; + struct wiphy *wiphy = priv->wdev->wiphy; + + if (chan) { + memset(&band_cfg, 0, sizeof(band_cfg)); + /* Set appropriate bands */ + if (chan->band == IEEE80211_BAND_2GHZ) + config_bands = BAND_B | BAND_G | BAND_GN; + else + config_bands = BAND_AN | BAND_A; + if (priv->bss_mode == NL80211_IFTYPE_STATION + || priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) { + band_cfg.config_bands = config_bands; + } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + band_cfg.config_bands = config_bands; + band_cfg.adhoc_start_band = config_bands; + } + + band_cfg.sec_chan_offset = + mwifiex_cfg80211_channel_type_to_mwifiex_channels + (channel_type); + + if (mwifiex_set_radio_band_cfg(priv, &band_cfg)) + return -EFAULT; + + mwifiex_send_domain_info_cmd_fw(wiphy); + } + + wiphy_dbg(wiphy, "info: setting band %d, channel offset %d and " + "mode %d\n", config_bands, band_cfg.sec_chan_offset, + priv->bss_mode); + if (!chan) + return 0; + + memset(&cfp, 0, sizeof(cfp)); + cfp.freq = chan->center_freq; + cfp.channel = ieee80211_frequency_to_channel(chan->center_freq); + + if (mwifiex_bss_set_channel(priv, &cfp)) + return -EFAULT; + + return mwifiex_drv_change_adhoc_chan(priv, cfp.channel); +} + +/* + * CFG802.11 operation handler to set channel. + * + * This function can only be used when station is not connected. + */ +static int +mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + if (priv->media_connected) { + wiphy_err(wiphy, "This setting is valid only when station " + "is not connected\n"); + return -EINVAL; + } + + return mwifiex_set_rf_channel(priv, chan, channel_type); +} + +/* + * This function sets the fragmentation threshold. + * + * The fragmentation threshold value must lie between MWIFIEX_FRAG_MIN_VALUE + * and MWIFIEX_FRAG_MAX_VALUE. + */ +static int +mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr) +{ + int ret; + + if (frag_thr < MWIFIEX_FRAG_MIN_VALUE + || frag_thr > MWIFIEX_FRAG_MAX_VALUE) + return -EINVAL; + + /* Send request to firmware */ + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, FRAG_THRESH_I, + &frag_thr); + + return ret; +} + +/* + * This function sets the RTS threshold. + + * The rts value must lie between MWIFIEX_RTS_MIN_VALUE + * and MWIFIEX_RTS_MAX_VALUE. + */ +static int +mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr) +{ + if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE) + rts_thr = MWIFIEX_RTS_MAX_VALUE; + + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, RTS_THRESH_I, + &rts_thr); +} + +/* + * CFG802.11 operation handler to set wiphy parameters. + * + * This function can be used to set the RTS threshold and the + * Fragmentation threshold of the driver. + */ +static int +mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + int ret = 0; + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + ret = mwifiex_set_rts(priv, wiphy->rts_threshold); + if (ret) + return ret; + } + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + ret = mwifiex_set_frag(priv, wiphy->frag_threshold); + + return ret; +} + +/* + * CFG802.11 operation handler to change interface type. + */ +static int +mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + int ret; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (priv->bss_mode == type) { + wiphy_warn(wiphy, "already set to required type\n"); + return 0; + } + + priv->bss_mode = type; + + switch (type) { + case NL80211_IFTYPE_ADHOC: + dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC; + wiphy_dbg(wiphy, "info: setting interface type to adhoc\n"); + break; + case NL80211_IFTYPE_STATION: + dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; + wiphy_dbg(wiphy, "info: setting interface type to managed\n"); + break; + case NL80211_IFTYPE_UNSPECIFIED: + dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; + wiphy_dbg(wiphy, "info: setting interface type to auto\n"); + return 0; + default: + wiphy_err(wiphy, "unknown interface type: %d\n", type); + return -EINVAL; + } + + mwifiex_deauthenticate(priv, NULL); + + priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; + + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL); + + return ret; +} + +/* + * This function dumps the station information on a buffer. + * + * The following information are shown - + * - Total bytes transmitted + * - Total bytes received + * - Total packets transmitted + * - Total packets received + * - Signal quality level + * - Transmission rate + */ +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; + + /* 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_drv_get_data_rate(priv, &rate)) { + dev_err(priv->adapter->dev, "getting data rate\n"); + ret = -EFAULT; + } + + 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->w_stats.qual.level; + sinfo->txrate.legacy = rate.rate; + + return ret; +} + +/* + * CFG802.11 operation handler to get station information. + * + * This function only works in connected mode, and dumps the + * requested station information, if available. + */ +static int +mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + mwifiex_dump_station_info(priv, sinfo); + + if (!priv->media_connected) + return -ENOENT; + if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) + return -ENOENT; + + return mwifiex_dump_station_info(priv, sinfo); +} + +/* Supported rates to be advertised to the cfg80211 */ + +static struct ieee80211_rate mwifiex_rates[] = { + {.bitrate = 10, .hw_value = 2, }, + {.bitrate = 20, .hw_value = 4, }, + {.bitrate = 55, .hw_value = 11, }, + {.bitrate = 110, .hw_value = 22, }, + {.bitrate = 220, .hw_value = 44, }, + {.bitrate = 60, .hw_value = 12, }, + {.bitrate = 90, .hw_value = 18, }, + {.bitrate = 120, .hw_value = 24, }, + {.bitrate = 180, .hw_value = 36, }, + {.bitrate = 240, .hw_value = 48, }, + {.bitrate = 360, .hw_value = 72, }, + {.bitrate = 480, .hw_value = 96, }, + {.bitrate = 540, .hw_value = 108, }, + {.bitrate = 720, .hw_value = 144, }, +}; + +/* Channel definitions to be advertised to cfg80211 */ + +static struct ieee80211_channel mwifiex_channels_2ghz[] = { + {.center_freq = 2412, .hw_value = 1, }, + {.center_freq = 2417, .hw_value = 2, }, + {.center_freq = 2422, .hw_value = 3, }, + {.center_freq = 2427, .hw_value = 4, }, + {.center_freq = 2432, .hw_value = 5, }, + {.center_freq = 2437, .hw_value = 6, }, + {.center_freq = 2442, .hw_value = 7, }, + {.center_freq = 2447, .hw_value = 8, }, + {.center_freq = 2452, .hw_value = 9, }, + {.center_freq = 2457, .hw_value = 10, }, + {.center_freq = 2462, .hw_value = 11, }, + {.center_freq = 2467, .hw_value = 12, }, + {.center_freq = 2472, .hw_value = 13, }, + {.center_freq = 2484, .hw_value = 14, }, +}; + +static struct ieee80211_supported_band mwifiex_band_2ghz = { + .channels = mwifiex_channels_2ghz, + .n_channels = ARRAY_SIZE(mwifiex_channels_2ghz), + .bitrates = mwifiex_rates, + .n_bitrates = 14, +}; + +static struct ieee80211_channel mwifiex_channels_5ghz[] = { + {.center_freq = 5040, .hw_value = 8, }, + {.center_freq = 5060, .hw_value = 12, }, + {.center_freq = 5080, .hw_value = 16, }, + {.center_freq = 5170, .hw_value = 34, }, + {.center_freq = 5190, .hw_value = 38, }, + {.center_freq = 5210, .hw_value = 42, }, + {.center_freq = 5230, .hw_value = 46, }, + {.center_freq = 5180, .hw_value = 36, }, + {.center_freq = 5200, .hw_value = 40, }, + {.center_freq = 5220, .hw_value = 44, }, + {.center_freq = 5240, .hw_value = 48, }, + {.center_freq = 5260, .hw_value = 52, }, + {.center_freq = 5280, .hw_value = 56, }, + {.center_freq = 5300, .hw_value = 60, }, + {.center_freq = 5320, .hw_value = 64, }, + {.center_freq = 5500, .hw_value = 100, }, + {.center_freq = 5520, .hw_value = 104, }, + {.center_freq = 5540, .hw_value = 108, }, + {.center_freq = 5560, .hw_value = 112, }, + {.center_freq = 5580, .hw_value = 116, }, + {.center_freq = 5600, .hw_value = 120, }, + {.center_freq = 5620, .hw_value = 124, }, + {.center_freq = 5640, .hw_value = 128, }, + {.center_freq = 5660, .hw_value = 132, }, + {.center_freq = 5680, .hw_value = 136, }, + {.center_freq = 5700, .hw_value = 140, }, + {.center_freq = 5745, .hw_value = 149, }, + {.center_freq = 5765, .hw_value = 153, }, + {.center_freq = 5785, .hw_value = 157, }, + {.center_freq = 5805, .hw_value = 161, }, + {.center_freq = 5825, .hw_value = 165, }, +}; + +static struct ieee80211_supported_band mwifiex_band_5ghz = { + .channels = mwifiex_channels_5ghz, + .n_channels = ARRAY_SIZE(mwifiex_channels_5ghz), + .bitrates = mwifiex_rates - 4, + .n_bitrates = ARRAY_SIZE(mwifiex_rates) + 4, +}; + + +/* Supported crypto cipher suits to be advertised to cfg80211 */ + +static const u32 mwifiex_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +}; + +/* + * CFG802.11 operation handler for disconnection request. + * + * This function does not work when there is already a disconnection + * procedure going on. + */ +static int +mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (priv->disconnect) + return -EBUSY; + + priv->disconnect = 1; + if (mwifiex_deauthenticate(priv, NULL)) + return -EFAULT; + + wiphy_dbg(wiphy, "info: successfully disconnected from %pM:" + " reason code %d\n", priv->cfg_bssid, reason_code); + + queue_work(priv->workqueue, &priv->cfg_workqueue); + + return 0; +} + +/* + * This function informs the CFG802.11 subsystem of a new IBSS. + * + * The following information are sent to the CFG802.11 subsystem + * to register the new IBSS. If we do not register the new IBSS, + * a kernel panic will result. + * - SSID + * - SSID length + * - BSSID + * - Channel + */ +static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) +{ + struct ieee80211_channel *chan; + struct mwifiex_bss_info bss_info; + int ie_len; + u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; + + if (mwifiex_get_bss_info(priv, &bss_info)) + return -1; + + ie_buf[0] = WLAN_EID_SSID; + ie_buf[1] = bss_info.ssid.ssid_len; + + memcpy(&ie_buf[sizeof(struct ieee_types_header)], + &bss_info.ssid.ssid, + bss_info.ssid.ssid_len); + ie_len = ie_buf[1] + sizeof(struct ieee_types_header); + + chan = __ieee80211_get_channel(priv->wdev->wiphy, + ieee80211_channel_to_frequency(bss_info.bss_chan, + priv->curr_bss_params.band)); + + cfg80211_inform_bss(priv->wdev->wiphy, chan, + bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, + 0, ie_buf, ie_len, 0, GFP_KERNEL); + memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); + + return 0; +} + +/* + * This function informs the CFG802.11 subsystem of a new BSS connection. + * + * The following information are sent to the CFG802.11 subsystem + * to register the new BSS connection. If we do not register the new BSS, + * a kernel panic will result. + * - MAC address + * - Capabilities + * - Beacon period + * - RSSI value + * - Channel + * - Supported rates IE + * - Extended capabilities IE + * - DS parameter set IE + * - HT Capability IE + * - Vendor Specific IE (221) + * - WPA IE + * - RSN IE + */ +static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *ssid) +{ + struct mwifiex_bssdescriptor *scan_table; + int i, j; + struct ieee80211_channel *chan; + u8 *ie, *ie_buf; + u32 ie_len; + u8 *beacon; + int beacon_size; + u8 element_id, element_len; + +#define MAX_IE_BUF 2048 + ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); + if (!ie_buf) { + dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n", + __func__); + return -ENOMEM; + } + + scan_table = priv->adapter->scan_table; + for (i = 0; i < priv->adapter->num_in_scan_table; i++) { + if (ssid) { + /* Inform specific BSS only */ + if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, + ssid->ssid_len)) + continue; + } + memset(ie_buf, 0, MAX_IE_BUF); + ie_buf[0] = WLAN_EID_SSID; + ie_buf[1] = scan_table[i].ssid.ssid_len; + memcpy(&ie_buf[sizeof(struct ieee_types_header)], + scan_table[i].ssid.ssid, ie_buf[1]); + + ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header); + ie_len = ie_buf[1] + sizeof(struct ieee_types_header); + + ie[0] = WLAN_EID_SUPP_RATES; + + for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { + if (!scan_table[i].supported_rates[j]) + break; + else + ie[j + sizeof(struct ieee_types_header)] = + scan_table[i].supported_rates[j]; + } + + ie[1] = j; + ie_len += ie[1] + sizeof(struct ieee_types_header); + + beacon = scan_table[i].beacon_buf; + beacon_size = scan_table[i].beacon_buf_size; + + /* Skip time stamp, beacon interval and capability */ + + if (beacon) { + beacon += sizeof(scan_table[i].beacon_period) + + sizeof(scan_table[i].time_stamp) + + +sizeof(scan_table[i].cap_info_bitmap); + + beacon_size -= sizeof(scan_table[i].beacon_period) + + sizeof(scan_table[i].time_stamp) + + sizeof(scan_table[i].cap_info_bitmap); + } + + while (beacon_size >= sizeof(struct ieee_types_header)) { + ie = ie_buf + ie_len; + element_id = *beacon; + element_len = *(beacon + 1); + if (beacon_size < (int) element_len + + sizeof(struct ieee_types_header)) { + dev_err(priv->adapter->dev, "%s: in processing" + " IE, bytes left < IE length\n", + __func__); + break; + } + switch (element_id) { + case WLAN_EID_EXT_CAPABILITY: + case WLAN_EID_DS_PARAMS: + case WLAN_EID_HT_CAPABILITY: + case WLAN_EID_VENDOR_SPECIFIC: + case WLAN_EID_RSN: + case WLAN_EID_BSS_AC_ACCESS_DELAY: + ie[0] = element_id; + ie[1] = element_len; + memcpy(&ie[sizeof(struct ieee_types_header)], + (u8 *) beacon + + sizeof(struct ieee_types_header), + element_len); + ie_len += ie[1] + + sizeof(struct ieee_types_header); + break; + default: + break; + } + beacon += element_len + + sizeof(struct ieee_types_header); + beacon_size -= element_len + + sizeof(struct ieee_types_header); + } + chan = ieee80211_get_channel(priv->wdev->wiphy, + scan_table[i].freq); + cfg80211_inform_bss(priv->wdev->wiphy, chan, + scan_table[i].mac_address, + 0, scan_table[i].cap_info_bitmap, + scan_table[i].beacon_period, + ie_buf, ie_len, + scan_table[i].rssi, GFP_KERNEL); + } + + kfree(ie_buf); + return 0; +} + +/* + * This function connects with a BSS. + * + * This function handles both Infra and Ad-Hoc modes. It also performs + * validity checking on the provided parameters, disconnects from the + * current BSS (if any), sets up the association/scan parameters, + * including security settings, and performs specific SSID scan before + * trying to connect. + * + * For Infra mode, the function returns failure if the specified SSID + * is not found in scan table. However, for Ad-Hoc mode, it can create + * the IBSS if it does not exist. On successful completion in either case, + * the function notifies the CFG802.11 subsystem of the new BSS connection, + * otherwise the kernel will panic. + */ +static int +mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, + u8 *bssid, int mode, struct ieee80211_channel *channel, + struct cfg80211_connect_params *sme, bool privacy) +{ + struct mwifiex_802_11_ssid req_ssid; + struct mwifiex_ssid_bssid ssid_bssid; + int ret, auth_type = 0; + + memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); + memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); + + req_ssid.ssid_len = ssid_len; + if (ssid_len > IEEE80211_MAX_SSID_LEN) { + dev_err(priv->adapter->dev, "invalid SSID - aborting\n"); + return -EINVAL; + } + + memcpy(req_ssid.ssid, ssid, ssid_len); + if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) { + dev_err(priv->adapter->dev, "invalid SSID - aborting\n"); + return -EINVAL; + } + + /* disconnect before try to associate */ + mwifiex_deauthenticate(priv, NULL); + + if (channel) + ret = mwifiex_set_rf_channel(priv, channel, + mwifiex_channels_to_cfg80211_channel_type + (priv->adapter->chan_offset)); + + ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); /* Disable keys */ + + if (mode == NL80211_IFTYPE_ADHOC) { + /* "privacy" is set only for ad-hoc mode */ + if (privacy) { + /* + * Keep WLAN_CIPHER_SUITE_WEP104 for now so that + * the firmware can find a matching network from the + * scan. The cfg80211 does not give us the encryption + * mode at this stage so just setting it to WEP here. + */ + priv->sec_info.encryption_mode = + WLAN_CIPHER_SUITE_WEP104; + priv->sec_info.authentication_mode = + NL80211_AUTHTYPE_OPEN_SYSTEM; + } + + goto done; + } + + /* Now handle infra mode. "sme" is valid for infra mode only */ + if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC + || sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) + auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; + else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) + auth_type = NL80211_AUTHTYPE_SHARED_KEY; + + if (sme->crypto.n_ciphers_pairwise) { + priv->sec_info.encryption_mode = + sme->crypto.ciphers_pairwise[0]; + priv->sec_info.authentication_mode = auth_type; + } + + if (sme->crypto.cipher_group) { + priv->sec_info.encryption_mode = sme->crypto.cipher_group; + priv->sec_info.authentication_mode = auth_type; + } + if (sme->ie) + ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len); + + if (sme->key) { + if (mwifiex_is_alg_wep(0) | mwifiex_is_alg_wep(0)) { + dev_dbg(priv->adapter->dev, + "info: setting wep encryption" + " with key len %d\n", sme->key_len); + ret = mwifiex_set_encode(priv, sme->key, sme->key_len, + sme->key_idx, 0); + } + } +done: + /* Do specific SSID scanning */ + if (mwifiex_request_scan(priv, &req_ssid)) { + dev_err(priv->adapter->dev, "scan error\n"); + return -EFAULT; + } + + + memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid)); + + if (mode != NL80211_IFTYPE_ADHOC) { + if (mwifiex_find_best_bss(priv, &ssid_bssid)) + return -EFAULT; + /* Inform the BSS information to kernel, otherwise + * kernel will give a panic after successful assoc */ + if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid)) + return -EFAULT; + } + + dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", + (char *) req_ssid.ssid, ssid_bssid.bssid); + + memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6); + + /* Connect to BSS by ESSID */ + memset(&ssid_bssid.bssid, 0, ETH_ALEN); + + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + + if (mwifiex_bss_start(priv, &ssid_bssid)) + return -EFAULT; + + if (mode == NL80211_IFTYPE_ADHOC) { + /* Inform the BSS information to kernel, otherwise + * kernel will give a panic after successful assoc */ + if (mwifiex_cfg80211_inform_ibss_bss(priv)) + return -EFAULT; + } + + return ret; +} + +/* + * CFG802.11 operation handler for association request. + * + * This function does not work when the current mode is set to Ad-Hoc, or + * when there is already an association procedure going on. The given BSS + * information is used to associate. + */ +static int +mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + int ret = 0; + + if (priv->assoc_request) + return -EBUSY; + + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + wiphy_err(wiphy, "received infra assoc request " + "when station is in ibss mode\n"); + goto done; + } + + priv->assoc_request = -EINPROGRESS; + + wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", + (char *) sme->ssid, sme->bssid); + + ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, + priv->bss_mode, sme->channel, sme, 0); + + priv->assoc_request = 1; +done: + priv->assoc_result = ret; + queue_work(priv->workqueue, &priv->cfg_workqueue); + return ret; +} + +/* + * CFG802.11 operation handler to join an IBSS. + * + * This function does not work in any mode other than Ad-Hoc, or if + * a join operation is already in progress. + */ +static int +mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + int ret = 0; + + if (priv->ibss_join_request) + return -EBUSY; + + if (priv->bss_mode != NL80211_IFTYPE_ADHOC) { + wiphy_err(wiphy, "request to join ibss received " + "when station is not in ibss mode\n"); + goto done; + } + + priv->ibss_join_request = -EINPROGRESS; + + wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n", + (char *) params->ssid, params->bssid); + + ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, + params->bssid, priv->bss_mode, + params->channel, NULL, params->privacy); + + priv->ibss_join_request = 1; +done: + priv->ibss_join_result = ret; + queue_work(priv->workqueue, &priv->cfg_workqueue); + return ret; +} + +/* + * CFG802.11 operation handler to leave an IBSS. + * + * This function does not work if a leave operation is + * already in progress. + */ +static int +mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + if (priv->disconnect) + return -EBUSY; + + priv->disconnect = 1; + + wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n", + priv->cfg_bssid); + if (mwifiex_deauthenticate(priv, NULL)) + return -EFAULT; + + queue_work(priv->workqueue, &priv->cfg_workqueue); + + return 0; +} + +/* + * CFG802.11 operation handler for scan request. + * + * This function issues a scan request to the firmware based upon + * the user specified scan configuration. On successfull completion, + * it also informs the results. + */ +static int +mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); + + if (priv->scan_request && priv->scan_request != request) + return -EBUSY; + + priv->scan_request = request; + + queue_work(priv->workqueue, &priv->cfg_workqueue); + return 0; +} + +/* + * This function sets up the CFG802.11 specific HT capability fields + * with default values. + * + * The following default values are set - + * - HT Supported = True + * - Maximum AMPDU length factor = IEEE80211_HT_MAX_AMPDU_64K + * - Minimum AMPDU spacing = IEEE80211_HT_MPDU_DENSITY_NONE + * - HT Capabilities supported by firmware + * - MCS information, Rx mask = 0xff + * - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01) + */ +static void +mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, + struct mwifiex_private *priv) +{ + int rx_mcs_supp; + struct ieee80211_mcs_info mcs_set; + u8 *mcs = (u8 *)&mcs_set; + struct mwifiex_adapter *adapter = priv->adapter; + + ht_info->ht_supported = true; + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; + + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + + /* Fill HT capability information */ + if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + else + ht_info->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + else + ht_info->cap &= ~IEEE80211_HT_CAP_SGI_20; + + if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_SGI_40; + else + ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40; + + if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; + else + ht_info->cap &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + + if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; + else + ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC; + + ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; + ht_info->cap |= IEEE80211_HT_CAP_SM_PS; + + rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); + /* Set MCS for 1x1 */ + memset(mcs, 0xff, rx_mcs_supp); + /* Clear all the other values */ + memset(&mcs[rx_mcs_supp], 0, + sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); + if (priv->bss_mode == NL80211_IFTYPE_STATION || + ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) + /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ + SETHT_MCS32(mcs_set.rx_mask); + + memcpy((u8 *) &ht_info->mcs, mcs, sizeof(struct ieee80211_mcs_info)); + + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; +} + +/* station cfg80211 operations */ +static struct cfg80211_ops mwifiex_cfg80211_ops = { + .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf, + .scan = mwifiex_cfg80211_scan, + .connect = mwifiex_cfg80211_connect, + .disconnect = mwifiex_cfg80211_disconnect, + .get_station = mwifiex_cfg80211_get_station, + .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params, + .set_channel = mwifiex_cfg80211_set_channel, + .join_ibss = mwifiex_cfg80211_join_ibss, + .leave_ibss = mwifiex_cfg80211_leave_ibss, + .add_key = mwifiex_cfg80211_add_key, + .del_key = mwifiex_cfg80211_del_key, + .set_default_key = mwifiex_cfg80211_set_default_key, + .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt, + .set_tx_power = mwifiex_cfg80211_set_tx_power, +}; + +/* + * This function registers the device with CFG802.11 subsystem. + * + * The function creates the wireless device/wiphy, populates it with + * default parameters and handler function pointers, and finally + * registers the device. + */ +int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, + struct mwifiex_private *priv) +{ + int ret; + void *wdev_priv; + struct wireless_dev *wdev; + + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) { + dev_err(priv->adapter->dev, "%s: allocating wireless device\n", + __func__); + return -ENOMEM; + } + wdev->wiphy = + wiphy_new(&mwifiex_cfg80211_ops, + sizeof(struct mwifiex_private *)); + if (!wdev->wiphy) { + kfree(wdev); + return -ENOMEM; + } + wdev->iftype = NL80211_IFTYPE_STATION; + wdev->wiphy->max_scan_ssids = 10; + wdev->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz; + mwifiex_setup_ht_caps( + &wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv); + + if (priv->adapter->config_bands & BAND_A) { + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; + mwifiex_setup_ht_caps( + &wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv); + } else { + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; + } + + /* Initialize cipher suits */ + wdev->wiphy->cipher_suites = mwifiex_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); + + memcpy(wdev->wiphy->perm_addr, mac, 6); + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + /* We are using custom domains */ + wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + + wdev->wiphy->reg_notifier = mwifiex_reg_notifier; + + /* Set struct mwifiex_private pointer in wiphy_priv */ + wdev_priv = wiphy_priv(wdev->wiphy); + + *(unsigned long *) wdev_priv = (unsigned long) priv; + + ret = wiphy_register(wdev->wiphy); + if (ret < 0) { + dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n", + __func__); + wiphy_free(wdev->wiphy); + kfree(wdev); + return ret; + } else { + dev_dbg(priv->adapter->dev, + "info: successfully registered wiphy device\n"); + } + + dev_net_set(dev, wiphy_net(wdev->wiphy)); + dev->ieee80211_ptr = wdev; + memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6); + memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6); + SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); + priv->wdev = wdev; + + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT; + dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN; + + return ret; +} + +/* + * This function handles the result of different pending network operations. + * + * The following operations are handled and CFG802.11 subsystem is + * notified accordingly - + * - Scan request completion + * - Association request completion + * - IBSS join request completion + * - Disconnect request completion + */ +void +mwifiex_cfg80211_results(struct work_struct *work) +{ + struct mwifiex_private *priv = + container_of(work, struct mwifiex_private, cfg_workqueue); + struct mwifiex_user_scan_cfg *scan_req; + int ret = 0, i; + struct ieee80211_channel *chan; + + if (priv->scan_request) { + scan_req = kzalloc(sizeof(struct mwifiex_user_scan_cfg), + GFP_KERNEL); + if (!scan_req) { + dev_err(priv->adapter->dev, "failed to alloc " + "scan_req\n"); + return; + } + for (i = 0; i < priv->scan_request->n_ssids; i++) { + memcpy(scan_req->ssid_list[i].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + scan_req->ssid_list[i].max_len = + priv->scan_request->ssids[i].ssid_len; + } + for (i = 0; i < priv->scan_request->n_channels; i++) { + chan = priv->scan_request->channels[i]; + scan_req->chan_list[i].chan_number = chan->hw_value; + scan_req->chan_list[i].radio_type = chan->band; + if (chan->flags & IEEE80211_CHAN_DISABLED) + scan_req->chan_list[i].scan_type = + MWIFIEX_SCAN_TYPE_PASSIVE; + else + scan_req->chan_list[i].scan_type = + MWIFIEX_SCAN_TYPE_ACTIVE; + scan_req->chan_list[i].scan_time = 0; + } + if (mwifiex_set_user_scan_ioctl(priv, scan_req)) { + ret = -EFAULT; + goto done; + } + if (mwifiex_inform_bss_from_scan_result(priv, NULL)) + ret = -EFAULT; +done: + priv->scan_result_status = ret; + dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", + __func__); + cfg80211_scan_done(priv->scan_request, + (priv->scan_result_status < 0)); + priv->scan_request = NULL; + kfree(scan_req); + } + + if (priv->assoc_request == 1) { + if (!priv->assoc_result) { + cfg80211_connect_result(priv->netdev, priv->cfg_bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_SUCCESS, + GFP_KERNEL); + dev_dbg(priv->adapter->dev, + "info: associated to bssid %pM successfully\n", + priv->cfg_bssid); + } else { + dev_dbg(priv->adapter->dev, + "info: association to bssid %pM failed\n", + priv->cfg_bssid); + memset(priv->cfg_bssid, 0, ETH_ALEN); + } + priv->assoc_request = 0; + priv->assoc_result = 0; + } + + if (priv->ibss_join_request == 1) { + if (!priv->ibss_join_result) { + cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, + GFP_KERNEL); + dev_dbg(priv->adapter->dev, + "info: joined/created adhoc network with bssid" + " %pM successfully\n", priv->cfg_bssid); + } else { + dev_dbg(priv->adapter->dev, + "info: failed creating/joining adhoc network\n"); + } + priv->ibss_join_request = 0; + priv->ibss_join_result = 0; + } + + if (priv->disconnect) { + memset(priv->cfg_bssid, 0, ETH_ALEN); + priv->disconnect = 0; + } +} diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h new file mode 100644 index 000000000000..c4db8f36aa16 --- /dev/null +++ b/drivers/net/wireless/mwifiex/cfg80211.h @@ -0,0 +1,31 @@ +/* + * Marvell Wireless LAN device driver: CFG80211 + * + * Copyright (C) 2011, 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_CFG80211__ +#define __MWIFIEX_CFG80211__ + +#include + +#include "main.h" + +int mwifiex_register_cfg80211(struct net_device *, u8 *, + struct mwifiex_private *); + +void mwifiex_cfg80211_results(struct work_struct *work); +#endif diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c new file mode 100644 index 000000000000..d0cada5a29a0 --- /dev/null +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -0,0 +1,360 @@ +/* + * Marvell Wireless LAN device driver: Channel, Frequence and Power + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cfg80211.h" + +/* 100mW */ +#define MWIFIEX_TX_PWR_DEFAULT 20 +/* 100mW */ +#define MWIFIEX_TX_PWR_US_DEFAULT 20 +/* 50mW */ +#define MWIFIEX_TX_PWR_JP_DEFAULT 16 +/* 100mW */ +#define MWIFIEX_TX_PWR_FR_100MW 20 +/* 10mW */ +#define MWIFIEX_TX_PWR_FR_10MW 10 +/* 100mW */ +#define MWIFIEX_TX_PWR_EMEA_DEFAULT 20 + +static u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 }; + +static u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24, + 0xb0, 0x48, 0x60, 0x6c, 0 }; + +static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, + 0x0c, 0x12, 0x18, 0x24, + 0x30, 0x48, 0x60, 0x6c, 0 }; + +static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24, + 0xb0, 0x48, 0x60, 0x6c, 0 }; +u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, + 0xb0, 0x48, 0x60, 0x6c, 0 }; +static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04, + 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18, + 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90, + 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68, + 0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51, + 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 }; + +u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 }; + +u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, + 0x30, 0x48, 0x60, 0x6c, 0 }; + +u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c, + 0x12, 0x16, 0x18, 0x24, 0x30, 0x48, + 0x60, 0x6c, 0 }; + +u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, + 0x32, 0x40, 0x41, 0xff }; + +u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; + +/* + * This function maps an index in supported rates table into + * the corresponding data rate. + */ +u32 mwifiex_index_to_data_rate(u8 index, u8 ht_info) +{ + u16 mcs_rate[4][8] = { + {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e} + , /* LG 40M */ + {0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c} + , /* SG 40M */ + {0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82} + , /* LG 20M */ + {0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90} + }; /* SG 20M */ + + u32 rate; + + if (ht_info & BIT(0)) { + if (index == MWIFIEX_RATE_BITMAP_MCS0) { + if (ht_info & BIT(2)) + rate = 0x0D; /* MCS 32 SGI rate */ + else + rate = 0x0C; /* MCS 32 LGI rate */ + } else if (index < 8) { + if (ht_info & BIT(1)) { + if (ht_info & BIT(2)) + /* SGI, 40M */ + rate = mcs_rate[1][index]; + else + /* LGI, 40M */ + rate = mcs_rate[0][index]; + } else { + if (ht_info & BIT(2)) + /* SGI, 20M */ + rate = mcs_rate[3][index]; + else + /* LGI, 20M */ + rate = mcs_rate[2][index]; + } + } else + rate = mwifiex_data_rates[0]; + } else { + if (index >= MWIFIEX_SUPPORTED_RATES_EXT) + index = 0; + rate = mwifiex_data_rates[index]; + } + return rate; +} + +/* + * This function maps a data rate value into corresponding index in supported + * rates table. + */ +u8 mwifiex_data_rate_to_index(u32 rate) +{ + u16 *ptr; + + if (rate) { + ptr = memchr(mwifiex_data_rates, rate, + sizeof(mwifiex_data_rates)); + if (ptr) + return (u8) (ptr - mwifiex_data_rates); + } + return 0; +} + +/* + * This function returns the current active data rates. + * + * The result may vary depending upon connection status. + */ +u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates) +{ + if (!priv->media_connected) + return mwifiex_get_supported_rates(priv, rates); + else + return mwifiex_copy_rates(rates, 0, + priv->curr_bss_params.data_rates, + priv->curr_bss_params.num_of_rates); +} + +/* + * This function locates the Channel-Frequency-Power triplet based upon + * band and channel parameters. + */ +struct mwifiex_chan_freq_power * +mwifiex_get_cfp_by_band_and_channel_from_cfg80211(struct mwifiex_private + *priv, u8 band, u16 channel) +{ + struct mwifiex_chan_freq_power *cfp = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + int i; + + if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) + sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; + else + sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; + + if (!sband) { + dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" + " & channel %d\n", __func__, band, channel); + return cfp; + } + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if (((ch->hw_value == channel) || + (channel == FIRST_VALID_CHANNEL)) + && !(ch->flags & IEEE80211_CHAN_DISABLED)) { + priv->cfp.channel = channel; + priv->cfp.freq = ch->center_freq; + priv->cfp.max_tx_power = ch->max_power; + cfp = &priv->cfp; + break; + } + } + if (i == sband->n_channels) + dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" + " & channel %d\n", __func__, band, channel); + + return cfp; +} + +/* + * This function locates the Channel-Frequency-Power triplet based upon + * band and frequency parameters. + */ +struct mwifiex_chan_freq_power * +mwifiex_get_cfp_by_band_and_freq_from_cfg80211(struct mwifiex_private *priv, + u8 band, u32 freq) +{ + struct mwifiex_chan_freq_power *cfp = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + int i; + + if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) + sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; + else + sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; + + if (!sband) { + dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" + " & freq %d\n", __func__, band, freq); + return cfp; + } + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if ((ch->center_freq == freq) && + !(ch->flags & IEEE80211_CHAN_DISABLED)) { + priv->cfp.channel = ch->hw_value; + priv->cfp.freq = freq; + priv->cfp.max_tx_power = ch->max_power; + cfp = &priv->cfp; + break; + } + } + if (i == sband->n_channels) + dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" + " & freq %d\n", __func__, band, freq); + + return cfp; +} + +/* + * This function checks if the data rate is set to auto. + */ +u8 +mwifiex_is_rate_auto(struct mwifiex_private *priv) +{ + u32 i; + int rate_num = 0; + + for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++) + if (priv->bitmap_rates[i]) + rate_num++; + + if (rate_num > 1) + return true; + else + return false; +} + +/* + * This function converts rate bitmap into rate index. + */ +int mwifiex_get_rate_index(u16 *rate_bitmap, int size) +{ + int i; + + for (i = 0; i < size * 8; i++) + if (rate_bitmap[i / 16] & (1 << (i % 16))) + return i; + + return 0; +} + +/* + * This function gets the supported data rates. + * + * The function works in both Ad-Hoc and infra mode by printing the + * band and returning the data rates. + */ +u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) +{ + u32 k = 0; + struct mwifiex_adapter *adapter = priv->adapter; + if (priv->bss_mode == NL80211_IFTYPE_STATION) { + switch (adapter->config_bands) { + case BAND_B: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_b\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_b, + sizeof(supported_rates_b)); + break; + case BAND_G: + case BAND_G | BAND_GN: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_g\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_g, + sizeof(supported_rates_g)); + break; + case BAND_B | BAND_G: + case BAND_A | BAND_B | BAND_G: + case BAND_A | BAND_B: + case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN: + case BAND_B | BAND_G | BAND_GN: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_bg\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_bg, + sizeof(supported_rates_bg)); + break; + case BAND_A: + case BAND_A | BAND_G: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_a\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_a, + sizeof(supported_rates_a)); + break; + case BAND_A | BAND_AN: + case BAND_A | BAND_G | BAND_AN | BAND_GN: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_a\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_a, + sizeof(supported_rates_a)); + break; + case BAND_GN: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_n\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_n, + sizeof(supported_rates_n)); + break; + } + } else { + /* Ad-hoc mode */ + switch (adapter->adhoc_start_band) { + case BAND_B: + dev_dbg(adapter->dev, "info: adhoc B\n"); + k = mwifiex_copy_rates(rates, k, adhoc_rates_b, + sizeof(adhoc_rates_b)); + break; + case BAND_G: + case BAND_G | BAND_GN: + dev_dbg(adapter->dev, "info: adhoc G only\n"); + k = mwifiex_copy_rates(rates, k, adhoc_rates_g, + sizeof(adhoc_rates_g)); + break; + case BAND_B | BAND_G: + case BAND_B | BAND_G | BAND_GN: + dev_dbg(adapter->dev, "info: adhoc BG\n"); + k = mwifiex_copy_rates(rates, k, adhoc_rates_bg, + sizeof(adhoc_rates_bg)); + break; + case BAND_A: + case BAND_A | BAND_AN: + dev_dbg(adapter->dev, "info: adhoc A\n"); + k = mwifiex_copy_rates(rates, k, adhoc_rates_a, + sizeof(adhoc_rates_a)); + break; + } + } + + return k; +} diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c new file mode 100644 index 000000000000..cd89fed206ae --- /dev/null +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -0,0 +1,1414 @@ +/* + * Marvell Wireless LAN device driver: commands and events + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * This function initializes a command node. + * + * The actual allocation of the node is not done by this function. It only + * initiates a node by filling it with default parameters. Similarly, + * allocation of the different buffers used (IOCTL buffer, data buffer) are + * not done by this function either. + */ +static void +mwifiex_init_cmd_node(struct mwifiex_private *priv, + struct cmd_ctrl_node *cmd_node, + u32 cmd_oid, void *data_buf) +{ + cmd_node->priv = priv; + cmd_node->cmd_oid = cmd_oid; + cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required; + priv->adapter->cmd_wait_q_required = false; + cmd_node->data_buf = data_buf; + cmd_node->cmd_skb = cmd_node->skb; +} + +/* + * This function returns a command node from the free queue depending upon + * availability. + */ +static struct cmd_ctrl_node * +mwifiex_get_cmd_node(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_node; + unsigned long flags; + + spin_lock_irqsave(&adapter->cmd_free_q_lock, flags); + if (list_empty(&adapter->cmd_free_q)) { + dev_err(adapter->dev, "GET_CMD_NODE: cmd node not available\n"); + spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); + return NULL; + } + cmd_node = list_first_entry(&adapter->cmd_free_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); + + return cmd_node; +} + +/* + * This function cleans up a command node. + * + * The function resets the fields including the buffer pointers. + * This function does not try to free the buffers. They must be + * freed before calling this function. + * + * This function will however call the receive completion callback + * in case a response buffer is still available before resetting + * the pointer. + */ +static void +mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node) +{ + cmd_node->cmd_oid = 0; + cmd_node->cmd_flag = 0; + cmd_node->data_buf = NULL; + cmd_node->wait_q_enabled = false; + + if (cmd_node->resp_skb) { + dev_kfree_skb_any(cmd_node->resp_skb); + cmd_node->resp_skb = NULL; + } +} + +/* + * This function sends a host command to the firmware. + * + * The function copies the host command into the driver command + * buffer, which will be transferred to the firmware later by the + * main thread. + */ +static int mwifiex_cmd_host_cmd(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct mwifiex_ds_misc_cmd *pcmd_ptr = + (struct mwifiex_ds_misc_cmd *) data_buf; + + /* Copy the HOST command to command buffer */ + memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len); + dev_dbg(priv->adapter->dev, "cmd: host cmd size = %d\n", pcmd_ptr->len); + return 0; +} + +/* + * This function downloads a command to the firmware. + * + * The function performs sanity tests, sets the command sequence + * number and size, converts the header fields to CPU format before + * sending. Afterwards, it logs the command ID and action for debugging + * and sets up the command timeout timer. + */ +static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, + struct cmd_ctrl_node *cmd_node) +{ + + struct mwifiex_adapter *adapter = priv->adapter; + int ret; + struct host_cmd_ds_command *host_cmd; + uint16_t cmd_code; + uint16_t cmd_size; + struct timeval tstamp; + unsigned long flags; + + if (!adapter || !cmd_node) + return -1; + + host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); + + /* Sanity test */ + if (host_cmd == NULL || host_cmd->size == 0) { + dev_err(adapter->dev, "DNLD_CMD: host_cmd is null" + " or cmd size is 0, not sending\n"); + if (cmd_node->wait_q_enabled) + adapter->cmd_wait_q.status = -1; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + return -1; + } + + /* Set command sequence number */ + adapter->seq_num++; + host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO + (adapter->seq_num, cmd_node->priv->bss_num, + cmd_node->priv->bss_type)); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = cmd_node; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + cmd_code = le16_to_cpu(host_cmd->command); + cmd_size = le16_to_cpu(host_cmd->size); + + skb_trim(cmd_node->cmd_skb, cmd_size); + + do_gettimeofday(&tstamp); + dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d," + " seqno %#x\n", + tstamp.tv_sec, tstamp.tv_usec, cmd_code, + 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->data, + cmd_node->cmd_skb->len, 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 (cmd_node->wait_q_enabled) + adapter->cmd_wait_q.status = -1; + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + adapter->dbg.num_cmd_host_to_card_failure++; + return -1; + } + + /* Save the last command id and action to debug log */ + adapter->dbg.last_cmd_index = + (adapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM; + adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index] = cmd_code; + adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index] = + le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)); + + /* Clear BSS_NO_BITS from HostCmd */ + cmd_code &= HostCmd_CMD_ID_MASK; + + /* Setup the timer after transmit command */ + mod_timer(&adapter->cmd_timer, + jiffies + (MWIFIEX_TIMER_10S * HZ) / 1000); + + return 0; +} + +/* + * This function downloads a sleep confirm command to the firmware. + * + * The function performs sanity tests, sets the command sequence + * number and size, converts the header fields to CPU format before + * sending. + * + * No responses are needed for sleep confirm command. + */ +static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) +{ + int ret; + struct mwifiex_private *priv; + struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = + (struct mwifiex_opt_sleep_confirm *) + adapter->sleep_cfm->data; + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + + sleep_cfm_buf->seq_num = + cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO + (adapter->seq_num, priv->bss_num, + 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->data, + adapter->sleep_cfm->len, NULL); + skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN); + + if (ret == -1) { + dev_err(adapter->dev, "SLEEP_CFM: failed\n"); + adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++; + return -1; + } + if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY)) + == MWIFIEX_BSS_ROLE_STA) { + if (!sleep_cfm_buf->resp_ctrl) + /* Response is not needed for sleep + confirm command */ + adapter->ps_state = PS_STATE_SLEEP; + else + adapter->ps_state = PS_STATE_SLEEP_CFM; + + if (!sleep_cfm_buf->resp_ctrl + && (adapter->is_hs_configured + && !adapter->sleep_period.period)) { + adapter->pm_wakeup_card_req = true; + mwifiex_hs_activated_event(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_STA), true); + } + } + + return ret; +} + +/* + * This function allocates the command buffers and links them to + * the command free queue. + * + * The driver uses a pre allocated number of command buffers, which + * are created at driver initializations and freed at driver cleanup. + * Every command needs to obtain a command buffer from this pool before + * it can be issued. The command free queue lists the command buffers + * currently free to use, while the command pending queue lists the + * command buffers already in use and awaiting handling. Command buffers + * are returned to the free queue after use. + */ +int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_array; + u32 buf_size; + u32 i; + + /* Allocate and initialize struct cmd_ctrl_node */ + buf_size = sizeof(struct cmd_ctrl_node) * MWIFIEX_NUM_OF_CMD_BUFFER; + cmd_array = kzalloc(buf_size, GFP_KERNEL); + if (!cmd_array) { + dev_err(adapter->dev, "%s: failed to alloc cmd_array\n", + __func__); + return -ENOMEM; + } + + adapter->cmd_pool = cmd_array; + memset(adapter->cmd_pool, 0, buf_size); + + /* Allocate and initialize command buffers */ + for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) { + cmd_array[i].skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER); + if (!cmd_array[i].skb) { + dev_err(adapter->dev, "ALLOC_CMD_BUF: out of memory\n"); + return -1; + } + } + + for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) + mwifiex_insert_cmd_to_free_q(adapter, &cmd_array[i]); + + return 0; +} + +/* + * This function frees the command buffers. + * + * The function calls the completion callback for all the command + * buffers that still have response buffers associated with them. + */ +int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_array; + u32 i; + + /* Need to check if cmd pool is allocated or not */ + if (!adapter->cmd_pool) { + dev_dbg(adapter->dev, "info: FREE_CMD_BUF: cmd_pool is null\n"); + return 0; + } + + cmd_array = adapter->cmd_pool; + + /* Release shared memory buffers */ + for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) { + if (cmd_array[i].skb) { + dev_dbg(adapter->dev, "cmd: free cmd buffer %d\n", i); + dev_kfree_skb_any(cmd_array[i].skb); + } + if (!cmd_array[i].resp_skb) + continue; + dev_kfree_skb_any(cmd_array[i].resp_skb); + } + /* Release struct cmd_ctrl_node */ + if (adapter->cmd_pool) { + dev_dbg(adapter->dev, "cmd: free cmd pool\n"); + kfree(adapter->cmd_pool); + adapter->cmd_pool = NULL; + } + + return 0; +} + +/* + * This function handles events generated by firmware. + * + * Event body of events received from firmware are not used (though they are + * saved), only the event ID is used. Some events are re-invoked by + * the driver, with a new event body. + * + * After processing, the function calls the completion callback + * for cleanup. + */ +int mwifiex_process_event(struct mwifiex_adapter *adapter) +{ + int ret; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + struct sk_buff *skb = adapter->event_skb; + u32 eventcause = adapter->event_cause; + struct timeval tstamp; + struct mwifiex_rxinfo *rx_info; + + /* Save the last event to debug log */ + adapter->dbg.last_event_index = + (adapter->dbg.last_event_index + 1) % DBG_CMD_NUM; + adapter->dbg.last_event[adapter->dbg.last_event_index] = + (u16) eventcause; + + /* Get BSS number and corresponding priv */ + priv = mwifiex_get_priv_by_id(adapter, EVENT_GET_BSS_NUM(eventcause), + EVENT_GET_BSS_TYPE(eventcause)); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + /* Clear BSS_NO_BITS from event */ + eventcause &= EVENT_ID_MASK; + adapter->event_cause = eventcause; + + if (skb) { + rx_info = MWIFIEX_SKB_RXCB(skb); + rx_info->bss_index = priv->bss_index; + } + + if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) { + do_gettimeofday(&tstamp); + dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n", + tstamp.tv_sec, tstamp.tv_usec, eventcause); + } + + ret = mwifiex_process_sta_event(priv); + + adapter->event_cause = 0; + adapter->event_skb = NULL; + + dev_kfree_skb_any(skb); + + return ret; +} + +/* + * This function is used to send synchronous command to the firmware. + * + * it allocates a wait queue for the command and wait for the command + * response. + */ +int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, void *data_buf) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + + adapter->cmd_wait_q_required = true; + adapter->cmd_wait_q.condition = false; + + ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid, + data_buf); + if (!ret) + ret = mwifiex_wait_queue_complete(adapter); + + return ret; +} + + +/* + * This function prepares a command and asynchronously send it to the firmware. + * + * Preparation includes - + * - Sanity tests to make sure the card is still present or the FW + * is not reset + * - Getting a new command node from the command free queue + * - Initializing the command node for default parameters + * - Fill up the non-default parameters and buffer pointers + * - Add the command to pending queue + */ +int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, void *data_buf) +{ + int ret; + struct mwifiex_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node; + struct host_cmd_ds_command *cmd_ptr; + + if (!adapter) { + pr_err("PREP_CMD: adapter is NULL\n"); + return -1; + } + + if (adapter->is_suspended) { + dev_err(adapter->dev, "PREP_CMD: device in suspended state\n"); + return -1; + } + + if (adapter->surprise_removed) { + dev_err(adapter->dev, "PREP_CMD: card is removed\n"); + return -1; + } + + if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) { + if (cmd_no != HostCmd_CMD_FUNC_INIT) { + dev_err(adapter->dev, "PREP_CMD: FW in reset state\n"); + return -1; + } + } + + /* Get a new command node */ + cmd_node = mwifiex_get_cmd_node(adapter); + + if (!cmd_node) { + dev_err(adapter->dev, "PREP_CMD: no free cmd node\n"); + return -1; + } + + /* Initialize the command node */ + mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf); + + if (!cmd_node->cmd_skb) { + dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n"); + return -1; + } + + memset(skb_put(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)), + 0, sizeof(struct host_cmd_ds_command)); + + cmd_ptr = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->result = 0; + + /* Prepare command */ + if (cmd_no) { + ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action, + cmd_oid, data_buf, cmd_ptr); + } else { + ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf); + cmd_node->cmd_flag |= CMD_F_HOSTCMD; + } + + /* Return error, since the command preparation failed */ + if (ret) { + dev_err(adapter->dev, "PREP_CMD: cmd %#x preparation failed\n", + cmd_no); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + return -1; + } + + /* Send command */ + if (cmd_no == HostCmd_CMD_802_11_SCAN) + mwifiex_queue_scan_cmd(priv, cmd_node); + else + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + + return ret; +} + +/* + * This function returns a command to the command free queue. + * + * The function also calls the completion callback if required, before + * cleaning the command node and re-inserting it into the free queue. + */ +void +mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node) +{ + unsigned long flags; + + if (!cmd_node) + return; + + if (cmd_node->wait_q_enabled) + mwifiex_complete_cmd(adapter); + /* Clean the node */ + mwifiex_clean_cmd_node(adapter, cmd_node); + + /* Insert node into cmd_free_q */ + spin_lock_irqsave(&adapter->cmd_free_q_lock, flags); + list_add_tail(&cmd_node->list, &adapter->cmd_free_q); + spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); +} + +/* + * This function queues a command to the command pending queue. + * + * This in effect adds the command to the command list to be executed. + * Exit PS command is handled specially, by placing it always to the + * front of the command queue. + */ +void +mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node, u32 add_tail) +{ + struct host_cmd_ds_command *host_cmd = NULL; + u16 command; + unsigned long flags; + + host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); + if (!host_cmd) { + dev_err(adapter->dev, "QUEUE_CMD: host_cmd is NULL\n"); + return; + } + + command = le16_to_cpu(host_cmd->command); + + /* Exit_PS command needs to be queued in the header always. */ + if (command == HostCmd_CMD_802_11_PS_MODE_ENH) { + struct host_cmd_ds_802_11_ps_mode_enh *pm = + &host_cmd->params.psmode_enh; + if ((le16_to_cpu(pm->action) == DIS_PS) + || (le16_to_cpu(pm->action) == DIS_AUTO_PS)) { + if (adapter->ps_state != PS_STATE_AWAKE) + add_tail = false; + } + } + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + if (add_tail) + list_add_tail(&cmd_node->list, &adapter->cmd_pending_q); + else + list_add(&cmd_node->list, &adapter->cmd_pending_q); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command); +} + +/* + * This function executes the next command in command pending queue. + * + * This function will fail if a command is already in processing stage, + * otherwise it will dequeue the first command from the command pending + * queue and send to the firmware. + * + * If the device is currently in host sleep mode, any commands, except the + * host sleep configuration command will de-activate the host sleep. For PS + * mode, the function will put the firmware back to sleep if applicable. + */ +int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv; + struct cmd_ctrl_node *cmd_node; + int ret = 0; + struct host_cmd_ds_command *host_cmd; + unsigned long cmd_flags; + unsigned long cmd_pending_q_flags; + + /* Check if already in processing */ + if (adapter->curr_cmd) { + dev_err(adapter->dev, "EXEC_NEXT_CMD: cmd in processing\n"); + return -1; + } + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + /* Check if any command is pending */ + spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); + if (list_empty(&adapter->cmd_pending_q)) { + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + return 0; + } + cmd_node = list_first_entry(&adapter->cmd_pending_q, + struct cmd_ctrl_node, list); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + + host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); + priv = cmd_node->priv; + + if (adapter->ps_state != PS_STATE_AWAKE) { + dev_err(adapter->dev, "%s: cannot send cmd in sleep state," + " this should not happen\n", __func__); + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + return ret; + } + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + ret = mwifiex_dnld_cmd_to_fw(priv, cmd_node); + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + /* Any command sent to the firmware when host is in sleep + * mode should de-configure host sleep. We should skip the + * host sleep configuration command itself though + */ + if (priv && (host_cmd->command != + cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) { + if (adapter->hs_activated) { + adapter->is_hs_configured = false; + mwifiex_hs_activated_event(priv, false); + } + } + + return ret; +} + +/* + * This function handles the command response. + * + * After processing, the function cleans the command node and puts + * it back to the command free queue. + */ +int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) +{ + struct host_cmd_ds_command *resp; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + int ret = 0; + uint16_t orig_cmdresp_no; + uint16_t cmdresp_no; + uint16_t cmdresp_result; + struct timeval tstamp; + unsigned long flags; + + /* Now we got response from FW, cancel the command timer */ + del_timer(&adapter->cmd_timer); + + if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) { + resp = (struct host_cmd_ds_command *) adapter->upld_buf; + dev_err(adapter->dev, "CMD_RESP: NULL curr_cmd, %#x\n", + le16_to_cpu(resp->command)); + return -1; + } + + adapter->num_cmd_timeout = 0; + + resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data; + if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { + dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n", + le16_to_cpu(resp->command)); + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + return -1; + } + + if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { + /* Copy original response back to response buffer */ + struct mwifiex_ds_misc_cmd *hostcmd = NULL; + uint16_t size = le16_to_cpu(resp->size); + dev_dbg(adapter->dev, "info: host cmd resp size = %d\n", size); + size = min_t(u16, size, MWIFIEX_SIZE_OF_CMD_BUFFER); + if (adapter->curr_cmd->data_buf) { + hostcmd = (struct mwifiex_ds_misc_cmd *) + adapter->curr_cmd->data_buf; + hostcmd->len = size; + memcpy(hostcmd->cmd, (void *) resp, size); + } + } + orig_cmdresp_no = le16_to_cpu(resp->command); + + /* Get BSS number and corresponding priv */ + priv = mwifiex_get_priv_by_id(adapter, + HostCmd_GET_BSS_NO(le16_to_cpu(resp->seq_num)), + HostCmd_GET_BSS_TYPE(le16_to_cpu(resp->seq_num))); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + /* Clear RET_BIT from HostCmd */ + resp->command = cpu_to_le16(orig_cmdresp_no & HostCmd_CMD_ID_MASK); + + cmdresp_no = le16_to_cpu(resp->command); + cmdresp_result = le16_to_cpu(resp->result); + + /* Save the last command response to debug log */ + adapter->dbg.last_cmd_resp_index = + (adapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM; + adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] = + orig_cmdresp_no; + + do_gettimeofday(&tstamp); + dev_dbg(adapter->dev, "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d," + " len %d, seqno 0x%x\n", + tstamp.tv_sec, tstamp.tv_usec, orig_cmdresp_no, cmdresp_result, + le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num)); + + if (!(orig_cmdresp_no & HostCmd_RET_BIT)) { + dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n"); + if (adapter->curr_cmd->wait_q_enabled) + adapter->cmd_wait_q.status = -1; + + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + return -1; + } + + if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { + adapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD; + if ((cmdresp_result == HostCmd_RESULT_OK) + && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH)) + ret = mwifiex_ret_802_11_hs_cfg(priv, resp); + } else { + /* handle response */ + ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp); + } + + /* Check init command response */ + if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) { + if (ret == -1) { + dev_err(adapter->dev, "%s: cmd %#x failed during " + "initialization\n", __func__, cmdresp_no); + mwifiex_init_fw_complete(adapter); + return -1; + } else if (adapter->last_init_cmd == cmdresp_no) + adapter->hw_status = MWIFIEX_HW_STATUS_INIT_DONE; + } + + if (adapter->curr_cmd) { + if (adapter->curr_cmd->wait_q_enabled && (!ret)) + adapter->cmd_wait_q.status = 0; + else if (adapter->curr_cmd->wait_q_enabled && (ret == -1)) + adapter->cmd_wait_q.status = -1; + + /* Clean up and put current command back to cmd_free_q */ + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + } + + return ret; +} + +/* + * This function handles the timeout of command sending. + * + * It will re-send the same command again. + */ +void +mwifiex_cmd_timeout_func(unsigned long function_context) +{ + struct mwifiex_adapter *adapter = + (struct mwifiex_adapter *) function_context; + struct cmd_ctrl_node *cmd_node; + struct timeval tstamp; + + adapter->num_cmd_timeout++; + adapter->dbg.num_cmd_timeout++; + if (!adapter->curr_cmd) { + dev_dbg(adapter->dev, "cmd: empty curr_cmd\n"); + return; + } + cmd_node = adapter->curr_cmd; + if (cmd_node->wait_q_enabled) + adapter->cmd_wait_q.status = -ETIMEDOUT; + + if (cmd_node) { + adapter->dbg.timeout_cmd_id = + adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; + adapter->dbg.timeout_cmd_act = + adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index]; + do_gettimeofday(&tstamp); + dev_err(adapter->dev, "%s: Timeout cmd id (%lu.%lu) = %#x," + " act = %#x\n", __func__, + tstamp.tv_sec, tstamp.tv_usec, + adapter->dbg.timeout_cmd_id, + adapter->dbg.timeout_cmd_act); + + dev_err(adapter->dev, "num_data_h2c_failure = %d\n", + adapter->dbg.num_tx_host_to_card_failure); + dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n", + adapter->dbg.num_cmd_host_to_card_failure); + + dev_err(adapter->dev, "num_cmd_timeout = %d\n", + adapter->dbg.num_cmd_timeout); + dev_err(adapter->dev, "num_tx_timeout = %d\n", + adapter->dbg.num_tx_timeout); + + dev_err(adapter->dev, "last_cmd_index = %d\n", + adapter->dbg.last_cmd_index); + print_hex_dump_bytes("last_cmd_id: ", DUMP_PREFIX_OFFSET, + adapter->dbg.last_cmd_id, DBG_CMD_NUM); + print_hex_dump_bytes("last_cmd_act: ", DUMP_PREFIX_OFFSET, + adapter->dbg.last_cmd_act, DBG_CMD_NUM); + + dev_err(adapter->dev, "last_cmd_resp_index = %d\n", + adapter->dbg.last_cmd_resp_index); + print_hex_dump_bytes("last_cmd_resp_id: ", DUMP_PREFIX_OFFSET, + adapter->dbg.last_cmd_resp_id, DBG_CMD_NUM); + + dev_err(adapter->dev, "last_event_index = %d\n", + adapter->dbg.last_event_index); + print_hex_dump_bytes("last_event: ", DUMP_PREFIX_OFFSET, + adapter->dbg.last_event, DBG_CMD_NUM); + + dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n", + adapter->data_sent, adapter->cmd_sent); + + dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n", + adapter->ps_mode, adapter->ps_state); + } + if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) + mwifiex_init_fw_complete(adapter); +} + +/* + * This function cancels all the pending commands. + * + * The current command, all commands in command pending queue and all scan + * commands in scan pending queue are cancelled. All the completion callbacks + * are called with failure status to ensure cleanup. + */ +void +mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node; + unsigned long flags; + + /* Cancel current cmd */ + if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd->wait_q_enabled = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + adapter->cmd_wait_q.status = -1; + mwifiex_complete_cmd(adapter); + } + /* Cancel all pending command */ + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->cmd_pending_q, list) { + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + if (cmd_node->wait_q_enabled) { + adapter->cmd_wait_q.status = -1; + mwifiex_complete_cmd(adapter); + cmd_node->wait_q_enabled = false; + } + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + } + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + /* Cancel all pending scan command */ + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + cmd_node->wait_q_enabled = false; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); +} + +/* + * This function cancels all pending commands that matches with + * the given IOCTL request. + * + * Both the current command buffer and the pending command queue are + * searched for matching IOCTL request. The completion callback of + * the matched command is called with failure status to ensure cleanup. + * In case of scan commands, all pending commands in scan pending queue + * are cancelled. + */ +void +mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; + unsigned long cmd_flags; + unsigned long cmd_pending_q_flags; + unsigned long scan_pending_q_flags; + uint16_t cancel_scan_cmd = false; + + if ((adapter->curr_cmd) && + (adapter->curr_cmd->wait_q_enabled)) { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + cmd_node = adapter->curr_cmd; + cmd_node->wait_q_enabled = false; + cmd_node->cmd_flag |= CMD_F_CANCELED; + spin_lock_irqsave(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + } + + /* Cancel all pending scan command */ + spin_lock_irqsave(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + cmd_node->wait_q_enabled = false; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + cancel_scan_cmd = true; + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + + if (cancel_scan_cmd) { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + } + adapter->cmd_wait_q.status = -1; + mwifiex_complete_cmd(adapter); +} + +/* + * This function sends the sleep confirm command to firmware, if + * possible. + * + * The sleep confirm command cannot be issued if command response, + * data response or event response is awaiting handling, or if we + * are in the middle of sending a command, or expecting a command + * response. + */ +void +mwifiex_check_ps_cond(struct mwifiex_adapter *adapter) +{ + if (!adapter->cmd_sent && + !adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter)) + mwifiex_dnld_sleep_confirm_cmd(adapter); + else + dev_dbg(adapter->dev, + "cmd: Delay Sleep Confirm (%s%s%s)\n", + (adapter->cmd_sent) ? "D" : "", + (adapter->curr_cmd) ? "C" : "", + (IS_CARD_RX_RCVD(adapter)) ? "R" : ""); +} + +/* + * This function sends a Host Sleep activated event to applications. + * + * This event is generated by the driver, with a blank event body. + */ +void +mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated) +{ + if (activated) { + if (priv->adapter->is_hs_configured) { + priv->adapter->hs_activated = true; + dev_dbg(priv->adapter->dev, "event: hs_activated\n"); + priv->adapter->hs_activate_wait_q_woken = true; + wake_up_interruptible( + &priv->adapter->hs_activate_wait_q); + } else { + dev_dbg(priv->adapter->dev, "event: HS not configured\n"); + } + } else { + dev_dbg(priv->adapter->dev, "event: hs_deactivated\n"); + priv->adapter->hs_activated = false; + } +} + +/* + * This function handles the command response of a Host Sleep configuration + * command. + * + * Handling includes changing the header fields into CPU format + * and setting the current host sleep activation status in driver. + * + * In case host sleep status change, the function generates an event to + * notify the applications. + */ +int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_hs_cfg_enh *phs_cfg = + &resp->params.opt_hs_cfg; + uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions); + + if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) { + mwifiex_hs_activated_event(priv, true); + return 0; + } else { + dev_dbg(adapter->dev, "cmd: CMD_RESP: HS_CFG cmd reply" + " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n", + resp->result, conditions, + phs_cfg->params.hs_config.gpio, + phs_cfg->params.hs_config.gap); + } + if (conditions != HOST_SLEEP_CFG_CANCEL) { + adapter->is_hs_configured = true; + } else { + adapter->is_hs_configured = false; + if (adapter->hs_activated) + mwifiex_hs_activated_event(priv, false); + } + + return 0; +} + +/* + * This function wakes up the adapter and generates a Host Sleep + * cancel event on receiving the power up interrupt. + */ +void +mwifiex_process_hs_config(struct mwifiex_adapter *adapter) +{ + dev_dbg(adapter->dev, "info: %s: auto cancelling host sleep" + " since there is interrupt from the firmware\n", __func__); + + adapter->if_ops.wakeup(adapter); + adapter->hs_activated = false; + adapter->is_hs_configured = false; + mwifiex_hs_activated_event(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), false); +} + +/* + * This function handles the command response of a sleep confirm command. + * + * The function sets the card state to SLEEP if the response indicates success. + */ +void +mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, + u8 *pbuf, u32 upld_len) +{ + struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + uint16_t result = le16_to_cpu(cmd->result); + uint16_t command = le16_to_cpu(cmd->command); + uint16_t seq_num = le16_to_cpu(cmd->seq_num); + + if (!upld_len) { + dev_err(adapter->dev, "%s: cmd size is 0\n", __func__); + return; + } + + /* Get BSS number and corresponding priv */ + priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num), + HostCmd_GET_BSS_TYPE(seq_num)); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + + /* Update sequence number */ + seq_num = HostCmd_GET_SEQ_NO(seq_num); + /* Clear RET_BIT from HostCmd */ + command &= HostCmd_CMD_ID_MASK; + + if (command != HostCmd_CMD_802_11_PS_MODE_ENH) { + dev_err(adapter->dev, "%s: received unexpected response for" + " cmd %x, result = %x\n", __func__, command, result); + return; + } + + if (result) { + dev_err(adapter->dev, "%s: sleep confirm cmd failed\n", + __func__); + adapter->pm_wakeup_card_req = false; + adapter->ps_state = PS_STATE_AWAKE; + return; + } + adapter->pm_wakeup_card_req = true; + if (adapter->is_hs_configured) + mwifiex_hs_activated_event(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), true); + adapter->ps_state = PS_STATE_SLEEP; + cmd->command = cpu_to_le16(command); + cmd->seq_num = cpu_to_le16(seq_num); +} +EXPORT_SYMBOL_GPL(mwifiex_process_sleep_confirm_resp); + +/* + * This function prepares an enhanced power mode command. + * + * This function can be used to disable power save or to configure + * power save with auto PS or STA PS or auto deep sleep. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting Power Save bitmap, PS parameters TLV, PS mode TLV, + * auto deep sleep TLV (as required) + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, uint16_t ps_bitmap, + void *data_buf) +{ + struct host_cmd_ds_802_11_ps_mode_enh *psmode_enh = + &cmd->params.psmode_enh; + u8 *tlv; + u16 cmd_size = 0; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); + if (cmd_action == DIS_AUTO_PS) { + psmode_enh->action = cpu_to_le16(DIS_AUTO_PS); + psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); + cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) + + sizeof(psmode_enh->params.ps_bitmap)); + } else if (cmd_action == GET_PS) { + psmode_enh->action = cpu_to_le16(GET_PS); + psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); + cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) + + sizeof(psmode_enh->params.ps_bitmap)); + } else if (cmd_action == EN_AUTO_PS) { + psmode_enh->action = cpu_to_le16(EN_AUTO_PS); + psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); + cmd_size = S_DS_GEN + sizeof(psmode_enh->action) + + sizeof(psmode_enh->params.ps_bitmap); + tlv = (u8 *) cmd + cmd_size; + if (ps_bitmap & BITMAP_STA_PS) { + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_ie_types_ps_param *ps_tlv = + (struct mwifiex_ie_types_ps_param *) tlv; + struct mwifiex_ps_param *ps_mode = &ps_tlv->param; + ps_tlv->header.type = cpu_to_le16(TLV_TYPE_PS_PARAM); + ps_tlv->header.len = cpu_to_le16(sizeof(*ps_tlv) - + sizeof(struct mwifiex_ie_types_header)); + cmd_size += sizeof(*ps_tlv); + tlv += sizeof(*ps_tlv); + dev_dbg(adapter->dev, "cmd: PS Command: Enter PS\n"); + ps_mode->null_pkt_interval = + cpu_to_le16(adapter->null_pkt_interval); + ps_mode->multiple_dtims = + cpu_to_le16(adapter->multiple_dtim); + ps_mode->bcn_miss_timeout = + cpu_to_le16(adapter->bcn_miss_time_out); + ps_mode->local_listen_interval = + cpu_to_le16(adapter->local_listen_interval); + ps_mode->adhoc_wake_period = + cpu_to_le16(adapter->adhoc_awake_period); + ps_mode->delay_to_ps = + cpu_to_le16(adapter->delay_to_ps); + ps_mode->mode = + cpu_to_le16(adapter->enhanced_ps_mode); + + } + if (ps_bitmap & BITMAP_AUTO_DS) { + struct mwifiex_ie_types_auto_ds_param *auto_ds_tlv = + (struct mwifiex_ie_types_auto_ds_param *) tlv; + u16 idletime = 0; + + auto_ds_tlv->header.type = + cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM); + auto_ds_tlv->header.len = + cpu_to_le16(sizeof(*auto_ds_tlv) - + sizeof(struct mwifiex_ie_types_header)); + cmd_size += sizeof(*auto_ds_tlv); + tlv += sizeof(*auto_ds_tlv); + if (data_buf) + idletime = ((struct mwifiex_ds_auto_ds *) + data_buf)->idle_time; + dev_dbg(priv->adapter->dev, + "cmd: PS Command: Enter Auto Deep Sleep\n"); + auto_ds_tlv->deep_sleep_timeout = cpu_to_le16(idletime); + } + cmd->size = cpu_to_le16(cmd_size); + } + return 0; +} + +/* + * This function handles the command response of an enhanced power mode + * command. + * + * Handling includes changing the header fields into CPU format + * and setting the current enhanced power mode in driver. + */ +int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_ps_mode_enh *ps_mode = + &resp->params.psmode_enh; + uint16_t action = le16_to_cpu(ps_mode->action); + uint16_t ps_bitmap = le16_to_cpu(ps_mode->params.ps_bitmap); + uint16_t auto_ps_bitmap = + le16_to_cpu(ps_mode->params.ps_bitmap); + + dev_dbg(adapter->dev, "info: %s: PS_MODE cmd reply result=%#x action=%#X\n", + __func__, resp->result, action); + if (action == EN_AUTO_PS) { + if (auto_ps_bitmap & BITMAP_AUTO_DS) { + dev_dbg(adapter->dev, "cmd: Enabled auto deep sleep\n"); + priv->adapter->is_deep_sleep = true; + } + if (auto_ps_bitmap & BITMAP_STA_PS) { + dev_dbg(adapter->dev, "cmd: Enabled STA power save\n"); + if (adapter->sleep_period.period) + dev_dbg(adapter->dev, "cmd: set to uapsd/pps mode\n"); + } + } else if (action == DIS_AUTO_PS) { + if (ps_bitmap & BITMAP_AUTO_DS) { + priv->adapter->is_deep_sleep = false; + dev_dbg(adapter->dev, "cmd: Disabled auto deep sleep\n"); + } + if (ps_bitmap & BITMAP_STA_PS) { + dev_dbg(adapter->dev, "cmd: Disabled STA power save\n"); + if (adapter->sleep_period.period) { + adapter->delay_null_pkt = false; + adapter->tx_lock_flag = false; + adapter->pps_uapsd_mode = false; + } + } + } else if (action == GET_PS) { + if (ps_bitmap & BITMAP_STA_PS) + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; + else + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + + dev_dbg(adapter->dev, "cmd: ps_bitmap=%#x\n", ps_bitmap); + + if (data_buf) { + /* This section is for get power save mode */ + struct mwifiex_ds_pm_cfg *pm_cfg = + (struct mwifiex_ds_pm_cfg *)data_buf; + if (ps_bitmap & BITMAP_STA_PS) + pm_cfg->param.ps_mode = 1; + else + pm_cfg->param.ps_mode = 0; + } + } + return 0; +} + +/* + * This function prepares command to get hardware specifications. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting permanent address parameter + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd) +{ + struct host_cmd_ds_get_hw_spec *hw_spec = &cmd->params.hw_spec; + + cmd->command = cpu_to_le16(HostCmd_CMD_GET_HW_SPEC); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_ds_get_hw_spec) + S_DS_GEN); + memcpy(hw_spec->permanent_addr, priv->curr_addr, ETH_ALEN); + + return 0; +} + +/* + * This function handles the command response of get hardware + * specifications. + * + * Handling includes changing the header fields into CPU format + * and saving/updating the following parameters in driver - + * - Firmware capability information + * - Firmware band settings + * - Ad-hoc start band and channel + * - Ad-hoc 11n activation status + * - Firmware release number + * - Number of antennas + * - Hardware address + * - Hardware interface version + * - Firmware version + * - Region code + * - 11n capabilities + * - MCS support fields + * - MP end port + */ +int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec; + struct mwifiex_adapter *adapter = priv->adapter; + int i; + + adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info); + + if (IS_SUPPORT_MULTI_BANDS(adapter)) + adapter->fw_bands = (u8) GET_FW_DEFAULT_BANDS(adapter); + else + adapter->fw_bands = BAND_B; + + adapter->config_bands = adapter->fw_bands; + + if (adapter->fw_bands & BAND_A) { + if (adapter->fw_bands & BAND_GN) { + adapter->config_bands |= BAND_AN; + adapter->fw_bands |= BAND_AN; + } + if (adapter->fw_bands & BAND_AN) { + adapter->adhoc_start_band = BAND_A | BAND_AN; + adapter->adhoc_11n_enabled = true; + } else { + adapter->adhoc_start_band = BAND_A; + } + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A; + } else if (adapter->fw_bands & BAND_GN) { + adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN; + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + adapter->adhoc_11n_enabled = true; + } else if (adapter->fw_bands & BAND_G) { + adapter->adhoc_start_band = BAND_G | BAND_B; + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + } else if (adapter->fw_bands & BAND_B) { + adapter->adhoc_start_band = BAND_B; + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + } + + adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); + adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna); + + dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n", + adapter->fw_release_number); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n", + hw_spec->permanent_addr); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n", + le16_to_cpu(hw_spec->hw_if_version), + le16_to_cpu(hw_spec->version)); + + if (priv->curr_addr[0] == 0xff) + memmove(priv->curr_addr, hw_spec->permanent_addr, ETH_ALEN); + + adapter->region_code = le16_to_cpu(hw_spec->region_code); + + for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++) + /* Use the region code to search for the index */ + if (adapter->region_code == region_code_index[i]) + break; + + /* If it's unidentified region code, use the default (USA) */ + if (i >= MWIFIEX_MAX_REGION_CODE) { + adapter->region_code = 0x10; + dev_dbg(adapter->dev, "cmd: unknown region code, use default (USA)\n"); + } + + adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap); + adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support; + + if (adapter->if_ops.update_mp_end_port) + adapter->if_ops.update_mp_end_port(adapter, + le16_to_cpu(hw_spec->mp_end_port)); + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c new file mode 100644 index 000000000000..46d65e02c7ba --- /dev/null +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -0,0 +1,770 @@ +/* + * Marvell Wireless LAN device driver: debugfs + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include + +#include "main.h" +#include "11n.h" + + +static struct dentry *mwifiex_dfs_dir; + +static char *bss_modes[] = { + "Unknown", + "Managed", + "Ad-hoc", + "Auto" +}; + +/* size/addr for mwifiex_debug_info */ +#define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n)) +#define item_addr(n) (offsetof(struct mwifiex_debug_info, n)) + +/* size/addr for struct mwifiex_adapter */ +#define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n)) +#define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n)) + +struct mwifiex_debug_data { + char name[32]; /* variable/array name */ + u32 size; /* size of the variable/array */ + size_t addr; /* address of the variable/array */ + int num; /* number of variables in an array */ +}; + +static struct mwifiex_debug_data items[] = { + {"int_counter", item_size(int_counter), + item_addr(int_counter), 1}, + {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]), + item_addr(packets_out[WMM_AC_VO]), 1}, + {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]), + item_addr(packets_out[WMM_AC_VI]), 1}, + {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]), + item_addr(packets_out[WMM_AC_BE]), 1}, + {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), + item_addr(packets_out[WMM_AC_BK]), 1}, + {"max_tx_buf_size", item_size(max_tx_buf_size), + item_addr(max_tx_buf_size), 1}, + {"tx_buf_size", item_size(tx_buf_size), + item_addr(tx_buf_size), 1}, + {"curr_tx_buf_size", item_size(curr_tx_buf_size), + item_addr(curr_tx_buf_size), 1}, + {"ps_mode", item_size(ps_mode), + item_addr(ps_mode), 1}, + {"ps_state", item_size(ps_state), + item_addr(ps_state), 1}, + {"is_deep_sleep", item_size(is_deep_sleep), + item_addr(is_deep_sleep), 1}, + {"wakeup_dev_req", item_size(pm_wakeup_card_req), + item_addr(pm_wakeup_card_req), 1}, + {"wakeup_tries", item_size(pm_wakeup_fw_try), + item_addr(pm_wakeup_fw_try), 1}, + {"hs_configured", item_size(is_hs_configured), + item_addr(is_hs_configured), 1}, + {"hs_activated", item_size(hs_activated), + item_addr(hs_activated), 1}, + {"num_tx_timeout", item_size(num_tx_timeout), + item_addr(num_tx_timeout), 1}, + {"num_cmd_timeout", item_size(num_cmd_timeout), + item_addr(num_cmd_timeout), 1}, + {"timeout_cmd_id", item_size(timeout_cmd_id), + item_addr(timeout_cmd_id), 1}, + {"timeout_cmd_act", item_size(timeout_cmd_act), + item_addr(timeout_cmd_act), 1}, + {"last_cmd_id", item_size(last_cmd_id), + item_addr(last_cmd_id), DBG_CMD_NUM}, + {"last_cmd_act", item_size(last_cmd_act), + item_addr(last_cmd_act), DBG_CMD_NUM}, + {"last_cmd_index", item_size(last_cmd_index), + item_addr(last_cmd_index), 1}, + {"last_cmd_resp_id", item_size(last_cmd_resp_id), + item_addr(last_cmd_resp_id), DBG_CMD_NUM}, + {"last_cmd_resp_index", item_size(last_cmd_resp_index), + item_addr(last_cmd_resp_index), 1}, + {"last_event", item_size(last_event), + item_addr(last_event), DBG_CMD_NUM}, + {"last_event_index", item_size(last_event_index), + item_addr(last_event_index), 1}, + {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), + item_addr(num_cmd_host_to_card_failure), 1}, + {"num_cmd_sleep_cfm_fail", + item_size(num_cmd_sleep_cfm_host_to_card_failure), + item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1}, + {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure), + item_addr(num_tx_host_to_card_failure), 1}, + {"num_evt_deauth", item_size(num_event_deauth), + item_addr(num_event_deauth), 1}, + {"num_evt_disassoc", item_size(num_event_disassoc), + item_addr(num_event_disassoc), 1}, + {"num_evt_link_lost", item_size(num_event_link_lost), + item_addr(num_event_link_lost), 1}, + {"num_cmd_deauth", item_size(num_cmd_deauth), + item_addr(num_cmd_deauth), 1}, + {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success), + item_addr(num_cmd_assoc_success), 1}, + {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure), + item_addr(num_cmd_assoc_failure), 1}, + {"cmd_sent", item_size(cmd_sent), + item_addr(cmd_sent), 1}, + {"data_sent", item_size(data_sent), + item_addr(data_sent), 1}, + {"cmd_resp_received", item_size(cmd_resp_received), + item_addr(cmd_resp_received), 1}, + {"event_received", item_size(event_received), + item_addr(event_received), 1}, + + /* variables defined in struct mwifiex_adapter */ + {"cmd_pending", adapter_item_size(cmd_pending), + adapter_item_addr(cmd_pending), 1}, + {"tx_pending", adapter_item_size(tx_pending), + adapter_item_addr(tx_pending), 1}, + {"rx_pending", adapter_item_size(rx_pending), + adapter_item_addr(rx_pending), 1}, +}; + +static int num_of_items = ARRAY_SIZE(items); + +/* + * Generic proc file open handler. + * + * This function is called every time a file is accessed for read or write. + */ +static int +mwifiex_open_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +/* + * Proc info file read handler. + * + * This function is called when the 'info' file is opened for reading. + * It prints the following driver related information - + * - Driver name + * - Driver version + * - Driver extended version + * - Interface name + * - BSS mode + * - Media state (connected or disconnected) + * - MAC address + * - Total number of Tx bytes + * - Total number of Rx bytes + * - Total number of Tx packets + * - Total number of Rx packets + * - Total number of dropped Tx packets + * - Total number of dropped Rx packets + * - Total number of corrupted Tx packets + * - Total number of corrupted Rx packets + * - Carrier status (on or off) + * - Tx queue status (started or stopped) + * + * For STA mode drivers, it also prints the following extra - + * - ESSID + * - BSSID + * - Channel + * - Region code + * - Multicast count + * - Multicast addresses + */ +static ssize_t +mwifiex_info_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + struct net_device *netdev = priv->netdev; + struct netdev_hw_addr *ha; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *) page, fmt[64]; + struct mwifiex_bss_info info; + ssize_t ret; + int i = 0; + + if (!p) + return -ENOMEM; + + memset(&info, 0, sizeof(info)); + ret = mwifiex_get_bss_info(priv, &info); + if (ret) + goto free_and_exit; + + mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1); + + if (!priv->version_str[0]) + mwifiex_get_ver_ext(priv); + + p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); + p += sprintf(p, "driver_version = %s", fmt); + p += sprintf(p, "\nverext = %s", priv->version_str); + p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); + p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); + p += sprintf(p, "media_state=\"%s\"\n", + (!priv->media_connected ? "Disconnected" : "Connected")); + p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", + netdev->dev_addr[0], netdev->dev_addr[1], + netdev->dev_addr[2], netdev->dev_addr[3], + netdev->dev_addr[4], netdev->dev_addr[5]); + + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { + p += sprintf(p, "multicast_count=\"%d\"\n", + netdev_mc_count(netdev)); + p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); + p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", + info.bssid[0], info.bssid[1], + info.bssid[2], info.bssid[3], + info.bssid[4], info.bssid[5]); + p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); + p += sprintf(p, "region_code = \"%02x\"\n", info.region_code); + + netdev_for_each_mc_addr(ha, netdev) + p += sprintf(p, "multicast_address[%d]=" + "\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", i++, + ha->addr[0], ha->addr[1], + ha->addr[2], ha->addr[3], + ha->addr[4], ha->addr[5]); + } + + p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); + p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); + p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); + p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); + p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); + p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); + p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); + p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); + p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) + ? "on" : "off")); + p += sprintf(p, "tx queue %s\n", ((netif_queue_stopped(priv->netdev)) + ? "stopped" : "started")); + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, + (unsigned long) p - page); + +free_and_exit: + free_page(page); + return ret; +} + +/* + * Proc getlog file read handler. + * + * This function is called when the 'getlog' file is opened for reading + * It prints the following log information - + * - Number of multicast Tx frames + * - Number of failed packets + * - Number of Tx retries + * - Number of multicast Tx retries + * - Number of duplicate frames + * - Number of RTS successes + * - Number of RTS failures + * - Number of ACK failures + * - Number of fragmented Rx frames + * - Number of multicast Rx frames + * - Number of FCS errors + * - Number of Tx frames + * - WEP ICV error counts + */ +static ssize_t +mwifiex_getlog_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *) page; + ssize_t ret; + struct mwifiex_ds_get_stats stats; + + if (!p) + return -ENOMEM; + + memset(&stats, 0, sizeof(stats)); + ret = mwifiex_get_stats_info(priv, &stats); + if (ret) + goto free_and_exit; + + p += sprintf(p, "\n" + "mcasttxframe %u\n" + "failed %u\n" + "retry %u\n" + "multiretry %u\n" + "framedup %u\n" + "rtssuccess %u\n" + "rtsfailure %u\n" + "ackfailure %u\n" + "rxfrag %u\n" + "mcastrxframe %u\n" + "fcserror %u\n" + "txframe %u\n" + "wepicverrcnt-1 %u\n" + "wepicverrcnt-2 %u\n" + "wepicverrcnt-3 %u\n" + "wepicverrcnt-4 %u\n", + stats.mcast_tx_frame, + stats.failed, + stats.retry, + stats.multi_retry, + stats.frame_dup, + stats.rts_success, + stats.rts_failure, + stats.ack_failure, + stats.rx_frag, + stats.mcast_rx_frame, + stats.fcs_error, + stats.tx_frame, + stats.wep_icv_error[0], + stats.wep_icv_error[1], + stats.wep_icv_error[2], + stats.wep_icv_error[3]); + + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, + (unsigned long) p - page); + +free_and_exit: + free_page(page); + return ret; +} + +static struct mwifiex_debug_info info; + +/* + * Proc debug file read handler. + * + * This function is called when the 'debug' file is opened for reading + * It prints the following log information - + * - Interrupt count + * - WMM AC VO packets count + * - WMM AC VI packets count + * - WMM AC BE packets count + * - WMM AC BK packets count + * - Maximum Tx buffer size + * - Tx buffer size + * - Current Tx buffer size + * - Power Save mode + * - Power Save state + * - Deep Sleep status + * - Device wakeup required status + * - Number of wakeup tries + * - Host Sleep configured status + * - Host Sleep activated status + * - Number of Tx timeouts + * - Number of command timeouts + * - Last timed out command ID + * - Last timed out command action + * - Last command ID + * - Last command action + * - Last command index + * - Last command response ID + * - Last command response index + * - Last event + * - Last event index + * - Number of host to card command failures + * - Number of sleep confirm command failures + * - Number of host to card data failure + * - Number of deauthentication events + * - Number of disassociation events + * - Number of link lost events + * - Number of deauthentication commands + * - Number of association success commands + * - Number of association failure commands + * - Number of commands sent + * - Number of data packets sent + * - Number of command responses received + * - Number of events received + * - Tx BA stream table (TID, RA) + * - Rx reorder table (TID, TA, Start window, Window size, Buffer) + */ +static ssize_t +mwifiex_debug_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + struct mwifiex_debug_data *d = &items[0]; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *) page; + ssize_t ret; + size_t size, addr; + long val; + int i, j; + + if (!p) + return -ENOMEM; + + ret = mwifiex_get_debug_info(priv, &info); + if (ret) + goto free_and_exit; + + for (i = 0; i < num_of_items; i++) { + p += sprintf(p, "%s=", d[i].name); + + size = d[i].size / d[i].num; + + if (i < (num_of_items - 3)) + addr = d[i].addr + (size_t) &info; + else /* The last 3 items are struct mwifiex_adapter variables */ + addr = d[i].addr + (size_t) priv->adapter; + + for (j = 0; j < d[i].num; j++) { + switch (size) { + case 1: + val = *((u8 *) addr); + break; + case 2: + val = *((u16 *) addr); + break; + case 4: + val = *((u32 *) addr); + break; + case 8: + val = *((long long *) addr); + break; + default: + val = -1; + break; + } + + p += sprintf(p, "%#lx ", val); + addr += size; + } + + p += sprintf(p, "\n"); + } + + if (info.tx_tbl_num) { + p += sprintf(p, "Tx BA stream table:\n"); + for (i = 0; i < info.tx_tbl_num; i++) + p += sprintf(p, "tid = %d, " + "ra = %02x:%02x:%02x:%02x:%02x:%02x\n", + info.tx_tbl[i].tid, info.tx_tbl[i].ra[0], + info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2], + info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4], + info.tx_tbl[i].ra[5]); + } + + if (info.rx_tbl_num) { + p += sprintf(p, "Rx reorder table:\n"); + for (i = 0; i < info.rx_tbl_num; i++) { + + p += sprintf(p, "tid = %d, " + "ta = %02x:%02x:%02x:%02x:%02x:%02x, " + "start_win = %d, " + "win_size = %d, buffer: ", + info.rx_tbl[i].tid, + info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1], + info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3], + info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5], + info.rx_tbl[i].start_win, + info.rx_tbl[i].win_size); + + for (j = 0; j < info.rx_tbl[i].win_size; j++) + p += sprintf(p, "%c ", + info.rx_tbl[i].buffer[j] ? + '1' : '0'); + + p += sprintf(p, "\n"); + } + } + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, + (unsigned long) p - page); + +free_and_exit: + free_page(page); + return ret; +} + +static u32 saved_reg_type, saved_reg_offset, saved_reg_value; + +/* + * Proc regrdwr file write handler. + * + * This function is called when the 'regrdwr' file is opened for writing + * + * This function can be used to write to a register. + */ +static ssize_t +mwifiex_regrdwr_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); + int ret; + u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; + + if (!buf) + return -ENOMEM; + + + if (copy_from_user(buf, ubuf, buf_size)) { + ret = -EFAULT; + goto done; + } + + sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value); + + if (reg_type == 0 || reg_offset == 0) { + ret = -EINVAL; + goto done; + } else { + saved_reg_type = reg_type; + saved_reg_offset = reg_offset; + saved_reg_value = reg_value; + ret = count; + } +done: + free_page(addr); + return ret; +} + +/* + * Proc regrdwr file read handler. + * + * This function is called when the 'regrdwr' file is opened for reading + * + * This function can be used to read from a register. + */ +static ssize_t +mwifiex_regrdwr_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + int pos = 0, ret = 0; + u32 reg_value; + + if (!buf) + return -ENOMEM; + + if (!saved_reg_type) { + /* No command has been given */ + pos += snprintf(buf, PAGE_SIZE, "0"); + goto done; + } + /* Set command has been given */ + if (saved_reg_value != UINT_MAX) { + ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset, + saved_reg_value); + + pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", + saved_reg_type, saved_reg_offset, + saved_reg_value); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + + goto done; + } + /* Get command has been given */ + ret = mwifiex_reg_read(priv, saved_reg_type, + saved_reg_offset, ®_value); + if (ret) { + ret = -EINVAL; + goto done; + } + + pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type, + saved_reg_offset, reg_value); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + +done: + free_page(addr); + return ret; +} + +static u32 saved_offset = -1, saved_bytes = -1; + +/* + * Proc rdeeprom file write handler. + * + * This function is called when the 'rdeeprom' file is opened for writing + * + * This function can be used to write to a RDEEPROM location. + */ +static ssize_t +mwifiex_rdeeprom_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); + int ret = 0; + int offset = -1, bytes = -1; + + if (!buf) + return -ENOMEM; + + + if (copy_from_user(buf, ubuf, buf_size)) { + ret = -EFAULT; + goto done; + } + + sscanf(buf, "%d %d", &offset, &bytes); + + if (offset == -1 || bytes == -1) { + ret = -EINVAL; + goto done; + } else { + saved_offset = offset; + saved_bytes = bytes; + ret = count; + } +done: + free_page(addr); + return ret; +} + +/* + * Proc rdeeprom read write handler. + * + * This function is called when the 'rdeeprom' file is opened for reading + * + * This function can be used to read from a RDEEPROM location. + */ +static ssize_t +mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + int pos = 0, ret = 0, i; + u8 value[MAX_EEPROM_DATA]; + + if (!buf) + return -ENOMEM; + + if (saved_offset == -1) { + /* No command has been given */ + pos += snprintf(buf, PAGE_SIZE, "0"); + goto done; + } + + /* Get command has been given */ + ret = mwifiex_eeprom_read(priv, (u16) saved_offset, + (u16) saved_bytes, value); + if (ret) { + ret = -EINVAL; + goto done; + } + + pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); + + for (i = 0; i < saved_bytes; i++) + pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + +done: + free_page(addr); + return ret; +} + + +#define MWIFIEX_DFS_ADD_FILE(name) do { \ + if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \ + priv, &mwifiex_dfs_##name##_fops)) \ + return; \ +} while (0); + +#define MWIFIEX_DFS_FILE_OPS(name) \ +static const struct file_operations mwifiex_dfs_##name##_fops = { \ + .read = mwifiex_##name##_read, \ + .write = mwifiex_##name##_write, \ + .open = mwifiex_open_generic, \ +}; + +#define MWIFIEX_DFS_FILE_READ_OPS(name) \ +static const struct file_operations mwifiex_dfs_##name##_fops = { \ + .read = mwifiex_##name##_read, \ + .open = mwifiex_open_generic, \ +}; + +#define MWIFIEX_DFS_FILE_WRITE_OPS(name) \ +static const struct file_operations mwifiex_dfs_##name##_fops = { \ + .write = mwifiex_##name##_write, \ + .open = mwifiex_open_generic, \ +}; + + +MWIFIEX_DFS_FILE_READ_OPS(info); +MWIFIEX_DFS_FILE_READ_OPS(debug); +MWIFIEX_DFS_FILE_READ_OPS(getlog); +MWIFIEX_DFS_FILE_OPS(regrdwr); +MWIFIEX_DFS_FILE_OPS(rdeeprom); + +/* + * This function creates the debug FS directory structure and the files. + */ +void +mwifiex_dev_debugfs_init(struct mwifiex_private *priv) +{ + if (!mwifiex_dfs_dir || !priv) + return; + + priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, + mwifiex_dfs_dir); + + if (!priv->dfs_dev_dir) + return; + + MWIFIEX_DFS_ADD_FILE(info); + MWIFIEX_DFS_ADD_FILE(debug); + MWIFIEX_DFS_ADD_FILE(getlog); + MWIFIEX_DFS_ADD_FILE(regrdwr); + MWIFIEX_DFS_ADD_FILE(rdeeprom); +} + +/* + * This function removes the debug FS directory structure and the files. + */ +void +mwifiex_dev_debugfs_remove(struct mwifiex_private *priv) +{ + if (!priv) + return; + + debugfs_remove_recursive(priv->dfs_dev_dir); +} + +/* + * This function creates the top level proc directory. + */ +void +mwifiex_debugfs_init(void) +{ + if (!mwifiex_dfs_dir) + mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL); +} + +/* + * This function removes the top level proc directory. + */ +void +mwifiex_debugfs_remove(void) +{ + if (mwifiex_dfs_dir) + debugfs_remove(mwifiex_dfs_dir); +} diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h new file mode 100644 index 000000000000..0e90b0986ed8 --- /dev/null +++ b/drivers/net/wireless/mwifiex/decl.h @@ -0,0 +1,129 @@ +/* + * Marvell Wireless LAN device driver: generic data structures and APIs + * + * Copyright (C) 2011, 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_DECL_H_ +#define _MWIFIEX_DECL_H_ + +#undef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + + +#define MWIFIEX_MAX_BSS_NUM (1) + +#define MWIFIEX_MIN_DATA_HEADER_LEN 32 /* (sizeof(mwifiex_txpd)) */ + +#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2 +#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16 + +#define MWIFIEX_AMPDU_DEF_TXWINSIZE 32 +#define MWIFIEX_AMPDU_DEF_RXWINSIZE 16 +#define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff + +#define MWIFIEX_RATE_INDEX_HRDSSS0 0 +#define MWIFIEX_RATE_INDEX_HRDSSS3 3 +#define MWIFIEX_RATE_INDEX_OFDM0 4 +#define MWIFIEX_RATE_INDEX_OFDM7 11 +#define MWIFIEX_RATE_INDEX_MCS0 12 + +#define MWIFIEX_RATE_BITMAP_OFDM0 16 +#define MWIFIEX_RATE_BITMAP_OFDM7 23 +#define MWIFIEX_RATE_BITMAP_MCS0 32 +#define MWIFIEX_RATE_BITMAP_MCS127 159 + +#define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024) + +#define MWIFIEX_RTS_MIN_VALUE (0) +#define MWIFIEX_RTS_MAX_VALUE (2347) +#define MWIFIEX_FRAG_MIN_VALUE (256) +#define MWIFIEX_FRAG_MAX_VALUE (2346) + +#define MWIFIEX_SDIO_BLOCK_SIZE 256 + +#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) + +enum mwifiex_bss_type { + MWIFIEX_BSS_TYPE_STA = 0, + MWIFIEX_BSS_TYPE_UAP = 1, + MWIFIEX_BSS_TYPE_ANY = 0xff, +}; + +enum mwifiex_bss_role { + MWIFIEX_BSS_ROLE_STA = 0, + MWIFIEX_BSS_ROLE_UAP = 1, + MWIFIEX_BSS_ROLE_ANY = 0xff, +}; + +#define BSS_ROLE_BIT_MASK BIT(0) + +#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK) + +enum mwifiex_data_frame_type { + MWIFIEX_DATA_FRAME_TYPE_ETH_II = 0, + MWIFIEX_DATA_FRAME_TYPE_802_11, +}; + +struct mwifiex_fw_image { + u8 *helper_buf; + u32 helper_len; + u8 *fw_buf; + u32 fw_len; +}; + +struct mwifiex_802_11_ssid { + u32 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; +}; + +struct mwifiex_wait_queue { + wait_queue_head_t wait; + u16 condition; + int status; +}; + +struct mwifiex_rxinfo { + u8 bss_index; + struct sk_buff *parent; + u8 use_count; +}; + +struct mwifiex_txinfo { + u32 status_code; + u8 flags; + u8 bss_index; +}; + +struct mwifiex_bss_attr { + u8 bss_type; + u8 frame_type; + u8 active; + u8 bss_priority; + u8 bss_num; +}; + +enum mwifiex_wmm_ac_e { + WMM_AC_BK, + WMM_AC_BE, + WMM_AC_VI, + WMM_AC_VO +} __packed; +#endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h new file mode 100644 index 000000000000..afdd145dff0b --- /dev/null +++ b/drivers/net/wireless/mwifiex/fw.h @@ -0,0 +1,1187 @@ +/* + * Marvell Wireless LAN device driver: Firmware specific macros & structures + * + * Copyright (C) 2011, 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_FW_H_ +#define _MWIFIEX_FW_H_ + +#include + + +#define INTF_HEADER_LEN 4 + +struct rfc_1042_hdr { + u8 llc_dsap; + u8 llc_ssap; + u8 llc_ctrl; + u8 snap_oui[3]; + u16 snap_type; +}; + +struct rx_packet_hdr { + struct ethhdr eth803_hdr; + struct rfc_1042_hdr rfc1042_hdr; +}; + +struct tx_packet_hdr { + struct ethhdr eth803_hdr; + struct rfc_1042_hdr rfc1042_hdr; +}; + +#define B_SUPPORTED_RATES 5 +#define G_SUPPORTED_RATES 9 +#define BG_SUPPORTED_RATES 13 +#define A_SUPPORTED_RATES 9 +#define HOSTCMD_SUPPORTED_RATES 14 +#define N_SUPPORTED_RATES 3 +#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN) + +#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11)) +#define IS_SUPPORT_MULTI_BANDS(adapter) \ + (adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT) +#define GET_FW_DEFAULT_BANDS(adapter) \ + ((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS) + +extern u8 supported_rates_b[B_SUPPORTED_RATES]; +extern u8 supported_rates_g[G_SUPPORTED_RATES]; +extern u8 supported_rates_bg[BG_SUPPORTED_RATES]; +extern u8 supported_rates_a[A_SUPPORTED_RATES]; +extern u8 supported_rates_n[N_SUPPORTED_RATES]; + +#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff + +#define KEY_INFO_ENABLED 0x01 +enum KEY_TYPE_ID { + KEY_TYPE_ID_WEP = 0, + KEY_TYPE_ID_TKIP, + KEY_TYPE_ID_AES, + KEY_TYPE_ID_WAPI, +}; +#define KEY_MCAST BIT(0) +#define KEY_UNICAST BIT(1) +#define KEY_ENABLED BIT(2) + +#define WAPI_KEY_LEN 50 + +#define MAX_POLL_TRIES 100 + +#define MAX_MULTI_INTERFACE_POLL_TRIES 1000 + +#define MAX_FIRMWARE_POLL_TRIES 100 + +#define FIRMWARE_READY 0xfedc + +enum MWIFIEX_802_11_PRIVACY_FILTER { + MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL, + MWIFIEX_802_11_PRIV_FILTER_8021X_WEP +}; + +enum MWIFIEX_802_11_WEP_STATUS { + MWIFIEX_802_11_WEP_ENABLED, + MWIFIEX_802_11_WEP_DISABLED, +}; + +#define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF))) + +#define PROPRIETARY_TLV_BASE_ID 0x0100 +#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_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_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_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113) +#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114) + +#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 + +#define SSN_MASK 0xfff0 + +#define BA_RESULT_SUCCESS 0x0 +#define BA_RESULT_TIMEOUT 0x2 + +#define IS_BASTREAM_SETUP(ptr) (ptr->ba_status) + +#define BA_STREAM_NOT_ALLOWED 0xff + +#define IS_11N_ENABLED(priv) ((priv->adapter->config_bands & BAND_GN || \ + priv->adapter->config_bands & BAND_AN) \ + && priv->curr_bss_params.bss_descriptor.bcn_ht_cap) +#define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) &\ + BIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS) + +#define MWIFIEX_TX_DATA_BUF_SIZE_4K 4096 +#define MWIFIEX_TX_DATA_BUF_SIZE_8K 8192 + +#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) + +/* dev_cap bitmap + * BIT + * 0-16 reserved + * 17 IEEE80211_HT_CAP_SUP_WIDTH_20_40 + * 18-22 reserved + * 23 IEEE80211_HT_CAP_SGI_20 + * 24 IEEE80211_HT_CAP_SGI_40 + * 25 IEEE80211_HT_CAP_TX_STBC + * 26 IEEE80211_HT_CAP_RX_STBC + * 27-28 reserved + * 29 IEEE80211_HT_CAP_GRN_FLD + * 30-31 reserved + */ +#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & BIT(17)) +#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & BIT(23)) +#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & BIT(24)) +#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25)) +#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26)) +#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) + +#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f) +#define SETHT_MCS32(x) (x[4] |= 1) + +#define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4)) + +#define LLC_SNAP_LEN 8 + +#define MOD_CLASS_HR_DSSS 0x03 +#define MOD_CLASS_OFDM 0x07 +#define MOD_CLASS_HT 0x08 +#define HT_BW_20 0 +#define HT_BW_40 1 + +#define HostCmd_CMD_GET_HW_SPEC 0x0003 +#define HostCmd_CMD_802_11_SCAN 0x0006 +#define HostCmd_CMD_802_11_GET_LOG 0x000b +#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010 +#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059 +#define HostCmd_CMD_802_11_ASSOCIATE 0x0012 +#define HostCmd_CMD_802_11_SNMP_MIB 0x0016 +#define HostCmd_CMD_MAC_REG_ACCESS 0x0019 +#define HostCmd_CMD_BBP_REG_ACCESS 0x001a +#define HostCmd_CMD_RF_REG_ACCESS 0x001b +#define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad +#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d +#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024 +#define HostCmd_CMD_MAC_CONTROL 0x0028 +#define HostCmd_CMD_802_11_AD_HOC_START 0x002b +#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c +#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040 +#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D +#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b +#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_TX_RATE_QUERY 0x007f +#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083 +#define HostCmd_CMD_VERSION_EXT 0x0097 +#define HostCmd_CMD_RSSI_INFO 0x00a4 +#define HostCmd_CMD_FUNC_INIT 0x00a9 +#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa +#define HostCmd_CMD_11N_CFG 0x00cd +#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce +#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf +#define HostCmd_CMD_11N_DELBA 0x00d0 +#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9 +#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df +#define HostCmd_CMD_TXPWR_CFG 0x00d1 +#define HostCmd_CMD_TX_RATE_CFG 0x00d6 +#define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4 +#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5 +#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed +#define HostCmd_CMD_SET_BSS_MODE 0x00f7 + + +enum ENH_PS_MODES { + EN_PS = 1, + DIS_PS = 2, + EN_AUTO_DS = 3, + DIS_AUTO_DS = 4, + SLEEP_CONFIRM = 5, + GET_PS = 0, + EN_AUTO_PS = 0xff, + DIS_AUTO_PS = 0xfe, +}; + +#define HostCmd_RET_BIT 0x8000 +#define HostCmd_ACT_GEN_GET 0x0000 +#define HostCmd_ACT_GEN_SET 0x0001 +#define HostCmd_RESULT_OK 0x0000 + +#define HostCmd_ACT_MAC_RX_ON 0x0001 +#define HostCmd_ACT_MAC_TX_ON 0x0002 +#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008 +#define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010 +#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 +#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 +#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000 + +#define HostCmd_BSS_MODE_IBSS 0x0002 +#define HostCmd_BSS_MODE_ANY 0x0003 + +#define HostCmd_SCAN_RADIO_TYPE_BG 0 +#define HostCmd_SCAN_RADIO_TYPE_A 1 + +#define HOST_SLEEP_CFG_CANCEL 0xffffffff +#define HOST_SLEEP_CFG_COND_DEF 0x0000000f +#define HOST_SLEEP_CFG_GPIO_DEF 0xff +#define HOST_SLEEP_CFG_GAP_DEF 0 + +#define CMD_F_HOSTCMD (1 << 0) +#define CMD_F_CANCELED (1 << 1) + +#define HostCmd_CMD_ID_MASK 0x0fff + +#define HostCmd_SEQ_NUM_MASK 0x00ff + +#define HostCmd_BSS_NUM_MASK 0x0f00 + +#define HostCmd_BSS_TYPE_MASK 0xf000 + +#define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) { \ + (((seq) & 0x00ff) | \ + (((num) & 0x000f) << 8)) | \ + (((type) & 0x000f) << 12); } + +#define HostCmd_GET_SEQ_NO(seq) \ + ((seq) & HostCmd_SEQ_NUM_MASK) + +#define HostCmd_GET_BSS_NO(seq) \ + (((seq) & HostCmd_BSS_NUM_MASK) >> 8) + +#define HostCmd_GET_BSS_TYPE(seq) \ + (((seq) & HostCmd_BSS_TYPE_MASK) >> 12) + +#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001 +#define EVENT_LINK_LOST 0x00000003 +#define EVENT_LINK_SENSED 0x00000004 +#define EVENT_MIB_CHANGED 0x00000006 +#define EVENT_INIT_DONE 0x00000007 +#define EVENT_DEAUTHENTICATED 0x00000008 +#define EVENT_DISASSOCIATED 0x00000009 +#define EVENT_PS_AWAKE 0x0000000a +#define EVENT_PS_SLEEP 0x0000000b +#define EVENT_MIC_ERR_MULTICAST 0x0000000d +#define EVENT_MIC_ERR_UNICAST 0x0000000e +#define EVENT_DEEP_SLEEP_AWAKE 0x00000010 +#define EVENT_ADHOC_BCN_LOST 0x00000011 + +#define EVENT_WMM_STATUS_CHANGE 0x00000017 +#define EVENT_BG_SCAN_REPORT 0x00000018 +#define EVENT_RSSI_LOW 0x00000019 +#define EVENT_SNR_LOW 0x0000001a +#define EVENT_MAX_FAIL 0x0000001b +#define EVENT_RSSI_HIGH 0x0000001c +#define EVENT_SNR_HIGH 0x0000001d +#define EVENT_IBSS_COALESCED 0x0000001e +#define EVENT_DATA_RSSI_LOW 0x00000024 +#define EVENT_DATA_SNR_LOW 0x00000025 +#define EVENT_DATA_RSSI_HIGH 0x00000026 +#define EVENT_DATA_SNR_HIGH 0x00000027 +#define EVENT_LINK_QUALITY 0x00000028 +#define EVENT_PORT_RELEASE 0x0000002b +#define EVENT_PRE_BEACON_LOST 0x00000031 +#define EVENT_ADDBA 0x00000033 +#define EVENT_DELBA 0x00000034 +#define EVENT_BA_STREAM_TIEMOUT 0x00000037 +#define EVENT_AMSDU_AGGR_CTRL 0x00000042 +#define EVENT_WEP_ICV_ERR 0x00000046 +#define EVENT_HS_ACT_REQ 0x00000047 +#define EVENT_BW_CHANGE 0x00000048 + +#define EVENT_HOSTWAKE_STAIE 0x0000004d + +#define EVENT_ID_MASK 0xffff +#define BSS_NUM_MASK 0xf + +#define EVENT_GET_BSS_NUM(event_cause) \ + (((event_cause) >> 16) & BSS_NUM_MASK) + +#define EVENT_GET_BSS_TYPE(event_cause) \ + (((event_cause) >> 24) & 0x00ff) + +struct mwifiex_ie_types_header { + __le16 type; + __le16 len; +} __packed; + +struct mwifiex_ie_types_data { + struct mwifiex_ie_types_header header; + u8 data[1]; +} __packed; + +#define MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET 0x01 +#define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08 + +struct txpd { + u8 bss_type; + u8 bss_num; + __le16 tx_pkt_length; + __le16 tx_pkt_offset; + __le16 tx_pkt_type; + __le32 tx_control; + u8 priority; + u8 flags; + u8 pkt_delay_2ms; + u8 reserved1; +} __packed; + +struct rxpd { + u8 bss_type; + u8 bss_num; + u16 rx_pkt_length; + u16 rx_pkt_offset; + u16 rx_pkt_type; + u16 seq_num; + u8 priority; + u8 rx_rate; + s8 snr; + s8 nf; + /* Ht Info [Bit 0] RxRate format: LG=0, HT=1 + * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 + * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */ + u8 ht_info; + u8 reserved; +} __packed; + +enum mwifiex_chan_scan_mode_bitmasks { + MWIFIEX_PASSIVE_SCAN = BIT(0), + MWIFIEX_DISABLE_CHAN_FILT = BIT(1), +}; + +#define SECOND_CHANNEL_BELOW 0x30 +#define SECOND_CHANNEL_ABOVE 0x10 +struct mwifiex_chan_scan_param_set { + u8 radio_type; + u8 chan_number; + u8 chan_scan_mode_bitmap; + __le16 min_scan_time; + __le16 max_scan_time; +} __packed; + +struct mwifiex_ie_types_chan_list_param_set { + struct mwifiex_ie_types_header header; + struct mwifiex_chan_scan_param_set chan_scan_param[1]; +} __packed; + +struct chan_band_param_set { + u8 radio_type; + u8 chan_number; +}; + +struct mwifiex_ie_types_chan_band_list_param_set { + struct mwifiex_ie_types_header header; + struct chan_band_param_set chan_band_param[1]; +} __packed; + +struct mwifiex_ie_types_rates_param_set { + struct mwifiex_ie_types_header header; + u8 rates[1]; +} __packed; + +struct mwifiex_ie_types_ssid_param_set { + struct mwifiex_ie_types_header header; + u8 ssid[1]; +} __packed; + +struct mwifiex_ie_types_num_probes { + struct mwifiex_ie_types_header header; + __le16 num_probes; +} __packed; + +struct mwifiex_ie_types_wildcard_ssid_params { + struct mwifiex_ie_types_header header; + u8 max_ssid_length; + u8 ssid[1]; +} __packed; + +#define TSF_DATA_SIZE 8 +struct mwifiex_ie_types_tsf_timestamp { + struct mwifiex_ie_types_header header; + u8 tsf_data[1]; +} __packed; + +struct mwifiex_cf_param_set { + u8 cfp_cnt; + u8 cfp_period; + u16 cfp_max_duration; + u16 cfp_duration_remaining; +} __packed; + +struct mwifiex_ibss_param_set { + u16 atim_window; +} __packed; + +struct mwifiex_ie_types_ss_param_set { + struct mwifiex_ie_types_header header; + union { + struct mwifiex_cf_param_set cf_param_set[1]; + struct mwifiex_ibss_param_set ibss_param_set[1]; + } cf_ibss; +} __packed; + +struct mwifiex_fh_param_set { + u16 dwell_time; + u8 hop_set; + u8 hop_pattern; + u8 hop_index; +} __packed; + +struct mwifiex_ds_param_set { + u8 current_chan; +} __packed; + +struct mwifiex_ie_types_phy_param_set { + struct mwifiex_ie_types_header header; + union { + struct mwifiex_fh_param_set fh_param_set[1]; + struct mwifiex_ds_param_set ds_param_set[1]; + } fh_ds; +} __packed; + +struct mwifiex_ie_types_auth_type { + struct mwifiex_ie_types_header header; + __le16 auth_type; +} __packed; + +struct mwifiex_ie_types_vendor_param_set { + struct mwifiex_ie_types_header header; + u8 ie[MWIFIEX_MAX_VSIE_LEN]; +}; + +struct mwifiex_ie_types_rsn_param_set { + struct mwifiex_ie_types_header header; + u8 rsn_ie[1]; +} __packed; + +#define KEYPARAMSET_FIXED_LEN 6 + +struct mwifiex_ie_type_key_param_set { + __le16 type; + __le16 length; + __le16 key_type_id; + __le16 key_info; + __le16 key_len; + u8 key[50]; +} __packed; + +struct host_cmd_ds_802_11_key_material { + __le16 action; + struct mwifiex_ie_type_key_param_set key_param_set; +} __packed; + +struct host_cmd_ds_gen { + u16 command; + u16 size; + u16 seq_num; + u16 result; +}; + +#define S_DS_GEN sizeof(struct host_cmd_ds_gen) + +enum sleep_resp_ctrl { + RESP_NOT_NEEDED = 0, + RESP_NEEDED, +}; + +struct mwifiex_ps_param { + __le16 null_pkt_interval; + __le16 multiple_dtims; + __le16 bcn_miss_timeout; + __le16 local_listen_interval; + __le16 adhoc_wake_period; + __le16 mode; + __le16 delay_to_ps; +}; + +#define BITMAP_AUTO_DS 0x01 +#define BITMAP_STA_PS 0x10 + +struct mwifiex_ie_types_auto_ds_param { + struct mwifiex_ie_types_header header; + __le16 deep_sleep_timeout; +} __packed; + +struct mwifiex_ie_types_ps_param { + struct mwifiex_ie_types_header header; + struct mwifiex_ps_param param; +} __packed; + +struct host_cmd_ds_802_11_ps_mode_enh { + __le16 action; + + union { + struct mwifiex_ps_param opt_ps; + __le16 ps_bitmap; + } params; +} __packed; + +struct host_cmd_ds_get_hw_spec { + __le16 hw_if_version; + __le16 version; + __le16 reserved; + __le16 num_of_mcast_adr; + u8 permanent_addr[ETH_ALEN]; + __le16 region_code; + __le16 number_of_antenna; + __le32 fw_release_number; + __le32 reserved_1; + __le32 reserved_2; + __le32 reserved_3; + __le32 fw_cap_info; + __le32 dot_11n_dev_cap; + u8 dev_mcs_support; + __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ + __le16 reserved_4; +} __packed; + +struct host_cmd_ds_802_11_rssi_info { + __le16 action; + __le16 ndata; + __le16 nbcn; + __le16 reserved[9]; + long long reserved_1; +}; + +struct host_cmd_ds_802_11_rssi_info_rsp { + __le16 action; + __le16 ndata; + __le16 nbcn; + __le16 data_rssi_last; + __le16 data_nf_last; + __le16 data_rssi_avg; + __le16 data_nf_avg; + __le16 bcn_rssi_last; + __le16 bcn_nf_last; + __le16 bcn_rssi_avg; + __le16 bcn_nf_avg; + long long tsf_bcn; +}; + +struct host_cmd_ds_802_11_mac_address { + __le16 action; + u8 mac_addr[ETH_ALEN]; +}; + +struct host_cmd_ds_mac_control { + __le16 action; + __le16 reserved; +}; + +struct host_cmd_ds_mac_multicast_adr { + __le16 action; + __le16 num_of_adrs; + u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; +} __packed; + +struct host_cmd_ds_802_11_deauthenticate { + u8 mac_addr[ETH_ALEN]; + __le16 reason_code; +} __packed; + +struct host_cmd_ds_802_11_associate { + u8 peer_sta_addr[ETH_ALEN]; + __le16 cap_info_bitmap; + __le16 listen_interval; + __le16 beacon_period; + u8 dtim_period; +} __packed; + +struct ieee_types_assoc_rsp { + __le16 cap_info_bitmap; + __le16 status_code; + __le16 a_id; + u8 ie_buffer[1]; +} __packed; + +struct host_cmd_ds_802_11_associate_rsp { + struct ieee_types_assoc_rsp assoc_rsp; +} __packed; + +struct ieee_types_cf_param_set { + u8 element_id; + u8 len; + u8 cfp_cnt; + u8 cfp_period; + u16 cfp_max_duration; + u16 cfp_duration_remaining; +} __packed; + +struct ieee_types_ibss_param_set { + u8 element_id; + u8 len; + __le16 atim_window; +} __packed; + +union ieee_types_ss_param_set { + struct ieee_types_cf_param_set cf_param_set; + struct ieee_types_ibss_param_set ibss_param_set; +} __packed; + +struct ieee_types_fh_param_set { + u8 element_id; + u8 len; + __le16 dwell_time; + u8 hop_set; + u8 hop_pattern; + u8 hop_index; +} __packed; + +struct ieee_types_ds_param_set { + u8 element_id; + u8 len; + u8 current_chan; +} __packed; + +union ieee_types_phy_param_set { + struct ieee_types_fh_param_set fh_param_set; + struct ieee_types_ds_param_set ds_param_set; +} __packed; + +struct host_cmd_ds_802_11_ad_hoc_start { + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 bss_mode; + __le16 beacon_period; + u8 dtim_period; + union ieee_types_ss_param_set ss_param_set; + union ieee_types_phy_param_set phy_param_set; + u16 reserved1; + __le16 cap_info_bitmap; + u8 DataRate[HOSTCMD_SUPPORTED_RATES]; +} __packed; + +struct host_cmd_ds_802_11_ad_hoc_result { + u8 pad[3]; + u8 bssid[ETH_ALEN]; +} __packed; + +struct adhoc_bss_desc { + u8 bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 bss_mode; + __le16 beacon_period; + u8 dtim_period; + u8 time_stamp[8]; + u8 local_time[8]; + union ieee_types_phy_param_set phy_param_set; + union ieee_types_ss_param_set ss_param_set; + __le16 cap_info_bitmap; + u8 data_rates[HOSTCMD_SUPPORTED_RATES]; + + /* + * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. + * It is used in the Adhoc join command and will cause a + * binary layout mismatch with the firmware + */ +} __packed; + +struct host_cmd_ds_802_11_ad_hoc_join { + struct adhoc_bss_desc bss_descriptor; + u16 reserved1; + u16 reserved2; +} __packed; + +struct host_cmd_ds_802_11_get_log { + __le32 mcast_tx_frame; + __le32 failed; + __le32 retry; + __le32 multi_retry; + __le32 frame_dup; + __le32 rts_success; + __le32 rts_failure; + __le32 ack_failure; + __le32 rx_frag; + __le32 mcast_rx_frame; + __le32 fcs_error; + __le32 tx_frame; + __le32 reserved; + __le32 wep_icv_err_cnt[4]; +}; + +struct host_cmd_ds_tx_rate_query { + u8 tx_rate; + /* Ht Info [Bit 0] RxRate format: LG=0, HT=1 + * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 + * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */ + u8 ht_info; +} __packed; + +enum Host_Sleep_Action { + HS_CONFIGURE = 0x0001, + HS_ACTIVATE = 0x0002, +}; + +struct mwifiex_hs_config_param { + __le32 conditions; + u8 gpio; + u8 gap; +} __packed; + +struct hs_activate_param { + u16 resp_ctrl; +} __packed; + +struct host_cmd_ds_802_11_hs_cfg_enh { + __le16 action; + + union { + struct mwifiex_hs_config_param hs_config; + struct hs_activate_param hs_activate; + } params; +} __packed; + +enum SNMP_MIB_INDEX { + OP_RATE_SET_I = 1, + DTIM_PERIOD_I = 3, + RTS_THRESH_I = 5, + SHORT_RETRY_LIM_I = 6, + LONG_RETRY_LIM_I = 7, + FRAG_THRESH_I = 8, + DOT11D_I = 9, +}; + +#define MAX_SNMP_BUF_SIZE 128 + +struct host_cmd_ds_802_11_snmp_mib { + __le16 query_type; + __le16 oid; + __le16 buf_size; + u8 value[1]; +} __packed; + +struct mwifiex_rate_scope { + __le16 type; + __le16 length; + __le16 hr_dsss_rate_bitmap; + __le16 ofdm_rate_bitmap; + __le16 ht_mcs_rate_bitmap[8]; +} __packed; + +struct mwifiex_rate_drop_pattern { + __le16 type; + __le16 length; + __le32 rate_drop_mode; +} __packed; + +struct host_cmd_ds_tx_rate_cfg { + __le16 action; + __le16 cfg_index; +} __packed; + +struct mwifiex_power_group { + u8 modulation_class; + u8 first_rate_code; + u8 last_rate_code; + s8 power_step; + s8 power_min; + s8 power_max; + u8 ht_bandwidth; + u8 reserved; +} __packed; + +struct mwifiex_types_power_group { + u16 type; + u16 length; +} __packed; + +struct host_cmd_ds_txpwr_cfg { + __le16 action; + __le16 cfg_index; + __le32 mode; +} __packed; + +#define MWIFIEX_USER_SCAN_CHAN_MAX 50 + +#define MWIFIEX_MAX_SSID_LIST_LENGTH 10 + +struct mwifiex_scan_cmd_config { + /* + * BSS mode to be sent in the firmware command + */ + u8 bss_mode; + + /* Specific BSSID used to filter scan results in the firmware */ + u8 specific_bssid[ETH_ALEN]; + + /* Length of TLVs sent in command starting at tlvBuffer */ + u32 tlv_buf_len; + + /* + * SSID TLV(s) and ChanList TLVs to be sent in the firmware command + * + * TLV_TYPE_CHANLIST, mwifiex_ie_types_chan_list_param_set + * WLAN_EID_SSID, mwifiex_ie_types_ssid_param_set + */ + u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored + here */ +} __packed; + +struct mwifiex_user_scan_chan { + u8 chan_number; + u8 radio_type; + u8 scan_type; + u8 reserved; + u32 scan_time; +} __packed; + +struct mwifiex_user_scan_ssid { + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; + u8 max_len; +} __packed; + +struct mwifiex_user_scan_cfg { + /* + * Flag set to keep the previous scan table intact + * + * If set, the scan results will accumulate, replacing any previous + * matched entries for a BSS with the new scan data + */ + u8 keep_previous_scan; + /* + * BSS mode to be sent in the firmware command + */ + u8 bss_mode; + /* Configure the number of probe requests for active chan scans */ + u8 num_probes; + u8 reserved; + /* BSSID filter sent in the firmware command to limit the results */ + u8 specific_bssid[ETH_ALEN]; + /* SSID filter list used in the to limit the scan results */ + struct mwifiex_user_scan_ssid ssid_list[MWIFIEX_MAX_SSID_LIST_LENGTH]; + /* Variable number (fixed maximum) of channels to scan up */ + struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX]; +} __packed; + +struct ie_body { + u8 grp_key_oui[4]; + u8 ptk_cnt[2]; + u8 ptk_body[4]; +} __packed; + +struct host_cmd_ds_802_11_scan { + u8 bss_mode; + u8 bssid[ETH_ALEN]; + u8 tlv_buffer[1]; +} __packed; + +struct host_cmd_ds_802_11_scan_rsp { + __le16 bss_descript_size; + u8 number_of_sets; + u8 bss_desc_and_tlv_buffer[1]; +} __packed; + +struct host_cmd_ds_802_11_bg_scan_query { + u8 flush; +} __packed; + +struct host_cmd_ds_802_11_bg_scan_query_rsp { + u32 report_condition; + struct host_cmd_ds_802_11_scan_rsp scan_resp; +} __packed; + +struct mwifiex_ietypes_domain_param_set { + struct mwifiex_ie_types_header header; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + struct ieee80211_country_ie_triplet triplet[1]; +} __packed; + +struct host_cmd_ds_802_11d_domain_info { + __le16 action; + struct mwifiex_ietypes_domain_param_set domain; +} __packed; + +struct host_cmd_ds_802_11d_domain_info_rsp { + __le16 action; + struct mwifiex_ietypes_domain_param_set domain; +} __packed; + +struct host_cmd_ds_11n_addba_req { + u8 add_req_result; + u8 peer_mac_addr[ETH_ALEN]; + u8 dialog_token; + __le16 block_ack_param_set; + __le16 block_ack_tmo; + __le16 ssn; +} __packed; + +struct host_cmd_ds_11n_addba_rsp { + u8 add_rsp_result; + u8 peer_mac_addr[ETH_ALEN]; + u8 dialog_token; + __le16 status_code; + __le16 block_ack_param_set; + __le16 block_ack_tmo; + __le16 ssn; +} __packed; + +struct host_cmd_ds_11n_delba { + u8 del_result; + u8 peer_mac_addr[ETH_ALEN]; + __le16 del_ba_param_set; + __le16 reason_code; + u8 reserved; +} __packed; + +struct host_cmd_ds_11n_batimeout { + u8 tid; + u8 peer_mac_addr[ETH_ALEN]; + u8 origninator; +} __packed; + +struct host_cmd_ds_11n_cfg { + __le16 action; + __le16 ht_tx_cap; + __le16 ht_tx_info; +} __packed; + +struct host_cmd_ds_txbuf_cfg { + __le16 action; + __le16 buff_size; + __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ + __le16 reserved3; +} __packed; + +struct host_cmd_ds_amsdu_aggr_ctrl { + __le16 action; + __le16 enable; + __le16 curr_buf_size; +} __packed; + +struct mwifiex_ie_types_wmm_param_set { + struct mwifiex_ie_types_header header; + u8 wmm_ie[1]; +}; + +struct mwifiex_ie_types_wmm_queue_status { + struct mwifiex_ie_types_header header; + u8 queue_index; + u8 disabled; + u16 medium_time; + u8 flow_required; + u8 flow_created; + u32 reserved; +}; + +struct ieee_types_vendor_header { + u8 element_id; + u8 len; + u8 oui[3]; + u8 oui_type; + u8 oui_subtype; + u8 version; +} __packed; + +struct ieee_types_wmm_ac_parameters { + u8 aci_aifsn_bitmap; + u8 ecw_bitmap; + __le16 tx_op_limit; +} __packed; + +struct ieee_types_wmm_parameter { + /* + * WMM Parameter IE - Vendor Specific Header: + * element_id [221/0xdd] + * Len [24] + * Oui [00:50:f2] + * OuiType [2] + * OuiSubType [1] + * Version [1] + */ + struct ieee_types_vendor_header vend_hdr; + u8 qos_info_bitmap; + u8 reserved; + struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_MAX_QUEUES]; +} __packed; + +struct ieee_types_wmm_info { + + /* + * WMM Info IE - Vendor Specific Header: + * element_id [221/0xdd] + * Len [7] + * Oui [00:50:f2] + * OuiType [2] + * OuiSubType [0] + * Version [1] + */ + struct ieee_types_vendor_header vend_hdr; + + u8 qos_info_bitmap; +} __packed; + +struct host_cmd_ds_wmm_get_status { + u8 queue_status_tlv[sizeof(struct mwifiex_ie_types_wmm_queue_status) * + IEEE80211_MAX_QUEUES]; + u8 wmm_param_tlv[sizeof(struct ieee_types_wmm_parameter) + 2]; +} __packed; + +struct mwifiex_wmm_ac_status { + u8 disabled; + u8 flow_required; + u8 flow_created; +}; + +struct mwifiex_ie_types_htcap { + struct mwifiex_ie_types_header header; + struct ieee80211_ht_cap ht_cap; +} __packed; + +struct mwifiex_ie_types_htinfo { + struct mwifiex_ie_types_header header; + struct ieee80211_ht_info ht_info; +} __packed; + +struct mwifiex_ie_types_2040bssco { + struct mwifiex_ie_types_header header; + u8 bss_co_2040; +} __packed; + +struct mwifiex_ie_types_extcap { + struct mwifiex_ie_types_header header; + u8 ext_cap; +} __packed; + +struct host_cmd_ds_mac_reg_access { + __le16 action; + __le16 offset; + __le32 value; +} __packed; + +struct host_cmd_ds_bbp_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __packed; + +struct host_cmd_ds_rf_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __packed; + +struct host_cmd_ds_pmic_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __packed; + +struct host_cmd_ds_802_11_eeprom_access { + __le16 action; + + __le16 offset; + __le16 byte_count; + u8 value; +} __packed; + +struct host_cmd_ds_802_11_rf_channel { + __le16 action; + __le16 current_channel; + __le16 rf_type; + __le16 reserved; + u8 reserved_1[32]; +} __packed; + +struct host_cmd_ds_version_ext { + u8 version_str_sel; + char version_str[128]; +} __packed; + +struct host_cmd_ds_802_11_ibss_status { + __le16 action; + __le16 enable; + u8 bssid[ETH_ALEN]; + __le16 beacon_interval; + __le16 atim_window; + __le16 use_g_rate_protect; +} __packed; + +#define CONNECTION_TYPE_INFRA 0 +#define CONNECTION_TYPE_ADHOC 1 + +struct host_cmd_ds_set_bss_mode { + u8 con_type; +} __packed; + +struct host_cmd_ds_command { + __le16 command; + __le16 size; + __le16 seq_num; + __le16 result; + union { + struct host_cmd_ds_get_hw_spec hw_spec; + struct host_cmd_ds_mac_control mac_ctrl; + struct host_cmd_ds_802_11_mac_address mac_addr; + struct host_cmd_ds_mac_multicast_adr mc_addr; + struct host_cmd_ds_802_11_get_log get_log; + struct host_cmd_ds_802_11_rssi_info rssi_info; + struct host_cmd_ds_802_11_rssi_info_rsp rssi_info_rsp; + struct host_cmd_ds_802_11_snmp_mib smib; + struct host_cmd_ds_802_11_rf_channel rf_channel; + struct host_cmd_ds_tx_rate_query tx_rate; + struct host_cmd_ds_tx_rate_cfg tx_rate_cfg; + struct host_cmd_ds_txpwr_cfg txp_cfg; + struct host_cmd_ds_802_11_ps_mode_enh psmode_enh; + struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg; + struct host_cmd_ds_802_11_scan scan; + struct host_cmd_ds_802_11_scan_rsp scan_resp; + struct host_cmd_ds_802_11_bg_scan_query bg_scan_query; + struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp; + struct host_cmd_ds_802_11_associate associate; + struct host_cmd_ds_802_11_associate_rsp associate_rsp; + struct host_cmd_ds_802_11_deauthenticate deauth; + struct host_cmd_ds_802_11_ad_hoc_start adhoc_start; + struct host_cmd_ds_802_11_ad_hoc_result adhoc_result; + struct host_cmd_ds_802_11_ad_hoc_join adhoc_join; + struct host_cmd_ds_802_11d_domain_info domain_info; + struct host_cmd_ds_802_11d_domain_info_rsp domain_info_resp; + struct host_cmd_ds_11n_addba_req add_ba_req; + struct host_cmd_ds_11n_addba_rsp add_ba_rsp; + struct host_cmd_ds_11n_delba del_ba; + struct host_cmd_ds_txbuf_cfg tx_buf; + struct host_cmd_ds_amsdu_aggr_ctrl amsdu_aggr_ctrl; + struct host_cmd_ds_11n_cfg htcfg; + struct host_cmd_ds_wmm_get_status get_wmm_status; + struct host_cmd_ds_802_11_key_material key_material; + struct host_cmd_ds_version_ext verext; + struct host_cmd_ds_802_11_ibss_status ibss_coalescing; + struct host_cmd_ds_mac_reg_access mac_reg; + struct host_cmd_ds_bbp_reg_access bbp_reg; + struct host_cmd_ds_rf_reg_access rf_reg; + struct host_cmd_ds_pmic_reg_access pmic_reg; + struct host_cmd_ds_set_bss_mode bss_mode; + struct host_cmd_ds_802_11_eeprom_access eeprom; + } params; +} __packed; + +struct mwifiex_opt_sleep_confirm { + __le16 command; + __le16 size; + __le16 seq_num; + __le16 result; + __le16 action; + __le16 resp_ctrl; +} __packed; +#endif /* !_MWIFIEX_FW_H_ */ diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c new file mode 100644 index 000000000000..3f1559e61320 --- /dev/null +++ b/drivers/net/wireless/mwifiex/init.c @@ -0,0 +1,645 @@ +/* + * Marvell Wireless LAN device driver: HW/FW Initialization + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * This function adds a BSS priority table to the table list. + * + * The function allocates a new BSS priority table node and adds it to + * the end of BSS priority table list, kept in driver memory. + */ +static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bss_prio_node *bss_prio; + unsigned long flags; + + bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL); + if (!bss_prio) { + dev_err(adapter->dev, "%s: failed to alloc bss_prio\n", + __func__); + return -ENOMEM; + } + + bss_prio->priv = priv; + INIT_LIST_HEAD(&bss_prio->list); + if (!adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur) + adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = + bss_prio; + + spin_lock_irqsave(&adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_lock, flags); + list_add_tail(&bss_prio->list, + &adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_head); + spin_unlock_irqrestore(&adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_lock, flags); + + return 0; +} + +/* + * This function initializes the private structure and sets default + * values to the members. + * + * Additionally, it also initializes all the locks and sets up all the + * lists. + */ +static int mwifiex_init_priv(struct mwifiex_private *priv) +{ + u32 i; + + priv->media_connected = false; + memset(priv->curr_addr, 0xff, ETH_ALEN); + + priv->pkt_tx_ctrl = 0; + priv->bss_mode = NL80211_IFTYPE_STATION; + priv->data_rate = 0; /* Initially indicate the rate as auto */ + priv->is_data_rate_auto = true; + priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; + priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; + + priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; + priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; + priv->sec_info.encryption_mode = 0; + for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++) + memset(&priv->wep_key[i], 0, sizeof(struct mwifiex_wep_key)); + priv->wep_key_curr_index = 0; + priv->curr_pkt_filter = HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON | + HostCmd_ACT_MAC_ETHERNETII_ENABLE; + + priv->beacon_period = 100; /* beacon interval */ ; + priv->attempted_bss_desc = NULL; + memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params)); + priv->listen_interval = MWIFIEX_DEFAULT_LISTEN_INTERVAL; + + memset(&priv->prev_ssid, 0, sizeof(priv->prev_ssid)); + memset(&priv->prev_bssid, 0, sizeof(priv->prev_bssid)); + memset(&priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf)); + priv->assoc_rsp_size = 0; + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + priv->atim_window = 0; + priv->adhoc_state = ADHOC_IDLE; + priv->tx_power_level = 0; + priv->max_tx_power_level = 0; + priv->min_tx_power_level = 0; + priv->tx_rate = 0; + priv->rxpd_htinfo = 0; + priv->rxpd_rate = 0; + priv->rate_bitmap = 0; + priv->data_rssi_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->data_nf_last = 0; + priv->bcn_rssi_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + priv->bcn_nf_last = 0; + memset(&priv->wpa_ie, 0, sizeof(priv->wpa_ie)); + memset(&priv->aes_key, 0, sizeof(priv->aes_key)); + priv->wpa_ie_len = 0; + priv->wpa_is_gtk_set = false; + + memset(&priv->assoc_tlv_buf, 0, sizeof(priv->assoc_tlv_buf)); + priv->assoc_tlv_buf_len = 0; + memset(&priv->wps, 0, sizeof(priv->wps)); + memset(&priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf)); + priv->gen_ie_buf_len = 0; + memset(priv->vs_ie, 0, sizeof(priv->vs_ie)); + + priv->wmm_required = true; + priv->wmm_enabled = false; + priv->wmm_qosinfo = 0; + priv->curr_bcn_buf = NULL; + priv->curr_bcn_size = 0; + + priv->scan_block = false; + + return mwifiex_add_bss_prio_tbl(priv); +} + +/* + * This function allocates buffers for members of the adapter + * structure. + * + * The memory allocated includes scan table, command buffers, and + * sleep confirm command buffer. In addition, the queues are + * also initialized. + */ +static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) +{ + int ret; + u32 buf_size; + struct mwifiex_bssdescriptor *temp_scan_table; + + /* Allocate buffer to store the BSSID list */ + buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP; + temp_scan_table = kzalloc(buf_size, GFP_KERNEL); + if (!temp_scan_table) { + dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n", + __func__); + return -ENOMEM; + } + + adapter->scan_table = temp_scan_table; + + /* Allocate command buffer */ + ret = mwifiex_alloc_cmd_buffer(adapter); + if (ret) { + dev_err(adapter->dev, "%s: failed to alloc cmd buffer\n", + __func__); + return -1; + } + + adapter->sleep_cfm = + dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm) + + INTF_HEADER_LEN); + + if (!adapter->sleep_cfm) { + dev_err(adapter->dev, "%s: failed to alloc sleep cfm" + " cmd buffer\n", __func__); + return -1; + } + skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN); + + return 0; +} + +/* + * This function initializes the adapter structure and sets default + * values to the members of adapter. + * + * This also initializes the WMM related parameters in the driver private + * structures. + */ +static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) +{ + struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = NULL; + + skb_put(adapter->sleep_cfm, sizeof(struct mwifiex_opt_sleep_confirm)); + sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *) + (adapter->sleep_cfm->data); + + adapter->cmd_sent = false; + adapter->data_sent = true; + adapter->cmd_resp_received = false; + adapter->event_received = false; + adapter->data_received = false; + + adapter->surprise_removed = false; + + adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; + + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + adapter->ps_state = PS_STATE_AWAKE; + adapter->need_to_wakeup = false; + + adapter->scan_mode = HostCmd_BSS_MODE_ANY; + adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME; + adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME; + adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME; + + adapter->num_in_scan_table = 0; + memset(adapter->scan_table, 0, + (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP)); + adapter->scan_probes = 1; + + memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf)); + adapter->bcn_buf_end = adapter->bcn_buf; + + adapter->multiple_dtim = 1; + + adapter->local_listen_interval = 0; /* default value in firmware + will be used */ + + adapter->is_deep_sleep = false; + + adapter->delay_null_pkt = false; + adapter->delay_to_ps = 1000; + adapter->enhanced_ps_mode = PS_MODE_AUTO; + + adapter->gen_null_pkt = false; /* Disable NULL Pkg generation by + default */ + adapter->pps_uapsd_mode = false; /* Disable pps/uapsd mode by + default */ + adapter->pm_wakeup_card_req = false; + + adapter->pm_wakeup_fw_try = false; + + adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + + adapter->is_hs_configured = false; + adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF); + adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF; + adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF; + adapter->hs_activated = false; + + memset(adapter->event_body, 0, sizeof(adapter->event_body)); + adapter->hw_dot_11n_dev_cap = 0; + adapter->hw_dev_mcs_support = 0; + adapter->chan_offset = 0; + adapter->adhoc_11n_enabled = false; + + mwifiex_wmm_init(adapter); + + if (adapter->sleep_cfm) { + memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len); + sleep_cfm_buf->command = + cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); + sleep_cfm_buf->size = + cpu_to_le16(adapter->sleep_cfm->len); + sleep_cfm_buf->result = 0; + sleep_cfm_buf->action = cpu_to_le16(SLEEP_CONFIRM); + sleep_cfm_buf->resp_ctrl = cpu_to_le16(RESP_NEEDED); + } + memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params)); + memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period)); + adapter->tx_lock_flag = false; + adapter->null_pkt_interval = 0; + adapter->fw_bands = 0; + adapter->config_bands = 0; + adapter->adhoc_start_band = 0; + adapter->scan_channels = NULL; + adapter->fw_release_number = 0; + adapter->fw_cap_info = 0; + memset(&adapter->upld_buf, 0, sizeof(adapter->upld_buf)); + adapter->event_cause = 0; + adapter->region_code = 0; + adapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT; + adapter->adhoc_awake_period = 0; + memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); + adapter->arp_filter_size = 0; +} + +/* + * This function frees the adapter structure. + * + * The freeing operation is done recursively, by canceling all + * pending commands, freeing the member buffers previously + * allocated (command buffers, scan table buffer, sleep confirm + * command buffer), stopping the timers and calling the cleanup + * routines for every interface, before the actual adapter + * structure is freed. + */ +static void +mwifiex_free_adapter(struct mwifiex_adapter *adapter) +{ + if (!adapter) { + pr_err("%s: adapter is NULL\n", __func__); + return; + } + + mwifiex_cancel_all_pending_cmd(adapter); + + /* Free lock variables */ + mwifiex_free_lock_list(adapter); + + /* Free command buffer */ + dev_dbg(adapter->dev, "info: free cmd buffer\n"); + mwifiex_free_cmd_buffer(adapter); + + del_timer(&adapter->cmd_timer); + + dev_dbg(adapter->dev, "info: free scan table\n"); + kfree(adapter->scan_table); + adapter->scan_table = NULL; + + adapter->if_ops.cleanup_if(adapter); + + dev_kfree_skb_any(adapter->sleep_cfm); +} + +/* + * This function intializes the lock variables and + * the list heads. + */ +int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv; + s32 i, j; + + spin_lock_init(&adapter->mwifiex_lock); + spin_lock_init(&adapter->int_lock); + spin_lock_init(&adapter->main_proc_lock); + spin_lock_init(&adapter->mwifiex_cmd_lock); + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + spin_lock_init(&priv->rx_pkt_lock); + spin_lock_init(&priv->wmm.ra_list_spinlock); + spin_lock_init(&priv->curr_bcn_buf_lock); + } + } + + /* Initialize cmd_free_q */ + INIT_LIST_HEAD(&adapter->cmd_free_q); + /* Initialize cmd_pending_q */ + INIT_LIST_HEAD(&adapter->cmd_pending_q); + /* Initialize scan_pending_q */ + INIT_LIST_HEAD(&adapter->scan_pending_q); + + spin_lock_init(&adapter->cmd_free_q_lock); + spin_lock_init(&adapter->cmd_pending_q_lock); + spin_lock_init(&adapter->scan_pending_q_lock); + + 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; + spin_lock_init(&adapter->bss_prio_tbl[i].bss_prio_lock); + } + + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i]) + continue; + priv = adapter->priv[i]; + for (j = 0; j < MAX_NUM_TID; ++j) { + INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list); + spin_lock_init(&priv->wmm.tid_tbl_ptr[j].tid_tbl_lock); + } + INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); + INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); + + spin_lock_init(&priv->tx_ba_stream_tbl_lock); + spin_lock_init(&priv->rx_reorder_tbl_lock); + } + + return 0; +} + +/* + * This function releases the lock variables and frees the locks and + * associated locks. + */ +void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv; + s32 i, j; + + /* Free lists */ + list_del(&adapter->cmd_free_q); + list_del(&adapter->cmd_pending_q); + list_del(&adapter->scan_pending_q); + + for (i = 0; i < adapter->priv_num; i++) + list_del(&adapter->bss_prio_tbl[i].bss_prio_head); + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + for (j = 0; j < MAX_NUM_TID; ++j) + list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); + list_del(&priv->tx_ba_stream_tbl_ptr); + list_del(&priv->rx_reorder_tbl_ptr); + } + } +} + +/* + * This function initializes the firmware. + * + * The following operations are performed sequentially - + * - Allocate adapter structure + * - Initialize the adapter structure + * - Initialize the private structure + * - Add BSS priority tables to the adapter structure + * - For each interface, send the init commands to firmware + * - Send the first command in command pending queue, if available + */ +int mwifiex_init_fw(struct mwifiex_adapter *adapter) +{ + int ret; + struct mwifiex_private *priv; + u8 i, first_sta = true; + int is_cmd_pend_q_empty; + unsigned long flags; + + adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; + + /* Allocate memory for member of adapter structure */ + ret = mwifiex_allocate_adapter(adapter); + if (ret) + return -1; + + /* Initialize adapter structure */ + mwifiex_init_adapter(adapter); + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + + /* Initialize private structure */ + ret = mwifiex_init_priv(priv); + if (ret) + return -1; + } + } + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta); + if (ret == -1) + return -1; + + first_sta = false; + } + } + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + if (!is_cmd_pend_q_empty) { + /* Send the first command in queue and return */ + if (mwifiex_main_process(adapter) != -1) + ret = -EINPROGRESS; + } else { + adapter->hw_status = MWIFIEX_HW_STATUS_READY; + } + + return ret; +} + +/* + * This function deletes the BSS priority tables. + * + * The function traverses through all the allocated BSS priority nodes + * in every BSS priority table and frees them. + */ +static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv) +{ + int i; + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bss_prio_node *bssprio_node, *tmp_node, **cur; + struct list_head *head; + spinlock_t *lock; + unsigned long flags; + + for (i = 0; i < adapter->priv_num; ++i) { + head = &adapter->bss_prio_tbl[i].bss_prio_head; + cur = &adapter->bss_prio_tbl[i].bss_prio_cur; + lock = &adapter->bss_prio_tbl[i].bss_prio_lock; + dev_dbg(adapter->dev, "info: delete BSS priority table," + " index = %d, i = %d, head = %p, cur = %p\n", + priv->bss_index, i, head, *cur); + if (*cur) { + spin_lock_irqsave(lock, flags); + if (list_empty(head)) { + spin_unlock_irqrestore(lock, flags); + continue; + } + bssprio_node = list_first_entry(head, + struct mwifiex_bss_prio_node, list); + spin_unlock_irqrestore(lock, flags); + + list_for_each_entry_safe(bssprio_node, tmp_node, head, + list) { + if (bssprio_node->priv == priv) { + dev_dbg(adapter->dev, "info: Delete " + "node %p, next = %p\n", + bssprio_node, tmp_node); + spin_lock_irqsave(lock, flags); + list_del(&bssprio_node->list); + spin_unlock_irqrestore(lock, flags); + kfree(bssprio_node); + } + } + *cur = (struct mwifiex_bss_prio_node *)head; + } + } +} + +/* + * This function is used to shutdown the driver. + * + * The following operations are performed sequentially - + * - Check if already shut down + * - Make sure the main process has stopped + * - Clean up the Tx and Rx queues + * - Delete BSS priority tables + * - Free the adapter + * - Notify completion + */ +int +mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) +{ + int ret = -EINPROGRESS; + struct mwifiex_private *priv; + s32 i; + unsigned long flags; + + /* mwifiex already shutdown */ + if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) + return 0; + + adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING; + /* wait for mwifiex_process to complete */ + if (adapter->mwifiex_processing) { + dev_warn(adapter->dev, "main process is still running\n"); + return ret; + } + + /* shut down mwifiex */ + dev_dbg(adapter->dev, "info: shutdown mwifiex...\n"); + + /* Clean up Tx/Rx queues and delete BSS priority table */ + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + + mwifiex_clean_txrx(priv); + mwifiex_delete_bss_prio_tbl(priv); + } + } + + spin_lock_irqsave(&adapter->mwifiex_lock, flags); + + /* Free adapter structure */ + mwifiex_free_adapter(adapter); + + spin_unlock_irqrestore(&adapter->mwifiex_lock, flags); + + /* Notify completion */ + ret = mwifiex_shutdown_fw_complete(adapter); + + return ret; +} + +/* + * This function downloads the firmware to the card. + * + * The actual download is preceded by two sanity checks - + * - Check if firmware is already running + * - Check if the interface is the winner to download the firmware + * + * ...and followed by another - + * - Check if the firmware is downloaded successfully + * + * After download is successfully completed, the host interrupts are enabled. + */ +int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, + struct mwifiex_fw_image *pmfw) +{ + int ret, winner; + u32 poll_num = 1; + + /* Check if firmware is already running */ + ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner); + 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 (!winner) { + dev_notice(adapter->dev, + "Other interface already running!" + " Skip FW download\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); + if (ret) { + dev_err(adapter->dev, "prog_fw failed ret=%#x\n", ret); + return ret; + } + } + +poll_fw: + /* Check if the firmware is downloaded successfully or not */ + ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL); + if (ret) { + dev_err(adapter->dev, "FW failed to be active in time\n"); + return -1; + } +done: + /* re-enable host interrupt for mwifiex after fw dnld is successful */ + adapter->if_ops.enable_int(adapter); + return ret; +} diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h new file mode 100644 index 000000000000..7c1c5ee40eb9 --- /dev/null +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -0,0 +1,331 @@ +/* + * Marvell Wireless LAN device driver: ioctl data structures & APIs + * + * Copyright (C) 2011, 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_IOCTL_H_ +#define _MWIFIEX_IOCTL_H_ + +#include + +enum { + MWIFIEX_SCAN_TYPE_UNCHANGED = 0, + MWIFIEX_SCAN_TYPE_ACTIVE, + MWIFIEX_SCAN_TYPE_PASSIVE +}; + +struct mwifiex_user_scan { + u32 scan_cfg_len; + u8 scan_cfg_buf[1]; +}; + +#define MWIFIEX_PROMISC_MODE 1 +#define MWIFIEX_MULTICAST_MODE 2 +#define MWIFIEX_ALL_MULTI_MODE 4 +#define MWIFIEX_MAX_MULTICAST_LIST_SIZE 32 + +struct mwifiex_multicast_list { + u32 mode; + u32 num_multicast_addr; + u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; +}; + +struct mwifiex_chan_freq { + u32 channel; + u32 freq; +}; + +struct mwifiex_ssid_bssid { + struct mwifiex_802_11_ssid ssid; + u8 bssid[ETH_ALEN]; +}; + +enum { + BAND_B = 1, + BAND_G = 2, + BAND_A = 4, + BAND_GN = 8, + BAND_AN = 16, +}; + +#define NO_SEC_CHANNEL 0 +#define SEC_CHANNEL_ABOVE 1 +#define SEC_CHANNEL_BELOW 3 + +struct mwifiex_ds_band_cfg { + u32 config_bands; + u32 adhoc_start_band; + u32 adhoc_channel; + u32 sec_chan_offset; +}; + +enum { + ADHOC_IDLE, + ADHOC_STARTED, + ADHOC_JOINED, + ADHOC_COALESCED +}; + +struct mwifiex_ds_get_stats { + u32 mcast_tx_frame; + u32 failed; + u32 retry; + u32 multi_retry; + u32 frame_dup; + u32 rts_success; + u32 rts_failure; + u32 ack_failure; + u32 rx_frag; + u32 mcast_rx_frame; + u32 fcs_error; + u32 tx_frame; + 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 { + u32 version_str_sel; + char version_str[MWIFIEX_MAX_VER_STR_LEN]; +}; + +struct mwifiex_bss_info { + u32 bss_mode; + struct mwifiex_802_11_ssid ssid; + u32 scan_table_idx; + u32 bss_chan; + u32 region_code; + u32 media_connected; + u32 max_power_level; + u32 min_power_level; + u32 adhoc_state; + signed int bcn_nf_last; + u32 wep_status; + u32 is_hs_configured; + u32 is_deep_sleep; + u8 bssid[ETH_ALEN]; +}; + +#define MAX_NUM_TID 8 + +#define MAX_RX_WINSIZE 64 + +struct mwifiex_ds_rx_reorder_tbl { + u16 tid; + u8 ta[ETH_ALEN]; + u32 start_win; + u32 win_size; + u32 buffer[MAX_RX_WINSIZE]; +}; + +struct mwifiex_ds_tx_ba_stream_tbl { + u16 tid; + u8 ra[ETH_ALEN]; +}; + +#define DBG_CMD_NUM 5 + +struct mwifiex_debug_info { + u32 int_counter; + u32 packets_out[MAX_NUM_TID]; + u32 max_tx_buf_size; + u32 tx_buf_size; + u32 curr_tx_buf_size; + u32 tx_tbl_num; + struct mwifiex_ds_tx_ba_stream_tbl + tx_tbl[MWIFIEX_MAX_TX_BASTREAM_SUPPORTED]; + u32 rx_tbl_num; + struct mwifiex_ds_rx_reorder_tbl rx_tbl + [MWIFIEX_MAX_RX_BASTREAM_SUPPORTED]; + u16 ps_mode; + u32 ps_state; + u8 is_deep_sleep; + u8 pm_wakeup_card_req; + u32 pm_wakeup_fw_try; + u8 is_hs_configured; + u8 hs_activated; + u32 num_cmd_host_to_card_failure; + u32 num_cmd_sleep_cfm_host_to_card_failure; + u32 num_tx_host_to_card_failure; + u32 num_event_deauth; + u32 num_event_disassoc; + u32 num_event_link_lost; + u32 num_cmd_deauth; + u32 num_cmd_assoc_success; + u32 num_cmd_assoc_failure; + u32 num_tx_timeout; + u32 num_cmd_timeout; + u16 timeout_cmd_id; + u16 timeout_cmd_act; + u16 last_cmd_id[DBG_CMD_NUM]; + u16 last_cmd_act[DBG_CMD_NUM]; + u16 last_cmd_index; + u16 last_cmd_resp_id[DBG_CMD_NUM]; + u16 last_cmd_resp_index; + u16 last_event[DBG_CMD_NUM]; + u16 last_event_index; + u8 data_sent; + u8 cmd_sent; + u8 cmd_resp_received; + u8 event_received; +}; + +#define MWIFIEX_KEY_INDEX_UNICAST 0x40000000 +#define WAPI_RXPN_LEN 16 + +struct mwifiex_ds_encrypt_key { + u32 key_disable; + u32 key_index; + u32 key_len; + u8 key_material[WLAN_MAX_KEY_LEN]; + u8 mac_addr[ETH_ALEN]; + u32 is_wapi_key; + u8 wapi_rxpn[WAPI_RXPN_LEN]; +}; + +struct mwifiex_rate_cfg { + u32 action; + u32 is_rate_auto; + u32 rate; +}; + +struct mwifiex_power_cfg { + u32 is_power_auto; + u32 power_level; +}; + +struct mwifiex_ds_hs_cfg { + u32 is_invoke_hostcmd; + /* Bit0: non-unicast data + * Bit1: unicast data + * Bit2: mac events + * Bit3: magic packet + */ + u32 conditions; + u32 gpio; + u32 gap; +}; + +#define DEEP_SLEEP_ON 1 +#define DEEP_SLEEP_IDLE_TIME 100 +#define PS_MODE_AUTO 1 + +struct mwifiex_ds_auto_ds { + u16 auto_ds; + u16 idle_time; +}; + +struct mwifiex_ds_pm_cfg { + union { + u32 ps_mode; + struct mwifiex_ds_hs_cfg hs_cfg; + struct mwifiex_ds_auto_ds auto_deep_sleep; + u32 sleep_period; + } param; +}; + +struct mwifiex_ds_11n_tx_cfg { + u16 tx_htcap; + u16 tx_htinfo; +}; + +struct mwifiex_ds_11n_amsdu_aggr_ctrl { + u16 enable; + u16 curr_buf_size; +}; + +#define MWIFIEX_NUM_OF_CMD_BUFFER 20 +#define MWIFIEX_SIZE_OF_CMD_BUFFER 2048 + +enum { + MWIFIEX_IE_TYPE_GEN_IE = 0, + MWIFIEX_IE_TYPE_ARP_FILTER, +}; + +enum { + MWIFIEX_REG_MAC = 1, + MWIFIEX_REG_BBP, + MWIFIEX_REG_RF, + MWIFIEX_REG_PMIC, + MWIFIEX_REG_CAU, +}; + +struct mwifiex_ds_reg_rw { + __le32 type; + __le32 offset; + __le32 value; +}; + +#define MAX_EEPROM_DATA 256 + +struct mwifiex_ds_read_eeprom { + __le16 offset; + __le16 byte_count; + u8 value[MAX_EEPROM_DATA]; +}; + +struct mwifiex_ds_misc_gen_ie { + u32 type; + u32 len; + u8 ie_data[IW_CUSTOM_MAX]; +}; + +struct mwifiex_ds_misc_cmd { + u32 len; + u8 cmd[MWIFIEX_SIZE_OF_CMD_BUFFER]; +}; + +#define MWIFIEX_MAX_VSIE_LEN (256) +#define MWIFIEX_MAX_VSIE_NUM (8) +#define MWIFIEX_VSIE_MASK_SCAN 0x01 +#define MWIFIEX_VSIE_MASK_ASSOC 0x02 +#define MWIFIEX_VSIE_MASK_ADHOC 0x04 + +enum { + MWIFIEX_FUNC_INIT = 1, + MWIFIEX_FUNC_SHUTDOWN, +}; + +#endif /* !_MWIFIEX_IOCTL_H_ */ diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c new file mode 100644 index 000000000000..5eab3dc29b1c --- /dev/null +++ b/drivers/net/wireless/mwifiex/join.c @@ -0,0 +1,1423 @@ +/* + * Marvell Wireless LAN device driver: association and ad-hoc start/join + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +#define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9))) + +/* + * Append a generic IE as a pass through TLV to a TLV buffer. + * + * This function 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 pass through TLV type to the request. + */ +static int +mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer) +{ + int ret_len = 0; + struct mwifiex_ie_types_header ie_header; + + /* Null Checks */ + if (!buffer) + return 0; + if (!(*buffer)) + return 0; + + /* + * If there is a generic ie buffer setup, append it to the return + * parameter buffer pointer. + */ + if (priv->gen_ie_buf_len) { + dev_dbg(priv->adapter->dev, "info: %s: append generic %d to %p\n", + __func__, priv->gen_ie_buf_len, *buffer); + + /* Wrap the generic IE buffer with a pass through TLV type */ + ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); + ie_header.len = cpu_to_le16(priv->gen_ie_buf_len); + memcpy(*buffer, &ie_header, sizeof(ie_header)); + + /* Increment the return size and the return buffer pointer + param */ + *buffer += sizeof(ie_header); + ret_len += sizeof(ie_header); + + /* Copy the generic IE buffer to the output buffer, advance + pointer */ + memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len); + + /* Increment the return size and the return buffer pointer + param */ + *buffer += priv->gen_ie_buf_len; + ret_len += priv->gen_ie_buf_len; + + /* Reset the generic IE buffer */ + priv->gen_ie_buf_len = 0; + } + + /* return the length appended to the buffer */ + return ret_len; +} + +/* + * Append TSF tracking info from the scan table for the target AP. + * + * This function is called from the network join command preparation routine. + * + * The TSF table TSF sent to the firmware contains two TSF values: + * - The TSF of the target AP from its previous beacon/probe response + * - The TSF timestamp of our local MAC at the time we observed the + * beacon/probe response. + * + * The firmware uses the timestamp values to set an initial TSF value + * in the MAC for the new association after a reassociation attempt. + */ +static int +mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, + struct mwifiex_bssdescriptor *bss_desc) +{ + struct mwifiex_ie_types_tsf_timestamp tsf_tlv; + __le64 tsf_val; + + /* Null Checks */ + if (buffer == NULL) + return 0; + if (*buffer == NULL) + return 0; + + memset(&tsf_tlv, 0x00, sizeof(struct mwifiex_ie_types_tsf_timestamp)); + + tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP); + tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val)); + + memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header)); + *buffer += sizeof(tsf_tlv.header); + + /* TSF at the time when beacon/probe_response was received */ + tsf_val = cpu_to_le64(bss_desc->network_tsf); + memcpy(*buffer, &tsf_val, sizeof(tsf_val)); + *buffer += sizeof(tsf_val); + + memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val)); + + dev_dbg(priv->adapter->dev, "info: %s: TSF offset calc: %016llx - " + "%016llx\n", __func__, tsf_val, bss_desc->network_tsf); + + memcpy(*buffer, &tsf_val, sizeof(tsf_val)); + *buffer += sizeof(tsf_val); + + return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val)); +} + +/* + * This function finds out the common rates between rate1 and rate2. + * + * It will fill common rates in rate1 as output if found. + * + * NOTE: Setting the MSB of the basic rates needs to be taken + * care of, either before or after calling this function. + */ +static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, + u32 rate1_size, u8 *rate2, u32 rate2_size) +{ + int ret; + u8 *ptr = rate1, *tmp; + u32 i, j; + + tmp = kmalloc(rate1_size, GFP_KERNEL); + if (!tmp) { + dev_err(priv->adapter->dev, "failed to alloc tmp buf\n"); + return -ENOMEM; + } + + memcpy(tmp, rate1, rate1_size); + memset(rate1, 0, rate1_size); + + for (i = 0; rate2[i] && i < rate2_size; i++) { + for (j = 0; tmp[j] && j < rate1_size; j++) { + /* Check common rate, excluding the bit for + basic rate */ + if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) { + *rate1++ = tmp[j]; + break; + } + } + } + + dev_dbg(priv->adapter->dev, "info: Tx data rate set to %#x\n", + priv->data_rate); + + if (!priv->is_data_rate_auto) { + while (*ptr) { + if ((*ptr & 0x7f) == priv->data_rate) { + ret = 0; + goto done; + } + ptr++; + } + dev_err(priv->adapter->dev, "previously set fixed data rate %#x" + " is not compatible with the network\n", + priv->data_rate); + + ret = -1; + goto done; + } + + ret = 0; +done: + kfree(tmp); + return ret; +} + +/* + * This function creates the intersection of the rates supported by a + * target BSS and our adapter settings for use in an assoc/join command. + */ +static int +mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + u8 *out_rates, u32 *out_rates_size) +{ + u8 card_rates[MWIFIEX_SUPPORTED_RATES]; + u32 card_rates_size; + + /* Copy AP supported rates */ + memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES); + /* Get the STA supported rates */ + card_rates_size = mwifiex_get_active_data_rates(priv, card_rates); + /* Get the common rates between AP and STA supported rates */ + if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES, + card_rates, card_rates_size)) { + *out_rates_size = 0; + dev_err(priv->adapter->dev, "%s: cannot get common rates\n", + __func__); + return -1; + } + + *out_rates_size = + min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES); + + return 0; +} + +/* + * This function updates the scan entry TSF timestamps to reflect + * a new association. + */ +static void +mwifiex_update_tsf_timestamps(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *new_bss_desc) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u32 table_idx; + long long new_tsf_base; + signed long long tsf_delta; + + memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base)); + + tsf_delta = new_tsf_base - new_bss_desc->network_tsf; + + dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, " + "0x%016llx -> 0x%016llx\n", + new_bss_desc->network_tsf, new_tsf_base); + + for (table_idx = 0; table_idx < adapter->num_in_scan_table; + table_idx++) + adapter->scan_table[table_idx].network_tsf += tsf_delta; +} + +/* + * This function appends a WAPI IE. + * + * This function 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 WAPI TLV type to the request. + */ +static int +mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer) +{ + int retLen = 0; + struct mwifiex_ie_types_header ie_header; + + /* Null Checks */ + if (buffer == NULL) + return 0; + if (*buffer == NULL) + return 0; + + /* + * If there is a wapi ie buffer setup, append it to the return + * parameter buffer pointer. + */ + if (priv->wapi_ie_len) { + dev_dbg(priv->adapter->dev, "cmd: append wapi ie %d to %p\n", + priv->wapi_ie_len, *buffer); + + /* Wrap the generic IE buffer with a pass through TLV type */ + ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE); + ie_header.len = cpu_to_le16(priv->wapi_ie_len); + memcpy(*buffer, &ie_header, sizeof(ie_header)); + + /* Increment the return size and the return buffer pointer + param */ + *buffer += sizeof(ie_header); + retLen += sizeof(ie_header); + + /* Copy the wapi IE buffer to the output buffer, advance + pointer */ + memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len); + + /* Increment the return size and the return buffer pointer + param */ + *buffer += priv->wapi_ie_len; + retLen += priv->wapi_ie_len; + + } + /* return the length appended to the buffer */ + return retLen; +} + +/* + * This function appends rsn ie tlv for wpa/wpa2 security modes. + * It is called from the network join command preparation routine. + */ +static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv, + u8 **buffer) +{ + struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv; + int rsn_ie_len; + + if (!buffer || !(*buffer)) + return 0; + + rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer); + rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]); + rsn_ie_tlv->header.type = cpu_to_le16( + le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF); + rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]); + rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len) + & 0x00FF); + if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2)) + memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2], + le16_to_cpu(rsn_ie_tlv->header.len)); + else + return -1; + + rsn_ie_len = sizeof(rsn_ie_tlv->header) + + le16_to_cpu(rsn_ie_tlv->header.len); + *buffer += rsn_ie_len; + + return rsn_ie_len; +} + +/* + * This function prepares command for association. + * + * This sets the following parameters - + * - Peer MAC address + * - Listen interval + * - Beacon interval + * - Capability information + * + * ...and the following TLVs, as required - + * - SSID TLV + * - PHY TLV + * - SS TLV + * - Rates TLV + * - Authentication TLV + * - Channel TLV + * - WPA/WPA2 IE + * - 11n TLV + * - Vendor specific TLV + * - WMM TLV + * - WAPI IE + * - Generic IE + * - TSF TLV + * + * Preparation also includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate; + struct mwifiex_bssdescriptor *bss_desc; + struct mwifiex_ie_types_ssid_param_set *ssid_tlv; + struct mwifiex_ie_types_phy_param_set *phy_tlv; + struct mwifiex_ie_types_ss_param_set *ss_tlv; + struct mwifiex_ie_types_rates_param_set *rates_tlv; + struct mwifiex_ie_types_auth_type *auth_tlv; + struct mwifiex_ie_types_chan_list_param_set *chan_tlv; + u8 rates[MWIFIEX_SUPPORTED_RATES]; + u32 rates_size; + u16 tmp_cap; + u8 *pos; + int rsn_ie_len = 0; + + bss_desc = (struct mwifiex_bssdescriptor *) data_buf; + pos = (u8 *) assoc; + + mwifiex_cfg_tx_buf(priv, bss_desc); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); + + /* Save so we know which BSS Desc to use in the response handler */ + priv->attempted_bss_desc = bss_desc; + + memcpy(assoc->peer_sta_addr, + bss_desc->mac_address, sizeof(assoc->peer_sta_addr)); + pos += sizeof(assoc->peer_sta_addr); + + /* Set the listen interval */ + assoc->listen_interval = cpu_to_le16(priv->listen_interval); + /* Set the beacon period */ + assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period); + + pos += sizeof(assoc->cap_info_bitmap); + pos += sizeof(assoc->listen_interval); + pos += sizeof(assoc->beacon_period); + pos += sizeof(assoc->dtim_period); + + ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos; + ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID); + ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len); + memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid, + le16_to_cpu(ssid_tlv->header.len)); + pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len); + + phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos; + phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS); + phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set)); + memcpy(&phy_tlv->fh_ds.ds_param_set, + &bss_desc->phy_param_set.ds_param_set.current_chan, + sizeof(phy_tlv->fh_ds.ds_param_set)); + pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len); + + ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos; + ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS); + ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set)); + pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len); + + /* Get the common rates supported between the driver and the BSS Desc */ + if (mwifiex_setup_rates_from_bssdesc + (priv, bss_desc, rates, &rates_size)) + return -1; + + /* Save the data rates into Current BSS state structure */ + priv->curr_bss_params.num_of_rates = rates_size; + memcpy(&priv->curr_bss_params.data_rates, rates, rates_size); + + /* Setup the Rates TLV in the association command */ + rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos; + rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); + rates_tlv->header.len = cpu_to_le16((u16) rates_size); + memcpy(rates_tlv->rates, rates, rates_size); + pos += sizeof(rates_tlv->header) + rates_size; + dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n", + rates_size); + + /* Add the Authentication type to be used for Auth frames */ + auth_tlv = (struct mwifiex_ie_types_auth_type *) pos; + auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); + auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type)); + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) + auth_tlv->auth_type = cpu_to_le16( + (u16) priv->sec_info.authentication_mode); + else + auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM); + + pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); + + if (IS_SUPPORT_MULTI_BANDS(priv->adapter) + && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) + && (!bss_desc->disable_11n) + && (priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN) + && (bss_desc->bcn_ht_cap) + ) + ) { + /* Append a channel TLV for the channel the attempted AP was + found on */ + chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; + chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_tlv->header.len = + cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); + + memset(chan_tlv->chan_scan_param, 0x00, + sizeof(struct mwifiex_chan_scan_param_set)); + chan_tlv->chan_scan_param[0].chan_number = + (bss_desc->phy_param_set.ds_param_set.current_chan); + dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n", + chan_tlv->chan_scan_param[0].chan_number); + + chan_tlv->chan_scan_param[0].radio_type = + mwifiex_band_to_radio_type((u8) bss_desc->bss_band); + + dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n", + chan_tlv->chan_scan_param[0].radio_type); + pos += sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + } + + if (!priv->wps.session_enable) { + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); + + if (rsn_ie_len == -1) + return -1; + } + + if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) + && (!bss_desc->disable_11n) + && (priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN)) + mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos); + + /* Append vendor specific IE TLV */ + mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos); + + mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie, + bss_desc->bcn_ht_cap); + if (priv->sec_info.wapi_enabled && priv->wapi_ie_len) + mwifiex_cmd_append_wapi_ie(priv, &pos); + + + mwifiex_cmd_append_generic_ie(priv, &pos); + + mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc); + + cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN); + + /* Set the Capability info at last */ + tmp_cap = bss_desc->cap_info_bitmap; + + if (priv->adapter->config_bands == BAND_B) + tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; + + tmp_cap &= CAPINFO_MASK; + dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", + tmp_cap, CAPINFO_MASK); + assoc->cap_info_bitmap = cpu_to_le16(tmp_cap); + + return 0; +} + +/* + * Association firmware command response handler + * + * The response buffer for the association command has the following + * memory layout. + * + * For cases where an association response was not received (indicated + * by the CapInfo and AId field): + * + * .------------------------------------------------------------. + * | Header(4 * sizeof(t_u16)): Standard command response hdr | + * .------------------------------------------------------------. + * | cap_info/Error Return(t_u16): | + * | 0xFFFF(-1): Internal error | + * | 0xFFFE(-2): Authentication unhandled message | + * | 0xFFFD(-3): Authentication refused | + * | 0xFFFC(-4): Timeout waiting for AP response | + * .------------------------------------------------------------. + * | status_code(t_u16): | + * | If cap_info is -1: | + * | An internal firmware failure prevented the | + * | command from being processed. The status_code | + * | will be set to 1. | + * | | + * | If cap_info is -2: | + * | An authentication frame was received but was | + * | not handled by the firmware. IEEE Status | + * | code for the failure is returned. | + * | | + * | If cap_info is -3: | + * | An authentication frame was received and the | + * | status_code is the IEEE Status reported in the | + * | response. | + * | | + * | If cap_info is -4: | + * | (1) Association response timeout | + * | (2) Authentication response timeout | + * .------------------------------------------------------------. + * | a_id(t_u16): 0xFFFF | + * .------------------------------------------------------------. + * + * + * For cases where an association response was received, the IEEE + * standard association response frame is returned: + * + * .------------------------------------------------------------. + * | Header(4 * sizeof(t_u16)): Standard command response hdr | + * .------------------------------------------------------------. + * | cap_info(t_u16): IEEE Capability | + * .------------------------------------------------------------. + * | status_code(t_u16): IEEE Status Code | + * .------------------------------------------------------------. + * | a_id(t_u16): IEEE Association ID | + * .------------------------------------------------------------. + * | IEEE IEs(variable): Any received IEs comprising the | + * | remaining portion of a received | + * | association response frame. | + * .------------------------------------------------------------. + * + * For simplistic handling, the status_code field can be used to determine + * an association success (0) or failure (non-zero). + */ +int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + struct ieee_types_assoc_rsp *assoc_rsp; + struct mwifiex_bssdescriptor *bss_desc; + u8 enable_data = true; + + assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; + + priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, + sizeof(priv->assoc_rsp_buf)); + + memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); + + if (le16_to_cpu(assoc_rsp->status_code)) { + priv->adapter->dbg.num_cmd_assoc_failure++; + dev_err(priv->adapter->dev, "ASSOC_RESP: association failed, " + "status code = %d, error = 0x%x, a_id = 0x%x\n", + le16_to_cpu(assoc_rsp->status_code), + le16_to_cpu(assoc_rsp->cap_info_bitmap), + le16_to_cpu(assoc_rsp->a_id)); + + ret = -1; + goto done; + } + + /* Send a Media Connected event, according to the Spec */ + priv->media_connected = true; + + priv->adapter->ps_state = PS_STATE_AWAKE; + priv->adapter->pps_uapsd_mode = false; + priv->adapter->tx_lock_flag = false; + + /* Set the attempted BSSID Index to current */ + bss_desc = priv->attempted_bss_desc; + + dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n", + bss_desc->ssid.ssid); + + /* Make a copy of current BSSID descriptor */ + memcpy(&priv->curr_bss_params.bss_descriptor, + bss_desc, sizeof(struct mwifiex_bssdescriptor)); + + /* Update curr_bss_params */ + priv->curr_bss_params.bss_descriptor.channel + = bss_desc->phy_param_set.ds_param_set.current_chan; + + priv->curr_bss_params.band = (u8) bss_desc->bss_band; + + /* + * Adjust the timestamps in the scan table to be relative to the newly + * associated AP's TSF + */ + mwifiex_update_tsf_timestamps(priv, bss_desc); + + if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) + priv->curr_bss_params.wmm_enabled = true; + else + priv->curr_bss_params.wmm_enabled = false; + + if ((priv->wmm_required || bss_desc->bcn_ht_cap) + && priv->curr_bss_params.wmm_enabled) + priv->wmm_enabled = true; + else + priv->wmm_enabled = false; + + priv->curr_bss_params.wmm_uapsd_enabled = false; + + if (priv->wmm_enabled) + priv->curr_bss_params.wmm_uapsd_enabled + = ((bss_desc->wmm_ie.qos_info_bitmap & + IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); + + dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n", + priv->curr_pkt_filter); + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + priv->wpa_is_gtk_set = false; + + if (priv->wmm_enabled) { + /* Don't re-enable carrier until we get the WMM_GET_STATUS + event */ + enable_data = false; + } else { + /* Since WMM is not enabled, setup the queues with the + defaults */ + mwifiex_wmm_setup_queue_priorities(priv, NULL); + mwifiex_wmm_setup_ac_downgrade(priv); + } + + if (enable_data) + dev_dbg(priv->adapter->dev, + "info: post association, re-enabling data flow\n"); + + /* Reset SNR/NF/RSSI values */ + priv->data_rssi_last = 0; + priv->data_nf_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->bcn_rssi_last = 0; + priv->bcn_nf_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + priv->rxpd_rate = 0; + priv->rxpd_htinfo = 0; + + mwifiex_save_curr_bcn(priv); + + priv->adapter->dbg.num_cmd_assoc_success++; + + dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n"); + + /* Add the ra_list here for infra mode as there will be only 1 ra + always */ + mwifiex_ralist_add(priv, + priv->curr_bss_params.bss_descriptor.mac_address); + + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + if (netif_queue_stopped(priv->netdev)) + netif_wake_queue(priv->netdev); + + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + priv->scan_block = true; + +done: + /* Need to indicate IOCTL complete */ + if (adapter->curr_cmd->wait_q_enabled) { + if (ret) + adapter->cmd_wait_q.status = -1; + else + adapter->cmd_wait_q.status = 0; + } + + return ret; +} + +/* + * This function prepares command for ad-hoc start. + * + * Driver will fill up SSID, BSS mode, IBSS parameters, physical + * parameters, probe delay, and capability information. Firmware + * will fill up beacon period, basic rates and operational rates. + * + * In addition, the following TLVs are added - + * - Channel TLV + * - Vendor specific IE + * - WPA/WPA2 IE + * - HT Capabilities IE + * - HT Information IE + * + * Preparation also includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +int +mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + int rsn_ie_len = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start = + &cmd->params.adhoc_start; + struct mwifiex_bssdescriptor *bss_desc; + u32 cmd_append_size = 0; + u32 i; + u16 tmp_cap; + uint16_t ht_cap_info; + struct mwifiex_ie_types_chan_list_param_set *chan_tlv; + + struct mwifiex_ie_types_htcap *ht_cap; + struct mwifiex_ie_types_htinfo *ht_info; + u8 *pos = (u8 *) adhoc_start + + sizeof(struct host_cmd_ds_802_11_ad_hoc_start); + + if (!adapter) + return -1; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START); + + bss_desc = &priv->curr_bss_params.bss_descriptor; + priv->attempted_bss_desc = bss_desc; + + /* + * Fill in the parameters for 2 data structures: + * 1. struct host_cmd_ds_802_11_ad_hoc_start command + * 2. bss_desc + * Driver will fill up SSID, bss_mode,IBSS param, Physical Param, + * probe delay, and Cap info. + * Firmware will fill up beacon period, Basic rates + * and operational rates. + */ + + memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN); + + memcpy(adhoc_start->ssid, + ((struct mwifiex_802_11_ssid *) data_buf)->ssid, + ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len); + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n", + adhoc_start->ssid); + + memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN); + memcpy(bss_desc->ssid.ssid, + ((struct mwifiex_802_11_ssid *) data_buf)->ssid, + ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len); + + bss_desc->ssid.ssid_len = + ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len; + + /* Set the BSS mode */ + adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS; + bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; + adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period); + bss_desc->beacon_period = priv->beacon_period; + + /* Set Physical param set */ +/* Parameter IE Id */ +#define DS_PARA_IE_ID 3 +/* Parameter IE length */ +#define DS_PARA_IE_LEN 1 + + adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID; + adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN; + + if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, adapter->adhoc_start_band, (u16) + priv->adhoc_channel)) { + struct mwifiex_chan_freq_power *cfp; + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, + adapter->adhoc_start_band, FIRST_VALID_CHANNEL); + if (cfp) + priv->adhoc_channel = (u8) cfp->channel; + } + + if (!priv->adhoc_channel) { + dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n"); + return -1; + } + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n", + priv->adhoc_channel); + + priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel; + priv->curr_bss_params.band = adapter->adhoc_start_band; + + bss_desc->channel = priv->adhoc_channel; + adhoc_start->phy_param_set.ds_param_set.current_chan = + priv->adhoc_channel; + + memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set, + sizeof(union ieee_types_phy_param_set)); + + /* Set IBSS param set */ +/* IBSS parameter IE Id */ +#define IBSS_PARA_IE_ID 6 +/* IBSS parameter IE length */ +#define IBSS_PARA_IE_LEN 2 + + adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID; + adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN; + adhoc_start->ss_param_set.ibss_param_set.atim_window + = cpu_to_le16(priv->atim_window); + memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set, + sizeof(union ieee_types_ss_param_set)); + + /* Set Capability info */ + bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS; + tmp_cap = le16_to_cpu(adhoc_start->cap_info_bitmap); + tmp_cap &= ~WLAN_CAPABILITY_ESS; + tmp_cap |= WLAN_CAPABILITY_IBSS; + + /* Set up privacy in bss_desc */ + if (priv->sec_info.encryption_mode) { + /* Ad-Hoc capability privacy on */ + dev_dbg(adapter->dev, + "info: ADHOC_S_CMD: wep_status set privacy to WEP\n"); + bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; + tmp_cap |= WLAN_CAPABILITY_PRIVACY; + } else { + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set," + " setting privacy to ACCEPT ALL\n"); + bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; + } + + memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate)); + mwifiex_get_active_data_rates(priv, adhoc_start->DataRate); + if ((adapter->adhoc_start_band & BAND_G) && + (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter)) { + dev_err(adapter->dev, + "ADHOC_S_CMD: G Protection config failed\n"); + return -1; + } + } + /* Find the last non zero */ + for (i = 0; i < sizeof(adhoc_start->DataRate) && + adhoc_start->DataRate[i]; + i++) + ; + + priv->curr_bss_params.num_of_rates = i; + + /* Copy the ad-hoc creating rates into Current BSS rate structure */ + memcpy(&priv->curr_bss_params.data_rates, + &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates); + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n", + adhoc_start->DataRate[0], adhoc_start->DataRate[1], + adhoc_start->DataRate[2], adhoc_start->DataRate[3]); + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); + + if (IS_SUPPORT_MULTI_BANDS(adapter)) { + /* Append a channel TLV */ + chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; + chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_tlv->header.len = + cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); + + memset(chan_tlv->chan_scan_param, 0x00, + sizeof(struct mwifiex_chan_scan_param_set)); + chan_tlv->chan_scan_param[0].chan_number = + (u8) priv->curr_bss_params.bss_descriptor.channel; + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n", + chan_tlv->chan_scan_param[0].chan_number); + + chan_tlv->chan_scan_param[0].radio_type + = mwifiex_band_to_radio_type(priv->curr_bss_params.band); + if (adapter->adhoc_start_band & BAND_GN + || adapter->adhoc_start_band & BAND_AN) { + if (adapter->chan_offset == SEC_CHANNEL_ABOVE) + chan_tlv->chan_scan_param[0].radio_type |= + SECOND_CHANNEL_ABOVE; + else if (adapter->chan_offset == SEC_CHANNEL_BELOW) + chan_tlv->chan_scan_param[0].radio_type |= + SECOND_CHANNEL_BELOW; + } + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n", + chan_tlv->chan_scan_param[0].radio_type); + pos += sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + cmd_append_size += + sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + } + + /* Append vendor specific IE TLV */ + cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, + MWIFIEX_VSIE_MASK_ADHOC, &pos); + + if (priv->sec_info.wpa_enabled) { + rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); + if (rsn_ie_len == -1) + return -1; + cmd_append_size += rsn_ie_len; + } + + if (adapter->adhoc_11n_enabled) { + { + ht_cap = (struct mwifiex_ie_types_htcap *) pos; + memset(ht_cap, 0, + sizeof(struct mwifiex_ie_types_htcap)); + ht_cap->header.type = + cpu_to_le16(WLAN_EID_HT_CAPABILITY); + ht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); + + ht_cap_info |= IEEE80211_HT_CAP_SGI_20; + if (adapter->chan_offset) { + ht_cap_info |= IEEE80211_HT_CAP_SGI_40; + ht_cap_info |= IEEE80211_HT_CAP_DSSSCCK40; + ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); + } + + ht_cap->ht_cap.ampdu_params_info + = IEEE80211_HT_MAX_AMPDU_64K; + ht_cap->ht_cap.mcs.rx_mask[0] = 0xff; + pos += sizeof(struct mwifiex_ie_types_htcap); + cmd_append_size += + sizeof(struct mwifiex_ie_types_htcap); + } + { + 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.len = + cpu_to_le16(sizeof(struct ieee80211_ht_info)); + ht_info->ht_info.control_chan = + (u8) priv->curr_bss_params.bss_descriptor. + channel; + if (adapter->chan_offset) { + ht_info->ht_info.ht_param = + adapter->chan_offset; + ht_info->ht_info.ht_param |= + IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; + } + ht_info->ht_info.operation_mode = + cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + ht_info->ht_info.basic_set[0] = 0xff; + pos += sizeof(struct mwifiex_ie_types_htinfo); + cmd_append_size += + sizeof(struct mwifiex_ie_types_htinfo); + } + } + + cmd->size = cpu_to_le16((u16) + (sizeof(struct host_cmd_ds_802_11_ad_hoc_start) + + S_DS_GEN + cmd_append_size)); + + if (adapter->adhoc_start_band == BAND_B) + tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; + else + tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME; + + adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap); + + return 0; +} + +/* + * This function prepares command for ad-hoc join. + * + * Most of the parameters are set up by copying from the target BSS descriptor + * from the scan response. + * + * In addition, the following TLVs are added - + * - Channel TLV + * - Vendor specific IE + * - WPA/WPA2 IE + * - 11n IE + * + * Preparation also includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +int +mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + int rsn_ie_len = 0; + struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join = + &cmd->params.adhoc_join; + struct mwifiex_bssdescriptor *bss_desc = + (struct mwifiex_bssdescriptor *) data_buf; + struct mwifiex_ie_types_chan_list_param_set *chan_tlv; + u32 cmd_append_size = 0; + u16 tmp_cap; + u32 i, rates_size = 0; + u16 curr_pkt_filter; + u8 *pos = + (u8 *) adhoc_join + + sizeof(struct host_cmd_ds_802_11_ad_hoc_join); + +/* Use G protection */ +#define USE_G_PROTECTION 0x02 + if (bss_desc->erp_flags & USE_G_PROTECTION) { + curr_pkt_filter = + priv-> + curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON; + + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &curr_pkt_filter)) { + dev_err(priv->adapter->dev, + "ADHOC_J_CMD: G Protection config failed\n"); + return -1; + } + } + + priv->attempted_bss_desc = bss_desc; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN); + + adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS; + + adhoc_join->bss_descriptor.beacon_period + = cpu_to_le16(bss_desc->beacon_period); + + memcpy(&adhoc_join->bss_descriptor.bssid, + &bss_desc->mac_address, ETH_ALEN); + + memcpy(&adhoc_join->bss_descriptor.ssid, + &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len); + + memcpy(&adhoc_join->bss_descriptor.phy_param_set, + &bss_desc->phy_param_set, + sizeof(union ieee_types_phy_param_set)); + + memcpy(&adhoc_join->bss_descriptor.ss_param_set, + &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set)); + + tmp_cap = bss_desc->cap_info_bitmap; + + tmp_cap &= CAPINFO_MASK; + + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: tmp_cap=%4X" + " CAPINFO_MASK=%4lX\n", tmp_cap, CAPINFO_MASK); + + /* Information on BSSID descriptor passed to FW */ + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: BSSID = %pM, SSID = %s\n", + adhoc_join->bss_descriptor.bssid, + adhoc_join->bss_descriptor.ssid); + + for (i = 0; bss_desc->supported_rates[i] && + i < MWIFIEX_SUPPORTED_RATES; + i++) + ; + rates_size = i; + + /* Copy Data Rates from the Rates recorded in scan response */ + memset(adhoc_join->bss_descriptor.data_rates, 0, + sizeof(adhoc_join->bss_descriptor.data_rates)); + memcpy(adhoc_join->bss_descriptor.data_rates, + bss_desc->supported_rates, rates_size); + + /* Copy the adhoc join rates into Current BSS state structure */ + priv->curr_bss_params.num_of_rates = rates_size; + memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates, + rates_size); + + /* Copy the channel information */ + priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel; + priv->curr_bss_params.band = (u8) bss_desc->bss_band; + + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED + || priv->sec_info.wpa_enabled) + tmp_cap |= WLAN_CAPABILITY_PRIVACY; + + if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) { + /* Append a channel TLV */ + chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; + chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_tlv->header.len = + cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); + + memset(chan_tlv->chan_scan_param, 0x00, + sizeof(struct mwifiex_chan_scan_param_set)); + chan_tlv->chan_scan_param[0].chan_number = + (bss_desc->phy_param_set.ds_param_set.current_chan); + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Chan = %d\n", + chan_tlv->chan_scan_param[0].chan_number); + + chan_tlv->chan_scan_param[0].radio_type = + mwifiex_band_to_radio_type((u8) bss_desc->bss_band); + + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Band = %d\n", + chan_tlv->chan_scan_param[0].radio_type); + pos += sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + cmd_append_size += sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + } + + if (priv->sec_info.wpa_enabled) + rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); + if (rsn_ie_len == -1) + return -1; + cmd_append_size += rsn_ie_len; + + if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) + cmd_append_size += mwifiex_cmd_append_11n_tlv(priv, + bss_desc, &pos); + + /* Append vendor specific IE TLV */ + cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, + MWIFIEX_VSIE_MASK_ADHOC, &pos); + + cmd->size = cpu_to_le16((u16) + (sizeof(struct host_cmd_ds_802_11_ad_hoc_join) + + S_DS_GEN + cmd_append_size)); + + adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap); + + return 0; +} + +/* + * This function handles the command response of ad-hoc start and + * ad-hoc join. + * + * The function generates a device-connected event to notify + * the applications, in case of successful ad-hoc start/join, and + * saves the beacon buffer. + */ +int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result; + struct mwifiex_bssdescriptor *bss_desc; + + adhoc_result = &resp->params.adhoc_result; + + bss_desc = priv->attempted_bss_desc; + + /* Join result code 0 --> SUCCESS */ + if (le16_to_cpu(resp->result)) { + dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n"); + if (priv->media_connected) + mwifiex_reset_connect_state(priv); + + memset(&priv->curr_bss_params.bss_descriptor, + 0x00, sizeof(struct mwifiex_bssdescriptor)); + + ret = -1; + goto done; + } + + /* Send a Media Connected event, according to the Spec */ + priv->media_connected = true; + + if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) { + dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n", + bss_desc->ssid.ssid); + + /* Update the created network descriptor with the new BSSID */ + memcpy(bss_desc->mac_address, + adhoc_result->bssid, ETH_ALEN); + + priv->adhoc_state = ADHOC_STARTED; + } else { + /* + * Now the join cmd should be successful. + * If BSSID has changed use SSID to compare instead of BSSID + */ + dev_dbg(priv->adapter->dev, "info: ADHOC_J_RESP %s\n", + bss_desc->ssid.ssid); + + /* + * Make a copy of current BSSID descriptor, only needed for + * join since the current descriptor is already being used + * for adhoc start + */ + memcpy(&priv->curr_bss_params.bss_descriptor, + bss_desc, sizeof(struct mwifiex_bssdescriptor)); + + priv->adhoc_state = ADHOC_JOINED; + } + + dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: channel = %d\n", + priv->adhoc_channel); + dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: BSSID = %pM\n", + priv->curr_bss_params.bss_descriptor.mac_address); + + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + if (netif_queue_stopped(priv->netdev)) + netif_wake_queue(priv->netdev); + + mwifiex_save_curr_bcn(priv); + +done: + /* Need to indicate IOCTL complete */ + if (adapter->curr_cmd->wait_q_enabled) { + if (ret) + adapter->cmd_wait_q.status = -1; + else + adapter->cmd_wait_q.status = 0; + + } + + return ret; +} + +/* + * This function associates to a specific BSS discovered in a scan. + * + * It clears any past association response stored for application + * retrieval and calls the command preparation routine to send the + * command to firmware. + */ +int mwifiex_associate(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + u8 current_bssid[ETH_ALEN]; + + /* Return error if the adapter or table entry is not marked as infra */ + if ((priv->bss_mode != NL80211_IFTYPE_STATION) || + (bss_desc->bss_mode != NL80211_IFTYPE_STATION)) + return -1; + + memcpy(¤t_bssid, + &priv->curr_bss_params.bss_descriptor.mac_address, + sizeof(current_bssid)); + + /* Clear any past association response stored for application + retrieval */ + priv->assoc_rsp_size = 0; + + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_ASSOCIATE, + HostCmd_ACT_GEN_SET, 0, bss_desc); +} + +/* + * This function starts an ad-hoc network. + * + * It calls the command preparation routine to send the command to firmware. + */ +int +mwifiex_adhoc_start(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *adhoc_ssid) +{ + dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n", + priv->adhoc_channel); + dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n", + priv->curr_bss_params.bss_descriptor.channel); + dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n", + priv->curr_bss_params.band); + + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START, + HostCmd_ACT_GEN_SET, 0, adhoc_ssid); +} + +/* + * This function joins an ad-hoc network found in a previous scan. + * + * It calls the command preparation routine to send the command to firmware, + * if already not connected to the requested SSID. + */ +int mwifiex_adhoc_join(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid =%s\n", + priv->curr_bss_params.bss_descriptor.ssid.ssid); + dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid_len =%u\n", + priv->curr_bss_params.bss_descriptor.ssid.ssid_len); + dev_dbg(priv->adapter->dev, "info: adhoc join: ssid =%s\n", + bss_desc->ssid.ssid); + dev_dbg(priv->adapter->dev, "info: adhoc join: ssid_len =%u\n", + bss_desc->ssid.ssid_len); + + /* Check if the requested SSID is already joined */ + if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len && + !mwifiex_ssid_cmp(&bss_desc->ssid, + &priv->curr_bss_params.bss_descriptor.ssid) && + (priv->curr_bss_params.bss_descriptor.bss_mode == + NL80211_IFTYPE_ADHOC)) { + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: new ad-hoc SSID" + " is the same as current; not attempting to re-join\n"); + return -1; + } + + dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n", + priv->curr_bss_params.bss_descriptor.channel); + dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n", + priv->curr_bss_params.band); + + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, + HostCmd_ACT_GEN_SET, 0, bss_desc); +} + +/* + * This function deauthenticates/disconnects from infra network by sending + * deauthentication request. + */ +static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac) +{ + u8 mac_address[ETH_ALEN]; + int ret; + u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + + if (mac) { + if (!memcmp(mac, zero_mac, sizeof(zero_mac))) + memcpy((u8 *) &mac_address, + (u8 *) &priv->curr_bss_params.bss_descriptor. + mac_address, ETH_ALEN); + else + memcpy((u8 *) &mac_address, (u8 *) mac, ETH_ALEN); + } else { + memcpy((u8 *) &mac_address, (u8 *) &priv->curr_bss_params. + bss_descriptor.mac_address, ETH_ALEN); + } + + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, + HostCmd_ACT_GEN_SET, 0, &mac_address); + + return ret; +} + +/* + * This function deauthenticates/disconnects from a BSS. + * + * In case of infra made, it sends deauthentication request, and + * in case of ad-hoc mode, a stop network request is sent to the firmware. + */ +int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac) +{ + int ret = 0; + + if (priv->media_connected) { + if (priv->bss_mode == NL80211_IFTYPE_STATION) { + ret = mwifiex_deauthenticate_infra(priv, mac); + } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + ret = mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_AD_HOC_STOP, + HostCmd_ACT_GEN_SET, 0, NULL); + } + } + + return ret; +} +EXPORT_SYMBOL_GPL(mwifiex_deauthenticate); + +/* + * This function converts band to radio type used in channel TLV. + */ +u8 +mwifiex_band_to_radio_type(u8 band) +{ + switch (band) { + case BAND_A: + case BAND_AN: + case BAND_A | BAND_AN: + return HostCmd_SCAN_RADIO_TYPE_A; + case BAND_B: + case BAND_G: + case BAND_B | BAND_G: + default: + return HostCmd_SCAN_RADIO_TYPE_BG; + } +} diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c new file mode 100644 index 000000000000..f0582259c935 --- /dev/null +++ b/drivers/net/wireless/mwifiex/main.c @@ -0,0 +1,1055 @@ +/* + * Marvell Wireless LAN device driver: major functions + * + * Copyright (C) 2011, 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 "wmm.h" +#include "cfg80211.h" +#include "11n.h" + +#define VERSION "1.0" + +const char driver_version[] = "mwifiex " VERSION " (%s) "; + +struct mwifiex_adapter *g_adapter; +EXPORT_SYMBOL_GPL(g_adapter); + +static struct mwifiex_bss_attr mwifiex_bss_sta[] = { + {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0}, +}; + +static int drv_mode = DRV_MODE_STA; + +static char fw_name[32] = DEFAULT_FW_NAME; + +/* Supported drv_mode table */ +static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { + { + .drv_mode = DRV_MODE_STA, + .intf_num = ARRAY_SIZE(mwifiex_bss_sta), + .bss_attr = mwifiex_bss_sta, + }, +}; + +/* + * This function registers the device and performs all the necessary + * initializations. + * + * The following initialization operations are performed - + * - Allocate adapter structure + * - Save interface specific operations table in adapter + * - Call interface specific initialization routine + * - Allocate private structures + * - Set default adapter structure parameters + * - Initialize locks + * + * In case of any errors during inittialization, this function also ensures + * proper cleanup before exiting. + */ +static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, + struct mwifiex_drv_mode *drv_mode_ptr) +{ + struct mwifiex_adapter *adapter; + int i; + + adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL); + if (!adapter) + return -ENOMEM; + + g_adapter = adapter; + adapter->card = card; + + /* Save interface specific operations in adapter */ + 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; + + adapter->priv_num = 0; + for (i = 0; i < drv_mode_ptr->intf_num; i++) { + adapter->priv[i] = NULL; + + if (!drv_mode_ptr->bss_attr[i].active) + continue; + + /* Allocate memory for private structure */ + adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private), + GFP_KERNEL); + if (!adapter->priv[i]) { + dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n", + __func__, i); + goto error; + } + + adapter->priv_num++; + adapter->priv[i]->adapter = adapter; + /* Save bss_type, frame_type & bss_priority */ + adapter->priv[i]->bss_type = drv_mode_ptr->bss_attr[i].bss_type; + adapter->priv[i]->frame_type = + drv_mode_ptr->bss_attr[i].frame_type; + adapter->priv[i]->bss_priority = + drv_mode_ptr->bss_attr[i].bss_priority; + + if (drv_mode_ptr->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA) + adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA; + else if (drv_mode_ptr->bss_attr[i].bss_type == + MWIFIEX_BSS_TYPE_UAP) + adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP; + + /* Save bss_index & bss_num */ + adapter->priv[i]->bss_index = i; + adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num; + } + adapter->drv_mode = drv_mode_ptr; + + if (mwifiex_init_lock_list(adapter)) + goto error; + + init_timer(&adapter->cmd_timer); + adapter->cmd_timer.function = mwifiex_cmd_timeout_func; + adapter->cmd_timer.data = (unsigned long) adapter; + + return 0; + +error: + dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); + + mwifiex_free_lock_list(adapter); + for (i = 0; i < drv_mode_ptr->intf_num; i++) + kfree(adapter->priv[i]); + kfree(adapter); + + return -1; +} + +/* + * This function unregisters the device and performs all the necessary + * cleanups. + * + * The following cleanup operations are performed - + * - Free the timers + * - Free beacon buffers + * - Free private structures + * - Free adapter structure + */ +static int mwifiex_unregister(struct mwifiex_adapter *adapter) +{ + s32 i; + + del_timer(&adapter->cmd_timer); + + /* Free private structures */ + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + mwifiex_free_curr_bcn(adapter->priv[i]); + kfree(adapter->priv[i]); + } + } + + kfree(adapter); + return 0; +} + +/* + * The main process. + * + * This function is the main procedure of the driver and handles various driver + * operations. It runs in a loop and provides the core functionalities. + * + * The main responsibilities of this function are - + * - Ensure concurrency control + * - Handle pending interrupts and call interrupt handlers + * - Wake up the card if required + * - Handle command responses and call response handlers + * - Handle events and call event handlers + * - Execute pending commands + * - Transmit pending data packets + */ +int mwifiex_main_process(struct mwifiex_adapter *adapter) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + + /* Check if already processing */ + if (adapter->mwifiex_processing) { + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + goto exit_main_proc; + } else { + adapter->mwifiex_processing = true; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + } +process_start: + do { + if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) || + (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) + break; + + /* Handle pending interrupt if any */ + if (adapter->int_status) { + if (adapter->hs_activated) + mwifiex_process_hs_config(adapter); + adapter->if_ops.process_int_status(adapter); + } + + /* Need to wake up the card ? */ + if ((adapter->ps_state == PS_STATE_SLEEP) && + (adapter->pm_wakeup_card_req && + !adapter->pm_wakeup_fw_try) && + (is_command_pending(adapter) + || !mwifiex_wmm_lists_empty(adapter))) { + adapter->pm_wakeup_fw_try = true; + 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) + adapter->ps_state = PS_STATE_AWAKE; + } else { + /* We have tried to wakeup the card already */ + if (adapter->pm_wakeup_fw_try) + break; + if (adapter->ps_state != PS_STATE_AWAKE || + adapter->tx_lock_flag) + break; + + if (adapter->scan_processing || adapter->data_sent + || mwifiex_wmm_lists_empty(adapter)) { + if (adapter->cmd_sent || adapter->curr_cmd + || (!is_command_pending(adapter))) + break; + } + } + + /* Check for Cmd Resp */ + if (adapter->cmd_resp_received) { + adapter->cmd_resp_received = false; + mwifiex_process_cmdresp(adapter); + + /* call mwifiex back when init_fw is done */ + if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) { + adapter->hw_status = MWIFIEX_HW_STATUS_READY; + mwifiex_init_fw_complete(adapter); + } + } + + /* Check for event */ + if (adapter->event_received) { + adapter->event_received = false; + mwifiex_process_event(adapter); + } + + /* Check if we need to confirm Sleep Request + received previously */ + if (adapter->ps_state == PS_STATE_PRE_SLEEP) { + if (!adapter->cmd_sent && !adapter->curr_cmd) + mwifiex_check_ps_cond(adapter); + } + + /* * The ps_state may have been changed during processing of + * Sleep Request event. + */ + if ((adapter->ps_state == PS_STATE_SLEEP) + || (adapter->ps_state == PS_STATE_PRE_SLEEP) + || (adapter->ps_state == PS_STATE_SLEEP_CFM) + || adapter->tx_lock_flag) + continue; + + if (!adapter->cmd_sent && !adapter->curr_cmd) { + if (mwifiex_exec_next_cmd(adapter) == -1) { + ret = -1; + break; + } + } + + if (!adapter->scan_processing && !adapter->data_sent && + !mwifiex_wmm_lists_empty(adapter)) { + mwifiex_wmm_process_tx(adapter); + if (adapter->hs_activated) { + adapter->is_hs_configured = false; + mwifiex_hs_activated_event + (mwifiex_get_priv + (adapter, MWIFIEX_BSS_ROLE_ANY), + false); + } + } + + if (adapter->delay_null_pkt && !adapter->cmd_sent && + !adapter->curr_cmd && !is_command_pending(adapter) + && mwifiex_wmm_lists_empty(adapter)) { + if (!mwifiex_send_null_packet + (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), + MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) { + adapter->delay_null_pkt = false; + adapter->ps_state = PS_STATE_SLEEP; + } + break; + } + } while (true); + + if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter)) + goto process_start; + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + adapter->mwifiex_processing = false; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + +exit_main_proc: + if (adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) + mwifiex_shutdown_drv(adapter); + return ret; +} + +/* + * This function initializes the software. + * + * The main work includes allocating and initializing the adapter structure + * and initializing the private structures. + */ +static int +mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops) +{ + int i; + struct mwifiex_drv_mode *drv_mode_ptr; + + /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */ + drv_mode_ptr = NULL; + for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) { + if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) { + drv_mode_ptr = &mwifiex_drv_mode_tbl[i]; + break; + } + } + + if (!drv_mode_ptr) { + pr_err("invalid drv_mode=%d\n", drv_mode); + return -1; + } + + if (mwifiex_register(card, if_ops, drv_mode_ptr)) + return -1; + + return 0; +} + +/* + * This function frees the adapter structure. + * + * Additionally, this closes the netlink socket, frees the timers + * and private structures. + */ +static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) +{ + if (!adapter) { + pr_err("%s: adapter is NULL\n", __func__); + return; + } + + mwifiex_unregister(adapter); + pr_debug("info: %s: free adapter\n", __func__); +} + +/* + * This function initializes the hardware and firmware. + * + * 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) +{ + int ret, err; + struct mwifiex_fw_image fw; + + memset(&fw, 0, sizeof(struct mwifiex_fw_image)); + + switch (adapter->revision_id) { + case SD8787_W0: + case SD8787_W1: + strcpy(fw_name, SD8787_W1_FW_NAME); + break; + case SD8787_A0: + case SD8787_A1: + strcpy(fw_name, SD8787_AX_FW_NAME); + break; + default: + break; + } + + err = request_firmware(&adapter->firmware, fw_name, adapter->dev); + if (err < 0) { + dev_err(adapter->dev, "request_firmware() returned" + " error code %#x\n", err); + ret = -1; + goto done; + } + fw.fw_buf = (u8 *) adapter->firmware->data; + fw.fw_len = adapter->firmware->size; + + ret = mwifiex_dnld_fw(adapter, &fw); + if (ret == -1) + goto done; + + dev_notice(adapter->dev, "WLAN FW is active\n"); + + adapter->init_wait_q_woken = false; + ret = mwifiex_init_fw(adapter); + if (ret == -1) { + goto done; + } else if (!ret) { + adapter->hw_status = MWIFIEX_HW_STATUS_READY; + goto done; + } + /* 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; + goto done; + } + ret = 0; + +done: + if (adapter->firmware) + release_firmware(adapter->firmware); + if (ret) + ret = -1; + return ret; +} + +/* + * This function fills a driver buffer. + * + * The function associates a given SKB with the provided driver buffer + * and also updates some of the SKB parameters, including IP header, + * priority and timestamp. + */ +static void +mwifiex_fill_buffer(struct sk_buff *skb) +{ + struct ethhdr *eth; + struct iphdr *iph; + struct timeval tv; + u8 tid = 0; + + eth = (struct ethhdr *) skb->data; + switch (eth->h_proto) { + case __constant_htons(ETH_P_IP): + iph = ip_hdr(skb); + tid = IPTOS_PREC(iph->tos); + pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n", + eth->h_proto, tid, skb->priority); + break; + case __constant_htons(ETH_P_ARP): + pr_debug("data: ARP packet: %04x\n", eth->h_proto); + default: + break; + } +/* Offset for TOS field in the IP header */ +#define IPTOS_OFFSET 5 + tid = (tid >> IPTOS_OFFSET); + skb->priority = tid; + /* Record the current time the packet was queued; used to + determine the amount of time the packet was queued in + the driver before it was sent to the firmware. + The delay is then sent along with the packet to the + firmware for aggregate delay calculation for stats and + MSDU lifetime expiry. + */ + do_gettimeofday(&tv); + skb->tstamp = timeval_to_ktime(tv); +} + +/* + * CFG802.11 network device handler for open. + * + * Starts the data queue. + */ +static int +mwifiex_open(struct net_device *dev) +{ + netif_start_queue(dev); + return 0; +} + +/* + * CFG802.11 network device handler for close. + */ +static int +mwifiex_close(struct net_device *dev) +{ + return 0; +} + +/* + * CFG802.11 network device handler for data transmission. + */ +static int +mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct sk_buff *new_skb; + struct mwifiex_txinfo *tx_info; + + dev_dbg(priv->adapter->dev, "data: %lu BSS(%d): Data <= kernel\n", + jiffies, priv->bss_index); + + if (priv->adapter->surprise_removed) { + kfree_skb(skb); + priv->stats.tx_dropped++; + return 0; + } + if (!skb->len || (skb->len > ETH_FRAME_LEN)) { + dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len); + kfree_skb(skb); + priv->stats.tx_dropped++; + return 0; + } + if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) { + dev_dbg(priv->adapter->dev, + "data: Tx: insufficient skb headroom %d\n", + skb_headroom(skb)); + /* Insufficient skb headroom - allocate a new skb */ + new_skb = + skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN); + if (unlikely(!new_skb)) { + dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n"); + kfree_skb(skb); + priv->stats.tx_dropped++; + return 0; + } + kfree_skb(skb); + skb = new_skb; + dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n", + skb_headroom(skb)); + } + + tx_info = MWIFIEX_SKB_TXCB(skb); + tx_info->bss_index = priv->bss_index; + mwifiex_fill_buffer(skb); + + mwifiex_wmm_add_buf_txqueue(priv->adapter, skb); + atomic_inc(&priv->adapter->tx_pending); + + if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) { + netif_stop_queue(priv->netdev); + dev->trans_start = jiffies; + } + + queue_work(priv->adapter->workqueue, &priv->adapter->main_work); + + return 0; +} + +/* + * CFG802.11 network device handler for setting MAC address. + */ +static int +mwifiex_set_mac_address(struct net_device *dev, void *addr) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct sockaddr *hw_addr = (struct sockaddr *) addr; + int ret; + + memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); + + /* Send request to firmware */ + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_MAC_ADDRESS, + HostCmd_ACT_GEN_SET, 0, NULL); + + if (!ret) + memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN); + else + dev_err(priv->adapter->dev, "set mac address failed: ret=%d" + "\n", ret); + + memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); + + return ret; +} + +/* + * CFG802.11 network device handler for setting multicast list. + */ +static void mwifiex_set_multicast_list(struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_multicast_list mcast_list; + + if (dev->flags & IFF_PROMISC) { + mcast_list.mode = MWIFIEX_PROMISC_MODE; + } else if (dev->flags & IFF_ALLMULTI || + netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) { + mcast_list.mode = MWIFIEX_ALL_MULTI_MODE; + } else { + mcast_list.mode = MWIFIEX_MULTICAST_MODE; + if (netdev_mc_count(dev)) + mcast_list.num_multicast_addr = + mwifiex_copy_mcast_addr(&mcast_list, dev); + } + mwifiex_request_set_multicast_list(priv, &mcast_list); +} + +/* + * CFG802.11 network device handler for transmission timeout. + */ +static void +mwifiex_tx_timeout(struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_index=%d\n", + jiffies, priv->bss_index); + dev->trans_start = jiffies; + priv->num_tx_timeout++; +} + +/* + * CFG802.11 network device handler for statistics retrieval. + */ +static struct net_device_stats *mwifiex_get_stats(struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + return &priv->stats; +} + +/* Network device handlers */ +static const struct net_device_ops mwifiex_netdev_ops = { + .ndo_open = mwifiex_open, + .ndo_stop = mwifiex_close, + .ndo_start_xmit = mwifiex_hard_start_xmit, + .ndo_set_mac_address = mwifiex_set_mac_address, + .ndo_tx_timeout = mwifiex_tx_timeout, + .ndo_get_stats = mwifiex_get_stats, + .ndo_set_multicast_list = mwifiex_set_multicast_list, +}; + +/* + * This function initializes the private structure parameters. + * + * The following wait queues are initialized - + * - IOCTL wait queue + * - Command wait queue + * - Statistics wait queue + * + * ...and the following default parameters are set - + * - Current key index : Set to 0 + * - Rate index : Set to auto + * - Media connected : Set to disconnected + * - Adhoc link sensed : Set to false + * - Nick name : Set to null + * - Number of Tx timeout : Set to 0 + * - Device address : Set to current address + * + * In addition, the CFG80211 work queue is also created. + */ +static void +mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) +{ + dev->netdev_ops = &mwifiex_netdev_ops; + /* Initialize private structure */ + priv->current_key_index = 0; + priv->media_connected = false; + memset(&priv->nick_name, 0, sizeof(priv->nick_name)); + priv->num_tx_timeout = 0; + priv->workqueue = create_singlethread_workqueue("cfg80211_wq"); + INIT_WORK(&priv->cfg_workqueue, mwifiex_cfg80211_results); + memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); +} + +/* + * This function adds a new logical interface. + * + * It allocates, initializes and registers the interface by performing + * the following opearations - + * - Allocate a new net device structure + * - Assign device name + * - Register the new device with CFG80211 subsystem + * - Initialize semaphore and private structure + * - Register the new device with kernel + * - Create the complete debug FS structure if configured + */ +static struct mwifiex_private *mwifiex_add_interface( + struct mwifiex_adapter *adapter, + u8 bss_index, u8 bss_type) +{ + struct net_device *dev; + struct mwifiex_private *priv; + void *mdev_priv; + + dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d", + ether_setup, 1); + if (!dev) { + dev_err(adapter->dev, "no memory available for netdevice\n"); + goto error; + } + + if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr, + adapter->priv[bss_index]) != 0) { + dev_err(adapter->dev, "cannot register netdevice with cfg80211\n"); + goto error; + } + /* Save the priv pointer in netdev */ + priv = adapter->priv[bss_index]; + mdev_priv = netdev_priv(dev); + *((unsigned long *) mdev_priv) = (unsigned long) priv; + + priv->netdev = dev; + + sema_init(&priv->async_sem, 1); + priv->scan_pending_on_block = false; + + mwifiex_init_priv_params(priv, dev); + + SET_NETDEV_DEV(dev, adapter->dev); + + /* Register network device */ + if (register_netdev(dev)) { + dev_err(adapter->dev, "cannot register virtual network device\n"); + goto error; + } + + dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); +#ifdef CONFIG_DEBUG_FS + mwifiex_dev_debugfs_init(priv); +#endif + return priv; +error: + if (dev) + free_netdev(dev); + return NULL; +} + +/* + * This function removes a logical interface. + * + * It deregisters, resets and frees the interface by performing + * the following operations - + * - Disconnect the device if connected, send wireless event to + * notify applications. + * - Remove the debug FS structure if configured + * - Unregister the device from kernel + * - Free the net device structure + * - Cancel all works and destroy work queue + * - Unregister and free the wireless device from CFG80211 subsystem + */ +static void +mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index) +{ + struct net_device *dev; + struct mwifiex_private *priv = adapter->priv[bss_index]; + + if (!priv) + return; + dev = priv->netdev; + + if (priv->media_connected) + priv->media_connected = false; + +#ifdef CONFIG_DEBUG_FS + mwifiex_dev_debugfs_remove(priv); +#endif + /* Last reference is our one */ + dev_dbg(adapter->dev, "info: %s: refcnt = %d\n", + dev->name, netdev_refcnt_read(dev)); + + if (dev->reg_state == NETREG_REGISTERED) + unregister_netdev(dev); + + /* Clear the priv in adapter */ + priv->netdev = NULL; + if (dev) + free_netdev(dev); + + cancel_work_sync(&priv->cfg_workqueue); + flush_workqueue(priv->workqueue); + destroy_workqueue(priv->workqueue); + wiphy_unregister(priv->wdev->wiphy); + wiphy_free(priv->wdev->wiphy); + kfree(priv->wdev); +} + +/* + * This function check if command is pending. + */ +int is_command_pending(struct mwifiex_adapter *adapter) +{ + unsigned long flags; + int is_cmd_pend_q_empty; + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + return !is_cmd_pend_q_empty; +} + +/* + * This function returns the correct private structure pointer based + * upon the BSS number. + */ +struct mwifiex_private * +mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index) +{ + if (!adapter || (bss_index >= adapter->priv_num)) + return NULL; + return adapter->priv[bss_index]; +} + +/* + * This is the main work queue function. + * + * It handles the main process, which in turn handles the complete + * driver operations. + */ +static void mwifiex_main_work_queue(struct work_struct *work) +{ + struct mwifiex_adapter *adapter = + container_of(work, struct mwifiex_adapter, main_work); + + if (adapter->surprise_removed) + return; + mwifiex_main_process(adapter); +} + +/* + * This function cancels all works in the queue and destroys + * the main workqueue. + */ +static void +mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) +{ + flush_workqueue(adapter->workqueue); + destroy_workqueue(adapter->workqueue); + adapter->workqueue = NULL; +} + +/* + * This function adds the card. + * + * This function follows the following major steps to set up the device - + * - Initialize software. This includes probing the card, registering + * the interface operations table, and allocating/initializing the + * adapter structure + * - Set up the netlink socket + * - Create and start the main work queue + * - Register the device + * - Initialize firmware and hardware + * - Add logical interfaces + */ +int +mwifiex_add_card(void *card, struct semaphore *sem, + struct mwifiex_if_ops *if_ops) +{ + int i; + struct mwifiex_adapter *adapter; + + if (down_interruptible(sem)) + goto exit_sem_err; + + if (mwifiex_init_sw(card, if_ops)) { + pr_err("%s: software init failed\n", __func__); + goto err_init_sw; + } + + adapter = g_adapter; + + adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; + adapter->surprise_removed = false; + init_waitqueue_head(&adapter->init_wait_q); + adapter->is_suspended = false; + adapter->hs_activated = false; + init_waitqueue_head(&adapter->hs_activate_wait_q); + adapter->cmd_wait_q_required = false; + init_waitqueue_head(&adapter->cmd_wait_q.wait); + adapter->cmd_wait_q.condition = false; + adapter->cmd_wait_q.status = 0; + + adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE"); + if (!adapter->workqueue) + goto err_kmalloc; + + INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); + + /* Register the device. Fill up the private data structure with relevant + information from the card and request for the required IRQ. */ + if (adapter->if_ops.register_dev(adapter)) { + pr_err("%s: failed to register mwifiex device\n", __func__); + goto err_registerdev; + } + + if (mwifiex_init_hw_fw(adapter)) { + pr_err("%s: firmware init failed\n", __func__); + goto err_init_fw; + } + + /* Add interfaces */ + for (i = 0; i < adapter->drv_mode->intf_num; i++) { + if (!mwifiex_add_interface(adapter, i, + adapter->drv_mode->bss_attr[i].bss_type)) { + goto err_add_intf; + } + } + + up(sem); + + return 0; + +err_add_intf: + for (i = 0; i < adapter->priv_num; i++) + mwifiex_remove_interface(adapter, i); +err_init_fw: + pr_debug("info: %s: unregister device\n", __func__); + adapter->if_ops.unregister_dev(adapter); +err_registerdev: + adapter->surprise_removed = true; + mwifiex_terminate_workqueue(adapter); +err_kmalloc: + if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || + (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { + pr_debug("info: %s: shutdown mwifiex\n", __func__); + adapter->init_wait_q_woken = false; + + if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS) + wait_event_interruptible(adapter->init_wait_q, + adapter->init_wait_q_woken); + } + + mwifiex_free_adapter(adapter); + +err_init_sw: + up(sem); + +exit_sem_err: + return -1; +} +EXPORT_SYMBOL_GPL(mwifiex_add_card); + +/* + * This function removes the card. + * + * This function follows the following major steps to remove the device - + * - Stop data traffic + * - Shutdown firmware + * - Remove the logical interfaces + * - Terminate the work queue + * - Unregister the device + * - Free the adapter structure + */ +int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) +{ + struct mwifiex_private *priv = NULL; + int i; + + if (down_interruptible(sem)) + goto exit_sem_err; + + if (!adapter) + goto exit_remove; + + adapter->surprise_removed = true; + + /* Stop data */ + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv) { + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + } + } + + dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n"); + adapter->init_wait_q_woken = false; + + if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS) + wait_event_interruptible(adapter->init_wait_q, + adapter->init_wait_q_woken); + dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n"); + if (atomic_read(&adapter->rx_pending) || + atomic_read(&adapter->tx_pending) || + atomic_read(&adapter->cmd_pending)) { + dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, " + "cmd_pending=%d\n", + atomic_read(&adapter->rx_pending), + atomic_read(&adapter->tx_pending), + atomic_read(&adapter->cmd_pending)); + } + + /* Remove interface */ + for (i = 0; i < adapter->priv_num; i++) + mwifiex_remove_interface(adapter, i); + + mwifiex_terminate_workqueue(adapter); + + /* Unregister device */ + dev_dbg(adapter->dev, "info: unregister device\n"); + adapter->if_ops.unregister_dev(adapter); + /* Free adapter structure */ + dev_dbg(adapter->dev, "info: free adapter\n"); + mwifiex_free_adapter(adapter); + +exit_remove: + up(sem); +exit_sem_err: + return 0; +} +EXPORT_SYMBOL_GPL(mwifiex_remove_card); + +/* + * This function initializes the module. + * + * The debug FS is also initialized if configured. + */ +static int +mwifiex_init_module(void) +{ +#ifdef CONFIG_DEBUG_FS + mwifiex_debugfs_init(); +#endif + return 0; +} + +/* + * This function cleans up the module. + * + * The debug FS is removed if available. + */ +static void +mwifiex_cleanup_module(void) +{ +#ifdef CONFIG_DEBUG_FS + mwifiex_debugfs_remove(); +#endif +} + +module_init(mwifiex_init_module); +module_exit(mwifiex_cleanup_module); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION("Marvell WiFi-Ex Driver version " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h new file mode 100644 index 000000000000..672701dc2721 --- /dev/null +++ b/drivers/net/wireless/mwifiex/main.h @@ -0,0 +1,1004 @@ +/* + * Marvell Wireless LAN device driver: major data structures and prototypes + * + * Copyright (C) 2011, 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_MAIN_H_ +#define _MWIFIEX_MAIN_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" + +extern const char driver_version[]; +extern struct mwifiex_adapter *g_adapter; + +enum { + MWIFIEX_ASYNC_CMD, + MWIFIEX_SYNC_CMD +}; + +#define DRV_MODE_STA 0x1 + +#define SD8787_W0 0x30 +#define SD8787_W1 0x31 +#define SD8787_A0 0x40 +#define SD8787_A1 0x41 + +#define DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin" +#define SD8787_W1_FW_NAME "mrvl/sd8787_uapsta_w1.bin" +#define SD8787_AX_FW_NAME "mrvl/sd8787_uapsta.bin" + +struct mwifiex_drv_mode { + u16 drv_mode; + u16 intf_num; + struct mwifiex_bss_attr *bss_attr; +}; + + +#define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) + +#define MWIFIEX_TIMER_10S 10000 +#define MWIFIEX_TIMER_1S 1000 + +#define MAX_TX_PENDING 60 + +#define MWIFIEX_UPLD_SIZE (2312) + +#define MAX_EVENT_SIZE 1024 + +#define ARP_FILTER_MAX_BUF_SIZE 68 + +#define MWIFIEX_KEY_BUFFER_SIZE 16 +#define MWIFIEX_DEFAULT_LISTEN_INTERVAL 10 +#define MWIFIEX_MAX_REGION_CODE 7 + +#define DEFAULT_BCN_AVG_FACTOR 8 +#define DEFAULT_DATA_AVG_FACTOR 8 + +#define FIRST_VALID_CHANNEL 0xff +#define DEFAULT_AD_HOC_CHANNEL 6 +#define DEFAULT_AD_HOC_CHANNEL_A 36 + +#define DEFAULT_BCN_MISS_TIMEOUT 5 + +#define MAX_SCAN_BEACON_BUFFER 8000 + +#define SCAN_BEACON_ENTRY_PAD 6 + +#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 200 +#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 200 +#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 110 + +#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI))) + +#define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S) + +#define RSN_GTK_OUI_OFFSET 2 + +#define MWIFIEX_OUI_NOT_PRESENT 0 +#define MWIFIEX_OUI_PRESENT 1 + +#define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \ + adapter->event_received || \ + adapter->data_received) + +#define MWIFIEX_TYPE_CMD 1 +#define MWIFIEX_TYPE_DATA 0 +#define MWIFIEX_TYPE_EVENT 3 + +#define DBG_CMD_NUM 5 + +#define MAX_BITMAP_RATES_SIZE 10 + +#define MAX_CHANNEL_BAND_BG 14 + +#define MAX_FREQUENCY_BAND_BG 2484 + +struct mwifiex_dbg { + u32 num_cmd_host_to_card_failure; + u32 num_cmd_sleep_cfm_host_to_card_failure; + u32 num_tx_host_to_card_failure; + u32 num_event_deauth; + u32 num_event_disassoc; + u32 num_event_link_lost; + u32 num_cmd_deauth; + u32 num_cmd_assoc_success; + u32 num_cmd_assoc_failure; + u32 num_tx_timeout; + u32 num_cmd_timeout; + u16 timeout_cmd_id; + u16 timeout_cmd_act; + u16 last_cmd_id[DBG_CMD_NUM]; + u16 last_cmd_act[DBG_CMD_NUM]; + u16 last_cmd_index; + u16 last_cmd_resp_id[DBG_CMD_NUM]; + u16 last_cmd_resp_index; + u16 last_event[DBG_CMD_NUM]; + u16 last_event_index; +}; + +enum MWIFIEX_HARDWARE_STATUS { + MWIFIEX_HW_STATUS_READY, + MWIFIEX_HW_STATUS_INITIALIZING, + MWIFIEX_HW_STATUS_FW_READY, + MWIFIEX_HW_STATUS_INIT_DONE, + MWIFIEX_HW_STATUS_RESET, + MWIFIEX_HW_STATUS_CLOSING, + MWIFIEX_HW_STATUS_NOT_READY +}; + +enum MWIFIEX_802_11_POWER_MODE { + MWIFIEX_802_11_POWER_MODE_CAM, + MWIFIEX_802_11_POWER_MODE_PSP +}; + +struct mwifiex_tx_param { + u32 next_pkt_len; +}; + +enum MWIFIEX_PS_STATE { + PS_STATE_AWAKE, + PS_STATE_PRE_SLEEP, + PS_STATE_SLEEP_CFM, + PS_STATE_SLEEP +}; + +struct mwifiex_add_ba_param { + u32 tx_win_size; + u32 rx_win_size; + u32 timeout; +}; + +struct mwifiex_tx_aggr { + u8 ampdu_user; + u8 ampdu_ap; + u8 amsdu; +}; + +struct mwifiex_ra_list_tbl { + struct list_head list; + struct sk_buff_head skb_head; + u8 ra[ETH_ALEN]; + u32 total_pkts_size; + u32 is_11n_enabled; +}; + +struct mwifiex_tid_tbl { + struct list_head ra_list; + /* spin lock for tid table */ + spinlock_t tid_tbl_lock; + struct mwifiex_ra_list_tbl *ra_list_curr; +}; + +#define WMM_HIGHEST_PRIORITY 7 +#define HIGH_PRIO_TID 7 +#define LOW_PRIO_TID 0 + +struct mwifiex_wmm_desc { + struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID]; + 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]; + u32 drv_pkt_delay_max; + u8 queue_priority[IEEE80211_MAX_QUEUES]; + u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */ + +}; + +struct mwifiex_802_11_security { + u8 wpa_enabled; + u8 wpa2_enabled; + u8 wapi_enabled; + u8 wapi_key_on; + enum MWIFIEX_802_11_WEP_STATUS wep_status; + u32 authentication_mode; + u32 encryption_mode; +}; + +struct ieee_types_header { + u8 element_id; + u8 len; +} __packed; + +struct ieee_obss_scan_param { + u16 obss_scan_passive_dwell; + u16 obss_scan_active_dwell; + u16 bss_chan_width_trigger_scan_int; + u16 obss_scan_passive_total; + u16 obss_scan_active_total; + u16 bss_width_chan_trans_delay; + u16 obss_scan_active_threshold; +} __packed; + +struct ieee_types_obss_scan_param { + struct ieee_types_header ieee_hdr; + struct ieee_obss_scan_param obss_scan; +} __packed; + +#define MWIFIEX_SUPPORTED_RATES 14 + +#define MWIFIEX_SUPPORTED_RATES_EXT 32 + +#define IEEE_MAX_IE_SIZE 256 + +struct ieee_types_vendor_specific { + struct ieee_types_vendor_header vend_hdr; + u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)]; +} __packed; + +struct ieee_types_generic { + struct ieee_types_header ieee_hdr; + u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header)]; +} __packed; + +struct mwifiex_bssdescriptor { + u8 mac_address[ETH_ALEN]; + struct mwifiex_802_11_ssid ssid; + u32 privacy; + s32 rssi; + u32 channel; + u32 freq; + u16 beacon_period; + u8 erp_flags; + u32 bss_mode; + u8 supported_rates[MWIFIEX_SUPPORTED_RATES]; + u8 data_rates[MWIFIEX_SUPPORTED_RATES]; + /* Network band. + * BAND_B(0x01): 'b' band + * BAND_G(0x02): 'g' band + * BAND_A(0X04): 'a' band + */ + u16 bss_band; + u64 network_tsf; + u8 time_stamp[8]; + union ieee_types_phy_param_set phy_param_set; + union ieee_types_ss_param_set ss_param_set; + u16 cap_info_bitmap; + struct ieee_types_wmm_parameter wmm_ie; + u8 disable_11n; + struct ieee80211_ht_cap *bcn_ht_cap; + u16 ht_cap_offset; + struct ieee80211_ht_info *bcn_ht_info; + u16 ht_info_offset; + u8 *bcn_bss_co_2040; + u16 bss_co_2040_offset; + u8 *bcn_ext_cap; + u16 ext_cap_offset; + struct ieee_types_obss_scan_param *bcn_obss_scan; + u16 overlap_bss_offset; + struct ieee_types_vendor_specific *bcn_wpa_ie; + u16 wpa_offset; + struct ieee_types_generic *bcn_rsn_ie; + u16 rsn_offset; + struct ieee_types_generic *bcn_wapi_ie; + u16 wapi_offset; + u8 *beacon_buf; + u32 beacon_buf_size; + u32 beacon_buf_size_max; + +}; + +struct mwifiex_current_bss_params { + struct mwifiex_bssdescriptor bss_descriptor; + u8 wmm_enabled; + u8 wmm_uapsd_enabled; + u8 band; + u32 num_of_rates; + u8 data_rates[MWIFIEX_SUPPORTED_RATES]; +}; + +struct mwifiex_sleep_params { + u16 sp_error; + u16 sp_offset; + u16 sp_stable_time; + u8 sp_cal_control; + u8 sp_ext_sleep_clk; + u16 sp_reserved; +}; + +struct mwifiex_sleep_period { + u16 period; + u16 reserved; +}; + +struct mwifiex_wep_key { + u32 length; + u32 key_index; + u32 key_length; + u8 key_material[MWIFIEX_KEY_BUFFER_SIZE]; +}; + +#define MAX_REGION_CHANNEL_NUM 2 + +struct mwifiex_chan_freq_power { + u16 channel; + u32 freq; + u16 max_tx_power; + u8 unsupported; +}; + +enum state_11d_t { + DISABLE_11D = 0, + ENABLE_11D = 1, +}; + +#define MWIFIEX_MAX_TRIPLET_802_11D 83 + +struct mwifiex_802_11d_domain_reg { + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + u8 no_of_triplet; + struct ieee80211_country_ie_triplet + triplet[MWIFIEX_MAX_TRIPLET_802_11D]; +}; + +struct mwifiex_vendor_spec_cfg_ie { + u16 mask; + u16 flag; + u8 ie[MWIFIEX_MAX_VSIE_LEN]; +}; + +struct wps { + u8 session_enable; +}; + +struct mwifiex_adapter; +struct mwifiex_private; + +struct mwifiex_private { + struct mwifiex_adapter *adapter; + u8 bss_index; + u8 bss_type; + u8 bss_role; + u8 bss_priority; + u8 bss_num; + u8 frame_type; + u8 curr_addr[ETH_ALEN]; + u8 media_connected; + u32 num_tx_timeout; + struct net_device *netdev; + struct net_device_stats stats; + u16 curr_pkt_filter; + u32 bss_mode; + u32 pkt_tx_ctrl; + u16 tx_power_level; + u8 max_tx_power_level; + u8 min_tx_power_level; + u8 tx_rate; + u8 tx_htinfo; + u8 rxpd_htinfo; + u8 rxpd_rate; + u16 rate_bitmap; + u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; + u32 data_rate; + u8 is_data_rate_auto; + u16 bcn_avg_factor; + u16 data_avg_factor; + s16 data_rssi_last; + s16 data_nf_last; + s16 data_rssi_avg; + s16 data_nf_avg; + s16 bcn_rssi_last; + s16 bcn_nf_last; + s16 bcn_rssi_avg; + s16 bcn_nf_avg; + struct mwifiex_bssdescriptor *attempted_bss_desc; + struct mwifiex_802_11_ssid prev_ssid; + u8 prev_bssid[ETH_ALEN]; + struct mwifiex_current_bss_params curr_bss_params; + u16 beacon_period; + u16 listen_interval; + u16 atim_window; + u8 adhoc_channel; + u8 adhoc_is_link_sensed; + u8 adhoc_state; + struct mwifiex_802_11_security sec_info; + struct mwifiex_wep_key wep_key[NUM_WEP_KEYS]; + u16 wep_key_curr_index; + u8 wpa_ie[256]; + u8 wpa_ie_len; + u8 wpa_is_gtk_set; + struct host_cmd_ds_802_11_key_material aes_key; + u8 wapi_ie[256]; + u8 wapi_ie_len; + u8 wmm_required; + u8 wmm_enabled; + u8 wmm_qosinfo; + struct mwifiex_wmm_desc wmm; + struct list_head tx_ba_stream_tbl_ptr; + /* spin lock for tx_ba_stream_tbl_ptr queue */ + spinlock_t tx_ba_stream_tbl_lock; + struct mwifiex_tx_aggr aggr_prio_tbl[MAX_NUM_TID]; + struct mwifiex_add_ba_param add_ba_param; + u16 rx_seq[MAX_NUM_TID]; + struct list_head rx_reorder_tbl_ptr; + /* spin lock for rx_reorder_tbl_ptr queue */ + spinlock_t rx_reorder_tbl_lock; + /* spin lock for Rx packets */ + spinlock_t rx_pkt_lock; + +#define MWIFIEX_ASSOC_RSP_BUF_SIZE 500 + u8 assoc_rsp_buf[MWIFIEX_ASSOC_RSP_BUF_SIZE]; + u32 assoc_rsp_size; + +#define MWIFIEX_GENIE_BUF_SIZE 256 + u8 gen_ie_buf[MWIFIEX_GENIE_BUF_SIZE]; + u8 gen_ie_buf_len; + + struct mwifiex_vendor_spec_cfg_ie vs_ie[MWIFIEX_MAX_VSIE_NUM]; + +#define MWIFIEX_ASSOC_TLV_BUF_SIZE 256 + u8 assoc_tlv_buf[MWIFIEX_ASSOC_TLV_BUF_SIZE]; + u8 assoc_tlv_buf_len; + + u8 *curr_bcn_buf; + u32 curr_bcn_size; + /* spin lock for beacon buffer */ + spinlock_t curr_bcn_buf_lock; + struct wireless_dev *wdev; + struct mwifiex_chan_freq_power cfp; + char version_str[128]; +#ifdef CONFIG_DEBUG_FS + struct dentry *dfs_dev_dir; +#endif + u8 nick_name[16]; + struct iw_statistics w_stats; + u16 current_key_index; + struct semaphore async_sem; + u8 scan_pending_on_block; + u8 report_scan_result; + struct cfg80211_scan_request *scan_request; + int scan_result_status; + int assoc_request; + u16 assoc_result; + int ibss_join_request; + u16 ibss_join_result; + bool disconnect; + u8 cfg_bssid[6]; + struct workqueue_struct *workqueue; + struct work_struct cfg_workqueue; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + struct wps wps; + u8 scan_block; +}; + +enum mwifiex_ba_status { + BA_STREAM_NOT_SETUP = 0, + BA_STREAM_SETUP_INPROGRESS, + BA_STREAM_SETUP_COMPLETE +}; + +struct mwifiex_tx_ba_stream_tbl { + struct list_head list; + int tid; + u8 ra[ETH_ALEN]; + enum mwifiex_ba_status ba_status; +}; + +struct mwifiex_rx_reorder_tbl; + +struct reorder_tmr_cnxt { + struct timer_list timer; + struct mwifiex_rx_reorder_tbl *ptr; + struct mwifiex_private *priv; +}; + +struct mwifiex_rx_reorder_tbl { + struct list_head list; + int tid; + u8 ta[ETH_ALEN]; + int start_win; + int win_size; + void **rx_reorder_ptr; + struct reorder_tmr_cnxt timer_context; +}; + +struct mwifiex_bss_prio_node { + struct list_head list; + struct mwifiex_private *priv; +}; + +struct mwifiex_bss_prio_tbl { + struct list_head bss_prio_head; + /* spin lock for bss priority */ + spinlock_t bss_prio_lock; + struct mwifiex_bss_prio_node *bss_prio_cur; +}; + +struct cmd_ctrl_node { + struct list_head list; + struct mwifiex_private *priv; + u32 cmd_oid; + u32 cmd_flag; + struct sk_buff *cmd_skb; + struct sk_buff *resp_skb; + void *data_buf; + u32 wait_q_enabled; + struct sk_buff *skb; +}; + +struct mwifiex_if_ops { + int (*init_if) (struct mwifiex_adapter *); + void (*cleanup_if) (struct mwifiex_adapter *); + int (*check_fw_status) (struct mwifiex_adapter *, u32, int *); + int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); + int (*register_dev) (struct mwifiex_adapter *); + void (*unregister_dev) (struct mwifiex_adapter *); + int (*enable_int) (struct mwifiex_adapter *); + int (*process_int_status) (struct mwifiex_adapter *); + int (*host_to_card) (struct mwifiex_adapter *, u8, + u8 *payload, u32 pkt_len, + struct mwifiex_tx_param *); + int (*wakeup) (struct mwifiex_adapter *); + int (*wakeup_complete) (struct mwifiex_adapter *); + + void (*update_mp_end_port) (struct mwifiex_adapter *, u16); + void (*cleanup_mpa_buf) (struct mwifiex_adapter *); +}; + +struct mwifiex_adapter { + struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM]; + u8 priv_num; + struct mwifiex_drv_mode *drv_mode; + const struct firmware *firmware; + struct device *dev; + bool surprise_removed; + u32 fw_release_number; + u32 revision_id; + u16 init_wait_q_woken; + wait_queue_head_t init_wait_q; + void *card; + struct mwifiex_if_ops if_ops; + atomic_t rx_pending; + atomic_t tx_pending; + atomic_t cmd_pending; + struct workqueue_struct *workqueue; + struct work_struct main_work; + struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; + /* spin lock for init/shutdown */ + spinlock_t mwifiex_lock; + /* spin lock for main process */ + spinlock_t main_proc_lock; + u32 mwifiex_processing; + u16 max_tx_buf_size; + u16 tx_buf_size; + u16 curr_tx_buf_size; + u32 ioport; + enum MWIFIEX_HARDWARE_STATUS hw_status; + u16 number_of_antenna; + u32 fw_cap_info; + /* spin lock for interrupt handling */ + spinlock_t int_lock; + u8 int_status; + u32 event_cause; + struct sk_buff *event_skb; + u8 upld_buf[MWIFIEX_UPLD_SIZE]; + u8 data_sent; + u8 cmd_sent; + u8 cmd_resp_received; + u8 event_received; + u8 data_received; + u16 seq_num; + struct cmd_ctrl_node *cmd_pool; + struct cmd_ctrl_node *curr_cmd; + /* spin lock for command */ + spinlock_t mwifiex_cmd_lock; + u32 num_cmd_timeout; + u16 last_init_cmd; + struct timer_list cmd_timer; + struct list_head cmd_free_q; + /* spin lock for cmd_free_q */ + spinlock_t cmd_free_q_lock; + struct list_head cmd_pending_q; + /* spin lock for cmd_pending_q */ + spinlock_t cmd_pending_q_lock; + struct list_head scan_pending_q; + /* spin lock for scan_pending_q */ + spinlock_t scan_pending_q_lock; + u32 scan_processing; + u16 region_code; + struct mwifiex_802_11d_domain_reg domain_reg; + struct mwifiex_bssdescriptor *scan_table; + u32 num_in_scan_table; + u16 scan_probes; + u32 scan_mode; + u16 specific_scan_time; + u16 active_scan_time; + u16 passive_scan_time; + u8 bcn_buf[MAX_SCAN_BEACON_BUFFER]; + u8 *bcn_buf_end; + u8 fw_bands; + u8 adhoc_start_band; + u8 config_bands; + struct mwifiex_chan_scan_param_set *scan_channels; + u8 tx_lock_flag; + struct mwifiex_sleep_params sleep_params; + struct mwifiex_sleep_period sleep_period; + u16 ps_mode; + u32 ps_state; + u8 need_to_wakeup; + u16 multiple_dtim; + u16 local_listen_interval; + u16 null_pkt_interval; + struct sk_buff *sleep_cfm; + u16 bcn_miss_time_out; + u16 adhoc_awake_period; + u8 is_deep_sleep; + u8 delay_null_pkt; + u16 delay_to_ps; + u16 enhanced_ps_mode; + u8 pm_wakeup_card_req; + u16 gen_null_pkt; + u16 pps_uapsd_mode; + u32 pm_wakeup_fw_try; + u8 is_hs_configured; + struct mwifiex_hs_config_param hs_cfg; + u8 hs_activated; + u16 hs_activate_wait_q_woken; + wait_queue_head_t hs_activate_wait_q; + bool is_suspended; + u8 event_body[MAX_EVENT_SIZE]; + u32 hw_dot_11n_dev_cap; + u8 hw_dev_mcs_support; + u8 adhoc_11n_enabled; + u8 chan_offset; + struct mwifiex_dbg dbg; + u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE]; + u32 arp_filter_size; + u16 cmd_wait_q_required; + struct mwifiex_wait_queue cmd_wait_q; +}; + +int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); +void mwifiex_free_lock_list(struct mwifiex_adapter *adapter); + +int mwifiex_init_fw(struct mwifiex_adapter *adapter); + +int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter); + +int mwifiex_shutdown_drv(struct mwifiex_adapter *adapter); + +int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter); + +int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *); + +int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb); + +int mwifiex_process_event(struct mwifiex_adapter *adapter); + +int mwifiex_complete_cmd(struct mwifiex_adapter *adapter); + +int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, void *data_buf); + +int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, void *data_buf); + +void mwifiex_cmd_timeout_func(unsigned long function_context); + +int mwifiex_get_debug_info(struct mwifiex_private *, + struct mwifiex_debug_info *); + +int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter); +int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter); +void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter); +void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter); + +void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node); + +void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node, + u32 addtail); + +int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter); +int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter); +int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb); +int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, + struct mwifiex_tx_param *tx_param); +int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags); +int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb, int status); +int mwifiex_recv_packet_complete(struct mwifiex_adapter *, + struct sk_buff *skb, int status); +void mwifiex_clean_txrx(struct mwifiex_private *priv); +u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv); +void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter); +void mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *, u8 *, + u32); +int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, uint16_t ps_bitmap, + void *data_buf); +int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf); +void mwifiex_process_hs_config(struct mwifiex_adapter *adapter); +void mwifiex_hs_activated_event(struct mwifiex_private *priv, + u8 activated); +int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb); +int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, + void *data_buf, void *cmd_buf); +int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no, + void *cmd_buf); +int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, + struct sk_buff *skb); +int mwifiex_process_sta_event(struct mwifiex_private *); +void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb); +int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta); +int mwifiex_scan_networks(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg *user_scan_in); +int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, + void *data_buf); +void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, + struct cmd_ctrl_node *cmd_node); +int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *ssid, u8 *bssid, + u32 mode); +s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, + u32 mode); +int mwifiex_find_best_network(struct mwifiex_private *priv, + struct mwifiex_ssid_bssid *req_ssid_bssid); +s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, + struct mwifiex_802_11_ssid *ssid2); +int mwifiex_associate(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc); +int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, + struct host_cmd_ds_command + *cmd, void *data_buf); +int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +void mwifiex_reset_connect_state(struct mwifiex_private *priv); +void mwifiex_2040_coex_event(struct mwifiex_private *priv); +u8 mwifiex_band_to_radio_type(u8 band); +int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac); +int mwifiex_adhoc_start(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *adhoc_ssid); +int mwifiex_adhoc_join(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc); +int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd); +struct mwifiex_chan_freq_power * + mwifiex_get_cfp_by_band_and_channel_from_cfg80211( + struct mwifiex_private *priv, + u8 band, u16 channel); +struct mwifiex_chan_freq_power *mwifiex_get_cfp_by_band_and_freq_from_cfg80211( + struct mwifiex_private *priv, + u8 band, u32 freq); +u32 mwifiex_index_to_data_rate(u8 index, u8 ht_info); +u32 mwifiex_find_freq_from_band_chan(u8, u8); +int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask, + u8 **buffer); +u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, + u8 *rates); +u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates); +u8 mwifiex_data_rate_to_index(u32 rate); +u8 mwifiex_is_rate_auto(struct mwifiex_private *priv); +int mwifiex_get_rate_index(u16 *rateBitmap, int size); +extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE]; +void mwifiex_save_curr_bcn(struct mwifiex_private *priv); +void mwifiex_free_curr_bcn(struct mwifiex_private *priv); +int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd); +int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int is_command_pending(struct mwifiex_adapter *adapter); + +/* + * This function checks if the queuing is RA based or not. + */ +static inline u8 +mwifiex_queuing_ra_based(struct mwifiex_private *priv) +{ + /* + * Currently we assume if we are in Infra, then DA=RA. This might not be + * true in the future + */ + if ((priv->bss_mode == NL80211_IFTYPE_STATION) && + (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)) + return false; + + return true; +} + +/* + * This function copies rates. + */ +static inline u32 +mwifiex_copy_rates(u8 *dest, u32 pos, u8 *src, int len) +{ + int i; + + for (i = 0; i < len && src[i]; i++, pos++) { + if (pos >= MWIFIEX_SUPPORTED_RATES) + break; + dest[pos] = src[i]; + } + + return pos; +} + +/* + * This function returns the correct private structure pointer based + * upon the BSS type and BSS number. + */ +static inline struct mwifiex_private * +mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter, + u8 bss_num, u8 bss_type) +{ + int i; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + if ((adapter->priv[i]->bss_num == bss_num) + && (adapter->priv[i]->bss_type == bss_type)) + break; + } + } + return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); +} + +/* + * This function returns the first available private structure pointer + * based upon the BSS role. + */ +static inline struct mwifiex_private * +mwifiex_get_priv(struct mwifiex_adapter *adapter, + enum mwifiex_bss_role bss_role) +{ + int i; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + if (bss_role == MWIFIEX_BSS_ROLE_ANY || + GET_BSS_ROLE(adapter->priv[i]) == bss_role) + break; + } + } + + return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); +} + +/* + * This function returns the driver private structure of a network device. + */ +static inline struct mwifiex_private * +mwifiex_netdev_get_priv(struct net_device *dev) +{ + return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev)); +} + +struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter + *adapter, u8 bss_index); +int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, + u32 func_init_shutdown); +int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *); +int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *); + +void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version, + int maxlen); +int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, + struct mwifiex_multicast_list *mcast_list); +int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, + struct net_device *dev); +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); +int mwifiex_bss_start(struct mwifiex_private *priv, + struct mwifiex_ssid_bssid *ssid_bssid); +int mwifiex_set_hs_params(struct mwifiex_private *priv, + u16 action, int cmd_type, + struct mwifiex_ds_hs_cfg *hscfg); +int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); +int mwifiex_enable_hs(struct mwifiex_adapter *adapter); +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_find_best_bss(struct mwifiex_private *priv, + struct mwifiex_ssid_bssid *ssid_bssid); +int mwifiex_request_scan(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *req_ssid); +int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, + struct mwifiex_user_scan_cfg *scan_req); +int mwifiex_change_adhoc_chan(struct mwifiex_private *priv, int channel); +int mwifiex_set_radio(struct mwifiex_private *priv, u8 option); + +int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel); + +int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, + int key_len, u8 key_index, int disable); + +int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len); + +int mwifiex_get_ver_ext(struct mwifiex_private *priv); + +int mwifiex_get_stats_info(struct mwifiex_private *priv, + struct mwifiex_ds_get_stats *log); + +int mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, + u32 reg_offset, u32 reg_value); + +int mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, + u32 reg_offset, u32 *value); + +int mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, + u8 *value); + +int mwifiex_set_11n_httx_cfg(struct mwifiex_private *priv, int data); + +int mwifiex_get_11n_httx_cfg(struct mwifiex_private *priv, int *data); + +int mwifiex_set_tx_rate_cfg(struct mwifiex_private *priv, int tx_rate_index); + +int mwifiex_get_tx_rate_cfg(struct mwifiex_private *priv, int *tx_rate_index); + +int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode); + +int mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, + char *version, int max_len); + +int mwifiex_set_tx_power(struct mwifiex_private *priv, + struct mwifiex_power_cfg *power_cfg); + +int mwifiex_main_process(struct mwifiex_adapter *); + +int mwifiex_bss_set_channel(struct mwifiex_private *, + struct mwifiex_chan_freq_power *cfp); +int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *, + struct mwifiex_ssid_bssid *); +int mwifiex_set_radio_band_cfg(struct mwifiex_private *, + struct mwifiex_ds_band_cfg *); +int mwifiex_get_bss_info(struct mwifiex_private *, + struct mwifiex_bss_info *); + +#ifdef CONFIG_DEBUG_FS +void mwifiex_debugfs_init(void); +void mwifiex_debugfs_remove(void); + +void mwifiex_dev_debugfs_init(struct mwifiex_private *priv); +void mwifiex_dev_debugfs_remove(struct mwifiex_private *priv); +#endif +#endif /* !_MWIFIEX_MAIN_H_ */ diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c new file mode 100644 index 000000000000..5c22860fb40a --- /dev/null +++ b/drivers/net/wireless/mwifiex/scan.c @@ -0,0 +1,3025 @@ +/* + * Marvell Wireless LAN device driver: scan ioctl and command handling + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "11n.h" +#include "cfg80211.h" + +/* The maximum number of channels the firmware can scan per command */ +#define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN 14 + +#define MWIFIEX_CHANNELS_PER_SCAN_CMD 4 + +/* Memory needed to store a max sized Channel List TLV for a firmware scan */ +#define CHAN_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_header) \ + + (MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN \ + *sizeof(struct mwifiex_chan_scan_param_set))) + +/* Memory needed to store supported rate */ +#define RATE_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_rates_param_set) \ + + HOSTCMD_SUPPORTED_RATES) + +/* Memory needed to store a max number/size WildCard SSID TLV for a firmware + scan */ +#define WILDCARD_SSID_TLV_MAX_SIZE \ + (MWIFIEX_MAX_SSID_LIST_LENGTH * \ + (sizeof(struct mwifiex_ie_types_wildcard_ssid_params) \ + + IEEE80211_MAX_SSID_LEN)) + +/* Maximum memory needed for a mwifiex_scan_cmd_config with all TLVs at max */ +#define MAX_SCAN_CFG_ALLOC (sizeof(struct mwifiex_scan_cmd_config) \ + + sizeof(struct mwifiex_ie_types_num_probes) \ + + sizeof(struct mwifiex_ie_types_htcap) \ + + CHAN_TLV_MAX_SIZE \ + + RATE_TLV_MAX_SIZE \ + + WILDCARD_SSID_TLV_MAX_SIZE) + + +union mwifiex_scan_cmd_config_tlv { + /* Scan configuration (variable length) */ + struct mwifiex_scan_cmd_config config; + /* Max allocated block */ + u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC]; +}; + +enum cipher_suite { + CIPHER_SUITE_TKIP, + CIPHER_SUITE_CCMP, + CIPHER_SUITE_MAX +}; +static u8 mwifiex_wpa_oui[CIPHER_SUITE_MAX][4] = { + { 0x00, 0x50, 0xf2, 0x02 }, /* TKIP */ + { 0x00, 0x50, 0xf2, 0x04 }, /* AES */ +}; +static u8 mwifiex_rsn_oui[CIPHER_SUITE_MAX][4] = { + { 0x00, 0x0f, 0xac, 0x02 }, /* TKIP */ + { 0x00, 0x0f, 0xac, 0x04 }, /* AES */ +}; + +/* + * This function parses a given IE for a given OUI. + * + * This is used to parse a WPA/RSN IE to find if it has + * a given oui in PTK. + */ +static u8 +mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui) +{ + u8 count; + + count = iebody->ptk_cnt[0]; + + /* There could be multiple OUIs for PTK hence + 1) Take the length. + 2) Check all the OUIs for AES. + 3) If one of them is AES then pass success. */ + while (count) { + if (!memcmp(iebody->ptk_body, oui, sizeof(iebody->ptk_body))) + return MWIFIEX_OUI_PRESENT; + + --count; + if (count) + iebody = (struct ie_body *) ((u8 *) iebody + + sizeof(iebody->ptk_body)); + } + + pr_debug("info: %s: OUI is not found in PTK\n", __func__); + return MWIFIEX_OUI_NOT_PRESENT; +} + +/* + * This function checks if a given OUI is present in a RSN IE. + * + * The function first checks if a RSN IE is present or not in the + * BSS descriptor. It tries to locate the OUI only if such an IE is + * present. + */ +static u8 +mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) +{ + u8 *oui; + struct ie_body *iebody; + u8 ret = MWIFIEX_OUI_NOT_PRESENT; + + if (((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)). + ieee_hdr.element_id == WLAN_EID_RSN))) { + iebody = (struct ie_body *) + (((u8 *) bss_desc->bcn_rsn_ie->data) + + RSN_GTK_OUI_OFFSET); + oui = &mwifiex_rsn_oui[cipher][0]; + ret = mwifiex_search_oui_in_ie(iebody, oui); + if (ret) + return ret; + } + return ret; +} + +/* + * This function checks if a given OUI is present in a WPA IE. + * + * The function first checks if a WPA IE is present or not in the + * BSS descriptor. It tries to locate the OUI only if such an IE is + * present. + */ +static u8 +mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) +{ + u8 *oui; + struct ie_body *iebody; + u8 ret = MWIFIEX_OUI_NOT_PRESENT; + + if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id == WLAN_EID_WPA))) { + iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data; + oui = &mwifiex_wpa_oui[cipher][0]; + ret = mwifiex_search_oui_in_ie(iebody, oui); + if (ret) + return ret; + } + return ret; +} + +/* + * This function compares two SSIDs and checks if they match. + */ +s32 +mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, + struct mwifiex_802_11_ssid *ssid2) +{ + if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len)) + return -1; + return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len); +} + +/* + * Sends IOCTL request to get the best BSS. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_find_best_bss(struct mwifiex_private *priv, + struct mwifiex_ssid_bssid *ssid_bssid) +{ + struct mwifiex_ssid_bssid tmp_ssid_bssid; + u8 *mac; + + if (!ssid_bssid) + return -1; + + memcpy(&tmp_ssid_bssid, ssid_bssid, + sizeof(struct mwifiex_ssid_bssid)); + + if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) { + memcpy(ssid_bssid, &tmp_ssid_bssid, + sizeof(struct mwifiex_ssid_bssid)); + mac = (u8 *) &ssid_bssid->bssid; + dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s," + " %pM\n", ssid_bssid->ssid.ssid, mac); + return 0; + } + + return -1; +} + +/* + * Sends IOCTL request to start a scan with user configurations. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + * + * Upon completion, it also generates a wireless event to notify + * applications. + */ +int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, + struct mwifiex_user_scan_cfg *scan_req) +{ + int status; + + priv->adapter->cmd_wait_q.condition = false; + + status = mwifiex_scan_networks(priv, scan_req); + if (!status) + status = mwifiex_wait_queue_complete(priv->adapter); + + return status; +} + +/* + * This function checks if wapi is enabled in driver and scanned network is + * compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_wapi(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wapi_enabled && + (bss_desc->bcn_wapi_ie && + ((*(bss_desc->bcn_wapi_ie)).ieee_hdr.element_id == + WLAN_EID_BSS_AC_ACCESS_DELAY))) { + return true; + } + return false; +} + +/* + * This function checks if driver is configured with no security mode and + * scanned network is compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && ((!bss_desc->bcn_wpa_ie) || + ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != + WLAN_EID_WPA)) + && ((!bss_desc->bcn_rsn_ie) || + ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != + WLAN_EID_RSN)) + && !priv->sec_info.encryption_mode + && !bss_desc->privacy) { + return true; + } + return false; +} + +/* + * This function checks if static WEP is enabled in driver and scanned network + * is compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED + && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && bss_desc->privacy) { + return true; + } + return false; +} + +/* + * This function checks if wpa is enabled in driver and scanned network is + * compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + int index) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr. + element_id == WLAN_EID_WPA)) + /* + * Privacy bit may NOT be set in some APs like + * LinkSys WRT54G && bss_desc->privacy + */ + ) { + dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d" + " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " + "EncMode=%#x privacy=%#x\n", __func__, index, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)). + ieee_hdr.element_id : 0, + (priv->sec_info.wep_status == + MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", + (priv->sec_info.wpa_enabled) ? "e" : "d", + (priv->sec_info.wpa2_enabled) ? "e" : "d", + priv->sec_info.encryption_mode, + bss_desc->privacy); + return true; + } + return false; +} + +/* + * This function checks if wpa2 is enabled in driver and scanned network is + * compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + int index) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled + && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. + element_id == WLAN_EID_RSN)) + /* + * Privacy bit may NOT be set in some APs like + * LinkSys WRT54G && bss_desc->privacy + */ + ) { + dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d" + " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " + "EncMode=%#x privacy=%#x\n", __func__, index, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)). + ieee_hdr.element_id : 0, + (priv->sec_info.wep_status == + MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", + (priv->sec_info.wpa_enabled) ? "e" : "d", + (priv->sec_info.wpa2_enabled) ? "e" : "d", + priv->sec_info.encryption_mode, + bss_desc->privacy); + return true; + } + return false; +} + +/* + * This function checks if adhoc AES is enabled in driver and scanned network is + * compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr. + element_id != WLAN_EID_WPA)) + && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. + element_id != WLAN_EID_RSN)) + && !priv->sec_info.encryption_mode + && bss_desc->privacy) { + return true; + } + return false; +} + +/* + * This function checks if dynamic WEP is enabled in driver and scanned network + * is compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + int index) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr. + element_id != WLAN_EID_WPA)) + && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. + element_id != WLAN_EID_RSN)) + && priv->sec_info.encryption_mode + && bss_desc->privacy) { + dev_dbg(priv->adapter->dev, "info: %s: dynamic " + "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x " + "EncMode=%#x privacy=%#x\n", + __func__, index, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)). + ieee_hdr.element_id : 0, + priv->sec_info.encryption_mode, + bss_desc->privacy); + return true; + } + return false; +} + +/* + * This function checks if a scanned network is compatible with the driver + * settings. + * + * WEP WPA WPA2 ad-hoc encrypt Network + * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible + * 0 0 0 0 NONE 0 0 0 yes No security + * 0 1 0 0 x 1x 1 x yes WPA (disable + * HT if no AES) + * 0 0 1 0 x 1x x 1 yes WPA2 (disable + * HT if no AES) + * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES + * 1 0 0 0 NONE 1 0 0 yes Static WEP + * (disable HT) + * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP + * + * Compatibility is not matched while roaming, except for mode. + */ +static s32 +mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *bss_desc; + + bss_desc = &adapter->scan_table[index]; + bss_desc->disable_11n = false; + + /* Don't check for compatibility if roaming */ + if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION) + && (bss_desc->bss_mode == NL80211_IFTYPE_STATION)) + return index; + + if (priv->wps.session_enable) { + dev_dbg(adapter->dev, + "info: return success directly in WPS period\n"); + return index; + } + + if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) { + dev_dbg(adapter->dev, "info: return success for WAPI AP\n"); + return index; + } + + if (bss_desc->bss_mode == mode) { + if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) { + /* No security */ + return index; + } else if (mwifiex_is_network_compatible_for_static_wep(priv, + bss_desc)) { + /* Static WEP enabled */ + dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n"); + bss_desc->disable_11n = true; + return index; + } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc, + index)) { + /* WPA enabled */ + if (((priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN) + && bss_desc->bcn_ht_cap) + && !mwifiex_is_wpa_oui_present(bss_desc, + CIPHER_SUITE_CCMP)) { + + if (mwifiex_is_wpa_oui_present(bss_desc, + CIPHER_SUITE_TKIP)) { + dev_dbg(adapter->dev, + "info: Disable 11n if AES " + "is not supported by AP\n"); + bss_desc->disable_11n = true; + } else { + return -1; + } + } + return index; + } else if (mwifiex_is_network_compatible_for_wpa2(priv, + bss_desc, index)) { + /* WPA2 enabled */ + if (((priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN) + && bss_desc->bcn_ht_cap) + && !mwifiex_is_rsn_oui_present(bss_desc, + CIPHER_SUITE_CCMP)) { + + if (mwifiex_is_rsn_oui_present(bss_desc, + CIPHER_SUITE_TKIP)) { + dev_dbg(adapter->dev, + "info: Disable 11n if AES " + "is not supported by AP\n"); + bss_desc->disable_11n = true; + } else { + return -1; + } + } + return index; + } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv, + bss_desc)) { + /* Ad-hoc AES enabled */ + return index; + } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv, + bss_desc, index)) { + /* Dynamic WEP enabled */ + return index; + } + + /* Security doesn't match */ + dev_dbg(adapter->dev, "info: %s: failed: index=%d " + "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode" + "=%#x privacy=%#x\n", + __func__, index, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)).vend_hdr. + element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)).ieee_hdr. + element_id : 0, + (priv->sec_info.wep_status == + MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", + (priv->sec_info.wpa_enabled) ? "e" : "d", + (priv->sec_info.wpa2_enabled) ? "e" : "d", + priv->sec_info.encryption_mode, bss_desc->privacy); + return -1; + } + + /* Mode doesn't match */ + return -1; +} + +/* + * This function finds the best SSID in the scan list. + * + * It searches the scan table for the best SSID that also matches the current + * adapter network preference (mode, security etc.). + */ +static s32 +mwifiex_find_best_network_in_list(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u32 mode = priv->bss_mode; + s32 best_net = -1; + s32 best_rssi = 0; + u32 i; + + dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n", + adapter->num_in_scan_table); + + for (i = 0; i < adapter->num_in_scan_table; i++) { + switch (mode) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + if (mwifiex_is_network_compatible(priv, i, mode) >= 0) { + if (SCAN_RSSI(adapter->scan_table[i].rssi) > + best_rssi) { + best_rssi = SCAN_RSSI(adapter-> + scan_table[i].rssi); + best_net = i; + } + } + break; + case NL80211_IFTYPE_UNSPECIFIED: + default: + if (SCAN_RSSI(adapter->scan_table[i].rssi) > + best_rssi) { + best_rssi = SCAN_RSSI(adapter->scan_table[i]. + rssi); + best_net = i; + } + break; + } + } + + return best_net; +} + +/* + * This function creates a channel list for the driver to scan, based + * on region/band information. + * + * This routine is used for any scan that is not provided with a + * specific channel list to scan. + */ +static void +mwifiex_scan_create_channel_list(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg + *user_scan_in, + struct mwifiex_chan_scan_param_set + *scan_chan_list, + u8 filtered_scan) +{ + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + struct mwifiex_adapter *adapter = priv->adapter; + int chan_idx = 0, i; + u8 scan_type; + + for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) { + + if (!priv->wdev->wiphy->bands[band]) + continue; + + sband = priv->wdev->wiphy->bands[band]; + + for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + scan_chan_list[chan_idx].radio_type = band; + scan_type = ch->flags & IEEE80211_CHAN_PASSIVE_SCAN; + if (user_scan_in && + user_scan_in->chan_list[0].scan_time) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16((u16) user_scan_in-> + chan_list[0].scan_time); + else if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->passive_scan_time); + else + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->active_scan_time); + if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + scan_chan_list[chan_idx].chan_scan_mode_bitmap + |= MWIFIEX_PASSIVE_SCAN; + else + scan_chan_list[chan_idx].chan_scan_mode_bitmap + &= ~MWIFIEX_PASSIVE_SCAN; + scan_chan_list[chan_idx].chan_number = + (u32) ch->hw_value; + if (filtered_scan) { + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->specific_scan_time); + scan_chan_list[chan_idx].chan_scan_mode_bitmap + |= MWIFIEX_DISABLE_CHAN_FILT; + } + } + + } +} + +/* + * This function constructs and sends multiple scan config commands to + * the firmware. + * + * Previous routines in the code flow have created a scan command configuration + * with any requested TLVs. This function splits the channel TLV into maximum + * channels supported per scan lists and sends the portion of the channel TLV, + * along with the other TLVs, to the firmware. + */ +static int +mwifiex_scan_channel_list(struct mwifiex_private *priv, + u32 max_chan_per_scan, u8 filtered_scan, + struct mwifiex_scan_cmd_config *scan_cfg_out, + struct mwifiex_ie_types_chan_list_param_set + *chan_tlv_out, + struct mwifiex_chan_scan_param_set *scan_chan_list) +{ + int ret = 0; + struct mwifiex_chan_scan_param_set *tmp_chan_list; + struct mwifiex_chan_scan_param_set *start_chan; + + u32 tlv_idx; + u32 total_scan_time; + u32 done_early; + + if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) { + dev_dbg(priv->adapter->dev, + "info: Scan: Null detect: %p, %p, %p\n", + scan_cfg_out, chan_tlv_out, scan_chan_list); + return -1; + } + + chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + + /* Set the temp channel struct pointer to the start of the desired + list */ + tmp_chan_list = scan_chan_list; + + /* Loop through the desired channel list, sending a new firmware scan + commands for each max_chan_per_scan channels (or for 1,6,11 + individually if configured accordingly) */ + while (tmp_chan_list->chan_number) { + + tlv_idx = 0; + total_scan_time = 0; + chan_tlv_out->header.len = 0; + start_chan = tmp_chan_list; + done_early = false; + + /* + * Construct the Channel TLV for the scan command. Continue to + * insert channel TLVs until: + * - the tlv_idx hits the maximum configured per scan command + * - the next channel to insert is 0 (end of desired channel + * list) + * - done_early is set (controlling individual scanning of + * 1,6,11) + */ + while (tlv_idx < max_chan_per_scan + && tmp_chan_list->chan_number && !done_early) { + + dev_dbg(priv->adapter->dev, + "info: Scan: Chan(%3d), Radio(%d)," + " Mode(%d, %d), Dur(%d)\n", + tmp_chan_list->chan_number, + tmp_chan_list->radio_type, + tmp_chan_list->chan_scan_mode_bitmap + & MWIFIEX_PASSIVE_SCAN, + (tmp_chan_list->chan_scan_mode_bitmap + & MWIFIEX_DISABLE_CHAN_FILT) >> 1, + le16_to_cpu(tmp_chan_list->max_scan_time)); + + /* Copy the current channel TLV to the command being + prepared */ + memcpy(chan_tlv_out->chan_scan_param + tlv_idx, + tmp_chan_list, + sizeof(chan_tlv_out->chan_scan_param)); + + /* Increment the TLV header length by the size + appended */ + chan_tlv_out->header.len = + cpu_to_le16(le16_to_cpu(chan_tlv_out->header.len) + + (sizeof(chan_tlv_out->chan_scan_param))); + + /* + * The tlv buffer length is set to the number of bytes + * of the between the channel tlv pointer and the start + * of the tlv buffer. This compensates for any TLVs + * that were appended before the channel list. + */ + scan_cfg_out->tlv_buf_len = (u32) ((u8 *) chan_tlv_out - + scan_cfg_out->tlv_buf); + + /* Add the size of the channel tlv header and the data + length */ + scan_cfg_out->tlv_buf_len += + (sizeof(chan_tlv_out->header) + + le16_to_cpu(chan_tlv_out->header.len)); + + /* Increment the index to the channel tlv we are + constructing */ + tlv_idx++; + + /* Count the total scan time per command */ + total_scan_time += + le16_to_cpu(tmp_chan_list->max_scan_time); + + done_early = false; + + /* Stop the loop if the *current* channel is in the + 1,6,11 set and we are not filtering on a BSSID + or SSID. */ + if (!filtered_scan && (tmp_chan_list->chan_number == 1 + || tmp_chan_list->chan_number == 6 + || tmp_chan_list->chan_number == 11)) + done_early = true; + + /* Increment the tmp pointer to the next channel to + be scanned */ + tmp_chan_list++; + + /* Stop the loop if the *next* channel is in the 1,6,11 + set. This will cause it to be the only channel + scanned on the next interation */ + if (!filtered_scan && (tmp_chan_list->chan_number == 1 + || tmp_chan_list->chan_number == 6 + || tmp_chan_list->chan_number == 11)) + done_early = true; + } + + /* The total scan time should be less than scan command timeout + value */ + if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) { + dev_err(priv->adapter->dev, "total scan time %dms" + " is over limit (%dms), scan skipped\n", + total_scan_time, MWIFIEX_MAX_TOTAL_SCAN_TIME); + ret = -1; + break; + } + + priv->adapter->scan_channels = start_chan; + + /* Send the scan command to the firmware with the specified + cfg */ + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SCAN, + HostCmd_ACT_GEN_SET, 0, + scan_cfg_out); + if (ret) + break; + } + + if (ret) + return -1; + + return 0; +} + +/* + * This function constructs a scan command configuration structure to use + * in scan commands. + * + * Application layer or other functions can invoke network scanning + * with a scan configuration supplied in a user scan configuration structure. + * This structure is used as the basis of one or many scan command configuration + * commands that are sent to the command processing module and eventually to the + * firmware. + * + * This function creates a scan command configuration structure based on the + * following user supplied parameters (if present): + * - SSID filter + * - BSSID filter + * - Number of Probes to be sent + * - Channel list + * + * If the SSID or BSSID filter is not present, the filter is disabled/cleared. + * If the number of probes is not set, adapter default setting is used. + */ +static void +mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg *user_scan_in, + struct mwifiex_scan_cmd_config *scan_cfg_out, + struct mwifiex_ie_types_chan_list_param_set + **chan_list_out, + struct mwifiex_chan_scan_param_set + *scan_chan_list, + u8 *max_chan_per_scan, u8 *filtered_scan, + u8 *scan_current_only) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_ie_types_num_probes *num_probes_tlv; + struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; + struct mwifiex_ie_types_rates_param_set *rates_tlv; + const u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + u8 *tlv_pos; + u32 num_probes; + u32 ssid_len; + u32 chan_idx; + u32 scan_type; + u16 scan_dur; + u8 channel; + u8 radio_type; + u32 ssid_idx; + u8 ssid_filter; + u8 rates[MWIFIEX_SUPPORTED_RATES]; + u32 rates_size; + struct mwifiex_ie_types_htcap *ht_cap; + + /* The tlv_buf_len is calculated for each scan command. The TLVs added + in this routine will be preserved since the routine that sends the + command will append channelTLVs at *chan_list_out. The difference + between the *chan_list_out and the tlv_buf start will be used to + calculate the size of anything we add in this routine. */ + scan_cfg_out->tlv_buf_len = 0; + + /* Running tlv pointer. Assigned to chan_list_out at end of function + so later routines know where channels can be added to the command + buf */ + tlv_pos = scan_cfg_out->tlv_buf; + + /* Initialize the scan as un-filtered; the flag is later set to TRUE + below if a SSID or BSSID filter is sent in the command */ + *filtered_scan = false; + + /* Initialize the scan as not being only on the current channel. If + the channel list is customized, only contains one channel, and is + the active channel, this is set true and data flow is not halted. */ + *scan_current_only = false; + + if (user_scan_in) { + + /* Default the ssid_filter flag to TRUE, set false under + certain wildcard conditions and qualified by the existence + of an SSID list before marking the scan as filtered */ + ssid_filter = true; + + /* Set the BSS type scan filter, use Adapter setting if + unset */ + scan_cfg_out->bss_mode = + (user_scan_in->bss_mode ? (u8) user_scan_in-> + bss_mode : (u8) adapter->scan_mode); + + /* Set the number of probes to send, use Adapter setting + if unset */ + num_probes = + (user_scan_in->num_probes ? user_scan_in-> + num_probes : adapter->scan_probes); + + /* + * Set the BSSID filter to the incoming configuration, + * if non-zero. If not set, it will remain disabled + * (all zeros). + */ + memcpy(scan_cfg_out->specific_bssid, + user_scan_in->specific_bssid, + sizeof(scan_cfg_out->specific_bssid)); + + for (ssid_idx = 0; + ((ssid_idx < ARRAY_SIZE(user_scan_in->ssid_list)) + && (*user_scan_in->ssid_list[ssid_idx].ssid + || user_scan_in->ssid_list[ssid_idx].max_len)); + ssid_idx++) { + + ssid_len = strlen(user_scan_in->ssid_list[ssid_idx]. + ssid) + 1; + + wildcard_ssid_tlv = + (struct mwifiex_ie_types_wildcard_ssid_params *) + tlv_pos; + wildcard_ssid_tlv->header.type = + cpu_to_le16(TLV_TYPE_WILDCARDSSID); + wildcard_ssid_tlv->header.len = cpu_to_le16( + (u16) (ssid_len + sizeof(wildcard_ssid_tlv-> + max_ssid_length))); + wildcard_ssid_tlv->max_ssid_length = + user_scan_in->ssid_list[ssid_idx].max_len; + + memcpy(wildcard_ssid_tlv->ssid, + user_scan_in->ssid_list[ssid_idx].ssid, + ssid_len); + + tlv_pos += (sizeof(wildcard_ssid_tlv->header) + + le16_to_cpu(wildcard_ssid_tlv->header.len)); + + dev_dbg(adapter->dev, "info: scan: ssid_list[%d]: %s, %d\n", + ssid_idx, wildcard_ssid_tlv->ssid, + wildcard_ssid_tlv->max_ssid_length); + + /* Empty wildcard ssid with a maxlen will match many or + potentially all SSIDs (maxlen == 32), therefore do + not treat the scan as + filtered. */ + if (!ssid_len && wildcard_ssid_tlv->max_ssid_length) + ssid_filter = false; + + } + + /* + * The default number of channels sent in the command is low to + * ensure the response buffer from the firmware does not + * truncate scan results. That is not an issue with an SSID + * or BSSID filter applied to the scan results in the firmware. + */ + if ((ssid_idx && ssid_filter) + || memcmp(scan_cfg_out->specific_bssid, &zero_mac, + sizeof(zero_mac))) + *filtered_scan = true; + } else { + scan_cfg_out->bss_mode = (u8) adapter->scan_mode; + num_probes = adapter->scan_probes; + } + + /* + * If a specific BSSID or SSID is used, the number of channels in the + * scan command will be increased to the absolute maximum. + */ + if (*filtered_scan) + *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN; + else + *max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD; + + /* If the input config or adapter has the number of Probes set, + add tlv */ + if (num_probes) { + + dev_dbg(adapter->dev, "info: scan: num_probes = %d\n", + num_probes); + + num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos; + num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); + num_probes_tlv->header.len = + cpu_to_le16(sizeof(num_probes_tlv->num_probes)); + num_probes_tlv->num_probes = cpu_to_le16((u16) num_probes); + + tlv_pos += sizeof(num_probes_tlv->header) + + le16_to_cpu(num_probes_tlv->header.len); + + } + + /* Append rates tlv */ + memset(rates, 0, sizeof(rates)); + + rates_size = mwifiex_get_supported_rates(priv, rates); + + rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos; + rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); + rates_tlv->header.len = cpu_to_le16((u16) rates_size); + memcpy(rates_tlv->rates, rates, rates_size); + tlv_pos += sizeof(rates_tlv->header) + rates_size; + + dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size); + + if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) + && (priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN)) { + ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos; + memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); + ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); + ht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + radio_type = + mwifiex_band_to_radio_type(priv->adapter->config_bands); + mwifiex_fill_cap_info(priv, radio_type, ht_cap); + tlv_pos += sizeof(struct mwifiex_ie_types_htcap); + } + + /* Append vendor specific IE TLV */ + mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_SCAN, &tlv_pos); + + /* + * Set the output for the channel TLV to the address in the tlv buffer + * past any TLVs that were added in this function (SSID, num_probes). + * Channel TLVs will be added past this for each scan command, + * preserving the TLVs that were previously added. + */ + *chan_list_out = + (struct mwifiex_ie_types_chan_list_param_set *) tlv_pos; + + if (user_scan_in && user_scan_in->chan_list[0].chan_number) { + + dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n"); + + for (chan_idx = 0; + chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX + && user_scan_in->chan_list[chan_idx].chan_number; + chan_idx++) { + + channel = user_scan_in->chan_list[chan_idx].chan_number; + (scan_chan_list + chan_idx)->chan_number = channel; + + radio_type = + user_scan_in->chan_list[chan_idx].radio_type; + (scan_chan_list + chan_idx)->radio_type = radio_type; + + scan_type = user_scan_in->chan_list[chan_idx].scan_type; + + if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + (scan_chan_list + + chan_idx)->chan_scan_mode_bitmap + |= MWIFIEX_PASSIVE_SCAN; + else + (scan_chan_list + + chan_idx)->chan_scan_mode_bitmap + &= ~MWIFIEX_PASSIVE_SCAN; + + if (user_scan_in->chan_list[chan_idx].scan_time) { + scan_dur = (u16) user_scan_in-> + chan_list[chan_idx].scan_time; + } else { + if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + scan_dur = adapter->passive_scan_time; + else if (*filtered_scan) + scan_dur = adapter->specific_scan_time; + else + scan_dur = adapter->active_scan_time; + } + + (scan_chan_list + chan_idx)->min_scan_time = + cpu_to_le16(scan_dur); + (scan_chan_list + chan_idx)->max_scan_time = + cpu_to_le16(scan_dur); + } + + /* Check if we are only scanning the current channel */ + if ((chan_idx == 1) + && (user_scan_in->chan_list[0].chan_number + == priv->curr_bss_params.bss_descriptor.channel)) { + *scan_current_only = true; + dev_dbg(adapter->dev, + "info: Scan: Scanning current channel only\n"); + } + + } else { + dev_dbg(adapter->dev, + "info: Scan: Creating full region channel list\n"); + mwifiex_scan_create_channel_list(priv, user_scan_in, + scan_chan_list, + *filtered_scan); + } +} + +/* + * This function inspects the scan response buffer for pointers to + * expected TLVs. + * + * TLVs can be included at the end of the scan response BSS information. + * + * Data in the buffer is parsed pointers to TLVs that can potentially + * be passed back in the response. + */ +static void +mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, + struct mwifiex_ie_types_data *tlv, + u32 tlv_buf_size, u32 req_tlv_type, + struct mwifiex_ie_types_data **tlv_data) +{ + struct mwifiex_ie_types_data *current_tlv; + u32 tlv_buf_left; + u32 tlv_type; + u32 tlv_len; + + current_tlv = tlv; + tlv_buf_left = tlv_buf_size; + *tlv_data = NULL; + + dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n", + tlv_buf_size); + + while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) { + + tlv_type = le16_to_cpu(current_tlv->header.type); + tlv_len = le16_to_cpu(current_tlv->header.len); + + if (sizeof(tlv->header) + tlv_len > tlv_buf_left) { + dev_err(adapter->dev, "SCAN_RESP: TLV buffer corrupt\n"); + break; + } + + if (req_tlv_type == tlv_type) { + switch (tlv_type) { + case TLV_TYPE_TSFTIMESTAMP: + dev_dbg(adapter->dev, "info: SCAN_RESP: TSF " + "timestamp TLV, len = %d\n", tlv_len); + *tlv_data = (struct mwifiex_ie_types_data *) + current_tlv; + break; + case TLV_TYPE_CHANNELBANDLIST: + dev_dbg(adapter->dev, "info: SCAN_RESP: channel" + " band list TLV, len = %d\n", tlv_len); + *tlv_data = (struct mwifiex_ie_types_data *) + current_tlv; + break; + default: + dev_err(adapter->dev, + "SCAN_RESP: unhandled TLV = %d\n", + tlv_type); + /* Give up, this seems corrupted */ + return; + } + } + + if (*tlv_data) + break; + + + tlv_buf_left -= (sizeof(tlv->header) + tlv_len); + current_tlv = + (struct mwifiex_ie_types_data *) (current_tlv->data + + tlv_len); + + } /* while */ +} + +/* + * This function interprets a BSS scan response returned from the firmware. + * + * The various fixed fields and IEs are parsed and passed back for a BSS + * probe response or beacon from scan command. Information is recorded as + * needed in the scan table for that entry. + * + * The following IE types are recognized and parsed - + * - SSID + * - Supported rates + * - FH parameters set + * - DS parameters set + * - CF parameters set + * - IBSS parameters set + * - ERP information + * - Extended supported rates + * - Vendor specific (221) + * - RSN IE + * - WAPI IE + * - HT capability + * - HT operation + * - BSS Coexistence 20/40 + * - Extended capability + * - Overlapping BSS scan parameters + */ +static int +mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, + struct mwifiex_bssdescriptor *bss_entry, + u8 **beacon_info, u32 *bytes_left) +{ + int ret = 0; + u8 element_id; + struct ieee_types_fh_param_set *fh_param_set; + struct ieee_types_ds_param_set *ds_param_set; + struct ieee_types_cf_param_set *cf_param_set; + struct ieee_types_ibss_param_set *ibss_param_set; + __le16 beacon_interval; + __le16 capabilities; + u8 *current_ptr; + u8 *rate; + u8 element_len; + u16 total_ie_len; + u8 bytes_to_copy; + u8 rate_size; + u16 beacon_size; + u8 found_data_rate_ie; + u32 bytes_left_for_current_beacon; + struct ieee_types_vendor_specific *vendor_ie; + const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; + const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; + + found_data_rate_ie = false; + rate_size = 0; + beacon_size = 0; + + if (*bytes_left >= sizeof(beacon_size)) { + /* Extract & convert beacon size from the command buffer */ + memcpy(&beacon_size, *beacon_info, sizeof(beacon_size)); + *bytes_left -= sizeof(beacon_size); + *beacon_info += sizeof(beacon_size); + } + + if (!beacon_size || beacon_size > *bytes_left) { + *beacon_info += *bytes_left; + *bytes_left = 0; + return -1; + } + + /* Initialize the current working beacon pointer for this BSS + iteration */ + current_ptr = *beacon_info; + + /* Advance the return beacon pointer past the current beacon */ + *beacon_info += beacon_size; + *bytes_left -= beacon_size; + + bytes_left_for_current_beacon = beacon_size; + + memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN); + dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n", + bss_entry->mac_address); + + current_ptr += ETH_ALEN; + bytes_left_for_current_beacon -= ETH_ALEN; + + if (bytes_left_for_current_beacon < 12) { + dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); + return -1; + } + + /* + * Next 4 fields are RSSI, time stamp, beacon interval, + * and capability information + */ + + /* RSSI is 1 byte long */ + bss_entry->rssi = (s32) (*current_ptr); + dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr); + current_ptr += 1; + bytes_left_for_current_beacon -= 1; + + /* + * The RSSI is not part of the beacon/probe response. After we have + * advanced current_ptr past the RSSI field, save the remaining + * data for use at the application layer + */ + bss_entry->beacon_buf = current_ptr; + bss_entry->beacon_buf_size = bytes_left_for_current_beacon; + + /* Time stamp is 8 bytes long */ + memcpy(bss_entry->time_stamp, current_ptr, 8); + current_ptr += 8; + bytes_left_for_current_beacon -= 8; + + /* Beacon interval is 2 bytes long */ + memcpy(&beacon_interval, current_ptr, 2); + bss_entry->beacon_period = le16_to_cpu(beacon_interval); + current_ptr += 2; + bytes_left_for_current_beacon -= 2; + + /* Capability information is 2 bytes long */ + memcpy(&capabilities, current_ptr, 2); + dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", + capabilities); + bss_entry->cap_info_bitmap = le16_to_cpu(capabilities); + current_ptr += 2; + bytes_left_for_current_beacon -= 2; + + /* Rest of the current buffer are IE's */ + dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n", + bytes_left_for_current_beacon); + + if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { + dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n"); + bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; + } else { + bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; + } + + if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS) + bss_entry->bss_mode = NL80211_IFTYPE_ADHOC; + else + bss_entry->bss_mode = NL80211_IFTYPE_STATION; + + + /* Process variable IE */ + while (bytes_left_for_current_beacon >= 2) { + element_id = *current_ptr; + element_len = *(current_ptr + 1); + total_ie_len = element_len + sizeof(struct ieee_types_header); + + if (bytes_left_for_current_beacon < total_ie_len) { + dev_err(adapter->dev, "err: InterpretIE: in processing" + " IE, bytes left < IE length\n"); + bytes_left_for_current_beacon = 0; + ret = -1; + continue; + } + switch (element_id) { + case WLAN_EID_SSID: + bss_entry->ssid.ssid_len = element_len; + memcpy(bss_entry->ssid.ssid, (current_ptr + 2), + element_len); + dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n", + bss_entry->ssid.ssid); + break; + + case WLAN_EID_SUPP_RATES: + memcpy(bss_entry->data_rates, current_ptr + 2, + element_len); + memcpy(bss_entry->supported_rates, current_ptr + 2, + element_len); + rate_size = element_len; + found_data_rate_ie = true; + break; + + case WLAN_EID_FH_PARAMS: + fh_param_set = + (struct ieee_types_fh_param_set *) current_ptr; + memcpy(&bss_entry->phy_param_set.fh_param_set, + fh_param_set, + sizeof(struct ieee_types_fh_param_set)); + break; + + case WLAN_EID_DS_PARAMS: + ds_param_set = + (struct ieee_types_ds_param_set *) current_ptr; + + bss_entry->channel = ds_param_set->current_chan; + + memcpy(&bss_entry->phy_param_set.ds_param_set, + ds_param_set, + sizeof(struct ieee_types_ds_param_set)); + break; + + case WLAN_EID_CF_PARAMS: + cf_param_set = + (struct ieee_types_cf_param_set *) current_ptr; + memcpy(&bss_entry->ss_param_set.cf_param_set, + cf_param_set, + sizeof(struct ieee_types_cf_param_set)); + break; + + case WLAN_EID_IBSS_PARAMS: + ibss_param_set = + (struct ieee_types_ibss_param_set *) + current_ptr; + memcpy(&bss_entry->ss_param_set.ibss_param_set, + ibss_param_set, + sizeof(struct ieee_types_ibss_param_set)); + break; + + case WLAN_EID_ERP_INFO: + bss_entry->erp_flags = *(current_ptr + 2); + break; + + case WLAN_EID_EXT_SUPP_RATES: + /* + * Only process extended supported rate + * if data rate is already found. + * Data rate IE should come before + * extended supported rate IE + */ + if (found_data_rate_ie) { + if ((element_len + rate_size) > + MWIFIEX_SUPPORTED_RATES) + bytes_to_copy = + (MWIFIEX_SUPPORTED_RATES - + rate_size); + else + bytes_to_copy = element_len; + + rate = (u8 *) bss_entry->data_rates; + rate += rate_size; + memcpy(rate, current_ptr + 2, bytes_to_copy); + + rate = (u8 *) bss_entry->supported_rates; + rate += rate_size; + memcpy(rate, current_ptr + 2, bytes_to_copy); + } + break; + + case WLAN_EID_VENDOR_SPECIFIC: + vendor_ie = (struct ieee_types_vendor_specific *) + current_ptr; + + if (!memcmp + (vendor_ie->vend_hdr.oui, wpa_oui, + sizeof(wpa_oui))) { + bss_entry->bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + current_ptr; + bss_entry->wpa_offset = (u16) (current_ptr - + bss_entry->beacon_buf); + } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui, + sizeof(wmm_oui))) { + if (total_ie_len == + sizeof(struct ieee_types_wmm_parameter) + || total_ie_len == + sizeof(struct ieee_types_wmm_info)) + /* + * Only accept and copy the WMM IE if + * it matches the size expected for the + * WMM Info IE or the WMM Parameter IE. + */ + memcpy((u8 *) &bss_entry->wmm_ie, + current_ptr, total_ie_len); + } + break; + case WLAN_EID_RSN: + bss_entry->bcn_rsn_ie = + (struct ieee_types_generic *) current_ptr; + bss_entry->rsn_offset = (u16) (current_ptr - + bss_entry->beacon_buf); + break; + case WLAN_EID_BSS_AC_ACCESS_DELAY: + bss_entry->bcn_wapi_ie = + (struct ieee_types_generic *) current_ptr; + bss_entry->wapi_offset = (u16) (current_ptr - + bss_entry->beacon_buf); + break; + case WLAN_EID_HT_CAPABILITY: + bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *) + (current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->ht_cap_offset = (u16) (current_ptr + + 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 + + sizeof(struct ieee_types_header)); + bss_entry->ht_info_offset = (u16) (current_ptr + + sizeof(struct ieee_types_header) - + bss_entry->beacon_buf); + break; + case WLAN_EID_BSS_COEX_2040: + bss_entry->bcn_bss_co_2040 = (u8 *) (current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->bss_co_2040_offset = (u16) (current_ptr + + sizeof(struct ieee_types_header) - + bss_entry->beacon_buf); + break; + case WLAN_EID_EXT_CAPABILITY: + bss_entry->bcn_ext_cap = (u8 *) (current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->ext_cap_offset = (u16) (current_ptr + + sizeof(struct ieee_types_header) - + bss_entry->beacon_buf); + break; + case WLAN_EID_OVERLAP_BSS_SCAN_PARAM: + bss_entry->bcn_obss_scan = + (struct ieee_types_obss_scan_param *) + current_ptr; + bss_entry->overlap_bss_offset = (u16) (current_ptr - + bss_entry->beacon_buf); + break; + default: + break; + } + + current_ptr += element_len + 2; + + /* Need to account for IE ID and IE Len */ + bytes_left_for_current_beacon -= (element_len + 2); + + } /* while (bytes_left_for_current_beacon > 2) */ + return ret; +} + +/* + * This function adjusts the pointers used in beacon buffers to reflect + * shifts. + * + * The memory allocated for beacon buffers is of fixed sizes where all the + * saved beacons must be stored. New beacons are added in the free portion + * of this memory, space permitting; while duplicate beacon buffers are + * placed at the same start location. However, since duplicate beacon + * buffers may not match the size of the old one, all the following buffers + * in the memory must be shifted to either make space, or to fill up freed + * up space. + * + * This function is used to update the beacon buffer pointers that are past + * an existing beacon buffer that is updated with a new one of different + * size. The pointers are shifted by a fixed amount, either forward or + * backward. + * + * the following pointers in every affected beacon buffers are changed, if + * present - + * - WPA IE pointer + * - RSN IE pointer + * - WAPI IE pointer + * - HT capability IE pointer + * - HT information IE pointer + * - BSS coexistence 20/40 IE pointer + * - Extended capability IE pointer + * - Overlapping BSS scan parameter IE pointer + */ +static void +mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance, + u8 *bcn_store, u32 rem_bcn_size, + u32 num_of_ent) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u32 adj_idx; + for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) { + if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) { + + if (advance) + adapter->scan_table[adj_idx].beacon_buf += + rem_bcn_size; + else + adapter->scan_table[adj_idx].beacon_buf -= + rem_bcn_size; + + if (adapter->scan_table[adj_idx].bcn_wpa_ie) + adapter->scan_table[adj_idx].bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].wpa_offset); + if (adapter->scan_table[adj_idx].bcn_rsn_ie) + adapter->scan_table[adj_idx].bcn_rsn_ie = + (struct ieee_types_generic *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].rsn_offset); + if (adapter->scan_table[adj_idx].bcn_wapi_ie) + adapter->scan_table[adj_idx].bcn_wapi_ie = + (struct ieee_types_generic *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].wapi_offset); + if (adapter->scan_table[adj_idx].bcn_ht_cap) + adapter->scan_table[adj_idx].bcn_ht_cap = + (struct ieee80211_ht_cap *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].ht_cap_offset); + + if (adapter->scan_table[adj_idx].bcn_ht_info) + adapter->scan_table[adj_idx].bcn_ht_info = + (struct ieee80211_ht_info *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].ht_info_offset); + if (adapter->scan_table[adj_idx].bcn_bss_co_2040) + adapter->scan_table[adj_idx].bcn_bss_co_2040 = + (u8 *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].bss_co_2040_offset); + if (adapter->scan_table[adj_idx].bcn_ext_cap) + adapter->scan_table[adj_idx].bcn_ext_cap = + (u8 *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].ext_cap_offset); + if (adapter->scan_table[adj_idx].bcn_obss_scan) + adapter->scan_table[adj_idx].bcn_obss_scan = + (struct ieee_types_obss_scan_param *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].overlap_bss_offset); + } + } +} + +/* + * This function updates the pointers used in beacon buffer for given bss + * descriptor to reflect shifts + * + * Following pointers are updated + * - WPA IE pointer + * - RSN IE pointer + * - WAPI IE pointer + * - HT capability IE pointer + * - HT information IE pointer + * - BSS coexistence 20/40 IE pointer + * - Extended capability IE pointer + * - Overlapping BSS scan parameter IE pointer + */ +static void +mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon) +{ + if (beacon->bcn_wpa_ie) + beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *) + (beacon->beacon_buf + beacon->wpa_offset); + if (beacon->bcn_rsn_ie) + beacon->bcn_rsn_ie = (struct ieee_types_generic *) + (beacon->beacon_buf + beacon->rsn_offset); + if (beacon->bcn_wapi_ie) + beacon->bcn_wapi_ie = (struct ieee_types_generic *) + (beacon->beacon_buf + beacon->wapi_offset); + if (beacon->bcn_ht_cap) + beacon->bcn_ht_cap = (struct ieee80211_ht_cap *) + (beacon->beacon_buf + beacon->ht_cap_offset); + if (beacon->bcn_ht_info) + beacon->bcn_ht_info = (struct ieee80211_ht_info *) + (beacon->beacon_buf + beacon->ht_info_offset); + if (beacon->bcn_bss_co_2040) + beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf + + beacon->bss_co_2040_offset); + if (beacon->bcn_ext_cap) + beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf + + beacon->ext_cap_offset); + if (beacon->bcn_obss_scan) + beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *) + (beacon->beacon_buf + beacon->overlap_bss_offset); +} + +/* + * This function stores a beacon or probe response for a BSS returned + * in the scan. + * + * This stores a new scan response or an update for a previous scan response. + * New entries need to verify that they do not exceed the total amount of + * memory allocated for the table. + * + * Replacement entries need to take into consideration the amount of space + * currently allocated for the beacon/probe response and adjust the entry + * as needed. + * + * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved + * for an entry in case it is a beacon since a probe response for the + * network will by larger per the standard. This helps to reduce the + * amount of memory copying to fit a new probe response into an entry + * already occupied by a network's previously stored beacon. + */ +static void +mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv, + u32 beacon_idx, u32 num_of_ent, + struct mwifiex_bssdescriptor *new_beacon) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u8 *bcn_store; + u32 new_bcn_size; + u32 old_bcn_size; + u32 bcn_space; + + if (adapter->scan_table[beacon_idx].beacon_buf) { + + new_bcn_size = new_beacon->beacon_buf_size; + old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size; + bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max; + bcn_store = adapter->scan_table[beacon_idx].beacon_buf; + + /* Set the max to be the same as current entry unless changed + below */ + new_beacon->beacon_buf_size_max = bcn_space; + if (new_bcn_size == old_bcn_size) { + /* + * Beacon is the same size as the previous entry. + * Replace the previous contents with the scan result + */ + memcpy(bcn_store, new_beacon->beacon_buf, + new_beacon->beacon_buf_size); + + } else if (new_bcn_size <= bcn_space) { + /* + * New beacon size will fit in the amount of space + * we have previously allocated for it + */ + + /* Copy the new beacon buffer entry over the old one */ + memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); + + /* + * If the old beacon size was less than the maximum + * we had alloted for the entry, and the new entry + * is even smaller, reset the max size to the old + * beacon entry and compress the storage space + * (leaving a new pad space of (old_bcn_size - + * new_bcn_size). + */ + if (old_bcn_size < bcn_space + && new_bcn_size <= old_bcn_size) { + /* + * Old Beacon size is smaller than the alloted + * storage size. Shrink the alloted storage + * space. + */ + dev_dbg(adapter->dev, "info: AppControl:" + " smaller duplicate beacon " + "(%d), old = %d, new = %d, space = %d," + "left = %d\n", + beacon_idx, old_bcn_size, new_bcn_size, + bcn_space, + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - + adapter->bcn_buf))); + + /* + * memmove (since the memory overlaps) the + * data after the beacon we just stored to the + * end of the current beacon. This cleans up + * any unused space the old larger beacon was + * using in the buffer + */ + memmove(bcn_store + old_bcn_size, + bcn_store + bcn_space, + adapter->bcn_buf_end - (bcn_store + + bcn_space)); + + /* + * Decrement the end pointer by the difference + * between the old larger size and the new + * smaller size since we are using less space + * due to the new beacon being smaller + */ + adapter->bcn_buf_end -= + (bcn_space - old_bcn_size); + + /* Set the maximum storage size to the old + beacon size */ + new_beacon->beacon_buf_size_max = old_bcn_size; + + /* Adjust beacon buffer pointers that are past + the current */ + mwifiex_adjust_beacon_buffer_ptrs(priv, 0, + bcn_store, (bcn_space - old_bcn_size), + num_of_ent); + } + } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space) + < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) { + /* + * Beacon is larger than space previously allocated + * (bcn_space) and there is enough space left in the + * beaconBuffer to store the additional data + */ + dev_dbg(adapter->dev, "info: AppControl:" + " larger duplicate beacon (%d), " + "old = %d, new = %d, space = %d, left = %d\n", + beacon_idx, old_bcn_size, new_bcn_size, + bcn_space, + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - + adapter->bcn_buf))); + + /* + * memmove (since the memory overlaps) the data + * after the beacon we just stored to the end of + * the current beacon. This moves the data for + * the beacons after this further in memory to + * make space for the new larger beacon we are + * about to copy in. + */ + memmove(bcn_store + new_bcn_size, + bcn_store + bcn_space, + adapter->bcn_buf_end - (bcn_store + bcn_space)); + + /* Copy the new beacon buffer entry over the old one */ + memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); + + /* Move the beacon end pointer by the amount of new + beacon data we are adding */ + adapter->bcn_buf_end += (new_bcn_size - bcn_space); + + /* + * This entry is bigger than the alloted max space + * previously reserved. Increase the max space to + * be equal to the new beacon size + */ + new_beacon->beacon_buf_size_max = new_bcn_size; + + /* Adjust beacon buffer pointers that are past the + current */ + mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store, + (new_bcn_size - bcn_space), + num_of_ent); + } else { + /* + * Beacon is larger than the previously allocated space, + * but there is not enough free space to store the + * additional data. + */ + dev_err(adapter->dev, "AppControl: larger duplicate " + " beacon (%d), old = %d new = %d, space = %d," + " left = %d\n", beacon_idx, old_bcn_size, + new_bcn_size, bcn_space, + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - adapter->bcn_buf))); + + /* Storage failure, keep old beacon intact */ + new_beacon->beacon_buf_size = old_bcn_size; + if (new_beacon->bcn_wpa_ie) + new_beacon->wpa_offset = + adapter->scan_table[beacon_idx]. + wpa_offset; + if (new_beacon->bcn_rsn_ie) + new_beacon->rsn_offset = + adapter->scan_table[beacon_idx]. + rsn_offset; + if (new_beacon->bcn_wapi_ie) + new_beacon->wapi_offset = + adapter->scan_table[beacon_idx]. + wapi_offset; + if (new_beacon->bcn_ht_cap) + new_beacon->ht_cap_offset = + adapter->scan_table[beacon_idx]. + ht_cap_offset; + if (new_beacon->bcn_ht_info) + new_beacon->ht_info_offset = + adapter->scan_table[beacon_idx]. + ht_info_offset; + if (new_beacon->bcn_bss_co_2040) + new_beacon->bss_co_2040_offset = + adapter->scan_table[beacon_idx]. + bss_co_2040_offset; + if (new_beacon->bcn_ext_cap) + new_beacon->ext_cap_offset = + adapter->scan_table[beacon_idx]. + ext_cap_offset; + if (new_beacon->bcn_obss_scan) + new_beacon->overlap_bss_offset = + adapter->scan_table[beacon_idx]. + overlap_bss_offset; + } + /* Point the new entry to its permanent storage space */ + new_beacon->beacon_buf = bcn_store; + mwifiex_update_beacon_buffer_ptrs(new_beacon); + } else { + /* + * No existing beacon data exists for this entry, check to see + * if we can fit it in the remaining space + */ + if (adapter->bcn_buf_end + new_beacon->beacon_buf_size + + SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf + + sizeof(adapter->bcn_buf))) { + + /* + * Copy the beacon buffer data from the local entry to + * the adapter dev struct buffer space used to store + * the raw beacon data for each entry in the scan table + */ + memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf, + new_beacon->beacon_buf_size); + + /* Update the beacon ptr to point to the table save + area */ + new_beacon->beacon_buf = adapter->bcn_buf_end; + new_beacon->beacon_buf_size_max = + (new_beacon->beacon_buf_size + + SCAN_BEACON_ENTRY_PAD); + + mwifiex_update_beacon_buffer_ptrs(new_beacon); + + /* Increment the end pointer by the size reserved */ + adapter->bcn_buf_end += new_beacon->beacon_buf_size_max; + + dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]" + " sz=%03d, used = %04d, left = %04d\n", + beacon_idx, + new_beacon->beacon_buf_size, + (int)(adapter->bcn_buf_end - adapter->bcn_buf), + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - + adapter->bcn_buf))); + } else { + /* No space for new beacon */ + dev_dbg(adapter->dev, "info: AppControl: no space for" + " beacon (%d): %pM sz=%03d, left=%03d\n", + beacon_idx, new_beacon->mac_address, + new_beacon->beacon_buf_size, + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - + adapter->bcn_buf))); + + /* Storage failure; clear storage records for this + bcn */ + new_beacon->beacon_buf = NULL; + new_beacon->beacon_buf_size = 0; + new_beacon->beacon_buf_size_max = 0; + new_beacon->bcn_wpa_ie = NULL; + new_beacon->wpa_offset = 0; + new_beacon->bcn_rsn_ie = NULL; + new_beacon->rsn_offset = 0; + new_beacon->bcn_wapi_ie = NULL; + new_beacon->wapi_offset = 0; + new_beacon->bcn_ht_cap = NULL; + new_beacon->ht_cap_offset = 0; + new_beacon->bcn_ht_info = NULL; + new_beacon->ht_info_offset = 0; + new_beacon->bcn_bss_co_2040 = NULL; + new_beacon->bss_co_2040_offset = 0; + new_beacon->bcn_ext_cap = NULL; + new_beacon->ext_cap_offset = 0; + new_beacon->bcn_obss_scan = NULL; + new_beacon->overlap_bss_offset = 0; + } + } +} + +/* + * This function restores a beacon buffer of the current BSS descriptor. + */ +static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *curr_bss = + &priv->curr_bss_params.bss_descriptor; + unsigned long flags; + + if (priv->curr_bcn_buf && + ((adapter->bcn_buf_end + priv->curr_bcn_size) < + (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) { + spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); + + /* restore the current beacon buffer */ + memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf, + priv->curr_bcn_size); + curr_bss->beacon_buf = adapter->bcn_buf_end; + curr_bss->beacon_buf_size = priv->curr_bcn_size; + adapter->bcn_buf_end += priv->curr_bcn_size; + + /* adjust the pointers in the current BSS descriptor */ + if (curr_bss->bcn_wpa_ie) + curr_bss->bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (curr_bss->beacon_buf + + curr_bss->wpa_offset); + + if (curr_bss->bcn_rsn_ie) + curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) + (curr_bss->beacon_buf + + curr_bss->rsn_offset); + + if (curr_bss->bcn_ht_cap) + curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) + (curr_bss->beacon_buf + + curr_bss->ht_cap_offset); + + if (curr_bss->bcn_ht_info) + curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) + (curr_bss->beacon_buf + + curr_bss->ht_info_offset); + + if (curr_bss->bcn_bss_co_2040) + curr_bss->bcn_bss_co_2040 = + (u8 *) (curr_bss->beacon_buf + + curr_bss->bss_co_2040_offset); + + if (curr_bss->bcn_ext_cap) + curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf + + curr_bss->ext_cap_offset); + + if (curr_bss->bcn_obss_scan) + curr_bss->bcn_obss_scan = + (struct ieee_types_obss_scan_param *) + (curr_bss->beacon_buf + + curr_bss->overlap_bss_offset); + + spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); + + dev_dbg(adapter->dev, "info: current beacon restored %d\n", + priv->curr_bcn_size); + } else { + dev_warn(adapter->dev, + "curr_bcn_buf not saved or bcn_buf has no space\n"); + } +} + +/* + * This function post processes the scan table after a new scan command has + * completed. + * + * It inspects each entry of the scan table and tries to find an entry that + * matches with our current associated/joined network from the scan. If + * one is found, the stored copy of the BSS descriptor of our current network + * is updated. + * + * It also debug dumps the current scan table contents after processing is over. + */ +static void +mwifiex_process_scan_results(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + s32 j; + u32 i; + unsigned long flags; + + if (priv->media_connected) { + + j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params. + bss_descriptor.ssid, + priv->curr_bss_params. + bss_descriptor.mac_address, + priv->bss_mode); + + if (j >= 0) { + spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); + priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL; + priv->curr_bss_params.bss_descriptor.wpa_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL; + priv->curr_bss_params.bss_descriptor.rsn_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL; + priv->curr_bss_params.bss_descriptor.wapi_offset = 0; + 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.ht_info_offset = + 0; + priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = + NULL; + priv->curr_bss_params.bss_descriptor. + bss_co_2040_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL; + priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0; + priv->curr_bss_params.bss_descriptor. + bcn_obss_scan = NULL; + priv->curr_bss_params.bss_descriptor. + overlap_bss_offset = 0; + priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; + priv->curr_bss_params.bss_descriptor.beacon_buf_size = + 0; + priv->curr_bss_params.bss_descriptor. + beacon_buf_size_max = 0; + + dev_dbg(adapter->dev, "info: Found current ssid/bssid" + " in list @ index #%d\n", j); + /* Make a copy of current BSSID descriptor */ + memcpy(&priv->curr_bss_params.bss_descriptor, + &adapter->scan_table[j], + sizeof(priv->curr_bss_params.bss_descriptor)); + + mwifiex_save_curr_bcn(priv); + spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); + + } else { + mwifiex_restore_curr_bcn(priv); + } + } + + for (i = 0; i < adapter->num_in_scan_table; i++) + dev_dbg(adapter->dev, "info: scan:(%02d) %pM " + "RSSI[%03d], SSID[%s]\n", + i, adapter->scan_table[i].mac_address, + (s32) adapter->scan_table[i].rssi, + adapter->scan_table[i].ssid.ssid); +} + +/* + * This function converts radio type scan parameter to a band configuration + * to be used in join command. + */ +static u8 +mwifiex_radio_type_to_band(u8 radio_type) +{ + switch (radio_type) { + case HostCmd_SCAN_RADIO_TYPE_A: + return BAND_A; + case HostCmd_SCAN_RADIO_TYPE_BG: + default: + return BAND_G; + } +} + +/* + * This function deletes a specific indexed entry from the scan table. + * + * This also compacts the remaining entries and adjusts any buffering + * of beacon/probe response data if needed. + */ +static void +mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u32 del_idx; + u32 beacon_buf_adj; + u8 *beacon_buf; + + /* + * Shift the saved beacon buffer data for the scan table back over the + * entry being removed. Update the end of buffer pointer. Save the + * deleted buffer allocation size for pointer adjustments for entries + * compacted after the deleted index. + */ + beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max; + + dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer " + "removal = %d bytes\n", table_idx, beacon_buf_adj); + + /* Check if the table entry had storage allocated for its beacon */ + if (beacon_buf_adj) { + beacon_buf = adapter->scan_table[table_idx].beacon_buf; + + /* + * Remove the entry's buffer space, decrement the table end + * pointer by the amount we are removing + */ + adapter->bcn_buf_end -= beacon_buf_adj; + + dev_dbg(adapter->dev, "info: scan: delete entry %d," + " compact data: %p <- %p (sz = %d)\n", + table_idx, beacon_buf, + beacon_buf + beacon_buf_adj, + (int)(adapter->bcn_buf_end - beacon_buf)); + + /* + * Compact data storage. Copy all data after the deleted + * entry's end address (beacon_buf + beacon_buf_adj) back + * to the original start address (beacon_buf). + * + * Scan table entries affected by the move will have their + * entry pointer adjusted below. + * + * Use memmove since the dest/src memory regions overlap. + */ + memmove(beacon_buf, beacon_buf + beacon_buf_adj, + adapter->bcn_buf_end - beacon_buf); + } + + dev_dbg(adapter->dev, + "info: Scan: Delete Entry %d, num_in_scan_table = %d\n", + table_idx, adapter->num_in_scan_table); + + /* Shift all of the entries after the table_idx back by one, compacting + the table and removing the requested entry */ + for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table; + del_idx++) { + /* Copy the next entry over this one */ + memcpy(adapter->scan_table + del_idx, + adapter->scan_table + del_idx + 1, + sizeof(struct mwifiex_bssdescriptor)); + + /* + * Adjust this entry's pointer to its beacon buffer based on + * the removed/compacted entry from the deleted index. Don't + * decrement if the buffer pointer is NULL (no data stored for + * this entry). + */ + if (adapter->scan_table[del_idx].beacon_buf) { + adapter->scan_table[del_idx].beacon_buf -= + beacon_buf_adj; + if (adapter->scan_table[del_idx].bcn_wpa_ie) + adapter->scan_table[del_idx].bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (adapter->scan_table[del_idx]. + beacon_buf + + adapter->scan_table[del_idx]. + wpa_offset); + if (adapter->scan_table[del_idx].bcn_rsn_ie) + adapter->scan_table[del_idx].bcn_rsn_ie = + (struct ieee_types_generic *) + (adapter->scan_table[del_idx]. + beacon_buf + + adapter->scan_table[del_idx]. + rsn_offset); + if (adapter->scan_table[del_idx].bcn_wapi_ie) + adapter->scan_table[del_idx].bcn_wapi_ie = + (struct ieee_types_generic *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + wapi_offset); + if (adapter->scan_table[del_idx].bcn_ht_cap) + adapter->scan_table[del_idx].bcn_ht_cap = + (struct ieee80211_ht_cap *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + ht_cap_offset); + + if (adapter->scan_table[del_idx].bcn_ht_info) + adapter->scan_table[del_idx].bcn_ht_info = + (struct ieee80211_ht_info *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + ht_info_offset); + if (adapter->scan_table[del_idx].bcn_bss_co_2040) + adapter->scan_table[del_idx].bcn_bss_co_2040 = + (u8 *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + bss_co_2040_offset); + if (adapter->scan_table[del_idx].bcn_ext_cap) + adapter->scan_table[del_idx].bcn_ext_cap = + (u8 *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + ext_cap_offset); + if (adapter->scan_table[del_idx].bcn_obss_scan) + adapter->scan_table[del_idx]. + bcn_obss_scan = + (struct ieee_types_obss_scan_param *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + overlap_bss_offset); + } + } + + /* The last entry is invalid now that it has been deleted or moved + back */ + memset(adapter->scan_table + adapter->num_in_scan_table - 1, + 0x00, sizeof(struct mwifiex_bssdescriptor)); + + adapter->num_in_scan_table--; +} + +/* + * This function deletes all occurrences of a given SSID from the scan table. + * + * This iterates through the scan table and deletes all entries that match + * the given SSID. It also compacts the remaining scan table entries. + */ +static int +mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *del_ssid) +{ + s32 table_idx = -1; + + dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n", + del_ssid->ssid); + + /* If the requested SSID is found in the table, delete it. Then keep + searching the table for multiple entires for the SSID until no + more are found */ + while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL, + NL80211_IFTYPE_UNSPECIFIED)) >= 0) { + dev_dbg(priv->adapter->dev, + "info: Scan: Delete SSID Entry: Found Idx = %d\n", + table_idx); + mwifiex_scan_delete_table_entry(priv, table_idx); + } + + return table_idx == -1 ? -1 : 0; +} + +/* + * This is an internal function used to start a scan based on an input + * configuration. + * + * This uses the input user scan configuration information when provided in + * order to send the appropriate scan commands to firmware to populate or + * update the internal driver scan table. + */ +int mwifiex_scan_networks(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg *user_scan_in) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node; + union mwifiex_scan_cmd_config_tlv *scan_cfg_out; + struct mwifiex_ie_types_chan_list_param_set *chan_list_out; + u32 buf_size; + struct mwifiex_chan_scan_param_set *scan_chan_list; + u8 keep_previous_scan; + u8 filtered_scan; + u8 scan_current_chan_only; + u8 max_chan_per_scan; + unsigned long flags; + + if (adapter->scan_processing) { + dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); + return ret; + } + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = true; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + if (priv->scan_block) { + dev_dbg(adapter->dev, + "cmd: Scan is blocked during association...\n"); + return ret; + } + + scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv), + GFP_KERNEL); + if (!scan_cfg_out) { + dev_err(adapter->dev, "failed to alloc scan_cfg_out\n"); + return -ENOMEM; + } + + buf_size = sizeof(struct mwifiex_chan_scan_param_set) * + MWIFIEX_USER_SCAN_CHAN_MAX; + scan_chan_list = kzalloc(buf_size, GFP_KERNEL); + if (!scan_chan_list) { + dev_err(adapter->dev, "failed to alloc scan_chan_list\n"); + kfree(scan_cfg_out); + return -ENOMEM; + } + + keep_previous_scan = false; + + mwifiex_scan_setup_scan_config(priv, user_scan_in, + &scan_cfg_out->config, &chan_list_out, + scan_chan_list, &max_chan_per_scan, + &filtered_scan, &scan_current_chan_only); + + if (user_scan_in) + keep_previous_scan = user_scan_in->keep_previous_scan; + + + if (!keep_previous_scan) { + memset(adapter->scan_table, 0x00, + sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); + adapter->num_in_scan_table = 0; + adapter->bcn_buf_end = adapter->bcn_buf; + } + + ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan, + &scan_cfg_out->config, chan_list_out, + scan_chan_list); + + /* Get scan command from scan_pending_q and put to cmd_pending_q */ + if (!ret) { + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + if (!list_empty(&adapter->scan_pending_q)) { + cmd_node = list_first_entry(&adapter->scan_pending_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, + true); + } else { + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); + } + } else { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = true; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + } + + kfree(scan_cfg_out); + kfree(scan_chan_list); + return ret; +} + +/* + * This function prepares a scan command to be sent to the firmware. + * + * This uses the scan command configuration sent to the command processing + * module in command preparation stage to configure a scan command structure + * to send to firmware. + * + * The fixed fields specifying the BSS type and BSSID filters as well as a + * variable number/length of TLVs are sent in the command to firmware. + * + * Preparation also includes - + * - Setting command ID, and proper size + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan; + struct mwifiex_scan_cmd_config *scan_cfg; + + scan_cfg = (struct mwifiex_scan_cmd_config *) data_buf; + + /* Set fixed field variables in scan command */ + scan_cmd->bss_mode = scan_cfg->bss_mode; + memcpy(scan_cmd->bssid, scan_cfg->specific_bssid, + sizeof(scan_cmd->bssid)); + memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN); + + /* Size is equal to the sizeof(fixed portions) + the TLV len + header */ + cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode) + + sizeof(scan_cmd->bssid) + + scan_cfg->tlv_buf_len + S_DS_GEN)); + + return 0; +} + +/* + * This function handles the command response of scan. + * + * The response buffer for the scan command has the following + * memory layout: + * + * .-------------------------------------------------------------. + * | Header (4 * sizeof(t_u16)): Standard command response hdr | + * .-------------------------------------------------------------. + * | BufSize (t_u16) : sizeof the BSS Description data | + * .-------------------------------------------------------------. + * | NumOfSet (t_u8) : Number of BSS Descs returned | + * .-------------------------------------------------------------. + * | BSSDescription data (variable, size given in BufSize) | + * .-------------------------------------------------------------. + * | TLV data (variable, size calculated using Header->Size, | + * | BufSize and sizeof the fixed fields above) | + * .-------------------------------------------------------------. + */ +int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node; + struct host_cmd_ds_802_11_scan_rsp *scan_rsp; + struct mwifiex_bssdescriptor *bss_new_entry = NULL; + struct mwifiex_ie_types_data *tlv_data; + struct mwifiex_ie_types_tsf_timestamp *tsf_tlv; + u8 *bss_info; + u32 scan_resp_size; + u32 bytes_left; + u32 num_in_table; + u32 bss_idx; + u32 idx; + u32 tlv_buf_size; + long long tsf_val; + struct mwifiex_chan_freq_power *cfp; + struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; + struct chan_band_param_set *chan_band; + u8 band; + u8 is_bgscan_resp; + unsigned long flags; + + is_bgscan_resp = (le16_to_cpu(resp->command) + == HostCmd_CMD_802_11_BG_SCAN_QUERY); + if (is_bgscan_resp) + scan_rsp = &resp->params.bg_scan_query_resp.scan_resp; + else + scan_rsp = &resp->params.scan_resp; + + + if (scan_rsp->number_of_sets > IW_MAX_AP) { + dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", + scan_rsp->number_of_sets); + ret = -1; + goto done; + } + + bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); + dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n", + bytes_left); + + scan_resp_size = le16_to_cpu(resp->size); + + dev_dbg(adapter->dev, + "info: SCAN_RESP: returned %d APs before parsing\n", + scan_rsp->number_of_sets); + + num_in_table = adapter->num_in_scan_table; + bss_info = scan_rsp->bss_desc_and_tlv_buffer; + + /* + * The size of the TLV buffer is equal to the entire command response + * size (scan_resp_size) minus the fixed fields (sizeof()'s), the + * BSS Descriptions (bss_descript_size as bytesLef) and the command + * response header (S_DS_GEN) + */ + tlv_buf_size = scan_resp_size - (bytes_left + + sizeof(scan_rsp->bss_descript_size) + + sizeof(scan_rsp->number_of_sets) + + S_DS_GEN); + + tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp-> + bss_desc_and_tlv_buffer + + bytes_left); + + /* Search the TLV buffer space in the scan response for any valid + TLVs */ + mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, + TLV_TYPE_TSFTIMESTAMP, + (struct mwifiex_ie_types_data **) + &tsf_tlv); + + /* Search the TLV buffer space in the scan response for any valid + TLVs */ + mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, + TLV_TYPE_CHANNELBANDLIST, + (struct mwifiex_ie_types_data **) + &chan_band_tlv); + + /* + * Process each scan response returned (scan_rsp->number_of_sets). + * Save the information in the bss_new_entry and then insert into the + * driver scan table either as an update to an existing entry + * or as an addition at the end of the table + */ + bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor), + GFP_KERNEL); + if (!bss_new_entry) { + dev_err(adapter->dev, " failed to alloc bss_new_entry\n"); + return -ENOMEM; + } + + for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { + /* Zero out the bss_new_entry we are about to store info in */ + memset(bss_new_entry, 0x00, + sizeof(struct mwifiex_bssdescriptor)); + + if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry, + &bss_info, + &bytes_left)) { + /* Error parsing/interpreting scan response, skipped */ + dev_err(adapter->dev, "SCAN_RESP: " + "mwifiex_interpret_bss_desc_with_ie " + "returned ERROR\n"); + continue; + } + + /* Process the data fields and IEs returned for this BSS */ + dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n", + bss_new_entry->mac_address); + + /* Search the scan table for the same bssid */ + for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) { + if (memcmp(bss_new_entry->mac_address, + adapter->scan_table[bss_idx].mac_address, + sizeof(bss_new_entry->mac_address))) { + continue; + } + /* + * If the SSID matches as well, it is a + * duplicate of this entry. Keep the bss_idx + * set to this entry so we replace the old + * contents in the table + */ + if ((bss_new_entry->ssid.ssid_len + == adapter->scan_table[bss_idx]. ssid.ssid_len) + && (!memcmp(bss_new_entry->ssid.ssid, + adapter->scan_table[bss_idx].ssid.ssid, + bss_new_entry->ssid.ssid_len))) { + dev_dbg(adapter->dev, "info: SCAN_RESP:" + " duplicate of index: %d\n", bss_idx); + break; + } + } + /* + * If the bss_idx is equal to the number of entries in + * the table, the new entry was not a duplicate; append + * it to the scan table + */ + if (bss_idx == num_in_table) { + /* Range check the bss_idx, keep it limited to + the last entry */ + if (bss_idx == IW_MAX_AP) + bss_idx--; + else + num_in_table++; + } + + /* + * Save the beacon/probe response returned for later application + * retrieval. Duplicate beacon/probe responses are updated if + * possible + */ + mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx, + num_in_table, bss_new_entry); + /* + * 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. + */ + if (tsf_tlv) { + memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE] + , sizeof(tsf_val)); + memcpy(&bss_new_entry->network_tsf, &tsf_val, + sizeof(bss_new_entry->network_tsf)); + } + band = BAND_G; + if (chan_band_tlv) { + chan_band = &chan_band_tlv->chan_band_param[idx]; + band = mwifiex_radio_type_to_band(chan_band->radio_type + & (BIT(0) | BIT(1))); + } + + /* Save the band designation for this entry for use in join */ + bss_new_entry->bss_band = band; + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, + (u8) bss_new_entry->bss_band, + (u16)bss_new_entry->channel); + + if (cfp) + bss_new_entry->freq = cfp->freq; + else + bss_new_entry->freq = 0; + + /* Copy the locally created bss_new_entry to the scan table */ + memcpy(&adapter->scan_table[bss_idx], bss_new_entry, + sizeof(adapter->scan_table[bss_idx])); + + } + + dev_dbg(adapter->dev, + "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", + scan_rsp->number_of_sets, + num_in_table - adapter->num_in_scan_table, num_in_table); + + /* Update the total number of BSSIDs in the scan table */ + adapter->num_in_scan_table = num_in_table; + + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + if (list_empty(&adapter->scan_pending_q)) { + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + /* + * Process the resulting scan table: + * - Remove any bad ssids + * - Update our current BSS information from scan data + */ + mwifiex_process_scan_results(priv); + + /* Need to indicate IOCTL complete */ + if (adapter->curr_cmd->wait_q_enabled) { + adapter->cmd_wait_q.status = 0; + mwifiex_complete_cmd(adapter); + } + if (priv->report_scan_result) + priv->report_scan_result = false; + if (priv->scan_pending_on_block) { + priv->scan_pending_on_block = false; + up(&priv->async_sem); + } + + } else { + /* Get scan command from scan_pending_q and put to + cmd_pending_q */ + cmd_node = list_first_entry(&adapter->scan_pending_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + } + +done: + kfree((u8 *) bss_new_entry); + return ret; +} + +/* + * This function prepares command for background scan query. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting background scan flush parameter + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd) +{ + struct host_cmd_ds_802_11_bg_scan_query *bg_query = + &cmd->params.bg_scan_query; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query) + + S_DS_GEN); + + bg_query->flush = 1; + + return 0; +} + +/* + * This function finds a SSID in the scan table. + * + * A BSSID may optionally be provided to qualify the SSID. + * For non-Auto mode, further check is made to make sure the + * BSS found in the scan table is compatible with the current + * settings of the driver. + */ +s32 +mwifiex_find_ssid_in_list(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *ssid, u8 *bssid, + u32 mode) +{ + struct mwifiex_adapter *adapter = priv->adapter; + s32 net = -1, j; + u8 best_rssi = 0; + u32 i; + + dev_dbg(adapter->dev, "info: num of entries in table = %d\n", + adapter->num_in_scan_table); + + /* + * Loop through the table until the maximum is reached or until a match + * is found based on the bssid field comparison + */ + for (i = 0; + i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0)); + i++) { + if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) && + (!bssid + || !memcmp(adapter->scan_table[i].mac_address, bssid, + ETH_ALEN)) + && + (mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, (u8) adapter->scan_table[i].bss_band, + (u16) adapter->scan_table[i].channel))) { + switch (mode) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + j = mwifiex_is_network_compatible(priv, i, + mode); + + if (j >= 0) { + if (SCAN_RSSI + (adapter->scan_table[i].rssi) > + best_rssi) { + best_rssi = SCAN_RSSI(adapter-> + scan_table + [i].rssi); + net = i; + } + } else { + if (net == -1) + net = j; + } + break; + case NL80211_IFTYPE_UNSPECIFIED: + default: + /* + * Do not check compatibility if the mode + * requested is Auto/Unknown. Allows generic + * find to work without verifying against the + * Adapter security settings + */ + if (SCAN_RSSI(adapter->scan_table[i].rssi) > + best_rssi) { + best_rssi = SCAN_RSSI(adapter-> + scan_table[i].rssi); + net = i; + } + break; + } + } + } + + return net; +} + +/* + * This function finds a specific compatible BSSID in the scan list. + * + * This function loops through the scan table looking for a compatible + * match. If a BSSID matches, but the BSS is found to be not compatible + * the function ignores it and continues to search through the rest of + * the entries in case there is an AP with multiple SSIDs assigned to + * the same BSSID. + */ +s32 +mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, + u32 mode) +{ + struct mwifiex_adapter *adapter = priv->adapter; + s32 net = -1; + u32 i; + + if (!bssid) + return -1; + + dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n", + adapter->num_in_scan_table); + + /* + * Look through the scan table for a compatible match. The ret return + * variable will be equal to the index in the scan table (greater + * than zero) if the network is compatible. The loop will continue + * past a matched bssid that is not compatible in case there is an + * AP with multiple SSIDs assigned to the same BSSID + */ + for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) { + if (!memcmp + (adapter->scan_table[i].mac_address, bssid, ETH_ALEN) + && mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, + (u8) adapter-> + scan_table[i]. + bss_band, + (u16) adapter-> + scan_table[i]. + channel)) { + switch (mode) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + net = mwifiex_is_network_compatible(priv, i, + mode); + break; + default: + net = i; + break; + } + } + } + + return net; +} + +/* + * This function inserts scan command node to the scan pending queue. + */ +void +mwifiex_queue_scan_cmd(struct mwifiex_private *priv, + struct cmd_ctrl_node *cmd_node) +{ + struct mwifiex_adapter *adapter = priv->adapter; + unsigned long flags; + + cmd_node->wait_q_enabled = true; + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + list_add_tail(&cmd_node->list, &adapter->scan_pending_q); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); +} + +/* + * This function finds an AP with specific ssid in the scan list. + */ +int mwifiex_find_best_network(struct mwifiex_private *priv, + struct mwifiex_ssid_bssid *req_ssid_bssid) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *req_bss; + s32 i; + + memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); + + i = mwifiex_find_best_network_in_list(priv); + + if (i >= 0) { + req_bss = &adapter->scan_table[i]; + memcpy(&req_ssid_bssid->ssid, &req_bss->ssid, + sizeof(struct mwifiex_802_11_ssid)); + memcpy((u8 *) &req_ssid_bssid->bssid, + (u8 *) &req_bss->mac_address, ETH_ALEN); + + /* Make sure we are in the right mode */ + if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) + priv->bss_mode = req_bss->bss_mode; + } + + if (!req_ssid_bssid->ssid.ssid_len) + return -1; + + dev_dbg(adapter->dev, "info: Best network found = [%s], " + "[%pM]\n", req_ssid_bssid->ssid.ssid, + req_ssid_bssid->bssid); + + return 0; +} + +/* + * This function sends a scan command for all available channels to the + * firmware, filtered on a specific SSID. + */ +static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *req_ssid) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + struct mwifiex_user_scan_cfg *scan_cfg; + + if (!req_ssid) + return -1; + + if (adapter->scan_processing) { + dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); + return ret; + } + + if (priv->scan_block) { + dev_dbg(adapter->dev, + "cmd: Scan is blocked during association...\n"); + return ret; + } + + mwifiex_scan_delete_ssid_table_entry(priv, req_ssid); + + scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); + if (!scan_cfg) { + dev_err(adapter->dev, "failed to alloc scan_cfg\n"); + return -ENOMEM; + } + + memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid, + req_ssid->ssid_len); + scan_cfg->keep_previous_scan = true; + + ret = mwifiex_scan_networks(priv, scan_cfg); + + kfree(scan_cfg); + return ret; +} + +/* + * Sends IOCTL request to start a scan. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + * + * Scan command can be issued for both normal scan and specific SSID + * scan, depending upon whether an SSID is provided or not. + */ +int mwifiex_request_scan(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *req_ssid) +{ + int ret; + + if (down_interruptible(&priv->async_sem)) { + dev_err(priv->adapter->dev, "%s: acquire semaphore\n", + __func__); + return -1; + } + priv->scan_pending_on_block = true; + + priv->adapter->cmd_wait_q.condition = false; + + if (req_ssid && req_ssid->ssid_len != 0) + /* Specific SSID scan */ + ret = mwifiex_scan_specific_ssid(priv, req_ssid); + else + /* Normal scan */ + ret = mwifiex_scan_networks(priv, NULL); + + if (!ret) + ret = mwifiex_wait_queue_complete(priv->adapter); + + if (ret == -1) { + priv->scan_pending_on_block = false; + up(&priv->async_sem); + } + + return ret; +} + +/* + * This function appends the vendor specific IE TLV to a buffer. + */ +int +mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, + u16 vsie_mask, u8 **buffer) +{ + int id, ret_len = 0; + struct mwifiex_ie_types_vendor_param_set *vs_param_set; + + if (!buffer) + return 0; + if (!(*buffer)) + return 0; + + /* + * Traverse through the saved vendor specific IE array and append + * the selected(scan/assoc/adhoc) IE as TLV to the command + */ + for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) { + if (priv->vs_ie[id].mask & vsie_mask) { + vs_param_set = + (struct mwifiex_ie_types_vendor_param_set *) + *buffer; + vs_param_set->header.type = + cpu_to_le16(TLV_TYPE_PASSTHROUGH); + vs_param_set->header.len = + cpu_to_le16((((u16) priv->vs_ie[id].ie[1]) + & 0x00FF) + 2); + memcpy(vs_param_set->ie, priv->vs_ie[id].ie, + le16_to_cpu(vs_param_set->header.len)); + *buffer += le16_to_cpu(vs_param_set->header.len) + + sizeof(struct mwifiex_ie_types_header); + ret_len += le16_to_cpu(vs_param_set->header.len) + + sizeof(struct mwifiex_ie_types_header); + } + } + return ret_len; +} + +/* + * This function saves a beacon buffer of the current BSS descriptor. + * + * The current beacon buffer is saved so that it can be restored in the + * following cases that makes the beacon buffer not to contain the current + * ssid's beacon buffer. + * - The current ssid was not found somehow in the last scan. + * - The current ssid was the last entry of the scan table and overloaded. + */ +void +mwifiex_save_curr_bcn(struct mwifiex_private *priv) +{ + struct mwifiex_bssdescriptor *curr_bss = + &priv->curr_bss_params.bss_descriptor; + + if (!curr_bss->beacon_buf_size) + return; + + /* allocate beacon buffer at 1st time; or if it's size has changed */ + if (!priv->curr_bcn_buf || + priv->curr_bcn_size != curr_bss->beacon_buf_size) { + priv->curr_bcn_size = curr_bss->beacon_buf_size; + + kfree(priv->curr_bcn_buf); + priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size, + GFP_KERNEL); + if (!priv->curr_bcn_buf) { + dev_err(priv->adapter->dev, + "failed to alloc curr_bcn_buf\n"); + return; + } + } + + memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, + curr_bss->beacon_buf_size); + dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n", + priv->curr_bcn_size); +} + +/* + * This function frees the current BSS descriptor beacon buffer. + */ +void +mwifiex_free_curr_bcn(struct mwifiex_private *priv) +{ + kfree(priv->curr_bcn_buf); + priv->curr_bcn_buf = NULL; +} diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c new file mode 100644 index 000000000000..d425dbd91d19 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -0,0 +1,1754 @@ +/* + * Marvell Wireless LAN device driver: SDIO specific handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "sdio.h" + + +#define SDIO_VERSION "1.0" + +static struct mwifiex_if_ops sdio_ops; + +static struct semaphore add_remove_card_sem; + +/* + * SDIO probe. + * + * This function probes an mwifiex device and registers it. It allocates + * the card structure, enables SDIO function number and initiates the + * device registration and initialization procedure by adding a logical + * interface. + */ +static int +mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + int ret; + struct sdio_mmc_card *card = NULL; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n", + func->vendor, func->device, func->class, func->num); + + card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL); + if (!card) { + pr_err("%s: failed to alloc memory\n", __func__); + return -ENOMEM; + } + + card->func = func; + + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + + sdio_claim_host(func); + ret = sdio_enable_func(func); + sdio_release_host(func); + + if (ret) { + pr_err("%s: failed to enable function\n", __func__); + kfree(card); + return -EIO; + } + + if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) { + pr_err("%s: add card failed\n", __func__); + kfree(card); + sdio_claim_host(func); + ret = sdio_disable_func(func); + sdio_release_host(func); + ret = -1; + } + + return ret; +} + +/* + * SDIO remove. + * + * This function removes the interface and frees up the card structure. + */ +static void +mwifiex_sdio_remove(struct sdio_func *func) +{ + struct sdio_mmc_card *card; + + pr_debug("info: SDIO func num=%d\n", func->num); + + if (func) { + card = sdio_get_drvdata(func); + if (card) { + mwifiex_remove_card(card->adapter, + &add_remove_card_sem); + kfree(card); + } + } +} + +/* + * SDIO suspend. + * + * 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_sdio_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_mmc_card *card; + struct mwifiex_adapter *adapter; + mmc_pm_flag_t pm_flag = 0; + int hs_actived = 0; + int i; + int ret = 0; + + if (func) { + pm_flag = sdio_get_host_pm_caps(func); + pr_debug("cmd: %s: suspend: PM flag = 0x%x\n", + sdio_func_id(func), pm_flag); + if (!(pm_flag & MMC_PM_KEEP_POWER)) { + pr_err("%s: cannot remain alive while host is" + " suspended\n", sdio_func_id(func)); + return -ENOSYS; + } + + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + pr_err("suspend: invalid card or adapter\n"); + return 0; + } + } else { + pr_err("suspend: sdio_func is not specified\n"); + return 0; + } + + adapter = card->adapter; + + /* Enable the Host Sleep */ + hs_actived = mwifiex_enable_hs(adapter); + if (hs_actived) { + pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + } + + /* Indicate device suspended */ + adapter->is_suspended = true; + + for (i = 0; i < adapter->priv_num; i++) + netif_carrier_off(adapter->priv[i]->netdev); + + return ret; +} + +/* + * SDIO resume. + * + * 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_sdio_resume(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_mmc_card *card; + struct mwifiex_adapter *adapter; + mmc_pm_flag_t pm_flag = 0; + int i; + + if (func) { + pm_flag = sdio_get_host_pm_caps(func); + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + pr_err("resume: invalid card or adapter\n"); + return 0; + } + } else { + pr_err("resume: sdio_func is not specified\n"); + return 0; + } + + adapter = card->adapter; + + if (!adapter->is_suspended) { + dev_warn(adapter->dev, "device already resumed\n"); + return 0; + } + + adapter->is_suspended = false; + + for (i = 0; i < adapter->priv_num; i++) + if (adapter->priv[i]->media_connected) + netif_carrier_on(adapter->priv[i]->netdev); + + /* Disable Host Sleep */ + mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), + MWIFIEX_ASYNC_CMD); + + return 0; +} + +/* Device ID for SD8787 */ +#define SDIO_DEVICE_ID_MARVELL_8787 (0x9119) + +/* WLAN IDs */ +static const struct sdio_device_id mwifiex_ids[] = { + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)}, + {}, +}; + +MODULE_DEVICE_TABLE(sdio, mwifiex_ids); + +static const struct dev_pm_ops mwifiex_sdio_pm_ops = { + .suspend = mwifiex_sdio_suspend, + .resume = mwifiex_sdio_resume, +}; + +static struct sdio_driver mwifiex_sdio = { + .name = "mwifiex_sdio", + .id_table = mwifiex_ids, + .probe = mwifiex_sdio_probe, + .remove = mwifiex_sdio_remove, + .drv = { + .owner = THIS_MODULE, + .pm = &mwifiex_sdio_pm_ops, + } +}; + +/* + * This function writes data into SDIO card register. + */ +static int +mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = -1; + + sdio_claim_host(card->func); + sdio_writeb(card->func, (u8) data, reg, &ret); + sdio_release_host(card->func); + + return ret; +} + +/* + * This function reads data from SDIO card register. + */ +static int +mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = -1; + u8 val; + + sdio_claim_host(card->func); + val = sdio_readb(card->func, reg, &ret); + sdio_release_host(card->func); + + *data = val; + + return ret; +} + +/* + * This function writes multiple data into SDIO card memory. + * + * This does not work in suspended mode. + */ +static int +mwifiex_write_data_sync(struct mwifiex_adapter *adapter, + u8 *buffer, u32 pkt_len, u32 port) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = -1; + u8 blk_mode = + (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; + u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; + u32 blk_cnt = + (blk_mode == + BLOCK_MODE) ? (pkt_len / + MWIFIEX_SDIO_BLOCK_SIZE) : pkt_len; + u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); + + if (adapter->is_suspended) { + dev_err(adapter->dev, + "%s: not allowed while suspended\n", __func__); + return -1; + } + + sdio_claim_host(card->func); + + if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size)) + ret = 0; + + sdio_release_host(card->func); + + return ret; +} + +/* + * This function reads multiple data from SDIO card memory. + */ +static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, + u32 len, u32 port, u8 claim) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = -1; + u8 blk_mode = + (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; + u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; + u32 blk_cnt = + (blk_mode == + BLOCK_MODE) ? (len / MWIFIEX_SDIO_BLOCK_SIZE) : len; + u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); + + if (claim) + sdio_claim_host(card->func); + + if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size)) + ret = 0; + + if (claim) + sdio_release_host(card->func); + + return ret; +} + +/* + * This function wakes up the card. + * + * A host power up command is written to the card configuration + * register to wake up the card. + */ +static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) +{ + dev_dbg(adapter->dev, "event: wakeup device...\n"); + + return mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP); +} + +/* + * This function is called after the card has woken up. + * + * The card configuration register is reset. + */ +static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) +{ + dev_dbg(adapter->dev, "cmd: wakeup device completed\n"); + + return mwifiex_write_reg(adapter, CONFIGURATION_REG, 0); +} + +/* + * This function initializes the IO ports. + * + * The following operations are performed - + * - Read the IO ports (0, 1 and 2) + * - Set host interrupt Reset-To-Read to clear + * - Set auto re-enable interrupt + */ +static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) +{ + u32 reg; + + adapter->ioport = 0; + + /* Read the IO port */ + if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, ®)) + adapter->ioport |= (reg & 0xff); + else + return -1; + + if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, ®)) + adapter->ioport |= ((reg & 0xff) << 8); + else + return -1; + + if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, ®)) + adapter->ioport |= ((reg & 0xff) << 16); + else + return -1; + + pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); + + /* Set Host interrupt reset to read to clear */ + if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, ®)) + mwifiex_write_reg(adapter, HOST_INT_RSR_REG, + reg | SDIO_INT_MASK); + else + return -1; + + /* Dnld/Upld ready set to auto reset */ + if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, ®)) + mwifiex_write_reg(adapter, CARD_MISC_CFG_REG, + reg | AUTO_RE_ENABLE_INT); + else + return -1; + + return 0; +} + +/* + * This function sends data to the card. + */ +static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter, + u8 *payload, u32 pkt_len, u32 port) +{ + u32 i = 0; + int ret; + + do { + ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port); + if (ret) { + i++; + dev_err(adapter->dev, "host_to_card, write iomem" + " (%d) failed: %d\n", i, ret); + if (mwifiex_write_reg(adapter, + CONFIGURATION_REG, 0x04)) + dev_err(adapter->dev, "write CFG reg failed\n"); + + ret = -1; + if (i > MAX_WRITE_IOMEM_RETRY) + return ret; + } + } while (ret == -1); + + return ret; +} + +/* + * This function gets the read port. + * + * If control port bit is set in MP read bitmap, the control port + * is returned, otherwise the current read port is returned and + * the value is increased (provided it does not reach the maximum + * limit, in which case it is reset to 1) + */ +static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port) +{ + struct sdio_mmc_card *card = adapter->card; + u16 rd_bitmap = card->mp_rd_bitmap; + + dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%04x\n", rd_bitmap); + + if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK))) + return -1; + + if (card->mp_rd_bitmap & CTRL_PORT_MASK) { + card->mp_rd_bitmap &= (u16) (~CTRL_PORT_MASK); + *port = CTRL_PORT; + dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%04x\n", + *port, card->mp_rd_bitmap); + } else { + if (card->mp_rd_bitmap & (1 << card->curr_rd_port)) { + card->mp_rd_bitmap &= + (u16) (~(1 << card->curr_rd_port)); + *port = card->curr_rd_port; + + if (++card->curr_rd_port == MAX_PORT) + card->curr_rd_port = 1; + } else { + return -1; + } + + dev_dbg(adapter->dev, + "data: port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n", + *port, rd_bitmap, card->mp_rd_bitmap); + } + return 0; +} + +/* + * This function gets the write port for data. + * + * The current write port is returned if available and the value is + * increased (provided it does not reach the maximum limit, in which + * case it is reset to 1) + */ +static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port) +{ + struct sdio_mmc_card *card = adapter->card; + u16 wr_bitmap = card->mp_wr_bitmap; + + dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%04x\n", wr_bitmap); + + if (!(wr_bitmap & card->mp_data_port_mask)) + return -1; + + if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { + card->mp_wr_bitmap &= (u16) (~(1 << card->curr_wr_port)); + *port = card->curr_wr_port; + if (++card->curr_wr_port == card->mp_end_port) + card->curr_wr_port = 1; + } else { + adapter->data_sent = true; + return -EBUSY; + } + + if (*port == CTRL_PORT) { + dev_err(adapter->dev, "invalid data port=%d cur port=%d" + " mp_wr_bitmap=0x%04x -> 0x%04x\n", + *port, card->curr_wr_port, wr_bitmap, + card->mp_wr_bitmap); + return -1; + } + + dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n", + *port, wr_bitmap, card->mp_wr_bitmap); + + return 0; +} + +/* + * This function polls the card status. + */ +static int +mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) +{ + u32 tries; + u32 cs; + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs)) + break; + else if ((cs & bits) == bits) + return 0; + + udelay(10); + } + + dev_err(adapter->dev, "poll card status failed, tries = %d\n", + tries); + return -1; +} + +/* + * This function reads the firmware status. + */ +static int +mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) +{ + u32 fws0, fws1; + + if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0)) + return -1; + + if (mwifiex_read_reg(adapter, CARD_FW_STATUS1_REG, &fws1)) + return -1; + + *dat = (u16) ((fws1 << 8) | fws0); + + return 0; +} + +/* + * This function disables the host interrupt. + * + * The host interrupt mask is read, the disable bit is reset and + * written back to the card host interrupt mask register. + */ +static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) +{ + u32 host_int_mask; + + /* Read back the host_int_mask register */ + if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) + return -1; + + /* Update with the mask and write back to the register */ + host_int_mask &= ~HOST_INT_DISABLE; + + if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) { + dev_err(adapter->dev, "disable host interrupt failed\n"); + return -1; + } + + return 0; +} + +/* + * This function enables the host interrupt. + * + * The host interrupt enable mask is written to the card + * host interrupt mask register. + */ +static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter) +{ + /* Simply write the mask to the register */ + if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, HOST_INT_ENABLE)) { + dev_err(adapter->dev, "enable host interrupt failed\n"); + return -1; + } + return 0; +} + +/* + * This function sends a data buffer to the card. + */ +static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, + u32 *type, u8 *buffer, + u32 npayload, u32 ioport) +{ + int ret; + u32 nb; + + if (!buffer) { + dev_err(adapter->dev, "%s: buffer is NULL\n", __func__); + return -1; + } + + ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 1); + + if (ret) { + dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__, + ret); + return -1; + } + + nb = le16_to_cpu(*(__le16 *) (buffer)); + if (nb > npayload) { + dev_err(adapter->dev, "%s: invalid packet, nb=%d, npayload=%d\n", + __func__, nb, npayload); + return -1; + } + + *type = le16_to_cpu(*(__le16 *) (buffer + 2)); + + return ret; +} + +/* + * This function downloads the firmware to the card. + * + * Firmware is downloaded to the card in blocks. Every block download + * is tested for CRC errors, and retried a number of times before + * returning failure. + */ +static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, + struct mwifiex_fw_image *fw) +{ + int ret; + u8 *firmware = fw->fw_buf; + u32 firmware_len = fw->fw_len; + u32 offset = 0; + u32 base0, base1; + u8 *fwbuf; + u16 len = 0; + u32 txlen, tx_blocks = 0, tries; + u32 i = 0; + + if (!firmware_len) { + dev_err(adapter->dev, "firmware image not found!" + " Terminating download\n"); + return -1; + } + + dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n", + firmware_len); + + /* Assume that the allocated buffer is 8-byte aligned */ + fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL); + if (!fwbuf) { + dev_err(adapter->dev, "unable to alloc buffer for firmware." + " Terminating download\n"); + return -ENOMEM; + } + + /* Perform firmware data transfer */ + do { + /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY + bits */ + ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY | + DN_LD_CARD_RDY); + if (ret) { + dev_err(adapter->dev, "FW download with helper:" + " poll status timeout @ %d\n", offset); + goto done; + } + + /* More data? */ + if (offset >= firmware_len) + break; + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0, + &base0); + if (ret) { + dev_err(adapter->dev, "dev BASE0 register read" + " failed: base0=0x%04X(%d). Terminating " + "download\n", base0, base0); + goto done; + } + ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1, + &base1); + if (ret) { + dev_err(adapter->dev, "dev BASE1 register read" + " failed: base1=0x%04X(%d). Terminating " + "download\n", base1, base1); + goto done; + } + len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff)); + + if (len) + break; + + udelay(10); + } + + if (!len) { + break; + } else if (len > MWIFIEX_UPLD_SIZE) { + dev_err(adapter->dev, "FW download failed @ %d," + " invalid length %d\n", offset, len); + ret = -1; + goto done; + } + + txlen = len; + + if (len & BIT(0)) { + i++; + if (i > MAX_WRITE_IOMEM_RETRY) { + dev_err(adapter->dev, "FW download failed @" + " %d, over max retry count\n", offset); + ret = -1; + goto done; + } + dev_err(adapter->dev, "CRC indicated by the helper:" + " len = 0x%04X, txlen = %d\n", len, txlen); + len &= ~BIT(0); + /* Setting this to 0 to resend from same offset */ + txlen = 0; + } else { + i = 0; + + /* Set blocksize to transfer - checking for last + block */ + if (firmware_len - offset < txlen) + txlen = firmware_len - offset; + + tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE - + 1) / MWIFIEX_SDIO_BLOCK_SIZE; + + /* Copy payload to buffer */ + memmove(fwbuf, &firmware[offset], txlen); + } + + ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks * + MWIFIEX_SDIO_BLOCK_SIZE, + adapter->ioport); + if (ret) { + dev_err(adapter->dev, "FW download, write iomem (%d)" + " failed @ %d\n", i, offset); + if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) + dev_err(adapter->dev, "write CFG reg failed\n"); + + ret = -1; + goto done; + } + + offset += txlen; + } while (true); + + dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n", + offset); + + ret = 0; +done: + kfree(fwbuf); + return ret; +} + +/* + * This function checks the firmware status in card. + * + * The winner interface is also determined by this function. + */ +static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, + u32 poll_num, int *winner) +{ + int ret = 0; + u16 firmware_stat; + u32 tries; + u32 winner_status; + + /* Wait for firmware initialization event */ + for (tries = 0; tries < poll_num; tries++) { + ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); + if (ret) + continue; + if (firmware_stat == FIRMWARE_READY) { + ret = 0; + break; + } else { + mdelay(100); + ret = -1; + } + } + + if (winner && ret) { + if (mwifiex_read_reg + (adapter, CARD_FW_STATUS0_REG, &winner_status)) + winner_status = 0; + + if (winner_status) + *winner = 0; + else + *winner = 1; + } + return ret; +} + +/* + * This function reads the interrupt status from card. + */ +static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + u32 sdio_ireg; + unsigned long flags; + + if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS, + REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, + 0)) { + dev_err(adapter->dev, "read mp_regs failed\n"); + return; + } + + sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG]; + if (sdio_ireg) { + /* + * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS + * Clear the interrupt status register + */ + dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg); + spin_lock_irqsave(&adapter->int_lock, flags); + adapter->int_status |= sdio_ireg; + spin_unlock_irqrestore(&adapter->int_lock, flags); + } +} + +/* + * SDIO interrupt handler. + * + * This function reads the interrupt status from firmware and assigns + * the main process in workqueue which will handle the interrupt. + */ +static void +mwifiex_sdio_interrupt(struct sdio_func *func) +{ + struct mwifiex_adapter *adapter; + struct sdio_mmc_card *card; + + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + pr_debug("int: func=%p card=%p adapter=%p\n", + func, card, card ? card->adapter : NULL); + return; + } + adapter = card->adapter; + + if (adapter->surprise_removed) + return; + + if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) + adapter->ps_state = PS_STATE_AWAKE; + + mwifiex_interrupt_status(adapter); + queue_work(adapter->workqueue, &adapter->main_work); +} + +/* + * This function decodes a received packet. + * + * Based on the type, the packet is treated as either a data, or + * a command response, or an event, and the correct handler + * function is invoked. + */ +static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb, u32 upld_typ) +{ + u8 *cmd_buf; + + skb_pull(skb, INTF_HEADER_LEN); + + switch (upld_typ) { + case MWIFIEX_TYPE_DATA: + dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n"); + mwifiex_handle_rx_packet(adapter, skb); + break; + + case MWIFIEX_TYPE_CMD: + dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n"); + /* take care of curr_cmd = NULL case */ + if (!adapter->curr_cmd) { + cmd_buf = adapter->upld_buf; + + if (adapter->ps_state == PS_STATE_SLEEP_CFM) + mwifiex_process_sleep_confirm_resp(adapter, + skb->data, skb->len); + + memcpy(cmd_buf, skb->data, min_t(u32, + MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); + + dev_kfree_skb_any(skb); + } else { + adapter->cmd_resp_received = true; + adapter->curr_cmd->resp_skb = skb; + } + break; + + case MWIFIEX_TYPE_EVENT: + dev_dbg(adapter->dev, "info: --- Rx: Event ---\n"); + adapter->event_cause = *(u32 *) skb->data; + + skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN); + + if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE)) + memcpy(adapter->event_body, skb->data, skb->len); + + /* event cause has been saved to adapter->event_cause */ + adapter->event_received = true; + adapter->event_skb = skb; + + break; + + default: + dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ); + dev_kfree_skb_any(skb); + break; + } + + return 0; +} + +/* + * This function transfers received packets from card to driver, performing + * aggregation if required. + * + * For data received on control port, or if aggregation is disabled, the + * received buffers are uploaded as separate packets. However, if aggregation + * is enabled and required, the buffers are copied onto an aggregation buffer, + * provided there is space left, processed and finally uploaded. + */ +static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, + struct sk_buff *skb, u8 port) +{ + struct sdio_mmc_card *card = adapter->card; + s32 f_do_rx_aggr = 0; + s32 f_do_rx_cur = 0; + s32 f_aggr_cur = 0; + struct sk_buff *skb_deaggr; + u32 pind; + u32 pkt_len, pkt_type = 0; + u8 *curr_ptr; + u32 rx_len = skb->len; + + if (port == CTRL_PORT) { + /* Read the command Resp without aggr */ + dev_dbg(adapter->dev, "info: %s: no aggregation for cmd " + "response\n", __func__); + + f_do_rx_cur = 1; + goto rx_curr_single; + } + + if (!card->mpa_rx.enabled) { + dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n", + __func__); + + f_do_rx_cur = 1; + goto rx_curr_single; + } + + if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) { + /* Some more data RX pending */ + dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); + + if (MP_RX_AGGR_IN_PROGRESS(card)) { + if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) { + f_aggr_cur = 1; + } else { + /* No room in Aggr buf, do rx aggr now */ + f_do_rx_aggr = 1; + f_do_rx_cur = 1; + } + } else { + /* Rx aggr not in progress */ + f_aggr_cur = 1; + } + + } else { + /* No more data RX pending */ + dev_dbg(adapter->dev, "info: %s: last packet\n", __func__); + + if (MP_RX_AGGR_IN_PROGRESS(card)) { + f_do_rx_aggr = 1; + if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) + f_aggr_cur = 1; + else + /* No room in Aggr buf, do rx aggr now */ + f_do_rx_cur = 1; + } else { + f_do_rx_cur = 1; + } + } + + if (f_aggr_cur) { + dev_dbg(adapter->dev, "info: current packet aggregation\n"); + /* Curr pkt can be aggregated */ + MP_RX_AGGR_SETUP(card, skb, port); + + if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || + MP_RX_AGGR_PORT_LIMIT_REACHED(card)) { + dev_dbg(adapter->dev, "info: %s: aggregated packet " + "limit reached\n", __func__); + /* No more pkts allowed in Aggr buf, rx it */ + f_do_rx_aggr = 1; + } + } + + if (f_do_rx_aggr) { + /* do aggr RX now */ + dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n", + card->mpa_rx.pkt_cnt); + + if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, + card->mpa_rx.buf_len, + (adapter->ioport | 0x1000 | + (card->mpa_rx.ports << 4)) + + card->mpa_rx.start_port, 1)) + return -1; + + curr_ptr = card->mpa_rx.buf; + + for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { + + /* get curr PKT len & type */ + pkt_len = *(u16 *) &curr_ptr[0]; + pkt_type = *(u16 *) &curr_ptr[2]; + + /* copy pkt to deaggr buf */ + skb_deaggr = card->mpa_rx.skb_arr[pind]; + + if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <= + card->mpa_rx.len_arr[pind])) { + + memcpy(skb_deaggr->data, curr_ptr, pkt_len); + + skb_trim(skb_deaggr, pkt_len); + + /* Process de-aggr packet */ + mwifiex_decode_rx_packet(adapter, skb_deaggr, + pkt_type); + } else { + dev_err(adapter->dev, "wrong aggr pkt:" + " type=%d len=%d max_len=%d\n", + pkt_type, pkt_len, + card->mpa_rx.len_arr[pind]); + dev_kfree_skb_any(skb_deaggr); + } + curr_ptr += card->mpa_rx.len_arr[pind]; + } + MP_RX_AGGR_BUF_RESET(card); + } + +rx_curr_single: + if (f_do_rx_cur) { + dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", + port, rx_len); + + if (mwifiex_sdio_card_to_host(adapter, &pkt_type, + skb->data, skb->len, + adapter->ioport + port)) + return -1; + + mwifiex_decode_rx_packet(adapter, skb, pkt_type); + } + + return 0; +} + +/* + * This function checks the current interrupt status. + * + * The following interrupts are checked and handled by this function - + * - Data sent + * - Command sent + * - Packets received + * + * Since the firmware does not generate download ready interrupt if the + * port updated is command port only, command sent interrupt checking + * should be done manually, and for every SDIO interrupt. + * + * In case of Rx packets received, the packets are uploaded from card to + * host and processed accordingly. + */ +static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + u8 sdio_ireg; + struct sk_buff *skb; + u8 port = CTRL_PORT; + u32 len_reg_l, len_reg_u; + u32 rx_blocks; + u16 rx_len; + unsigned long flags; + + spin_lock_irqsave(&adapter->int_lock, flags); + sdio_ireg = adapter->int_status; + adapter->int_status = 0; + spin_unlock_irqrestore(&adapter->int_lock, flags); + + if (!sdio_ireg) + return ret; + + if (sdio_ireg & DN_LD_HOST_INT_STATUS) { + card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8; + card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L]; + dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n", + card->mp_wr_bitmap); + if (adapter->data_sent && + (card->mp_wr_bitmap & card->mp_data_port_mask)) { + dev_dbg(adapter->dev, + "info: <--- Tx DONE Interrupt --->\n"); + adapter->data_sent = false; + } + } + + /* As firmware will not generate download ready interrupt if the port + updated is command port only, cmd_sent should be done for any SDIO + interrupt. */ + if (adapter->cmd_sent) { + /* Check if firmware has attach buffer at command port and + update just that in wr_bit_map. */ + card->mp_wr_bitmap |= + (u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK; + if (card->mp_wr_bitmap & CTRL_PORT_MASK) + adapter->cmd_sent = false; + } + + dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n", + adapter->cmd_sent, adapter->data_sent); + if (sdio_ireg & UP_LD_HOST_INT_STATUS) { + card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8; + card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L]; + dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n", + card->mp_rd_bitmap); + + while (true) { + ret = mwifiex_get_rd_port(adapter, &port); + if (ret) { + dev_dbg(adapter->dev, + "info: no more rd_port available\n"); + break; + } + len_reg_l = RD_LEN_P0_L + (port << 1); + len_reg_u = RD_LEN_P0_U + (port << 1); + rx_len = ((u16) card->mp_regs[len_reg_u]) << 8; + rx_len |= (u16) card->mp_regs[len_reg_l]; + dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n", + port, rx_len); + rx_blocks = + (rx_len + MWIFIEX_SDIO_BLOCK_SIZE - + 1) / MWIFIEX_SDIO_BLOCK_SIZE; + if (rx_len <= INTF_HEADER_LEN + || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > + MWIFIEX_RX_DATA_BUF_SIZE) { + dev_err(adapter->dev, "invalid rx_len=%d\n", + rx_len); + return -1; + } + rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); + + skb = dev_alloc_skb(rx_len); + + if (!skb) { + dev_err(adapter->dev, "%s: failed to alloc skb", + __func__); + return -1; + } + + skb_put(skb, rx_len); + + dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n", + rx_len, skb->len); + + if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb, + port)) { + u32 cr = 0; + + dev_err(adapter->dev, "card_to_host_mpa failed:" + " int status=%#x\n", sdio_ireg); + if (mwifiex_read_reg(adapter, + CONFIGURATION_REG, &cr)) + dev_err(adapter->dev, + "read CFG reg failed\n"); + + dev_dbg(adapter->dev, + "info: CFG reg val = %d\n", cr); + if (mwifiex_write_reg(adapter, + CONFIGURATION_REG, + (cr | 0x04))) + dev_err(adapter->dev, + "write CFG reg failed\n"); + + dev_dbg(adapter->dev, "info: write success\n"); + if (mwifiex_read_reg(adapter, + CONFIGURATION_REG, &cr)) + dev_err(adapter->dev, + "read CFG reg failed\n"); + + dev_dbg(adapter->dev, + "info: CFG reg val =%x\n", cr); + dev_kfree_skb_any(skb); + return -1; + } + } + } + + return 0; +} + +/* + * This function aggregates transmission buffers in driver and downloads + * the aggregated packet to card. + * + * The individual packets are aggregated by copying into an aggregation + * buffer and then downloaded to the card. Previous unsent packets in the + * aggregation buffer are pre-copied first before new packets are added. + * Aggregation is done till there is space left in the aggregation buffer, + * or till new packets are available. + * + * The function will only download the packet to the card when aggregation + * stops, otherwise it will just aggregate the packet in aggregation buffer + * and return. + */ +static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, + u8 *payload, u32 pkt_len, u8 port, + u32 next_pkt_len) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + s32 f_send_aggr_buf = 0; + s32 f_send_cur_buf = 0; + s32 f_precopy_cur_buf = 0; + s32 f_postcopy_cur_buf = 0; + + if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) { + dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n", + __func__); + + f_send_cur_buf = 1; + goto tx_curr_single; + } + + if (next_pkt_len) { + /* More pkt in TX queue */ + dev_dbg(adapter->dev, "info: %s: more packets in queue.\n", + __func__); + + if (MP_TX_AGGR_IN_PROGRESS(card)) { + if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) && + MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { + f_precopy_cur_buf = 1; + + if (!(card->mp_wr_bitmap & + (1 << card->curr_wr_port)) + || !MP_TX_AGGR_BUF_HAS_ROOM( + card, next_pkt_len)) + f_send_aggr_buf = 1; + } else { + /* No room in Aggr buf, send it */ + f_send_aggr_buf = 1; + + if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) || + !(card->mp_wr_bitmap & + (1 << card->curr_wr_port))) + f_send_cur_buf = 1; + else + f_postcopy_cur_buf = 1; + } + } else { + if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len) + && (card->mp_wr_bitmap & (1 << card->curr_wr_port))) + f_precopy_cur_buf = 1; + else + f_send_cur_buf = 1; + } + } else { + /* Last pkt in TX queue */ + dev_dbg(adapter->dev, "info: %s: Last packet in Tx Queue.\n", + __func__); + + if (MP_TX_AGGR_IN_PROGRESS(card)) { + /* some packs in Aggr buf already */ + f_send_aggr_buf = 1; + + if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) + f_precopy_cur_buf = 1; + else + /* No room in Aggr buf, send it */ + f_send_cur_buf = 1; + } else { + f_send_cur_buf = 1; + } + } + + if (f_precopy_cur_buf) { + dev_dbg(adapter->dev, "data: %s: precopy current buffer\n", + __func__); + MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); + + if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) || + MP_TX_AGGR_PORT_LIMIT_REACHED(card)) + /* No more pkts allowed in Aggr buf, send it */ + f_send_aggr_buf = 1; + } + + if (f_send_aggr_buf) { + dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n", + __func__, + card->mpa_tx.start_port, card->mpa_tx.ports); + ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, + card->mpa_tx.buf_len, + (adapter->ioport | 0x1000 | + (card->mpa_tx.ports << 4)) + + card->mpa_tx.start_port); + + MP_TX_AGGR_BUF_RESET(card); + } + +tx_curr_single: + if (f_send_cur_buf) { + dev_dbg(adapter->dev, "data: %s: send current buffer %d\n", + __func__, port); + ret = mwifiex_write_data_to_card(adapter, payload, pkt_len, + adapter->ioport + port); + } + + if (f_postcopy_cur_buf) { + dev_dbg(adapter->dev, "data: %s: postcopy current buffer\n", + __func__); + MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); + } + + return ret; +} + +/* + * This function downloads data from driver to card. + * + * Both commands and data packets are transferred to the card by this + * function. + * + * This function adds the SDIO specific header to the front of the buffer + * before transferring. The header contains the length of the packet and + * the type. The firmware handles the packets based upon this set type. + */ +static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, + u8 type, u8 *payload, u32 pkt_len, + struct mwifiex_tx_param *tx_param) +{ + struct sdio_mmc_card *card = adapter->card; + int ret; + u32 buf_block_len; + u32 blk_size; + u8 port = CTRL_PORT; + + /* Allocate buffer and copy payload */ + blk_size = MWIFIEX_SDIO_BLOCK_SIZE; + buf_block_len = (pkt_len + blk_size - 1) / blk_size; + *(u16 *) &payload[0] = (u16) pkt_len; + *(u16 *) &payload[2] = type; + + /* + * This is SDIO specific header + * u16 length, + * u16 type (MWIFIEX_TYPE_DATA = 0, MWIFIEX_TYPE_CMD = 1, + * MWIFIEX_TYPE_EVENT = 3) + */ + if (type == MWIFIEX_TYPE_DATA) { + ret = mwifiex_get_wr_port_data(adapter, &port); + if (ret) { + dev_err(adapter->dev, "%s: no wr_port available\n", + __func__); + return ret; + } + } else { + adapter->cmd_sent = true; + /* Type must be MWIFIEX_TYPE_CMD */ + + if (pkt_len <= INTF_HEADER_LEN || + pkt_len > MWIFIEX_UPLD_SIZE) + dev_err(adapter->dev, "%s: payload=%p, nb=%d\n", + __func__, payload, pkt_len); + } + + /* Transfer data to card */ + pkt_len = buf_block_len * blk_size; + + if (tx_param) + ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, + port, tx_param->next_pkt_len); + else + ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, + port, 0); + + if (ret) { + if (type == MWIFIEX_TYPE_CMD) + adapter->cmd_sent = false; + if (type == MWIFIEX_TYPE_DATA) + adapter->data_sent = false; + } else { + if (type == MWIFIEX_TYPE_DATA) { + if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port))) + adapter->data_sent = true; + else + adapter->data_sent = false; + } + } + + return ret; +} + +/* + * This function allocates the MPA Tx and Rx buffers. + */ +static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, + u32 mpa_tx_buf_size, u32 mpa_rx_buf_size) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + + card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL); + if (!card->mpa_tx.buf) { + dev_err(adapter->dev, "could not alloc buffer for MP-A TX\n"); + ret = -1; + goto error; + } + + card->mpa_tx.buf_size = mpa_tx_buf_size; + + card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL); + if (!card->mpa_rx.buf) { + dev_err(adapter->dev, "could not alloc buffer for MP-A RX\n"); + ret = -1; + goto error; + } + + card->mpa_rx.buf_size = mpa_rx_buf_size; + +error: + if (ret) { + kfree(card->mpa_tx.buf); + kfree(card->mpa_rx.buf); + } + + return ret; +} + +/* + * This function unregisters the SDIO device. + * + * The SDIO IRQ is released, the function is disabled and driver + * data is set to null. + */ +static void +mwifiex_unregister_dev(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + if (adapter->card) { + /* Release the SDIO IRQ */ + sdio_claim_host(card->func); + sdio_release_irq(card->func); + sdio_disable_func(card->func); + sdio_release_host(card->func); + sdio_set_drvdata(card->func, NULL); + } +} + +/* + * This function registers the SDIO device. + * + * SDIO IRQ is claimed, block size is set and driver data is initialized. + */ +static int mwifiex_register_dev(struct mwifiex_adapter *adapter) +{ + int ret = 0; + struct sdio_mmc_card *card = adapter->card; + struct sdio_func *func = card->func; + + /* save adapter pointer in card */ + card->adapter = adapter; + + sdio_claim_host(func); + + /* Request the SDIO IRQ */ + ret = sdio_claim_irq(func, mwifiex_sdio_interrupt); + if (ret) { + pr_err("claim irq failed: ret=%d\n", ret); + goto disable_func; + } + + /* Set block size */ + ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE); + if (ret) { + pr_err("cannot set SDIO block size\n"); + ret = -1; + goto release_irq; + } + + sdio_release_host(func); + sdio_set_drvdata(func, card); + + adapter->dev = &func->dev; + + return 0; + +release_irq: + sdio_release_irq(func); +disable_func: + sdio_disable_func(func); + sdio_release_host(func); + adapter->card = NULL; + + return -1; +} + +/* + * This function initializes the SDIO driver. + * + * The following initializations steps are followed - + * - Read the Host interrupt status register to acknowledge + * the first interrupt got from bootloader + * - Disable host interrupt mask register + * - Get SDIO port + * - Get revision ID + * - Initialize SDIO variables in card + * - Allocate MP registers + * - Allocate MPA Tx and Rx buffers + */ +static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + int ret; + u32 sdio_ireg; + + /* + * Read the HOST_INT_STATUS_REG for ACK the first interrupt got + * from the bootloader. If we don't do this we get a interrupt + * as soon as we register the irq. + */ + mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg); + + /* Disable host interrupt mask register for SDIO */ + mwifiex_sdio_disable_host_int(adapter); + + /* Get SDIO ioport */ + mwifiex_init_sdio_ioport(adapter); + + /* Get revision ID */ +#define REV_ID_REG 0x5c + mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id); + + /* Initialize SDIO variables in card */ + card->mp_rd_bitmap = 0; + card->mp_wr_bitmap = 0; + card->curr_rd_port = 1; + card->curr_wr_port = 1; + + card->mp_data_port_mask = DATA_PORT_MASK; + + card->mpa_tx.buf_len = 0; + card->mpa_tx.pkt_cnt = 0; + card->mpa_tx.start_port = 0; + + card->mpa_tx.enabled = 0; + card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; + + card->mpa_rx.buf_len = 0; + card->mpa_rx.pkt_cnt = 0; + card->mpa_rx.start_port = 0; + + card->mpa_rx.enabled = 0; + card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; + + /* Allocate buffers for SDIO MP-A */ + card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL); + if (!card->mp_regs) { + dev_err(adapter->dev, "failed to alloc mp_regs\n"); + return -ENOMEM; + } + + ret = mwifiex_alloc_sdio_mpa_buffers(adapter, + SDIO_MP_TX_AGGR_DEF_BUF_SIZE, + SDIO_MP_RX_AGGR_DEF_BUF_SIZE); + if (ret) { + dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n"); + kfree(card->mp_regs); + return -1; + } + + return ret; +} + +/* + * This function resets the MPA Tx and Rx buffers. + */ +static void mwifiex_cleanup_mpa_buf(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + MP_TX_AGGR_BUF_RESET(card); + MP_RX_AGGR_BUF_RESET(card); +} + +/* + * This function cleans up the allocated card buffers. + * + * The following are freed by this function - + * - MP registers + * - MPA Tx buffer + * - MPA Rx buffer + */ +static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + kfree(card->mp_regs); + kfree(card->mpa_tx.buf); + kfree(card->mpa_rx.buf); +} + +/* + * This function updates the MP end port in card. + */ +static void +mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) +{ + struct sdio_mmc_card *card = adapter->card; + int i; + + card->mp_end_port = port; + + card->mp_data_port_mask = DATA_PORT_MASK; + + for (i = 1; i <= MAX_PORT - card->mp_end_port; i++) + card->mp_data_port_mask &= ~(1 << (MAX_PORT - i)); + + card->curr_wr_port = 1; + + dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n", + port, card->mp_data_port_mask); +} + +static struct mwifiex_if_ops sdio_ops = { + .init_if = mwifiex_init_sdio, + .cleanup_if = mwifiex_cleanup_sdio, + .check_fw_status = mwifiex_check_fw_status, + .prog_fw = mwifiex_prog_fw_w_helper, + .register_dev = mwifiex_register_dev, + .unregister_dev = mwifiex_unregister_dev, + .enable_int = mwifiex_sdio_enable_host_int, + .process_int_status = mwifiex_process_int_status, + .host_to_card = mwifiex_sdio_host_to_card, + .wakeup = mwifiex_pm_wakeup_card, + .wakeup_complete = mwifiex_pm_wakeup_card_complete, + + /* SDIO specific */ + .update_mp_end_port = mwifiex_update_mp_end_port, + .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, +}; + +/* + * This function initializes the SDIO driver. + * + * This initiates the semaphore and registers the device with + * SDIO bus. + */ +static int +mwifiex_sdio_init_module(void) +{ + sema_init(&add_remove_card_sem, 1); + + return sdio_register_driver(&mwifiex_sdio); +} + +/* + * This function cleans up the SDIO driver. + * + * The following major steps are followed for cleanup - + * - Resume the device if its suspended + * - Disconnect the device if connected + * - Shutdown the firmware + * - Unregister the device from SDIO bus. + */ +static void +mwifiex_sdio_cleanup_module(void) +{ + struct mwifiex_adapter *adapter = g_adapter; + int i; + + if (down_interruptible(&add_remove_card_sem)) + goto exit_sem_err; + + if (!adapter || !adapter->priv_num) + goto exit; + + if (adapter->is_suspended) + mwifiex_sdio_resume(adapter->dev); + + 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); + + if (!adapter->surprise_removed) + mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), + MWIFIEX_FUNC_SHUTDOWN); + +exit: + up(&add_remove_card_sem); + +exit_sem_err: + sdio_unregister_driver(&mwifiex_sdio); +} + +module_init(mwifiex_sdio_init_module); +module_exit(mwifiex_sdio_cleanup_module); + +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("sd8787.bin"); diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h new file mode 100644 index 000000000000..a0e9bc5253e0 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -0,0 +1,305 @@ +/* + * Marvell Wireless LAN device driver: SDIO specific definitions + * + * Copyright (C) 2011, 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_SDIO_H +#define _MWIFIEX_SDIO_H + + +#include +#include +#include +#include + +#include "main.h" + +#define BLOCK_MODE 1 +#define BYTE_MODE 0 + +#define REG_PORT 0 +#define RD_BITMAP_L 0x04 +#define RD_BITMAP_U 0x05 +#define WR_BITMAP_L 0x06 +#define WR_BITMAP_U 0x07 +#define RD_LEN_P0_L 0x08 +#define RD_LEN_P0_U 0x09 + +#define MWIFIEX_SDIO_IO_PORT_MASK 0xfffff + +#define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000 + +#define CTRL_PORT 0 +#define CTRL_PORT_MASK 0x0001 +#define DATA_PORT_MASK 0xfffe + +#define MAX_MP_REGS 64 +#define MAX_PORT 16 + +#define SDIO_MP_AGGR_DEF_PKT_LIMIT 8 + +#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ + +/* Multi port RX aggregation buffer size */ +#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ + +/* Misc. Config Register : Auto Re-enable interrupts */ +#define AUTO_RE_ENABLE_INT BIT(4) + +/* Host Control Registers */ +/* Host Control Registers : I/O port 0 */ +#define IO_PORT_0_REG 0x78 +/* Host Control Registers : I/O port 1 */ +#define IO_PORT_1_REG 0x79 +/* Host Control Registers : I/O port 2 */ +#define IO_PORT_2_REG 0x7A + +/* Host Control Registers : Configuration */ +#define CONFIGURATION_REG 0x00 +/* Host Control Registers : Host without Command 53 finish host*/ +#define HOST_TO_CARD_EVENT (0x1U << 3) +/* Host Control Registers : Host without Command 53 finish host */ +#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2) +/* Host Control Registers : Host power up */ +#define HOST_POWER_UP (0x1U << 1) +/* Host Control Registers : Host power down */ +#define HOST_POWER_DOWN (0x1U << 0) + +/* Host Control Registers : Host interrupt mask */ +#define HOST_INT_MASK_REG 0x02 +/* Host Control Registers : Upload host interrupt mask */ +#define UP_LD_HOST_INT_MASK (0x1U) +/* Host Control Registers : Download host interrupt mask */ +#define DN_LD_HOST_INT_MASK (0x2U) +/* Enable Host interrupt mask */ +#define HOST_INT_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK) +/* Disable Host interrupt mask */ +#define HOST_INT_DISABLE 0xff + +/* Host Control Registers : Host interrupt status */ +#define HOST_INTSTATUS_REG 0x03 +/* Host Control Registers : Upload host interrupt status */ +#define UP_LD_HOST_INT_STATUS (0x1U) +/* Host Control Registers : Download host interrupt status */ +#define DN_LD_HOST_INT_STATUS (0x2U) + +/* Host Control Registers : Host interrupt RSR */ +#define HOST_INT_RSR_REG 0x01 +/* Host Control Registers : Upload host interrupt RSR */ +#define UP_LD_HOST_INT_RSR (0x1U) +#define SDIO_INT_MASK 0x3F + +/* Host Control Registers : Host interrupt status */ +#define HOST_INT_STATUS_REG 0x28 +/* Host Control Registers : Upload CRC error */ +#define UP_LD_CRC_ERR (0x1U << 2) +/* Host Control Registers : Upload restart */ +#define UP_LD_RESTART (0x1U << 1) +/* Host Control Registers : Download restart */ +#define DN_LD_RESTART (0x1U << 0) + +/* Card Control Registers : Card status register */ +#define CARD_STATUS_REG 0x30 +/* Card Control Registers : Card I/O ready */ +#define CARD_IO_READY (0x1U << 3) +/* Card Control Registers : CIS card ready */ +#define CIS_CARD_RDY (0x1U << 2) +/* Card Control Registers : Upload card ready */ +#define UP_LD_CARD_RDY (0x1U << 1) +/* Card Control Registers : Download card ready */ +#define DN_LD_CARD_RDY (0x1U << 0) + +/* Card Control Registers : Host interrupt mask register */ +#define HOST_INTERRUPT_MASK_REG 0x34 +/* Card Control Registers : Host power interrupt mask */ +#define HOST_POWER_INT_MASK (0x1U << 3) +/* Card Control Registers : Abort card interrupt mask */ +#define ABORT_CARD_INT_MASK (0x1U << 2) +/* Card Control Registers : Upload card interrupt mask */ +#define UP_LD_CARD_INT_MASK (0x1U << 1) +/* Card Control Registers : Download card interrupt mask */ +#define DN_LD_CARD_INT_MASK (0x1U << 0) + +/* Card Control Registers : Card interrupt status register */ +#define CARD_INTERRUPT_STATUS_REG 0x38 +/* Card Control Registers : Power up interrupt */ +#define POWER_UP_INT (0x1U << 4) +/* Card Control Registers : Power down interrupt */ +#define POWER_DOWN_INT (0x1U << 3) + +/* Card Control Registers : Card interrupt RSR register */ +#define CARD_INTERRUPT_RSR_REG 0x3c +/* Card Control Registers : Power up RSR */ +#define POWER_UP_RSR (0x1U << 4) +/* Card Control Registers : Power down RSR */ +#define POWER_DOWN_RSR (0x1U << 3) + +/* Card Control Registers : Miscellaneous Configuration Register */ +#define CARD_MISC_CFG_REG 0x6C + +/* Host F1 read base 0 */ +#define HOST_F1_RD_BASE_0 0x0040 +/* Host F1 read base 1 */ +#define HOST_F1_RD_BASE_1 0x0041 +/* Host F1 card ready */ +#define HOST_F1_CARD_RDY 0x0020 + +/* Firmware status 0 register */ +#define CARD_FW_STATUS0_REG 0x60 +/* Firmware status 1 register */ +#define CARD_FW_STATUS1_REG 0x61 +/* Rx length register */ +#define CARD_RX_LEN_REG 0x62 +/* Rx unit register */ +#define CARD_RX_UNIT_REG 0x63 + +/* Event header Len*/ +#define MWIFIEX_EVENT_HEADER_LEN 8 + +/* Max retry number of CMD53 write */ +#define MAX_WRITE_IOMEM_RETRY 2 + +/* SDIO Tx aggregation in progress ? */ +#define MP_TX_AGGR_IN_PROGRESS(a) (a->mpa_tx.pkt_cnt > 0) + +/* SDIO Tx aggregation buffer room for next packet ? */ +#define MP_TX_AGGR_BUF_HAS_ROOM(a, len) ((a->mpa_tx.buf_len+len) \ + <= a->mpa_tx.buf_size) + +/* Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */ +#define MP_TX_AGGR_BUF_PUT(a, payload, pkt_len, port) do { \ + memmove(&a->mpa_tx.buf[a->mpa_tx.buf_len], \ + payload, pkt_len); \ + a->mpa_tx.buf_len += pkt_len; \ + if (!a->mpa_tx.pkt_cnt) \ + a->mpa_tx.start_port = port; \ + if (a->mpa_tx.start_port <= port) \ + a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \ + else \ + a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - \ + a->mp_end_port))); \ + a->mpa_tx.pkt_cnt++; \ +} while (0); + +/* SDIO Tx aggregation limit ? */ +#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \ + (a->mpa_tx.pkt_cnt == a->mpa_tx.pkt_aggr_limit) + +/* SDIO Tx aggregation port limit ? */ +#define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \ + a->mpa_tx.start_port) && (((MAX_PORT - \ + a->mpa_tx.start_port) + a->curr_wr_port) >= \ + SDIO_MP_AGGR_DEF_PKT_LIMIT)) + +/* Reset SDIO Tx aggregation buffer parameters */ +#define MP_TX_AGGR_BUF_RESET(a) do { \ + a->mpa_tx.pkt_cnt = 0; \ + a->mpa_tx.buf_len = 0; \ + a->mpa_tx.ports = 0; \ + a->mpa_tx.start_port = 0; \ +} while (0); + +/* SDIO Rx aggregation limit ? */ +#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \ + (a->mpa_rx.pkt_cnt == a->mpa_rx.pkt_aggr_limit) + +/* SDIO Tx aggregation port limit ? */ +#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \ + a->mpa_rx.start_port) && (((MAX_PORT - \ + a->mpa_rx.start_port) + a->curr_rd_port) >= \ + SDIO_MP_AGGR_DEF_PKT_LIMIT)) + +/* SDIO Rx aggregation in progress ? */ +#define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt > 0) + +/* SDIO Rx aggregation buffer room for next packet ? */ +#define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) \ + ((a->mpa_rx.buf_len+rx_len) <= a->mpa_rx.buf_size) + +/* Prepare to copy current packet from card to SDIO Rx aggregation buffer */ +#define MP_RX_AGGR_SETUP(a, skb, port) do { \ + a->mpa_rx.buf_len += skb->len; \ + if (!a->mpa_rx.pkt_cnt) \ + a->mpa_rx.start_port = port; \ + if (a->mpa_rx.start_port <= port) \ + a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \ + else \ + a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \ + 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); + +/* Reset SDIO Rx aggregation buffer parameters */ +#define MP_RX_AGGR_BUF_RESET(a) do { \ + a->mpa_rx.pkt_cnt = 0; \ + a->mpa_rx.buf_len = 0; \ + a->mpa_rx.ports = 0; \ + a->mpa_rx.start_port = 0; \ +} while (0); + + +/* data structure for SDIO MPA TX */ +struct mwifiex_sdio_mpa_tx { + /* multiport tx aggregation buffer pointer */ + u8 *buf; + u32 buf_len; + u32 pkt_cnt; + u16 ports; + u16 start_port; + u8 enabled; + u32 buf_size; + u32 pkt_aggr_limit; +}; + +struct mwifiex_sdio_mpa_rx { + u8 *buf; + u32 buf_len; + u32 pkt_cnt; + u16 ports; + u16 start_port; + + struct sk_buff *skb_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT]; + u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT]; + + u8 enabled; + u32 buf_size; + u32 pkt_aggr_limit; +}; + +int mwifiex_bus_register(void); +void mwifiex_bus_unregister(void); + +struct sdio_mmc_card { + struct sdio_func *func; + struct mwifiex_adapter *adapter; + + u16 mp_rd_bitmap; + u16 mp_wr_bitmap; + + u16 mp_end_port; + u16 mp_data_port_mask; + + u8 curr_rd_port; + u8 curr_wr_port; + + u8 *mp_regs; + + struct mwifiex_sdio_mpa_tx mpa_tx; + struct mwifiex_sdio_mpa_rx mpa_rx; +}; +#endif /* _MWIFIEX_SDIO_H */ diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c new file mode 100644 index 000000000000..8af3a78d2723 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -0,0 +1,1219 @@ +/* + * Marvell Wireless LAN device driver: station command handling + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * This function prepares command to set/get RSSI information. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting data/beacon average factors + * - Resetting SNR/NF/RSSI values in private structure + * - Ensuring correct endian-ness + */ +static int +mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, u16 cmd_action) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_RSSI_INFO); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rssi_info) + + S_DS_GEN); + cmd->params.rssi_info.action = cpu_to_le16(cmd_action); + cmd->params.rssi_info.ndata = cpu_to_le16(priv->data_avg_factor); + cmd->params.rssi_info.nbcn = cpu_to_le16(priv->bcn_avg_factor); + + /* Reset SNR/NF/RSSI values in private structure */ + priv->data_rssi_last = 0; + priv->data_nf_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->bcn_rssi_last = 0; + priv->bcn_nf_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + + return 0; +} + +/* + * This function prepares command to set MAC control. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_mac_control(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl; + u16 action = *((u16 *) data_buf); + + if (cmd_action != HostCmd_ACT_GEN_SET) { + dev_err(priv->adapter->dev, + "mac_control: only support set cmd\n"); + return -1; + } + + cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN); + mac_ctrl->action = cpu_to_le16(action); + + return 0; +} + +/* + * This function prepares command to set/get SNMP MIB. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting SNMP MIB OID number and value + * (as required) + * - Ensuring correct endian-ness + * + * The following SNMP MIB OIDs are supported - + * - FRAG_THRESH_I : Fragmentation threshold + * - RTS_THRESH_I : RTS threshold + * - SHORT_RETRY_LIM_I : Short retry limit + * - DOT11D_I : 11d support + */ +static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, u32 cmd_oid, + void *data_buf) +{ + struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib; + u32 ul_temp; + + dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib) + - 1 + S_DS_GEN); + + if (cmd_action == HostCmd_ACT_GEN_GET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET); + snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + MAX_SNMP_BUF_SIZE); + } + + switch (cmd_oid) { + case FRAG_THRESH_I: + snmp_mib->oid = cpu_to_le16((u16) FRAG_THRESH_I); + if (cmd_action == HostCmd_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + ul_temp = *((u32 *) data_buf); + *((__le16 *) (snmp_mib->value)) = + cpu_to_le16((u16) ul_temp); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(u16)); + } + break; + case RTS_THRESH_I: + snmp_mib->oid = cpu_to_le16((u16) RTS_THRESH_I); + if (cmd_action == HostCmd_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + ul_temp = *((u32 *) data_buf); + *(__le16 *) (snmp_mib->value) = + cpu_to_le16((u16) ul_temp); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(u16)); + } + break; + + case SHORT_RETRY_LIM_I: + snmp_mib->oid = cpu_to_le16((u16) SHORT_RETRY_LIM_I); + if (cmd_action == HostCmd_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + ul_temp = (*(u32 *) data_buf); + *((__le16 *) (snmp_mib->value)) = + cpu_to_le16((u16) ul_temp); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(u16)); + } + break; + case DOT11D_I: + snmp_mib->oid = cpu_to_le16((u16) DOT11D_I); + if (cmd_action == HostCmd_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + ul_temp = *(u32 *) data_buf; + *((__le16 *) (snmp_mib->value)) = + cpu_to_le16((u16) ul_temp); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(u16)); + } + break; + default: + break; + } + dev_dbg(priv->adapter->dev, + "cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x," + " Value=0x%x\n", + cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size), + le16_to_cpu(*(__le16 *) snmp_mib->value)); + return 0; +} + +/* + * This function prepares command to get log. + * + * Preparation includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +static int +mwifiex_cmd_802_11_get_log(struct host_cmd_ds_command *cmd) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) + + S_DS_GEN); + return 0; +} + +/* + * This function prepares command to set/get Tx data rate configuration. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting configuration index, rate scope and rate drop pattern + * parameters (as required) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg; + struct mwifiex_rate_scope *rate_scope; + struct mwifiex_rate_drop_pattern *rate_drop; + u16 *pbitmap_rates = (u16 *) data_buf; + + u32 i; + + cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG); + + rate_cfg->action = cpu_to_le16(cmd_action); + rate_cfg->cfg_index = 0; + + rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg + + sizeof(struct host_cmd_ds_tx_rate_cfg)); + rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE); + rate_scope->length = cpu_to_le16(sizeof(struct mwifiex_rate_scope) - + sizeof(struct mwifiex_ie_types_header)); + if (pbitmap_rates != NULL) { + rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]); + rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]); + for (i = 0; + i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); + i++) + rate_scope->ht_mcs_rate_bitmap[i] = + cpu_to_le16(pbitmap_rates[2 + i]); + } else { + rate_scope->hr_dsss_rate_bitmap = + cpu_to_le16(priv->bitmap_rates[0]); + rate_scope->ofdm_rate_bitmap = + cpu_to_le16(priv->bitmap_rates[1]); + for (i = 0; + i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); + i++) + rate_scope->ht_mcs_rate_bitmap[i] = + cpu_to_le16(priv->bitmap_rates[2 + i]); + } + + rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope + + sizeof(struct mwifiex_rate_scope)); + rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL); + rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode)); + rate_drop->rate_drop_mode = 0; + + cmd->size = + cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) + + sizeof(struct mwifiex_rate_scope) + + sizeof(struct mwifiex_rate_drop_pattern)); + + return 0; +} + +/* + * This function prepares command to set/get Tx power configuration. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting Tx power mode, power group TLV + * (as required) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct mwifiex_types_power_group *pg_tlv; + struct host_cmd_ds_txpwr_cfg *txp; + struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg; + + cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG); + cmd->size = + cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg)); + switch (cmd_action) { + case HostCmd_ACT_GEN_SET: + txp = (struct host_cmd_ds_txpwr_cfg *) data_buf; + if (txp->mode) { + pg_tlv = (struct mwifiex_types_power_group + *) ((unsigned long) data_buf + + sizeof(struct host_cmd_ds_txpwr_cfg)); + memmove(cmd_txp_cfg, data_buf, + sizeof(struct host_cmd_ds_txpwr_cfg) + + sizeof(struct mwifiex_types_power_group) + + pg_tlv->length); + + pg_tlv = (struct mwifiex_types_power_group *) ((u8 *) + cmd_txp_cfg + + sizeof(struct host_cmd_ds_txpwr_cfg)); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(struct mwifiex_types_power_group) + + pg_tlv->length); + } else { + memmove(cmd_txp_cfg, data_buf, + sizeof(struct host_cmd_ds_txpwr_cfg)); + } + cmd_txp_cfg->action = cpu_to_le16(cmd_action); + break; + case HostCmd_ACT_GEN_GET: + cmd_txp_cfg->action = cpu_to_le16(cmd_action); + break; + } + + return 0; +} + +/* + * This function prepares command to set Host Sleep configuration. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting Host Sleep action, conditions, ARP filters + * (as required) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, + struct mwifiex_hs_config_param *data_buf) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg; + u16 hs_activate = false; + + if (data_buf == NULL) + /* New Activate command */ + hs_activate = true; + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH); + + if (!hs_activate && + (data_buf->conditions + != cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) + && ((adapter->arp_filter_size > 0) + && (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) { + dev_dbg(adapter->dev, + "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n", + adapter->arp_filter_size); + memcpy(((u8 *) hs_cfg) + + sizeof(struct host_cmd_ds_802_11_hs_cfg_enh), + adapter->arp_filter, adapter->arp_filter_size); + cmd->size = cpu_to_le16(adapter->arp_filter_size + + sizeof(struct host_cmd_ds_802_11_hs_cfg_enh) + + S_DS_GEN); + } else { + cmd->size = cpu_to_le16(S_DS_GEN + sizeof(struct + host_cmd_ds_802_11_hs_cfg_enh)); + } + if (hs_activate) { + hs_cfg->action = cpu_to_le16(HS_ACTIVATE); + hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED; + } else { + hs_cfg->action = cpu_to_le16(HS_CONFIGURE); + hs_cfg->params.hs_config.conditions = data_buf->conditions; + hs_cfg->params.hs_config.gpio = data_buf->gpio; + hs_cfg->params.hs_config.gap = data_buf->gap; + dev_dbg(adapter->dev, + "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n", + hs_cfg->params.hs_config.conditions, + hs_cfg->params.hs_config.gpio, + hs_cfg->params.hs_config.gap); + } + + return 0; +} + +/* + * This function prepares command to set/get MAC address. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting MAC address (for SET only) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) + + S_DS_GEN); + cmd->result = 0; + + cmd->params.mac_addr.action = cpu_to_le16(cmd_action); + + if (cmd_action == HostCmd_ACT_GEN_SET) + memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr, + ETH_ALEN); + return 0; +} + +/* + * This function prepares command to set MAC multicast address. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting MAC multicast address + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct mwifiex_multicast_list *mcast_list = + (struct mwifiex_multicast_list *) data_buf; + struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr; + + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) + + S_DS_GEN); + cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR); + + mcast_addr->action = cpu_to_le16(cmd_action); + mcast_addr->num_of_adrs = + cpu_to_le16((u16) mcast_list->num_multicast_addr); + memcpy(mcast_addr->mac_list, mcast_list->mac_list, + mcast_list->num_multicast_addr * ETH_ALEN); + + return 0; +} + +/* + * This function prepares command to deauthenticate. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting AP MAC address and reason code + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate) + + S_DS_GEN); + + /* Set AP MAC address */ + memcpy(deauth->mac_addr, (u8 *) data_buf, ETH_ALEN); + + dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr); + + deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING); + + return 0; +} + +/* + * This function prepares command to stop Ad-Hoc network. + * + * Preparation includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_ad_hoc_stop(struct host_cmd_ds_command *cmd) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP); + cmd->size = cpu_to_le16(S_DS_GEN); + return 0; +} + +/* + * This function sets WEP key(s) to key parameter TLV(s). + * + * Multi-key parameter TLVs are supported, so we can send multiple + * WEP keys in a single buffer. + */ +static int +mwifiex_set_keyparamset_wep(struct mwifiex_private *priv, + struct mwifiex_ie_type_key_param_set *key_param_set, + u16 *key_param_len) +{ + int cur_key_param_len; + u8 i; + + /* Multi-key_param_set TLV is supported */ + for (i = 0; i < NUM_WEP_KEYS; i++) { + if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) || + (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) { + key_param_set->type = + cpu_to_le16(TLV_TYPE_KEY_MATERIAL); +/* Key_param_set WEP fixed length */ +#define KEYPARAMSET_WEP_FIXED_LEN 8 + key_param_set->length = cpu_to_le16((u16) + (priv->wep_key[i]. + key_length + + KEYPARAMSET_WEP_FIXED_LEN)); + key_param_set->key_type_id = + cpu_to_le16(KEY_TYPE_ID_WEP); + key_param_set->key_info = + cpu_to_le16(KEY_ENABLED | KEY_UNICAST | + KEY_MCAST); + key_param_set->key_len = + cpu_to_le16(priv->wep_key[i].key_length); + /* Set WEP key index */ + key_param_set->key[0] = i; + /* Set default Tx key flag */ + if (i == + (priv-> + wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK)) + key_param_set->key[1] = 1; + else + key_param_set->key[1] = 0; + memmove(&key_param_set->key[2], + priv->wep_key[i].key_material, + priv->wep_key[i].key_length); + + cur_key_param_len = priv->wep_key[i].key_length + + KEYPARAMSET_WEP_FIXED_LEN + + sizeof(struct mwifiex_ie_types_header); + *key_param_len += (u16) cur_key_param_len; + key_param_set = + (struct mwifiex_ie_type_key_param_set *) + ((u8 *)key_param_set + + cur_key_param_len); + } else if (!priv->wep_key[i].key_length) { + continue; + } else { + dev_err(priv->adapter->dev, + "key%d Length = %d is incorrect\n", + (i + 1), priv->wep_key[i].key_length); + return -1; + } + } + + return 0; +} + +/* + * This function prepares command to set/get/reset network key(s). + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting WEP keys, WAPI keys or WPA keys along with required + * encryption (TKIP, AES) (as required) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, + u32 cmd_oid, void *data_buf) +{ + struct host_cmd_ds_802_11_key_material *key_material = + &cmd->params.key_material; + struct mwifiex_ds_encrypt_key *enc_key = + (struct mwifiex_ds_encrypt_key *) data_buf; + u16 key_param_len = 0; + int ret = 0; + const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL); + key_material->action = cpu_to_le16(cmd_action); + + if (cmd_action == HostCmd_ACT_GEN_GET) { + cmd->size = + cpu_to_le16(sizeof(key_material->action) + S_DS_GEN); + return ret; + } + + if (!enc_key) { + memset(&key_material->key_param_set, 0, + (NUM_WEP_KEYS * + sizeof(struct mwifiex_ie_type_key_param_set))); + ret = mwifiex_set_keyparamset_wep(priv, + &key_material->key_param_set, + &key_param_len); + cmd->size = cpu_to_le16(key_param_len + + sizeof(key_material->action) + S_DS_GEN); + return ret; + } else + memset(&key_material->key_param_set, 0, + sizeof(struct mwifiex_ie_type_key_param_set)); + if (enc_key->is_wapi_key) { + dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n"); + key_material->key_param_set.key_type_id = + cpu_to_le16(KEY_TYPE_ID_WAPI); + if (cmd_oid == KEY_INFO_ENABLED) + key_material->key_param_set.key_info = + cpu_to_le16(KEY_ENABLED); + else + key_material->key_param_set.key_info = + cpu_to_le16(!KEY_ENABLED); + + key_material->key_param_set.key[0] = enc_key->key_index; + if (!priv->sec_info.wapi_key_on) + key_material->key_param_set.key[1] = 1; + else + /* set 0 when re-key */ + key_material->key_param_set.key[1] = 0; + + if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) { + /* WAPI pairwise key: unicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_UNICAST); + } else { /* WAPI group key: multicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_MCAST); + priv->sec_info.wapi_key_on = true; + } + + key_material->key_param_set.type = + cpu_to_le16(TLV_TYPE_KEY_MATERIAL); + key_material->key_param_set.key_len = + cpu_to_le16(WAPI_KEY_LEN); + memcpy(&key_material->key_param_set.key[2], + enc_key->key_material, enc_key->key_len); + memcpy(&key_material->key_param_set.key[2 + enc_key->key_len], + enc_key->wapi_rxpn, WAPI_RXPN_LEN); + key_material->key_param_set.length = + cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN); + + key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) + + sizeof(struct mwifiex_ie_types_header); + cmd->size = cpu_to_le16(key_param_len + + sizeof(key_material->action) + S_DS_GEN); + return ret; + } + if (enc_key->key_len == WLAN_KEY_LEN_CCMP) { + dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n"); + key_material->key_param_set.key_type_id = + cpu_to_le16(KEY_TYPE_ID_AES); + if (cmd_oid == KEY_INFO_ENABLED) + key_material->key_param_set.key_info = + cpu_to_le16(KEY_ENABLED); + else + key_material->key_param_set.key_info = + cpu_to_le16(!KEY_ENABLED); + + if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) + /* AES pairwise key: unicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_UNICAST); + else /* AES group key: multicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_MCAST); + } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) { + dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n"); + key_material->key_param_set.key_type_id = + cpu_to_le16(KEY_TYPE_ID_TKIP); + key_material->key_param_set.key_info = + cpu_to_le16(KEY_ENABLED); + + if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) + /* TKIP pairwise key: unicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_UNICAST); + else /* TKIP group key: multicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_MCAST); + } + + if (key_material->key_param_set.key_type_id) { + key_material->key_param_set.type = + cpu_to_le16(TLV_TYPE_KEY_MATERIAL); + key_material->key_param_set.key_len = + cpu_to_le16((u16) enc_key->key_len); + memcpy(key_material->key_param_set.key, enc_key->key_material, + enc_key->key_len); + key_material->key_param_set.length = + cpu_to_le16((u16) enc_key->key_len + + KEYPARAMSET_FIXED_LEN); + + key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN) + + sizeof(struct mwifiex_ie_types_header); + + cmd->size = cpu_to_le16(key_param_len + + sizeof(key_material->action) + S_DS_GEN); + } + + return ret; +} + +/* + * This function prepares command to set/get 11d domain information. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting domain information fields (for SET only) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11d_domain_info *domain_info = + &cmd->params.domain_info; + struct mwifiex_ietypes_domain_param_set *domain = + &domain_info->domain; + u8 no_of_triplet = adapter->domain_reg.no_of_triplet; + + dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO); + domain_info->action = cpu_to_le16(cmd_action); + if (cmd_action == HostCmd_ACT_GEN_GET) { + cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN); + return 0; + } + + /* Set domain info fields */ + domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY); + memcpy(domain->country_code, adapter->domain_reg.country_code, + sizeof(domain->country_code)); + + domain->header.len = cpu_to_le16((no_of_triplet * + sizeof(struct ieee80211_country_ie_triplet)) + + sizeof(domain->country_code)); + + if (no_of_triplet) { + memcpy(domain->triplet, adapter->domain_reg.triplet, + no_of_triplet * + sizeof(struct ieee80211_country_ie_triplet)); + + cmd->size = cpu_to_le16(sizeof(domain_info->action) + + le16_to_cpu(domain->header.len) + + sizeof(struct mwifiex_ie_types_header) + + S_DS_GEN); + } else { + cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN); + } + + return 0; +} + +/* + * This function prepares command to set/get RF channel. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting RF type and current RF channel (for SET only) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_802_11_rf_channel *rf_chan = + &cmd->params.rf_channel; + uint16_t rf_type = le16_to_cpu(rf_chan->rf_type); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rf_channel) + + S_DS_GEN); + + if (cmd_action == HostCmd_ACT_GEN_SET) { + if ((priv->adapter->adhoc_start_band & BAND_A) + || (priv->adapter->adhoc_start_band & BAND_AN)) + rf_chan->rf_type = + cpu_to_le16(HostCmd_SCAN_RADIO_TYPE_A); + + rf_type = le16_to_cpu(rf_chan->rf_type); + SET_SECONDARYCHAN(rf_type, priv->adapter->chan_offset); + rf_chan->current_channel = cpu_to_le16(*((u16 *) data_buf)); + } + rf_chan->action = cpu_to_le16(cmd_action); + return 0; +} + +/* + * This function prepares command to set/get IBSS coalescing status. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting status to enable or disable (for SET only) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_802_11_ibss_status *ibss_coal = + &(cmd->params.ibss_coalescing); + u16 enable = 0; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) + + S_DS_GEN); + cmd->result = 0; + ibss_coal->action = cpu_to_le16(cmd_action); + + switch (cmd_action) { + case HostCmd_ACT_GEN_SET: + if (data_buf != NULL) + enable = *(u16 *) data_buf; + ibss_coal->enable = cpu_to_le16(enable); + break; + + /* In other case.. Nothing to do */ + case HostCmd_ACT_GEN_GET: + default: + break; + } + + return 0; +} + +/* + * This function prepares command to set/get register value. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting register offset (for both GET and SET) and + * register value (for SET only) + * - Ensuring correct endian-ness + * + * The following type of registers can be accessed with this function - + * - MAC register + * - BBP register + * - RF register + * - PMIC register + * - CAU register + * - EEPROM + */ +static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct mwifiex_ds_reg_rw *reg_rw; + + reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; + switch (le16_to_cpu(cmd->command)) { + case HostCmd_CMD_MAC_REG_ACCESS: + { + struct host_cmd_ds_mac_reg_access *mac_reg; + + cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN); + mac_reg = (struct host_cmd_ds_mac_reg_access *) &cmd-> + params.mac_reg; + mac_reg->action = cpu_to_le16(cmd_action); + mac_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + mac_reg->value = reg_rw->value; + break; + } + case HostCmd_CMD_BBP_REG_ACCESS: + { + struct host_cmd_ds_bbp_reg_access *bbp_reg; + + cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN); + bbp_reg = (struct host_cmd_ds_bbp_reg_access *) &cmd-> + params.bbp_reg; + bbp_reg->action = cpu_to_le16(cmd_action); + bbp_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + bbp_reg->value = (u8) le32_to_cpu(reg_rw->value); + break; + } + case HostCmd_CMD_RF_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *rf_reg; + + cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN); + rf_reg = (struct host_cmd_ds_rf_reg_access *) &cmd-> + params.rf_reg; + rf_reg->action = cpu_to_le16(cmd_action); + rf_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + rf_reg->value = (u8) le32_to_cpu(reg_rw->value); + break; + } + case HostCmd_CMD_PMIC_REG_ACCESS: + { + struct host_cmd_ds_pmic_reg_access *pmic_reg; + + cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN); + pmic_reg = (struct host_cmd_ds_pmic_reg_access *) &cmd-> + params.pmic_reg; + pmic_reg->action = cpu_to_le16(cmd_action); + pmic_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + pmic_reg->value = (u8) le32_to_cpu(reg_rw->value); + break; + } + case HostCmd_CMD_CAU_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *cau_reg; + + cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN); + cau_reg = (struct host_cmd_ds_rf_reg_access *) &cmd-> + params.rf_reg; + cau_reg->action = cpu_to_le16(cmd_action); + cau_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + cau_reg->value = (u8) le32_to_cpu(reg_rw->value); + break; + } + case HostCmd_CMD_802_11_EEPROM_ACCESS: + { + struct mwifiex_ds_read_eeprom *rd_eeprom = + (struct mwifiex_ds_read_eeprom *) data_buf; + struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom = + (struct host_cmd_ds_802_11_eeprom_access *) + &cmd->params.eeprom; + + cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN); + cmd_eeprom->action = cpu_to_le16(cmd_action); + cmd_eeprom->offset = rd_eeprom->offset; + cmd_eeprom->byte_count = rd_eeprom->byte_count; + cmd_eeprom->value = 0; + break; + } + default: + return -1; + } + + return 0; +} + +/* + * This function prepares the commands before sending them to the firmware. + * + * This is a generic function which calls specific command preparation + * routines based upon the command number. + */ +int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, + void *data_buf, void *cmd_buf) +{ + struct host_cmd_ds_command *cmd_ptr = + (struct host_cmd_ds_command *) cmd_buf; + int ret = 0; + + /* Prepare command */ + switch (cmd_no) { + case HostCmd_CMD_GET_HW_SPEC: + ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr); + break; + case HostCmd_CMD_MAC_CONTROL: + ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_802_11_MAC_ADDRESS: + ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr, + cmd_action); + break; + case HostCmd_CMD_MAC_MULTICAST_ADR: + ret = mwifiex_cmd_mac_multicast_adr(cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_TX_RATE_CFG: + ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_TXPWR_CFG: + ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_802_11_PS_MODE_ENH: + ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action, + (uint16_t)cmd_oid, data_buf); + break; + case HostCmd_CMD_802_11_HS_CFG_ENH: + ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action, + (struct mwifiex_hs_config_param *) data_buf); + break; + case HostCmd_CMD_802_11_SCAN: + ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf); + break; + case HostCmd_CMD_802_11_BG_SCAN_QUERY: + ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr); + break; + case HostCmd_CMD_802_11_ASSOCIATE: + ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf); + break; + case HostCmd_CMD_802_11_DEAUTHENTICATE: + ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr, + data_buf); + break; + case HostCmd_CMD_802_11_AD_HOC_START: + ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr, + data_buf); + break; + case HostCmd_CMD_802_11_GET_LOG: + ret = mwifiex_cmd_802_11_get_log(cmd_ptr); + break; + case HostCmd_CMD_802_11_AD_HOC_JOIN: + ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr, + data_buf); + break; + case HostCmd_CMD_802_11_AD_HOC_STOP: + ret = mwifiex_cmd_802_11_ad_hoc_stop(cmd_ptr); + break; + case HostCmd_CMD_RSSI_INFO: + ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action); + break; + case HostCmd_CMD_802_11_SNMP_MIB: + ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action, + cmd_oid, data_buf); + break; + case HostCmd_CMD_802_11_TX_RATE_QUERY: + cmd_ptr->command = + cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY); + cmd_ptr->size = + cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) + + S_DS_GEN); + priv->tx_rate = 0; + ret = 0; + break; + case HostCmd_CMD_VERSION_EXT: + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->params.verext.version_str_sel = + (u8) (*((u32 *) data_buf)); + memcpy(&cmd_ptr->params, data_buf, + sizeof(struct host_cmd_ds_version_ext)); + cmd_ptr->size = + cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) + + S_DS_GEN); + ret = 0; + break; + case HostCmd_CMD_802_11_RF_CHANNEL: + ret = mwifiex_cmd_802_11_rf_channel(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_FUNC_INIT: + if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET) + priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY; + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->size = cpu_to_le16(S_DS_GEN); + break; + case HostCmd_CMD_FUNC_SHUTDOWN: + priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET; + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->size = cpu_to_le16(S_DS_GEN); + break; + case HostCmd_CMD_11N_ADDBA_REQ: + ret = mwifiex_cmd_11n_addba_req(cmd_ptr, data_buf); + break; + case HostCmd_CMD_11N_DELBA: + ret = mwifiex_cmd_11n_delba(cmd_ptr, data_buf); + break; + case HostCmd_CMD_11N_ADDBA_RSP: + ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf); + break; + case HostCmd_CMD_802_11_KEY_MATERIAL: + ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr, + cmd_action, cmd_oid, + data_buf); + break; + case HostCmd_CMD_802_11D_DOMAIN_INFO: + ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr, + cmd_action); + break; + case HostCmd_CMD_RECONFIGURE_TX_BUFF: + ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_AMSDU_AGGR_CTRL: + ret = mwifiex_cmd_amsdu_aggr_ctrl(cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_11N_CFG: + ret = mwifiex_cmd_11n_cfg(cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_WMM_GET_STATUS: + dev_dbg(priv->adapter->dev, + "cmd: WMM: WMM_GET_STATUS cmd sent\n"); + cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS); + cmd_ptr->size = + cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) + + S_DS_GEN); + ret = 0; + break; + case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: + ret = mwifiex_cmd_ibss_coalescing_status(cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_MAC_REG_ACCESS: + case HostCmd_CMD_BBP_REG_ACCESS: + case HostCmd_CMD_RF_REG_ACCESS: + case HostCmd_CMD_PMIC_REG_ACCESS: + case HostCmd_CMD_CAU_REG_ACCESS: + case HostCmd_CMD_802_11_EEPROM_ACCESS: + ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf); + break; + case HostCmd_CMD_SET_BSS_MODE: + cmd_ptr->command = cpu_to_le16(cmd_no); + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) + cmd_ptr->params.bss_mode.con_type = + CONNECTION_TYPE_ADHOC; + else if (priv->bss_mode == NL80211_IFTYPE_STATION) + cmd_ptr->params.bss_mode.con_type = + CONNECTION_TYPE_INFRA; + cmd_ptr->size = cpu_to_le16(sizeof(struct + host_cmd_ds_set_bss_mode) + S_DS_GEN); + ret = 0; + break; + default: + dev_err(priv->adapter->dev, + "PREP_CMD: unknown cmd- %#x\n", cmd_no); + ret = -1; + break; + } + return ret; +} + +/* + * This function issues commands to initialize firmware. + * + * This is called after firmware download to bring the card to + * working state. + * + * The following commands are issued sequentially - + * - Function init (for first interface only) + * - Read MAC address (for first interface only) + * - Reconfigure Tx buffer size (for first interface only) + * - Enable auto deep sleep (for first interface only) + * - Get Tx rate + * - Get Tx power + * - Set IBSS coalescing status + * - Set AMSDU aggregation control + * - Set 11d control + * - Set MAC control (this must be the last command to initialize firmware) + */ +int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) +{ + int ret; + u16 enable = true; + struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; + struct mwifiex_ds_auto_ds auto_ds; + enum state_11d_t state_11d; + + if (first_sta) { + + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT, + HostCmd_ACT_GEN_SET, 0, NULL); + if (ret) + return -1; + /* Read MAC address from HW */ + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_GET_HW_SPEC, + HostCmd_ACT_GEN_GET, 0, NULL); + if (ret) + return -1; + + /* Reconfigure tx buf size */ + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_RECONFIGURE_TX_BUFF, + HostCmd_ACT_GEN_SET, 0, + &priv->adapter->tx_buf_size); + if (ret) + return -1; + + /* Enable IEEE PS by default */ + priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_PS_MODE_ENH, + EN_AUTO_PS, BITMAP_STA_PS, NULL); + if (ret) + return -1; + } + + /* get tx rate */ + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TX_RATE_CFG, + HostCmd_ACT_GEN_GET, 0, NULL); + if (ret) + return -1; + priv->data_rate = 0; + + /* get tx power */ + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TXPWR_CFG, + HostCmd_ACT_GEN_GET, 0, NULL); + if (ret) + return -1; + + /* set ibss coalescing_status */ + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, + HostCmd_ACT_GEN_SET, 0, &enable); + if (ret) + return -1; + + memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl)); + amsdu_aggr_ctrl.enable = true; + /* Send request to firmware */ + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_AMSDU_AGGR_CTRL, + HostCmd_ACT_GEN_SET, 0, + (void *) &amsdu_aggr_ctrl); + if (ret) + return -1; + /* MAC Control must be the last command in init_fw */ + /* set MAC Control */ + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter); + if (ret) + return -1; + + if (first_sta) { + /* Enable auto deep sleep */ + auto_ds.auto_ds = DEEP_SLEEP_ON; + auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_PS_MODE_ENH, + EN_AUTO_PS, BITMAP_AUTO_DS, + &auto_ds); + if (ret) + return -1; + } + + /* Send cmd to FW to enable/disable 11D function */ + state_11d = ENABLE_11D; + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, DOT11D_I, &state_11d); + if (ret) + dev_err(priv->adapter->dev, "11D: failed to enable 11D\n"); + + /* set last_init_cmd */ + priv->adapter->last_init_cmd = HostCmd_CMD_802_11_SNMP_MIB; + ret = -EINPROGRESS; + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c new file mode 100644 index 000000000000..d08f76429a0a --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -0,0 +1,972 @@ +/* + * Marvell Wireless LAN device driver: station command response handling + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + + +/* + * This function handles the command response error case. + * + * For scan response error, the function cancels all the pending + * scan commands and generates an event to inform the applications + * of the scan completion. + * + * For Power Save command failure, we do not retry enter PS + * command in case of Ad-hoc mode. + * + * For all other response errors, the current command buffer is freed + * and returned to the free command queue. + */ +static void +mwifiex_process_cmdresp_error(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node; + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_ps_mode_enh *pm; + unsigned long flags; + + dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n", + resp->command, resp->result); + + if (adapter->curr_cmd->wait_q_enabled) + adapter->cmd_wait_q.status = -1; + + switch (le16_to_cpu(resp->command)) { + case HostCmd_CMD_802_11_PS_MODE_ENH: + pm = &resp->params.psmode_enh; + dev_err(adapter->dev, "PS_MODE_ENH cmd failed: " + "result=0x%x action=0x%X\n", + resp->result, le16_to_cpu(pm->action)); + /* We do not re-try enter-ps command in ad-hoc mode. */ + if (le16_to_cpu(pm->action) == EN_AUTO_PS && + (le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) && + priv->bss_mode == NL80211_IFTYPE_ADHOC) + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + + break; + case HostCmd_CMD_802_11_SCAN: + /* Cancel all pending scan command */ + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + if (priv->report_scan_result) + priv->report_scan_result = false; + if (priv->scan_pending_on_block) { + priv->scan_pending_on_block = false; + up(&priv->async_sem); + } + break; + + case HostCmd_CMD_MAC_CONTROL: + break; + + default: + break; + } + /* Handling errors here */ + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); +} + +/* + * This function handles the command response of get RSSI info. + * + * Handling includes changing the header fields into CPU format + * and saving the following parameters in driver - + * - Last data and beacon RSSI value + * - Average data and beacon RSSI value + * - Last data and beacon NF value + * - Average data and beacon NF value + * + * The parameters are send to the application as well, along with + * calculated SNR values. + */ +static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp = + &resp->params.rssi_info_rsp; + struct mwifiex_ds_get_signal *signal; + + 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); + + priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg); + priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg); + + priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last); + priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last); + + 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 (data_buf) { + signal = (struct mwifiex_ds_get_signal *) data_buf; + memset(signal, 0, sizeof(struct mwifiex_ds_get_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; + } + + return 0; +} + +/* + * This function handles the command response of set/get SNMP + * MIB parameters. + * + * Handling includes changing the header fields into CPU format + * and saving the parameter in driver. + * + * The following parameters are supported - + * - Fragmentation threshold + * - RTS threshold + * - Short retry limit + */ +static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; + u16 oid = le16_to_cpu(smib->oid); + u16 query_type = le16_to_cpu(smib->query_type); + u32 ul_temp; + + dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x," + " query_type = %#x, buf size = %#x\n", + oid, query_type, le16_to_cpu(smib->buf_size)); + if (query_type == HostCmd_ACT_GEN_GET) { + ul_temp = le16_to_cpu(*((__le16 *) (smib->value))); + if (data_buf) + *(u32 *)data_buf = ul_temp; + switch (oid) { + case FRAG_THRESH_I: + dev_dbg(priv->adapter->dev, + "info: SNMP_RESP: FragThsd =%u\n", ul_temp); + break; + case RTS_THRESH_I: + dev_dbg(priv->adapter->dev, + "info: SNMP_RESP: RTSThsd =%u\n", ul_temp); + break; + case SHORT_RETRY_LIM_I: + dev_dbg(priv->adapter->dev, + "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp); + break; + default: + break; + } + } + + return 0; +} + +/* + * This function handles the command response of get log request + * + * Handling includes changing the header fields into CPU format + * and sending the received parameters to application. + */ +static int mwifiex_ret_get_log(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_802_11_get_log *get_log = + (struct host_cmd_ds_802_11_get_log *) &resp->params.get_log; + struct mwifiex_ds_get_stats *stats; + + if (data_buf) { + stats = (struct mwifiex_ds_get_stats *) data_buf; + stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame); + stats->failed = le32_to_cpu(get_log->failed); + stats->retry = le32_to_cpu(get_log->retry); + stats->multi_retry = le32_to_cpu(get_log->multi_retry); + stats->frame_dup = le32_to_cpu(get_log->frame_dup); + stats->rts_success = le32_to_cpu(get_log->rts_success); + stats->rts_failure = le32_to_cpu(get_log->rts_failure); + stats->ack_failure = le32_to_cpu(get_log->ack_failure); + stats->rx_frag = le32_to_cpu(get_log->rx_frag); + stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame); + stats->fcs_error = le32_to_cpu(get_log->fcs_error); + stats->tx_frame = le32_to_cpu(get_log->tx_frame); + stats->wep_icv_error[0] = + le32_to_cpu(get_log->wep_icv_err_cnt[0]); + stats->wep_icv_error[1] = + le32_to_cpu(get_log->wep_icv_err_cnt[1]); + stats->wep_icv_error[2] = + le32_to_cpu(get_log->wep_icv_err_cnt[2]); + stats->wep_icv_error[3] = + le32_to_cpu(get_log->wep_icv_err_cnt[3]); + } + + return 0; +} + +/* + * This function handles the command response of set/get Tx rate + * configurations. + * + * Handling includes changing the header fields into CPU format + * and saving the following parameters in driver - + * - DSSS rate bitmap + * - OFDM rate bitmap + * - HT MCS rate bitmaps + * + * Based on the new rate bitmaps, the function re-evaluates if + * auto data rate has been activated. If not, it sends another + * query to the firmware to get the current Tx data rate and updates + * the driver value. + */ +static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_rate_cfg *ds_rate; + struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg; + struct mwifiex_rate_scope *rate_scope; + struct mwifiex_ie_types_header *head; + u16 tlv, tlv_buf_len; + u8 *tlv_buf; + u32 i; + int ret = 0; + + tlv_buf = (u8 *) ((u8 *) rate_cfg) + + sizeof(struct host_cmd_ds_tx_rate_cfg); + tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16)); + + while (tlv_buf && tlv_buf_len > 0) { + tlv = (*tlv_buf); + tlv = tlv | (*(tlv_buf + 1) << 8); + + switch (tlv) { + case TLV_TYPE_RATE_SCOPE: + rate_scope = (struct mwifiex_rate_scope *) tlv_buf; + priv->bitmap_rates[0] = + le16_to_cpu(rate_scope->hr_dsss_rate_bitmap); + priv->bitmap_rates[1] = + le16_to_cpu(rate_scope->ofdm_rate_bitmap); + for (i = 0; + i < + sizeof(rate_scope->ht_mcs_rate_bitmap) / + sizeof(u16); i++) + priv->bitmap_rates[2 + i] = + le16_to_cpu(rate_scope-> + ht_mcs_rate_bitmap[i]); + break; + /* Add RATE_DROP tlv here */ + } + + head = (struct mwifiex_ie_types_header *) tlv_buf; + tlv_buf += le16_to_cpu(head->len) + sizeof(*head); + tlv_buf_len -= le16_to_cpu(head->len); + } + + priv->is_data_rate_auto = mwifiex_is_rate_auto(priv); + + if (priv->is_data_rate_auto) + priv->data_rate = 0; + else + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL); + + if (data_buf) { + ds_rate = (struct mwifiex_rate_cfg *) data_buf; + if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) { + if (priv->is_data_rate_auto) { + ds_rate->is_rate_auto = 1; + } else { + ds_rate->rate = mwifiex_get_rate_index(priv-> + bitmap_rates, + sizeof(priv-> + bitmap_rates)); + if (ds_rate->rate >= + MWIFIEX_RATE_BITMAP_OFDM0 + && ds_rate->rate <= + MWIFIEX_RATE_BITMAP_OFDM7) + ds_rate->rate -= + (MWIFIEX_RATE_BITMAP_OFDM0 - + MWIFIEX_RATE_INDEX_OFDM0); + if (ds_rate->rate >= + MWIFIEX_RATE_BITMAP_MCS0 + && ds_rate->rate <= + MWIFIEX_RATE_BITMAP_MCS127) + ds_rate->rate -= + (MWIFIEX_RATE_BITMAP_MCS0 - + MWIFIEX_RATE_INDEX_MCS0); + } + } + } + + return ret; +} + +/* + * This function handles the command response of get Tx power level. + * + * Handling includes saving the maximum and minimum Tx power levels + * in driver, as well as sending the values to user. + */ +static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf) +{ + int length, max_power = -1, min_power = -1; + struct mwifiex_types_power_group *pg_tlv_hdr; + struct mwifiex_power_group *pg; + + if (data_buf) { + pg_tlv_hdr = + (struct mwifiex_types_power_group *) ((u8 *) data_buf + + sizeof(struct host_cmd_ds_txpwr_cfg)); + pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr + + sizeof(struct mwifiex_types_power_group)); + length = pg_tlv_hdr->length; + if (length > 0) { + max_power = pg->power_max; + min_power = pg->power_min; + length -= sizeof(struct mwifiex_power_group); + } + while (length) { + pg++; + if (max_power < pg->power_max) + max_power = pg->power_max; + + if (min_power > pg->power_min) + min_power = pg->power_min; + + length -= sizeof(struct mwifiex_power_group); + } + if (pg_tlv_hdr->length > 0) { + priv->min_tx_power_level = (u8) min_power; + priv->max_tx_power_level = (u8) max_power; + } + } else { + return -1; + } + + return 0; +} + +/* + * This function handles the command response of set/get Tx power + * configurations. + * + * Handling includes changing the header fields into CPU format + * and saving the current Tx power level in driver. + */ +static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg; + struct mwifiex_types_power_group *pg_tlv_hdr; + struct mwifiex_power_group *pg; + u16 action = le16_to_cpu(txp_cfg->action); + + switch (action) { + case HostCmd_ACT_GEN_GET: + { + pg_tlv_hdr = + (struct mwifiex_types_power_group *) ((u8 *) + txp_cfg + + sizeof + (struct + host_cmd_ds_txpwr_cfg)); + pg = (struct mwifiex_power_group *) ((u8 *) + pg_tlv_hdr + + sizeof(struct + mwifiex_types_power_group)); + if (adapter->hw_status == + MWIFIEX_HW_STATUS_INITIALIZING) + mwifiex_get_power_level(priv, txp_cfg); + priv->tx_power_level = (u16) pg->power_min; + break; + } + case HostCmd_ACT_GEN_SET: + if (le32_to_cpu(txp_cfg->mode)) { + pg_tlv_hdr = + (struct mwifiex_types_power_group *) ((u8 *) + txp_cfg + + sizeof + (struct + host_cmd_ds_txpwr_cfg)); + pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr + + + sizeof(struct + mwifiex_types_power_group)); + if (pg->power_max == pg->power_min) + priv->tx_power_level = (u16) pg->power_min; + } + break; + default: + dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n", + action); + return 0; + } + dev_dbg(adapter->dev, + "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n", + priv->tx_power_level, priv->max_tx_power_level, + priv->min_tx_power_level); + + return 0; +} + +/* + * This function handles the command response of set/get MAC address. + * + * Handling includes saving the MAC address in driver. + */ +static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_802_11_mac_address *cmd_mac_addr = + &resp->params.mac_addr; + + memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN); + + dev_dbg(priv->adapter->dev, + "info: set mac address: %pM\n", priv->curr_addr); + + return 0; +} + +/* + * This function handles the command response of set/get MAC multicast + * address. + */ +static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + return 0; +} + +/* + * This function handles the command response of get Tx rate query. + * + * Handling includes changing the header fields into CPU format + * and saving the Tx rate and HT information parameters in driver. + * + * Both rate configuration and current data rate can be retrieved + * with this request. + */ +static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + priv->tx_rate = resp->params.tx_rate.tx_rate; + priv->tx_htinfo = resp->params.tx_rate.ht_info; + if (!priv->is_data_rate_auto) + priv->data_rate = + mwifiex_index_to_data_rate(priv->tx_rate, + priv->tx_htinfo); + + return 0; +} + +/* + * This function handles the command response of a deauthenticate + * command. + * + * If the deauthenticated MAC matches the current BSS MAC, the connection + * state is reset. + */ +static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + adapter->dbg.num_cmd_deauth++; + if (!memcmp(resp->params.deauth.mac_addr, + &priv->curr_bss_params.bss_descriptor.mac_address, + sizeof(resp->params.deauth.mac_addr))) + mwifiex_reset_connect_state(priv); + + return 0; +} + +/* + * This function handles the command response of ad-hoc stop. + * + * The function resets the connection state in driver. + */ +static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + mwifiex_reset_connect_state(priv); + return 0; +} + +/* + * This function handles the command response of set/get key material. + * + * Handling includes updating the driver parameters to reflect the + * changes. + */ +static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_802_11_key_material *key = + &resp->params.key_material; + + if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) { + if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) { + dev_dbg(priv->adapter->dev, "info: key: GTK is set\n"); + priv->wpa_is_gtk_set = true; + priv->scan_block = false; + } + } + + memset(priv->aes_key.key_param_set.key, 0, + sizeof(key->key_param_set.key)); + priv->aes_key.key_param_set.key_len = key->key_param_set.key_len; + memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key, + le16_to_cpu(priv->aes_key.key_param_set.key_len)); + + return 0; +} + +/* + * This function handles the command response of get 11d domain information. + */ +static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_802_11d_domain_info_rsp *domain_info = + &resp->params.domain_info_resp; + struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain; + u16 action = le16_to_cpu(domain_info->action); + u8 no_of_triplet; + + no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) - + IEEE80211_COUNTRY_STRING_LEN) / + sizeof(struct ieee80211_country_ie_triplet)); + + dev_dbg(priv->adapter->dev, "info: 11D Domain Info Resp:" + " no_of_triplet=%d\n", no_of_triplet); + + if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) { + dev_warn(priv->adapter->dev, + "11D: invalid number of triplets %d " + "returned!!\n", no_of_triplet); + return -1; + } + + switch (action) { + case HostCmd_ACT_GEN_SET: /* Proc Set Action */ + break; + case HostCmd_ACT_GEN_GET: + break; + default: + dev_err(priv->adapter->dev, + "11D: invalid action:%d\n", domain_info->action); + return -1; + } + + return 0; +} + +/* + * This function handles the command response of get RF channel. + * + * Handling includes changing the header fields into CPU format + * and saving the new channel in driver. + */ +static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_802_11_rf_channel *rf_channel = + &resp->params.rf_channel; + u16 new_channel = le16_to_cpu(rf_channel->current_channel); + + if (priv->curr_bss_params.bss_descriptor.channel != new_channel) { + dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n", + priv->curr_bss_params.bss_descriptor.channel, + new_channel); + /* Update the channel again */ + priv->curr_bss_params.bss_descriptor.channel = new_channel; + } + if (data_buf) + *((u16 *)data_buf) = new_channel; + + return 0; +} + +/* + * This function handles the command response of get extended version. + * + * Handling includes forming the extended version string and sending it + * to application. + */ +static int mwifiex_ret_ver_ext(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext; + struct host_cmd_ds_version_ext *version_ext; + + if (data_buf) { + version_ext = (struct host_cmd_ds_version_ext *)data_buf; + version_ext->version_str_sel = ver_ext->version_str_sel; + memcpy(version_ext->version_str, ver_ext->version_str, + sizeof(char) * 128); + memcpy(priv->version_str, ver_ext->version_str, 128); + } + return 0; +} + +/* + * This function handles the command response of register access. + * + * The register value and offset are returned to the user. For EEPROM + * access, the byte count is also returned. + */ +static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_ds_reg_rw *reg_rw; + struct mwifiex_ds_read_eeprom *eeprom; + + if (data_buf) { + reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; + eeprom = (struct mwifiex_ds_read_eeprom *) data_buf; + switch (type) { + case HostCmd_CMD_MAC_REG_ACCESS: + { + struct host_cmd_ds_mac_reg_access *reg; + reg = (struct host_cmd_ds_mac_reg_access *) + &resp->params.mac_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = reg->value; + break; + } + case HostCmd_CMD_BBP_REG_ACCESS: + { + struct host_cmd_ds_bbp_reg_access *reg; + reg = (struct host_cmd_ds_bbp_reg_access *) + &resp->params.bbp_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = cpu_to_le32((u32) reg->value); + break; + } + + case HostCmd_CMD_RF_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *reg; + reg = (struct host_cmd_ds_rf_reg_access *) + &resp->params.rf_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = cpu_to_le32((u32) reg->value); + break; + } + case HostCmd_CMD_PMIC_REG_ACCESS: + { + struct host_cmd_ds_pmic_reg_access *reg; + reg = (struct host_cmd_ds_pmic_reg_access *) + &resp->params.pmic_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = cpu_to_le32((u32) reg->value); + break; + } + case HostCmd_CMD_CAU_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *reg; + reg = (struct host_cmd_ds_rf_reg_access *) + &resp->params.rf_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = cpu_to_le32((u32) reg->value); + break; + } + case HostCmd_CMD_802_11_EEPROM_ACCESS: + { + struct host_cmd_ds_802_11_eeprom_access + *cmd_eeprom = + (struct host_cmd_ds_802_11_eeprom_access + *) &resp->params.eeprom; + pr_debug("info: EEPROM read len=%x\n", + cmd_eeprom->byte_count); + if (le16_to_cpu(eeprom->byte_count) < + le16_to_cpu( + cmd_eeprom->byte_count)) { + eeprom->byte_count = cpu_to_le16(0); + pr_debug("info: EEPROM read " + "length is too big\n"); + return -1; + } + eeprom->offset = cmd_eeprom->offset; + eeprom->byte_count = cmd_eeprom->byte_count; + if (le16_to_cpu(eeprom->byte_count) > 0) + memcpy(&eeprom->value, + &cmd_eeprom->value, + le16_to_cpu(eeprom->byte_count)); + + break; + } + default: + return -1; + } + } + return 0; +} + +/* + * This function handles the command response of get IBSS coalescing status. + * + * If the received BSSID is different than the current one, the current BSSID, + * beacon interval, ATIM window and ERP information are updated, along with + * changing the ad-hoc state accordingly. + */ +static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp = + &(resp->params.ibss_coalescing); + u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + + if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET) + return 0; + + dev_dbg(priv->adapter->dev, + "info: new BSSID %pM\n", ibss_coal_resp->bssid); + + /* If rsp has NULL BSSID, Just return..... No Action */ + if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) { + dev_warn(priv->adapter->dev, "new BSSID is NULL\n"); + return 0; + } + + /* If BSSID is diff, modify current BSS parameters */ + if (memcmp(priv->curr_bss_params.bss_descriptor.mac_address, + ibss_coal_resp->bssid, ETH_ALEN)) { + /* BSSID */ + memcpy(priv->curr_bss_params.bss_descriptor.mac_address, + ibss_coal_resp->bssid, ETH_ALEN); + + /* Beacon Interval */ + priv->curr_bss_params.bss_descriptor.beacon_period + = le16_to_cpu(ibss_coal_resp->beacon_interval); + + /* ERP Information */ + priv->curr_bss_params.bss_descriptor.erp_flags = + (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect); + + priv->adhoc_state = ADHOC_COALESCED; + } + + return 0; +} + +/* + * This function handles the command responses. + * + * This is a generic function, which calls command specific + * response handlers based on the command ID. + */ +int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, + u16 cmdresp_no, void *cmd_buf) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_command *resp = + (struct host_cmd_ds_command *) cmd_buf; + void *data_buf = adapter->curr_cmd->data_buf; + + /* If the command is not successful, cleanup and return failure */ + if (resp->result != HostCmd_RESULT_OK) { + mwifiex_process_cmdresp_error(priv, resp); + return -1; + } + /* Command successful, handle response */ + switch (cmdresp_no) { + case HostCmd_CMD_GET_HW_SPEC: + ret = mwifiex_ret_get_hw_spec(priv, resp); + break; + case HostCmd_CMD_MAC_CONTROL: + break; + case HostCmd_CMD_802_11_MAC_ADDRESS: + ret = mwifiex_ret_802_11_mac_address(priv, resp); + break; + case HostCmd_CMD_MAC_MULTICAST_ADR: + ret = mwifiex_ret_mac_multicast_adr(priv, resp); + break; + case HostCmd_CMD_TX_RATE_CFG: + ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_SCAN: + ret = mwifiex_ret_802_11_scan(priv, resp); + adapter->curr_cmd->wait_q_enabled = false; + break; + case HostCmd_CMD_802_11_BG_SCAN_QUERY: + ret = mwifiex_ret_802_11_scan(priv, resp); + dev_dbg(adapter->dev, + "info: CMD_RESP: BG_SCAN result is ready!\n"); + break; + case HostCmd_CMD_TXPWR_CFG: + ret = mwifiex_ret_tx_power_cfg(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_PS_MODE_ENH: + ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_HS_CFG_ENH: + ret = mwifiex_ret_802_11_hs_cfg(priv, resp); + break; + case HostCmd_CMD_802_11_ASSOCIATE: + ret = mwifiex_ret_802_11_associate(priv, resp); + break; + case HostCmd_CMD_802_11_DEAUTHENTICATE: + ret = mwifiex_ret_802_11_deauthenticate(priv, resp); + break; + case HostCmd_CMD_802_11_AD_HOC_START: + case HostCmd_CMD_802_11_AD_HOC_JOIN: + ret = mwifiex_ret_802_11_ad_hoc(priv, resp); + break; + case HostCmd_CMD_802_11_AD_HOC_STOP: + ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp); + break; + case HostCmd_CMD_802_11_GET_LOG: + 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); + break; + case HostCmd_CMD_802_11_SNMP_MIB: + ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_TX_RATE_QUERY: + ret = mwifiex_ret_802_11_tx_rate_query(priv, resp); + break; + case HostCmd_CMD_802_11_RF_CHANNEL: + ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf); + break; + case HostCmd_CMD_VERSION_EXT: + ret = mwifiex_ret_ver_ext(priv, resp, data_buf); + break; + case HostCmd_CMD_FUNC_INIT: + case HostCmd_CMD_FUNC_SHUTDOWN: + break; + case HostCmd_CMD_802_11_KEY_MATERIAL: + ret = mwifiex_ret_802_11_key_material(priv, resp); + break; + case HostCmd_CMD_802_11D_DOMAIN_INFO: + ret = mwifiex_ret_802_11d_domain_info(priv, resp); + break; + case HostCmd_CMD_11N_ADDBA_REQ: + ret = mwifiex_ret_11n_addba_req(priv, resp); + break; + case HostCmd_CMD_11N_DELBA: + ret = mwifiex_ret_11n_delba(priv, resp); + break; + case HostCmd_CMD_11N_ADDBA_RSP: + ret = mwifiex_ret_11n_addba_resp(priv, resp); + break; + case HostCmd_CMD_RECONFIGURE_TX_BUFF: + adapter->tx_buf_size = (u16) le16_to_cpu(resp->params. + tx_buf.buff_size); + adapter->tx_buf_size = (adapter->tx_buf_size / + MWIFIEX_SDIO_BLOCK_SIZE) * + MWIFIEX_SDIO_BLOCK_SIZE; + adapter->curr_tx_buf_size = adapter->tx_buf_size; + dev_dbg(adapter->dev, + "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n", + adapter->max_tx_buf_size, adapter->tx_buf_size); + + if (adapter->if_ops.update_mp_end_port) + adapter->if_ops.update_mp_end_port(adapter, + le16_to_cpu(resp-> + params. + tx_buf. + mp_end_port)); + break; + case HostCmd_CMD_AMSDU_AGGR_CTRL: + ret = mwifiex_ret_amsdu_aggr_ctrl(resp, data_buf); + break; + case HostCmd_CMD_WMM_GET_STATUS: + ret = mwifiex_ret_wmm_get_status(priv, resp); + break; + case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: + ret = mwifiex_ret_ibss_coalescing_status(priv, resp); + break; + case HostCmd_CMD_MAC_REG_ACCESS: + case HostCmd_CMD_BBP_REG_ACCESS: + case HostCmd_CMD_RF_REG_ACCESS: + case HostCmd_CMD_PMIC_REG_ACCESS: + case HostCmd_CMD_CAU_REG_ACCESS: + case HostCmd_CMD_802_11_EEPROM_ACCESS: + ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf); + break; + case HostCmd_CMD_SET_BSS_MODE: + break; + case HostCmd_CMD_11N_CFG: + ret = mwifiex_ret_11n_cfg(resp, data_buf); + break; + default: + dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", + resp->command); + break; + } + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c new file mode 100644 index 000000000000..fc265cab0907 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -0,0 +1,406 @@ +/* + * Marvell Wireless LAN device driver: station event handling + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * This function resets the connection state. + * + * The function is invoked after receiving a disconnect event from firmware, + * and performs the following actions - + * - Set media status to disconnected + * - Clean up Tx and Rx packets + * - Resets SNR/NF/RSSI value in driver + * - Resets security configurations in driver + * - Enables auto data rate + * - Saves the previous SSID and BSSID so that they can + * be used for re-association, if required + * - Erases current SSID and BSSID information + * - Sends a disconnect event to upper layers/applications. + */ +void +mwifiex_reset_connect_state(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + if (!priv->media_connected) + return; + + dev_dbg(adapter->dev, "info: handles disconnect event\n"); + + priv->media_connected = false; + + priv->scan_block = false; + + /* Free Tx and Rx packets, report disconnect to upper layer */ + mwifiex_clean_txrx(priv); + + /* Reset SNR/NF/RSSI values */ + priv->data_rssi_last = 0; + priv->data_nf_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->bcn_rssi_last = 0; + priv->bcn_nf_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + priv->rxpd_rate = 0; + priv->rxpd_htinfo = 0; + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + priv->wpa_ie_len = 0; + + priv->sec_info.wapi_enabled = false; + priv->wapi_ie_len = 0; + priv->sec_info.wapi_key_on = false; + + priv->sec_info.encryption_mode = 0; + + /* Enable auto data rate */ + priv->is_data_rate_auto = true; + priv->data_rate = 0; + + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + priv->adhoc_state = ADHOC_IDLE; + priv->adhoc_is_link_sensed = false; + } + + /* + * Memorize the previous SSID and BSSID so + * it could be used for re-assoc + */ + + dev_dbg(adapter->dev, "info: previous SSID=%s, SSID len=%u\n", + priv->prev_ssid.ssid, priv->prev_ssid.ssid_len); + + dev_dbg(adapter->dev, "info: current SSID=%s, SSID len=%u\n", + priv->curr_bss_params.bss_descriptor.ssid.ssid, + priv->curr_bss_params.bss_descriptor.ssid.ssid_len); + + memcpy(&priv->prev_ssid, + &priv->curr_bss_params.bss_descriptor.ssid, + sizeof(struct mwifiex_802_11_ssid)); + + memcpy(priv->prev_bssid, + priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN); + + /* Need to erase the current SSID and BSSID info */ + memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params)); + + adapter->tx_lock_flag = false; + adapter->pps_uapsd_mode = false; + + if (adapter->num_cmd_timeout && adapter->curr_cmd) + return; + priv->media_connected = false; + if (!priv->disconnect) { + priv->disconnect = 1; + dev_dbg(adapter->dev, "info: successfully disconnected from" + " %pM: reason code %d\n", priv->cfg_bssid, + WLAN_REASON_DEAUTH_LEAVING); + cfg80211_disconnected(priv->netdev, + WLAN_REASON_DEAUTH_LEAVING, NULL, 0, + GFP_KERNEL); + queue_work(priv->workqueue, &priv->cfg_workqueue); + } + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + /* Reset wireless stats signal info */ + priv->w_stats.qual.level = 0; + priv->w_stats.qual.noise = 0; +} + +/* + * This function handles events generated by firmware. + * + * This is a generic function and handles all events. + * + * Event specific routines are called by this function based + * upon the generated event cause. + * + * For the following events, the function just forwards them to upper + * layers, optionally recording the change - + * - EVENT_LINK_SENSED + * - EVENT_MIC_ERR_UNICAST + * - EVENT_MIC_ERR_MULTICAST + * - EVENT_PORT_RELEASE + * - EVENT_RSSI_LOW + * - EVENT_SNR_LOW + * - EVENT_MAX_FAIL + * - EVENT_RSSI_HIGH + * - EVENT_SNR_HIGH + * - EVENT_DATA_RSSI_LOW + * - EVENT_DATA_SNR_LOW + * - EVENT_DATA_RSSI_HIGH + * - EVENT_DATA_SNR_HIGH + * - EVENT_LINK_QUALITY + * - EVENT_PRE_BEACON_LOST + * - EVENT_IBSS_COALESCED + * - EVENT_WEP_ICV_ERR + * - EVENT_BW_CHANGE + * - EVENT_HOSTWAKE_STAIE + * + * For the following events, no action is taken - + * - EVENT_MIB_CHANGED + * - EVENT_INIT_DONE + * - EVENT_DUMMY_HOST_WAKEUP_SIGNAL + * + * Rest of the supported events requires driver handling - + * - EVENT_DEAUTHENTICATED + * - EVENT_DISASSOCIATED + * - EVENT_LINK_LOST + * - EVENT_PS_SLEEP + * - EVENT_PS_AWAKE + * - EVENT_DEEP_SLEEP_AWAKE + * - EVENT_HS_ACT_REQ + * - EVENT_ADHOC_BCN_LOST + * - EVENT_BG_SCAN_REPORT + * - EVENT_WMM_STATUS_CHANGE + * - EVENT_ADDBA + * - EVENT_DELBA + * - EVENT_BA_STREAM_TIEMOUT + * - EVENT_AMSDU_AGGR_CTRL + */ +int mwifiex_process_sta_event(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + u32 eventcause = adapter->event_cause; + + switch (eventcause) { + case EVENT_DUMMY_HOST_WAKEUP_SIGNAL: + dev_err(adapter->dev, "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL," + " ignoring it\n"); + break; + case EVENT_LINK_SENSED: + dev_dbg(adapter->dev, "event: LINK_SENSED\n"); + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + if (netif_queue_stopped(priv->netdev)) + netif_wake_queue(priv->netdev); + break; + + case EVENT_DEAUTHENTICATED: + dev_dbg(adapter->dev, "event: Deauthenticated\n"); + adapter->dbg.num_event_deauth++; + if (priv->media_connected) + mwifiex_reset_connect_state(priv); + break; + + case EVENT_DISASSOCIATED: + dev_dbg(adapter->dev, "event: Disassociated\n"); + adapter->dbg.num_event_disassoc++; + if (priv->media_connected) + mwifiex_reset_connect_state(priv); + break; + + case EVENT_LINK_LOST: + dev_dbg(adapter->dev, "event: Link lost\n"); + adapter->dbg.num_event_link_lost++; + if (priv->media_connected) + mwifiex_reset_connect_state(priv); + break; + + case EVENT_PS_SLEEP: + dev_dbg(adapter->dev, "info: EVENT: SLEEP\n"); + + adapter->ps_state = PS_STATE_PRE_SLEEP; + + mwifiex_check_ps_cond(adapter); + break; + + case EVENT_PS_AWAKE: + dev_dbg(adapter->dev, "info: EVENT: AWAKE\n"); + if (!adapter->pps_uapsd_mode && + priv->media_connected && + adapter->sleep_period.period) { + adapter->pps_uapsd_mode = true; + dev_dbg(adapter->dev, + "event: PPS/UAPSD mode activated\n"); + } + adapter->tx_lock_flag = false; + if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) { + if (mwifiex_check_last_packet_indication(priv)) { + if (!adapter->data_sent) { + if (!mwifiex_send_null_packet(priv, + MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET + | + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) + adapter->ps_state = + PS_STATE_SLEEP; + return 0; + } + } + } + adapter->ps_state = PS_STATE_AWAKE; + adapter->pm_wakeup_card_req = false; + adapter->pm_wakeup_fw_try = false; + + break; + + case EVENT_DEEP_SLEEP_AWAKE: + adapter->if_ops.wakeup_complete(adapter); + dev_dbg(adapter->dev, "event: DS_AWAKE\n"); + if (adapter->is_deep_sleep) + adapter->is_deep_sleep = false; + break; + + case EVENT_HS_ACT_REQ: + dev_dbg(adapter->dev, "event: HS_ACT_REQ\n"); + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_HS_CFG_ENH, + 0, 0, NULL); + break; + + case EVENT_MIC_ERR_UNICAST: + dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n"); + break; + + case EVENT_MIC_ERR_MULTICAST: + dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n"); + break; + case EVENT_MIB_CHANGED: + case EVENT_INIT_DONE: + break; + + case EVENT_ADHOC_BCN_LOST: + dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n"); + priv->adhoc_is_link_sensed = false; + mwifiex_clean_txrx(priv); + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + break; + + case EVENT_BG_SCAN_REPORT: + dev_dbg(adapter->dev, "event: BGS_REPORT\n"); + /* Clear the previous scan result */ + memset(adapter->scan_table, 0x00, + sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); + adapter->num_in_scan_table = 0; + adapter->bcn_buf_end = adapter->bcn_buf; + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_BG_SCAN_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL); + break; + + case EVENT_PORT_RELEASE: + dev_dbg(adapter->dev, "event: PORT RELEASE\n"); + break; + + case EVENT_WMM_STATUS_CHANGE: + dev_dbg(adapter->dev, "event: WMM status changed\n"); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_WMM_GET_STATUS, + 0, 0, NULL); + break; + + case EVENT_RSSI_LOW: + dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n"); + break; + case EVENT_SNR_LOW: + dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n"); + break; + case EVENT_MAX_FAIL: + dev_dbg(adapter->dev, "event: MAX_FAIL\n"); + break; + case EVENT_RSSI_HIGH: + dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n"); + break; + case EVENT_SNR_HIGH: + dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n"); + break; + case EVENT_DATA_RSSI_LOW: + dev_dbg(adapter->dev, "event: Data RSSI_LOW\n"); + break; + case EVENT_DATA_SNR_LOW: + dev_dbg(adapter->dev, "event: Data SNR_LOW\n"); + break; + case EVENT_DATA_RSSI_HIGH: + dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n"); + break; + case EVENT_DATA_SNR_HIGH: + dev_dbg(adapter->dev, "event: Data SNR_HIGH\n"); + break; + case EVENT_LINK_QUALITY: + dev_dbg(adapter->dev, "event: Link Quality\n"); + break; + case EVENT_PRE_BEACON_LOST: + dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n"); + break; + case EVENT_IBSS_COALESCED: + dev_dbg(adapter->dev, "event: IBSS_COALESCED\n"); + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, + HostCmd_ACT_GEN_GET, 0, NULL); + break; + case EVENT_ADDBA: + dev_dbg(adapter->dev, "event: ADDBA Request\n"); + mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP, + HostCmd_ACT_GEN_SET, 0, + adapter->event_body); + break; + case EVENT_DELBA: + dev_dbg(adapter->dev, "event: DELBA Request\n"); + mwifiex_11n_delete_ba_stream(priv, adapter->event_body); + break; + case EVENT_BA_STREAM_TIEMOUT: + dev_dbg(adapter->dev, "event: BA Stream timeout\n"); + mwifiex_11n_ba_stream_timeout(priv, + (struct host_cmd_ds_11n_batimeout + *) + adapter->event_body); + break; + case EVENT_AMSDU_AGGR_CTRL: + dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", + *(u16 *) adapter->event_body); + adapter->tx_buf_size = + min(adapter->curr_tx_buf_size, + le16_to_cpu(*(__le16 *) adapter->event_body)); + dev_dbg(adapter->dev, "event: tx_buf_size %d\n", + adapter->tx_buf_size); + break; + + case EVENT_WEP_ICV_ERR: + dev_dbg(adapter->dev, "event: WEP ICV error\n"); + break; + + case EVENT_BW_CHANGE: + dev_dbg(adapter->dev, "event: BW Change\n"); + break; + + case EVENT_HOSTWAKE_STAIE: + dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause); + break; + default: + dev_dbg(adapter->dev, "event: unknown event id: %#x\n", + eventcause); + break; + } + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c new file mode 100644 index 000000000000..d05907d05039 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -0,0 +1,1593 @@ +/* + * Marvell Wireless LAN device driver: functions for station ioctl + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "cfg80211.h" + +/* + * Copies the multicast address list from device to driver. + * + * This function does not validate the destination memory for + * size, and the calling function must ensure enough memory is + * available. + */ +int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, + struct net_device *dev) +{ + int i = 0; + struct netdev_hw_addr *ha; + + netdev_for_each_mc_addr(ha, dev) + memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN); + + return i; +} + +/* + * Wait queue completion handler. + * + * This function waits on a cmd wait queue. It also cancels the pending + * request after waking up, in case of errors. + */ +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) +{ + bool cancel_flag = false; + int status = adapter->cmd_wait_q.status; + + dev_dbg(adapter->dev, "cmd pending\n"); + atomic_inc(&adapter->cmd_pending); + + /* Status pending, wake up main process */ + queue_work(adapter->workqueue, &adapter->main_work); + + /* Wait for completion */ + wait_event_interruptible(adapter->cmd_wait_q.wait, + adapter->cmd_wait_q.condition); + if (!adapter->cmd_wait_q.condition) + cancel_flag = true; + + if (cancel_flag) { + mwifiex_cancel_pending_ioctl(adapter); + dev_dbg(adapter->dev, "cmd cancel\n"); + } + adapter->cmd_wait_q.status = 0; + + return status; +} + +/* + * This function prepares the correct firmware command and + * issues it to set the multicast list. + * + * This function can be used to enable promiscuous mode, or enable all + * multicast packets, or to enable selective multicast. + */ +int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, + struct mwifiex_multicast_list *mcast_list) +{ + int ret = 0; + u16 old_pkt_filter; + + old_pkt_filter = priv->curr_pkt_filter; + + if (mcast_list->mode == MWIFIEX_PROMISC_MODE) { + dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n"); + priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; + priv->curr_pkt_filter &= + ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; + } else { + /* Multicast */ + priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; + if (mcast_list->mode == MWIFIEX_MULTICAST_MODE) { + dev_dbg(priv->adapter->dev, + "info: Enabling All Multicast!\n"); + priv->curr_pkt_filter |= + HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; + } else { + priv->curr_pkt_filter &= + ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; + if (mcast_list->num_multicast_addr) { + dev_dbg(priv->adapter->dev, + "info: Set multicast list=%d\n", + mcast_list->num_multicast_addr); + /* Set multicast addresses to firmware */ + if (old_pkt_filter == priv->curr_pkt_filter) { + /* Send request to firmware */ + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_MAC_MULTICAST_ADR, + HostCmd_ACT_GEN_SET, 0, + mcast_list); + } else { + /* Send request to firmware */ + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_MAC_MULTICAST_ADR, + HostCmd_ACT_GEN_SET, 0, + mcast_list); + } + } + } + } + dev_dbg(priv->adapter->dev, + "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n", + old_pkt_filter, priv->curr_pkt_filter); + if (old_pkt_filter != priv->curr_pkt_filter) { + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, + 0, &priv->curr_pkt_filter); + } + + return ret; +} + +/* + * In Ad-Hoc mode, the IBSS is created if not found in scan list. + * In both Ad-Hoc and infra mode, an deauthentication is performed + * first. + */ +int mwifiex_bss_start(struct mwifiex_private *priv, + struct mwifiex_ssid_bssid *ssid_bssid) +{ + int ret; + struct mwifiex_adapter *adapter = priv->adapter; + s32 i = -1; + + priv->scan_block = false; + if (!ssid_bssid) + return -1; + + if (priv->bss_mode == NL80211_IFTYPE_STATION) { + /* Infra mode */ + ret = mwifiex_deauthenticate(priv, NULL); + if (ret) + return ret; + + /* Search for the requested SSID in the scan table */ + if (ssid_bssid->ssid.ssid_len) + i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, + NULL, NL80211_IFTYPE_STATION); + else + i = mwifiex_find_bssid_in_list(priv, + (u8 *) &ssid_bssid->bssid, + NL80211_IFTYPE_STATION); + if (i < 0) + return -1; + + dev_dbg(adapter->dev, + "info: SSID found in scan list ... associating...\n"); + + /* Clear any past association response stored for + * application retrieval */ + priv->assoc_rsp_size = 0; + ret = mwifiex_associate(priv, &adapter->scan_table[i]); + if (ret) + return ret; + } else { + /* Adhoc mode */ + /* If the requested SSID matches current SSID, return */ + if (ssid_bssid->ssid.ssid_len && + (!mwifiex_ssid_cmp + (&priv->curr_bss_params.bss_descriptor.ssid, + &ssid_bssid->ssid))) + return 0; + + /* Exit Adhoc mode first */ + dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); + ret = mwifiex_deauthenticate(priv, NULL); + if (ret) + return ret; + + priv->adhoc_is_link_sensed = false; + + /* Search for the requested network in the scan table */ + if (ssid_bssid->ssid.ssid_len) + i = mwifiex_find_ssid_in_list(priv, + &ssid_bssid->ssid, NULL, + NL80211_IFTYPE_ADHOC); + else + i = mwifiex_find_bssid_in_list(priv, + (u8 *)&ssid_bssid->bssid, + NL80211_IFTYPE_ADHOC); + + if (i >= 0) { + dev_dbg(adapter->dev, "info: network found in scan" + " list. Joining...\n"); + ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]); + if (ret) + return ret; + } else { + dev_dbg(adapter->dev, "info: Network not found in " + "the list, creating adhoc with ssid = %s\n", + ssid_bssid->ssid.ssid); + ret = mwifiex_adhoc_start(priv, &ssid_bssid->ssid); + if (ret) + return ret; + } + } + + return ret; +} + +/* + * IOCTL request handler to set host sleep configuration. + * + * This function prepares the correct firmware command and + * issues it. + */ +int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, + int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) + +{ + struct mwifiex_adapter *adapter = priv->adapter; + int status = 0; + u32 prev_cond = 0; + + if (!hs_cfg) + return -ENOMEM; + + switch (action) { + case HostCmd_ACT_GEN_SET: + if (adapter->pps_uapsd_mode) { + dev_dbg(adapter->dev, "info: Host Sleep IOCTL" + " is blocked in UAPSD/PPS mode\n"); + status = -1; + break; + } + if (hs_cfg->is_invoke_hostcmd) { + if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) { + if (!adapter->is_hs_configured) + /* Already cancelled */ + break; + /* Save previous condition */ + prev_cond = le32_to_cpu(adapter->hs_cfg + .conditions); + adapter->hs_cfg.conditions = + cpu_to_le32(hs_cfg->conditions); + } else if (hs_cfg->conditions) { + adapter->hs_cfg.conditions = + cpu_to_le32(hs_cfg->conditions); + adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; + if (hs_cfg->gap) + adapter->hs_cfg.gap = (u8)hs_cfg->gap; + } else if (adapter->hs_cfg.conditions == + cpu_to_le32( + HOST_SLEEP_CFG_CANCEL)) { + /* Return failure if no parameters for HS + enable */ + status = -1; + break; + } + if (cmd_type == MWIFIEX_SYNC_CMD) + status = mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_HS_CFG_ENH, + HostCmd_ACT_GEN_SET, 0, + &adapter->hs_cfg); + else + status = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_HS_CFG_ENH, + HostCmd_ACT_GEN_SET, 0, + &adapter->hs_cfg); + if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) + /* Restore previous condition */ + adapter->hs_cfg.conditions = + cpu_to_le32(prev_cond); + } else { + adapter->hs_cfg.conditions = + cpu_to_le32(hs_cfg->conditions); + adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; + adapter->hs_cfg.gap = (u8)hs_cfg->gap; + } + break; + case HostCmd_ACT_GEN_GET: + hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions); + hs_cfg->gpio = adapter->hs_cfg.gpio; + hs_cfg->gap = adapter->hs_cfg.gap; + break; + default: + status = -1; + break; + } + + return status; +} + +/* + * Sends IOCTL request to cancel the existing Host Sleep configuration. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type) +{ + struct mwifiex_ds_hs_cfg hscfg; + + hscfg.conditions = HOST_SLEEP_CFG_CANCEL; + hscfg.is_invoke_hostcmd = true; + + return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, + cmd_type, &hscfg); +} +EXPORT_SYMBOL_GPL(mwifiex_cancel_hs); + +/* + * Sends IOCTL request to cancel the existing Host Sleep configuration. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_enable_hs(struct mwifiex_adapter *adapter) +{ + struct mwifiex_ds_hs_cfg hscfg; + + if (adapter->hs_activated) { + dev_dbg(adapter->dev, "cmd: HS Already actived\n"); + return true; + } + + adapter->hs_activate_wait_q_woken = false; + + memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param)); + hscfg.is_invoke_hostcmd = true; + + if (mwifiex_set_hs_params(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_STA), + HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD, + &hscfg)) { + dev_err(adapter->dev, "IOCTL request HS enable failed\n"); + return false; + } + + wait_event_interruptible(adapter->hs_activate_wait_q, + adapter->hs_activate_wait_q_woken); + + return true; +} +EXPORT_SYMBOL_GPL(mwifiex_enable_hs); + +/* + * IOCTL request handler to get BSS information. + * + * This function collates the information from different driver structures + * to send to the user. + */ +int mwifiex_get_bss_info(struct mwifiex_private *priv, + struct mwifiex_bss_info *info) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *bss_desc; + s32 tbl_idx; + + if (!info) + return -1; + + bss_desc = &priv->curr_bss_params.bss_descriptor; + + info->bss_mode = priv->bss_mode; + + memcpy(&info->ssid, &bss_desc->ssid, + sizeof(struct mwifiex_802_11_ssid)); + + memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN); + + info->bss_chan = bss_desc->channel; + + info->region_code = adapter->region_code; + + /* Scan table index if connected */ + info->scan_table_idx = 0; + if (priv->media_connected) { + tbl_idx = + mwifiex_find_ssid_in_list(priv, &bss_desc->ssid, + bss_desc->mac_address, + priv->bss_mode); + if (tbl_idx >= 0) + info->scan_table_idx = tbl_idx; + } + + info->media_connected = priv->media_connected; + + info->max_power_level = priv->max_tx_power_level; + info->min_power_level = priv->min_tx_power_level; + + info->adhoc_state = priv->adhoc_state; + + info->bcn_nf_last = priv->bcn_nf_last; + + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) + info->wep_status = true; + else + info->wep_status = false; + + info->is_hs_configured = adapter->is_hs_configured; + info->is_deep_sleep = adapter->is_deep_sleep; + + return 0; +} + +/* + * The function sets band configurations. + * + * it performs extra checks to make sure the Ad-Hoc + * band and channel are compatible. Otherwise it returns an error. + * + */ +int mwifiex_set_radio_band_cfg(struct mwifiex_private *priv, + struct mwifiex_ds_band_cfg *radio_cfg) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u8 infra_band, adhoc_band; + u32 adhoc_channel; + + infra_band = (u8) radio_cfg->config_bands; + adhoc_band = (u8) radio_cfg->adhoc_start_band; + adhoc_channel = radio_cfg->adhoc_channel; + + /* SET Infra band */ + if ((infra_band | adapter->fw_bands) & ~adapter->fw_bands) + return -1; + + adapter->config_bands = infra_band; + + /* SET Ad-hoc Band */ + if ((adhoc_band | adapter->fw_bands) & ~adapter->fw_bands) + return -1; + + if (adhoc_band) + adapter->adhoc_start_band = adhoc_band; + adapter->chan_offset = (u8) radio_cfg->sec_chan_offset; + /* + * If no adhoc_channel is supplied verify if the existing adhoc + * channel compiles with new adhoc_band + */ + if (!adhoc_channel) { + if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, adapter->adhoc_start_band, + priv->adhoc_channel)) { + /* Pass back the default channel */ + radio_cfg->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + if ((adapter->adhoc_start_band & BAND_A) + || (adapter->adhoc_start_band & BAND_AN)) + radio_cfg->adhoc_channel = + DEFAULT_AD_HOC_CHANNEL_A; + } + } else { /* Retrurn error if adhoc_band and + adhoc_channel combination is invalid */ + if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, adapter->adhoc_start_band, (u16) adhoc_channel)) + return -1; + priv->adhoc_channel = (u8) adhoc_channel; + } + if ((adhoc_band & BAND_GN) || (adhoc_band & BAND_AN)) + adapter->adhoc_11n_enabled = true; + else + adapter->adhoc_11n_enabled = false; + + return 0; +} + +/* + * IOCTL request handler to set/get active channel. + * + * This function performs validity checking on channel/frequency + * compatibility and returns failure if not valid. + */ +int mwifiex_bss_set_channel(struct mwifiex_private *priv, + struct mwifiex_chan_freq_power *chan) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_chan_freq_power *cfp = NULL; + + if (!chan) + return -1; + + if (!chan->channel && !chan->freq) + return -1; + if (adapter->adhoc_start_band & BAND_AN) + adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN; + else if (adapter->adhoc_start_band & BAND_A) + adapter->adhoc_start_band = BAND_G | BAND_B; + if (chan->channel) { + if (chan->channel <= MAX_CHANNEL_BAND_BG) + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, 0, (u16) chan->channel); + if (!cfp) { + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, BAND_A, (u16) chan->channel); + if (cfp) { + if (adapter->adhoc_11n_enabled) + adapter->adhoc_start_band = BAND_A + | BAND_AN; + else + adapter->adhoc_start_band = BAND_A; + } + } + } else { + if (chan->freq <= MAX_FREQUENCY_BAND_BG) + cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211( + priv, 0, chan->freq); + if (!cfp) { + cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211 + (priv, BAND_A, chan->freq); + if (cfp) { + if (adapter->adhoc_11n_enabled) + adapter->adhoc_start_band = BAND_A + | BAND_AN; + else + adapter->adhoc_start_band = BAND_A; + } + } + } + if (!cfp || !cfp->channel) { + dev_err(adapter->dev, "invalid channel/freq\n"); + return -1; + } + priv->adhoc_channel = (u8) cfp->channel; + chan->channel = cfp->channel; + chan->freq = cfp->freq; + + return 0; +} + +/* + * IOCTL request handler to set/get Ad-Hoc channel. + * + * This function prepares the correct firmware command and + * issues it to set or get the ad-hoc channel. + */ +static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, + u16 action, u16 *channel) +{ + if (action == HostCmd_ACT_GEN_GET) { + if (!priv->media_connected) { + *channel = priv->adhoc_channel; + return 0; + } + } else { + priv->adhoc_channel = (u8) *channel; + } + + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_RF_CHANNEL, + action, 0, channel); +} + +/* + * IOCTL request handler to find a particular BSS. + * + * The BSS can be searched with either a BSSID or a SSID. If none of + * these are provided, just the best BSS (best RSSI) is returned. + */ +int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, + struct mwifiex_ssid_bssid *ssid_bssid) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *bss_desc; + u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + u8 mac[ETH_ALEN]; + int i = 0; + + if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) { + i = mwifiex_find_bssid_in_list(priv, + (u8 *) ssid_bssid->bssid, + priv->bss_mode); + if (i < 0) { + memcpy(mac, ssid_bssid->bssid, sizeof(mac)); + dev_err(adapter->dev, "cannot find bssid %pM\n", mac); + return -1; + } + bss_desc = &adapter->scan_table[i]; + memcpy(&ssid_bssid->ssid, &bss_desc->ssid, + sizeof(struct mwifiex_802_11_ssid)); + } else if (ssid_bssid->ssid.ssid_len) { + i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL, + priv->bss_mode); + if (i < 0) { + dev_err(adapter->dev, "cannot find ssid %s\n", + ssid_bssid->ssid.ssid); + return -1; + } + bss_desc = &adapter->scan_table[i]; + memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN); + } else { + return mwifiex_find_best_network(priv, ssid_bssid); + } + + return 0; +} + +/* + * IOCTL request handler to change Ad-Hoc channel. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + * + * The function follows the following steps to perform the change - + * - Get current IBSS information + * - Get current channel + * - If no change is required, return + * - If not connected, change channel and return + * - If connected, + * - Disconnect + * - Change channel + * - Perform specific SSID scan with same SSID + * - Start/Join the IBSS + */ +int +mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) +{ + int ret; + struct mwifiex_bss_info bss_info; + struct mwifiex_ssid_bssid ssid_bssid; + u16 curr_chan = 0; + + memset(&bss_info, 0, sizeof(bss_info)); + + /* Get BSS information */ + if (mwifiex_get_bss_info(priv, &bss_info)) + return -1; + + /* Get current channel */ + ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_GET, + &curr_chan); + + if (curr_chan == channel) { + ret = 0; + goto done; + } + dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n", + curr_chan, channel); + + if (!bss_info.media_connected) { + ret = 0; + goto done; + } + + /* Do disonnect */ + memset(&ssid_bssid, 0, ETH_ALEN); + ret = mwifiex_deauthenticate(priv, ssid_bssid.bssid); + + ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_SET, + (u16 *) &channel); + + /* Do specific SSID scanning */ + if (mwifiex_request_scan(priv, &bss_info.ssid)) { + ret = -1; + goto done; + } + /* Start/Join Adhoc network */ + memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); + memcpy(&ssid_bssid.ssid, &bss_info.ssid, + sizeof(struct mwifiex_802_11_ssid)); + + ret = mwifiex_bss_start(priv, &ssid_bssid); +done: + return ret; +} + +/* + * IOCTL request handler to get rate. + * + * This function prepares the correct firmware command and + * issues it to get the current rate if it is connected, + * otherwise, the function returns the lowest supported rate + * for the band. + */ +static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, + struct mwifiex_rate_cfg *rate_cfg) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + rate_cfg->is_rate_auto = priv->is_data_rate_auto; + if (!priv->media_connected) { + switch (adapter->config_bands) { + case BAND_B: + /* Return the lowest supported rate for B band */ + rate_cfg->rate = supported_rates_b[0] & 0x7f; + break; + case BAND_G: + case BAND_G | BAND_GN: + /* Return the lowest supported rate for G band */ + rate_cfg->rate = supported_rates_g[0] & 0x7f; + break; + case BAND_B | BAND_G: + case BAND_A | BAND_B | BAND_G: + case BAND_A | BAND_B: + case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN: + case BAND_B | BAND_G | BAND_GN: + /* Return the lowest supported rate for BG band */ + rate_cfg->rate = supported_rates_bg[0] & 0x7f; + break; + case BAND_A: + case BAND_A | BAND_G: + case BAND_A | BAND_G | BAND_AN | BAND_GN: + case BAND_A | BAND_AN: + /* Return the lowest supported rate for A band */ + rate_cfg->rate = supported_rates_a[0] & 0x7f; + break; + case BAND_GN: + /* Return the lowest supported rate for N band */ + rate_cfg->rate = supported_rates_n[0] & 0x7f; + break; + default: + dev_warn(adapter->dev, "invalid band %#x\n", + adapter->config_bands); + break; + } + } else { + return mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL); + } + + return 0; +} + +/* + * IOCTL request handler to set rate. + * + * This function prepares the correct firmware command and + * issues it to set the current rate. + * + * The function also performs validation checking on the supplied value. + */ +static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, + struct mwifiex_rate_cfg *rate_cfg) +{ + u8 rates[MWIFIEX_SUPPORTED_RATES]; + u8 *rate; + int rate_index, ret; + u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; + u32 i; + struct mwifiex_adapter *adapter = priv->adapter; + + if (rate_cfg->is_rate_auto) { + memset(bitmap_rates, 0, sizeof(bitmap_rates)); + /* Support all HR/DSSS rates */ + bitmap_rates[0] = 0x000F; + /* Support all OFDM rates */ + bitmap_rates[1] = 0x00FF; + /* Support all HT-MCSs rate */ + for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates) - 3; i++) + bitmap_rates[i + 2] = 0xFFFF; + bitmap_rates[9] = 0x3FFF; + } else { + memset(rates, 0, sizeof(rates)); + mwifiex_get_active_data_rates(priv, rates); + rate = rates; + for (i = 0; (rate[i] && i < MWIFIEX_SUPPORTED_RATES); i++) { + dev_dbg(adapter->dev, "info: rate=%#x wanted=%#x\n", + rate[i], rate_cfg->rate); + if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f)) + break; + } + if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) { + dev_err(adapter->dev, "fixed data rate %#x is out " + "of range\n", rate_cfg->rate); + return -1; + } + memset(bitmap_rates, 0, sizeof(bitmap_rates)); + + rate_index = mwifiex_data_rate_to_index(rate_cfg->rate); + + /* Only allow b/g rates to be set */ + if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 && + rate_index <= MWIFIEX_RATE_INDEX_HRDSSS3) { + bitmap_rates[0] = 1 << rate_index; + } else { + rate_index -= 1; /* There is a 0x00 in the table */ + if (rate_index >= MWIFIEX_RATE_INDEX_OFDM0 && + rate_index <= MWIFIEX_RATE_INDEX_OFDM7) + bitmap_rates[1] = 1 << (rate_index - + MWIFIEX_RATE_INDEX_OFDM0); + } + } + + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG, + HostCmd_ACT_GEN_SET, 0, bitmap_rates); + + return ret; +} + +/* + * IOCTL request handler to set/get rate. + * + * This function can be used to set/get either the rate value or the + * rate index. + */ +static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv, + struct mwifiex_rate_cfg *rate_cfg) +{ + int status; + + if (!rate_cfg) + return -1; + + if (rate_cfg->action == HostCmd_ACT_GEN_GET) + status = mwifiex_rate_ioctl_get_rate_value(priv, rate_cfg); + else + status = mwifiex_rate_ioctl_set_rate_value(priv, rate_cfg); + + return status; +} + +/* + * Sends IOCTL request to get the data rate. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, + struct mwifiex_rate_cfg *rate) +{ + int ret; + + memset(rate, 0, sizeof(struct mwifiex_rate_cfg)); + rate->action = HostCmd_ACT_GEN_GET; + ret = mwifiex_rate_ioctl_cfg(priv, rate); + + if (!ret) { + if (rate && rate->is_rate_auto) + rate->rate = mwifiex_index_to_data_rate(priv->tx_rate, + priv->tx_htinfo); + else if (rate) + rate->rate = priv->data_rate; + } else { + ret = -1; + } + + return ret; +} + +/* + * IOCTL request handler to set tx power configuration. + * + * This function prepares the correct firmware command and + * issues it. + * + * For non-auto power mode, all the following power groups are set - + * - Modulation class HR/DSSS + * - Modulation class OFDM + * - Modulation class HTBW20 + * - Modulation class HTBW40 + */ +int mwifiex_set_tx_power(struct mwifiex_private *priv, + struct mwifiex_power_cfg *power_cfg) +{ + int ret; + struct host_cmd_ds_txpwr_cfg *txp_cfg; + struct mwifiex_types_power_group *pg_tlv; + struct mwifiex_power_group *pg; + u8 *buf; + u16 dbm = 0; + + if (!power_cfg->is_power_auto) { + dbm = (u16) power_cfg->power_level; + if ((dbm < priv->min_tx_power_level) || + (dbm > priv->max_tx_power_level)) { + dev_err(priv->adapter->dev, "txpower value %d dBm" + " is out of range (%d dBm-%d dBm)\n", + dbm, priv->min_tx_power_level, + priv->max_tx_power_level); + return -1; + } + } + buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL); + if (!buf) { + dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n", + __func__); + return -ENOMEM; + } + + txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf; + txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + if (!power_cfg->is_power_auto) { + txp_cfg->mode = cpu_to_le32(1); + pg_tlv = (struct mwifiex_types_power_group *) (buf + + sizeof(struct host_cmd_ds_txpwr_cfg)); + pg_tlv->type = TLV_TYPE_POWER_GROUP; + pg_tlv->length = 4 * sizeof(struct mwifiex_power_group); + pg = (struct mwifiex_power_group *) (buf + + sizeof(struct host_cmd_ds_txpwr_cfg) + + sizeof(struct mwifiex_types_power_group)); + /* Power group for modulation class HR/DSSS */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x03; + pg->modulation_class = MOD_CLASS_HR_DSSS; + pg->power_step = 0; + pg->power_min = (s8) dbm; + pg->power_max = (s8) dbm; + pg++; + /* Power group for modulation class OFDM */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x07; + pg->modulation_class = MOD_CLASS_OFDM; + pg->power_step = 0; + pg->power_min = (s8) dbm; + pg->power_max = (s8) dbm; + pg++; + /* Power group for modulation class HTBW20 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x20; + pg->modulation_class = MOD_CLASS_HT; + pg->power_step = 0; + pg->power_min = (s8) dbm; + pg->power_max = (s8) dbm; + pg->ht_bandwidth = HT_BW_20; + pg++; + /* Power group for modulation class HTBW40 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x20; + pg->modulation_class = MOD_CLASS_HT; + pg->power_step = 0; + pg->power_min = (s8) dbm; + pg->power_max = (s8) dbm; + pg->ht_bandwidth = HT_BW_40; + } + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TXPWR_CFG, + HostCmd_ACT_GEN_SET, 0, buf); + + kfree(buf); + return ret; +} + +/* + * IOCTL request handler to get power save mode. + * + * This function prepares the correct firmware command and + * issues it. + */ +int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode) +{ + int ret; + struct mwifiex_adapter *adapter = priv->adapter; + u16 sub_cmd; + + if (*ps_mode) + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; + else + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS; + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + sub_cmd, BITMAP_STA_PS, NULL); + if ((!ret) && (sub_cmd == DIS_AUTO_PS)) + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS, + 0, NULL); + + return ret; +} + +/* + * IOCTL request handler to set/reset WPA IE. + * + * The supplied WPA IE is treated as a opaque buffer. Only the first field + * is checked to determine WPA version. If buffer length is zero, the existing + * WPA IE is reset. + */ +static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv, + u8 *ie_data_ptr, u16 ie_len) +{ + if (ie_len) { + if (ie_len > sizeof(priv->wpa_ie)) { + dev_err(priv->adapter->dev, + "failed to copy WPA IE, too big\n"); + return -1; + } + memcpy(priv->wpa_ie, ie_data_ptr, ie_len); + priv->wpa_ie_len = (u8) ie_len; + dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n", + priv->wpa_ie_len, priv->wpa_ie[0]); + + if (priv->wpa_ie[0] == WLAN_EID_WPA) { + priv->sec_info.wpa_enabled = true; + } else if (priv->wpa_ie[0] == WLAN_EID_RSN) { + priv->sec_info.wpa2_enabled = true; + } else { + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + } + } else { + memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie)); + priv->wpa_ie_len = 0; + dev_dbg(priv->adapter->dev, "info: reset wpa_ie_len=%d IE=%#x\n", + priv->wpa_ie_len, priv->wpa_ie[0]); + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + } + + return 0; +} + +/* + * IOCTL request handler to set/reset WAPI IE. + * + * The supplied WAPI IE is treated as a opaque buffer. Only the first field + * is checked to internally enable WAPI. If buffer length is zero, the existing + * WAPI IE is reset. + */ +static int mwifiex_set_wapi_ie(struct mwifiex_private *priv, + u8 *ie_data_ptr, u16 ie_len) +{ + if (ie_len) { + if (ie_len > sizeof(priv->wapi_ie)) { + dev_dbg(priv->adapter->dev, + "info: failed to copy WAPI IE, too big\n"); + return -1; + } + memcpy(priv->wapi_ie, ie_data_ptr, ie_len); + priv->wapi_ie_len = ie_len; + dev_dbg(priv->adapter->dev, "cmd: Set wapi_ie_len=%d IE=%#x\n", + priv->wapi_ie_len, priv->wapi_ie[0]); + + if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY) + priv->sec_info.wapi_enabled = true; + } else { + memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie)); + priv->wapi_ie_len = ie_len; + dev_dbg(priv->adapter->dev, + "info: Reset wapi_ie_len=%d IE=%#x\n", + priv->wapi_ie_len, priv->wapi_ie[0]); + priv->sec_info.wapi_enabled = false; + } + return 0; +} + +/* + * IOCTL request handler to set WAPI key. + * + * This function prepares the correct firmware command and + * issues it. + */ +static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv, + struct mwifiex_ds_encrypt_key *encrypt_key) +{ + + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + encrypt_key); +} + +/* + * IOCTL request handler to set WEP network key. + * + * This function prepares the correct firmware command and + * issues it, after validation checks. + */ +static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, + struct mwifiex_ds_encrypt_key *encrypt_key) +{ + int ret; + struct mwifiex_wep_key *wep_key; + int index; + + if (priv->wep_key_curr_index >= NUM_WEP_KEYS) + priv->wep_key_curr_index = 0; + wep_key = &priv->wep_key[priv->wep_key_curr_index]; + index = encrypt_key->key_index; + if (encrypt_key->key_disable) { + priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; + } else if (!encrypt_key->key_len) { + /* Copy the required key as the current key */ + wep_key = &priv->wep_key[index]; + if (!wep_key->key_length) { + dev_err(priv->adapter->dev, + "key not set, so cannot enable it\n"); + return -1; + } + priv->wep_key_curr_index = (u16) index; + priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; + } else { + wep_key = &priv->wep_key[index]; + memset(wep_key, 0, sizeof(struct mwifiex_wep_key)); + /* Copy the key in the driver */ + memcpy(wep_key->key_material, + encrypt_key->key_material, + encrypt_key->key_len); + wep_key->key_index = index; + wep_key->key_length = encrypt_key->key_len; + priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; + } + if (wep_key->key_length) { + /* Send request to firmware */ + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, 0, NULL); + if (ret) + return ret; + } + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) + priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; + else + priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; + + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter); + + return ret; +} + +/* + * IOCTL request handler to set WPA key. + * + * This function prepares the correct firmware command and + * issues it, after validation checks. + * + * Current driver only supports key length of up to 32 bytes. + * + * This function can also be used to disable a currently set key. + */ +static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv, + struct mwifiex_ds_encrypt_key *encrypt_key) +{ + int ret; + u8 remove_key = false; + struct host_cmd_ds_802_11_key_material *ibss_key; + + /* Current driver only supports key length of up to 32 bytes */ + if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) { + dev_err(priv->adapter->dev, "key length too long\n"); + return -1; + } + + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + /* + * IBSS/WPA-None uses only one key (Group) for both receiving + * and sending unicast and multicast packets. + */ + /* Send the key as PTK to firmware */ + encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + encrypt_key); + if (ret) + return ret; + + ibss_key = &priv->aes_key; + memset(ibss_key, 0, + sizeof(struct host_cmd_ds_802_11_key_material)); + /* Copy the key in the driver */ + memcpy(ibss_key->key_param_set.key, encrypt_key->key_material, + encrypt_key->key_len); + memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len, + sizeof(ibss_key->key_param_set.key_len)); + ibss_key->key_param_set.key_type_id + = cpu_to_le16(KEY_TYPE_ID_TKIP); + ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED); + + /* Send the key as GTK to firmware */ + encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST; + } + + if (!encrypt_key->key_index) + encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; + + if (remove_key) + ret = mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, !(KEY_INFO_ENABLED), + encrypt_key); + else + ret = mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + encrypt_key); + + return ret; +} + +/* + * IOCTL request handler to set/get network keys. + * + * This is a generic key handling function which supports WEP, WPA + * and WAPI. + */ +static int +mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv, + struct mwifiex_ds_encrypt_key *encrypt_key) +{ + int status; + + if (encrypt_key->is_wapi_key) + status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key); + else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104) + status = mwifiex_sec_ioctl_set_wpa_key(priv, encrypt_key); + else + status = mwifiex_sec_ioctl_set_wep_key(priv, encrypt_key); + return status; +} + +/* + * This function returns the driver version. + */ +int +mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version, + int max_len) +{ + union { + u32 l; + u8 c[4]; + } ver; + char fw_ver[32]; + + ver.l = adapter->fw_release_number; + sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]); + + snprintf(version, max_len, driver_version, fw_ver); + + dev_dbg(adapter->dev, "info: MWIFIEX VERSION: %s\n", 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->w_stats.qual.level = signal->bcn_rssi_avg; + if (signal->selector & BCN_NF_AVG_MASK) + priv->w_stats.qual.noise = signal->bcn_nf_avg; + } + + return status; +} + +/* + * Sends IOCTL request to set encoding parameters. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, + int key_len, u8 key_index, int disable) +{ + struct mwifiex_ds_encrypt_key encrypt_key; + + memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key)); + encrypt_key.key_len = key_len; + if (!disable) { + encrypt_key.key_index = key_index; + if (key_len) + memcpy(encrypt_key.key_material, key, key_len); + } else { + encrypt_key.key_disable = true; + } + + return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key); +} + +/* + * Sends IOCTL request to get extended version. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_get_ver_ext(struct mwifiex_private *priv) +{ + struct mwifiex_ver_ext ver_ext; + + memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext)); + if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_VERSION_EXT, + HostCmd_ACT_GEN_GET, 0, &ver_ext)) + return -1; + + return 0; +} + +/* + * Sends IOCTL request to get statistics information. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_get_stats_info(struct mwifiex_private *priv, + struct mwifiex_ds_get_stats *log) +{ + int ret; + + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, + HostCmd_ACT_GEN_GET, 0, log); + + if (!ret) { + priv->w_stats.discard.fragment = log->fcs_error; + priv->w_stats.discard.retries = log->retry; + priv->w_stats.discard.misc = log->ack_failure; + } + + return ret; +} + +/* + * IOCTL request handler to read/write register. + * + * This function prepares the correct firmware command and + * issues it. + * + * Access to the following registers are supported - + * - MAC + * - BBP + * - RF + * - PMIC + * - CAU + */ +static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv, + struct mwifiex_ds_reg_rw *reg_rw, + u16 action) +{ + u16 cmd_no; + + switch (le32_to_cpu(reg_rw->type)) { + case MWIFIEX_REG_MAC: + cmd_no = HostCmd_CMD_MAC_REG_ACCESS; + break; + case MWIFIEX_REG_BBP: + cmd_no = HostCmd_CMD_BBP_REG_ACCESS; + break; + case MWIFIEX_REG_RF: + cmd_no = HostCmd_CMD_RF_REG_ACCESS; + break; + case MWIFIEX_REG_PMIC: + cmd_no = HostCmd_CMD_PMIC_REG_ACCESS; + break; + case MWIFIEX_REG_CAU: + cmd_no = HostCmd_CMD_CAU_REG_ACCESS; + break; + default: + return -1; + } + + return mwifiex_send_cmd_sync(priv, cmd_no, action, 0, reg_rw); + +} + +/* + * Sends IOCTL request to write to a register. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, + u32 reg_offset, u32 reg_value) +{ + struct mwifiex_ds_reg_rw reg_rw; + + reg_rw.type = cpu_to_le32(reg_type); + reg_rw.offset = cpu_to_le32(reg_offset); + reg_rw.value = cpu_to_le32(reg_value); + + return mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_SET); +} + +/* + * Sends IOCTL request to read from a register. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, + u32 reg_offset, u32 *value) +{ + int ret; + struct mwifiex_ds_reg_rw reg_rw; + + reg_rw.type = cpu_to_le32(reg_type); + reg_rw.offset = cpu_to_le32(reg_offset); + ret = mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_GET); + + if (ret) + goto done; + + *value = le32_to_cpu(reg_rw.value); + +done: + return ret; +} + +/* + * Sends IOCTL request to read from EEPROM. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, + u8 *value) +{ + int ret; + struct mwifiex_ds_read_eeprom rd_eeprom; + + rd_eeprom.offset = cpu_to_le16((u16) offset); + rd_eeprom.byte_count = cpu_to_le16((u16) bytes); + + /* Send request to firmware */ + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_EEPROM_ACCESS, + HostCmd_ACT_GEN_GET, 0, &rd_eeprom); + + if (!ret) + memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA); + return ret; +} + +/* + * This function sets a generic IE. In addition to generic IE, it can + * also handle WPA, WPA2 and WAPI IEs. + */ +static int +mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, + u16 ie_len) +{ + int ret = 0; + struct ieee_types_vendor_header *pvendor_ie; + const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 }; + const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; + + /* If the passed length is zero, reset the buffer */ + if (!ie_len) { + priv->gen_ie_buf_len = 0; + priv->wps.session_enable = false; + + return 0; + } else if (!ie_data_ptr) { + return -1; + } + pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; + /* Test to see if it is a WPA IE, if not, then it is a gen IE */ + if (((pvendor_ie->element_id == WLAN_EID_WPA) + && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui)))) + || (pvendor_ie->element_id == WLAN_EID_RSN)) { + + /* IE is a WPA/WPA2 IE so call set_wpa function */ + ret = mwifiex_set_wpa_ie_helper(priv, ie_data_ptr, ie_len); + priv->wps.session_enable = false; + + return ret; + } else if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) { + /* IE is a WAPI IE so call set_wapi function */ + ret = mwifiex_set_wapi_ie(priv, ie_data_ptr, ie_len); + + return ret; + } + /* + * Verify that the passed length is not larger than the + * available space remaining in the buffer + */ + if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) { + + /* Test to see if it is a WPS IE, if so, enable + * wps session flag + */ + pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; + if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) + && (!memcmp(pvendor_ie->oui, wps_oui, + sizeof(wps_oui)))) { + priv->wps.session_enable = true; + dev_dbg(priv->adapter->dev, + "info: WPS Session Enabled.\n"); + } + + /* Append the passed data to the end of the + genIeBuffer */ + memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr, + ie_len); + /* Increment the stored buffer length by the + size passed */ + priv->gen_ie_buf_len += ie_len; + } else { + /* Passed data does not fit in the remaining + buffer space */ + ret = -1; + } + + /* Return 0, or -1 for error case */ + return ret; +} + +/* + * IOCTL request handler to set/get generic IE. + * + * In addition to various generic IEs, this function can also be + * used to set the ARP filter. + */ +static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv, + struct mwifiex_ds_misc_gen_ie *gen_ie, + u16 action) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + switch (gen_ie->type) { + case MWIFIEX_IE_TYPE_GEN_IE: + if (action == HostCmd_ACT_GEN_GET) { + gen_ie->len = priv->wpa_ie_len; + memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len); + } else { + mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data, + (u16) gen_ie->len); + } + break; + case MWIFIEX_IE_TYPE_ARP_FILTER: + memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter)); + if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) { + adapter->arp_filter_size = 0; + dev_err(adapter->dev, "invalid ARP filter size\n"); + return -1; + } else { + memcpy(adapter->arp_filter, gen_ie->ie_data, + gen_ie->len); + adapter->arp_filter_size = gen_ie->len; + } + break; + default: + dev_err(adapter->dev, "invalid IE type\n"); + return -1; + } + return 0; +} + +/* + * Sends IOCTL request to set a generic IE. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len) +{ + struct mwifiex_ds_misc_gen_ie gen_ie; + + if (ie_len > IW_CUSTOM_MAX) + return -EFAULT; + + gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE; + gen_ie.len = ie_len; + memcpy(gen_ie.ie_data, ie, ie_len); + if (mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET)) + return -EFAULT; + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c new file mode 100644 index 000000000000..1fdddece7479 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -0,0 +1,200 @@ +/* + * Marvell Wireless LAN device driver: station RX data handling + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "11n_aggr.h" +#include "11n_rxreorder.h" + +/* + * This function processes the received packet and forwards it + * to kernel/upper layer. + * + * This function parses through the received packet and determines + * if it is a debug packet or normal packet. + * + * For non-debug packets, the function chops off unnecessary leading + * header bytes, reconstructs the packet as an ethernet frame or + * 802.2/llc/snap frame as required, and sends it to kernel/upper layer. + * + * The completion callback is called after processing in complete. + */ +int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + int ret; + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; + struct rx_packet_hdr *rx_pkt_hdr; + struct rxpd *local_rx_pd; + int hdr_chop; + struct ethhdr *eth_hdr; + u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + + local_rx_pd = (struct rxpd *) (skb->data); + + rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd + + local_rx_pd->rx_pkt_offset); + + if (!memcmp(&rx_pkt_hdr->rfc1042_hdr, + rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) { + /* + * Replace the 803 header and rfc1042 header (llc/snap) with an + * EthernetII header, keep the src/dst and snap_type + * (ethertype). + * The firmware only passes up SNAP frames converting + * all RX Data from 802.11 to 802.2/LLC/SNAP frames. + * To create the Ethernet II, just move the src, dst address + * right before the snap_type. + */ + eth_hdr = (struct ethhdr *) + ((u8 *) &rx_pkt_hdr->eth803_hdr + + sizeof(rx_pkt_hdr->eth803_hdr) + + sizeof(rx_pkt_hdr->rfc1042_hdr) + - sizeof(rx_pkt_hdr->eth803_hdr.h_dest) + - sizeof(rx_pkt_hdr->eth803_hdr.h_source) + - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type)); + + memcpy(eth_hdr->h_source, rx_pkt_hdr->eth803_hdr.h_source, + sizeof(eth_hdr->h_source)); + memcpy(eth_hdr->h_dest, rx_pkt_hdr->eth803_hdr.h_dest, + sizeof(eth_hdr->h_dest)); + + /* Chop off the rxpd + the excess memory from the 802.2/llc/snap + header that was removed. */ + hdr_chop = (u8 *) eth_hdr - (u8 *) local_rx_pd; + } else { + /* Chop off the rxpd */ + hdr_chop = (u8 *) &rx_pkt_hdr->eth803_hdr - + (u8 *) local_rx_pd; + } + + /* Chop off the leading header bytes so the it points to the start of + either the reconstructed EthII frame or the 802.2/llc/snap frame */ + skb_pull(skb, hdr_chop); + + priv->rxpd_rate = local_rx_pd->rx_rate; + + priv->rxpd_htinfo = local_rx_pd->ht_info; + + ret = mwifiex_recv_packet(adapter, skb); + if (ret == -1) + dev_err(adapter->dev, "recv packet failed\n"); + + return ret; +} + +/* + * This function processes the received buffer. + * + * The function looks into the RxPD and performs sanity tests on the + * received buffer to ensure its a valid packet, before processing it + * further. If the packet is determined to be aggregated, it is + * de-aggregated accordingly. Non-unicast packets are sent directly to + * the kernel/upper layers. Unicast packets are handed over to the + * Rx reordering routine if 11n is enabled. + * + * The completion callback is called after processing in complete. + */ +int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + int ret = 0; + struct rxpd *local_rx_pd; + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + struct rx_packet_hdr *rx_pkt_hdr; + u8 ta[ETH_ALEN]; + u16 rx_pkt_type; + struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; + + local_rx_pd = (struct rxpd *) (skb->data); + rx_pkt_type = local_rx_pd->rx_pkt_type; + + rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd + + local_rx_pd->rx_pkt_offset); + + if ((local_rx_pd->rx_pkt_offset + local_rx_pd->rx_pkt_length) > + (u16) skb->len) { + dev_err(adapter->dev, "wrong rx packet: len=%d," + " 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); + return ret; + } + + if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) { + struct sk_buff_head list; + struct sk_buff *rx_skb; + + __skb_queue_head_init(&list); + + skb_pull(skb, local_rx_pd->rx_pkt_offset); + skb_trim(skb, local_rx_pd->rx_pkt_length); + + ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, + priv->wdev->iftype, 0, false); + + while (!skb_queue_empty(&list)) { + rx_skb = __skb_dequeue(&list); + ret = mwifiex_recv_packet(adapter, rx_skb); + if (ret == -1) + dev_err(adapter->dev, "Rx of A-MSDU failed"); + } + return 0; + } + + /* + * If the packet is not an unicast packet then send the packet + * directly to os. Don't pass thru rx reordering + */ + if (!IS_11N_ENABLED(priv) || + memcmp(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN)) { + mwifiex_process_rx_packet(adapter, skb); + return ret; + } + + if (mwifiex_queuing_ra_based(priv)) { + memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN); + } else { + if (rx_pkt_type != PKT_TYPE_BAR) + priv->rx_seq[local_rx_pd->priority] = + local_rx_pd->seq_num; + memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address, + ETH_ALEN); + } + + /* Reorder and send to OS */ + ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num, + local_rx_pd->priority, ta, + (u8) local_rx_pd->rx_pkt_type, + (void *) skb); + + if (ret || (rx_pkt_type == PKT_TYPE_BAR)) { + if (priv && (ret == -1)) + priv->stats.rx_dropped++; + + dev_kfree_skb_any(skb); + } + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c new file mode 100644 index 000000000000..fa6221bc9104 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -0,0 +1,198 @@ +/* + * Marvell Wireless LAN device driver: station TX data handling + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" + +/* + * This function fills the TxPD for tx packets. + * + * The Tx buffer received by this function should already have the + * header space allocated for TxPD. + * + * This function inserts the TxPD in between interface header and actual + * data and adjusts the buffer pointers accordingly. + * + * The following TxPD fields are set by this function, as required - + * - BSS number + * - Tx packet length and offset + * - Priority + * - Packet delay + * - Priority specific Tx control + * - Flags + */ +void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct txpd *local_tx_pd; + struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); + + if (!skb->len) { + dev_err(adapter->dev, "Tx: bad packet length: %d\n", + skb->len); + tx_info->status_code = -1; + return skb->data; + } + + BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN)); + skb_push(skb, sizeof(*local_tx_pd)); + + local_tx_pd = (struct txpd *) skb->data; + memset(local_tx_pd, 0, sizeof(struct txpd)); + local_tx_pd->bss_num = priv->bss_num; + local_tx_pd->bss_type = priv->bss_type; + local_tx_pd->tx_pkt_length = cpu_to_le16((u16) (skb->len - + sizeof(struct txpd))); + + local_tx_pd->priority = (u8) skb->priority; + local_tx_pd->pkt_delay_2ms = + mwifiex_wmm_compute_drv_pkt_delay(priv, skb); + + if (local_tx_pd->priority < + ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) + /* + * Set the priority specific tx_control field, setting of 0 will + * cause the default value to be used later in this function + */ + local_tx_pd->tx_control = + cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[local_tx_pd-> + priority]); + + if (adapter->pps_uapsd_mode) { + if (mwifiex_check_last_packet_indication(priv)) { + adapter->tx_lock_flag = true; + local_tx_pd->flags = + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; + } + } + + /* Offset of actual data */ + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + + /* make space for INTF_HEADER_LEN */ + skb_push(skb, INTF_HEADER_LEN); + + if (!local_tx_pd->tx_control) + /* TxCtrl set by user or default */ + local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); + + return skb->data; +} + +/* + * This function tells firmware to send a NULL data packet. + * + * The function creates a NULL data packet with TxPD and sends to the + * firmware for transmission, with highest priority setting. + */ +int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct txpd *local_tx_pd; +/* sizeof(struct txpd) + Interface specific header */ +#define NULL_PACKET_HDR 64 + u32 data_len = NULL_PACKET_HDR; + struct sk_buff *skb; + int ret; + struct mwifiex_txinfo *tx_info = NULL; + + if (adapter->surprise_removed) + return -1; + + if (!priv->media_connected) + return -1; + + if (adapter->data_sent) + return -1; + + skb = dev_alloc_skb(data_len); + if (!skb) + return -1; + + tx_info = MWIFIEX_SKB_TXCB(skb); + tx_info->bss_index = priv->bss_index; + skb_reserve(skb, sizeof(struct txpd) + INTF_HEADER_LEN); + skb_push(skb, sizeof(struct txpd)); + + local_tx_pd = (struct txpd *) skb->data; + local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); + local_tx_pd->flags = flags; + local_tx_pd->priority = WMM_HIGHEST_PRIORITY; + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + 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->data, skb->len, NULL); + switch (ret) { + case -EBUSY: + adapter->data_sent = true; + /* Fall through FAILURE handling */ + case -1: + dev_kfree_skb_any(skb); + dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n", + __func__, ret); + adapter->dbg.num_tx_host_to_card_failure++; + break; + case 0: + dev_kfree_skb_any(skb); + dev_dbg(adapter->dev, "data: %s: host_to_card succeeded\n", + __func__); + adapter->tx_lock_flag = true; + break; + case -EINPROGRESS: + break; + default: + break; + } + + return ret; +} + +/* + * This function checks if we need to send last packet indication. + */ +u8 +mwifiex_check_last_packet_indication(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u8 ret = false; + + if (!adapter->sleep_period.period) + return ret; + if (mwifiex_wmm_lists_empty(adapter)) + ret = true; + + if (ret && !adapter->cmd_sent && !adapter->curr_cmd + && !is_command_pending(adapter)) { + adapter->delay_null_pkt = false; + ret = true; + } else { + ret = false; + adapter->delay_null_pkt = true; + } + return ret; +} diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c new file mode 100644 index 000000000000..210120889dfe --- /dev/null +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -0,0 +1,200 @@ +/* + * Marvell Wireless LAN device driver: generic TX/RX data handling + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" + +/* + * This function processes the received buffer. + * + * Main responsibility of this function is to parse the RxPD to + * identify the correct interface this packet is headed for and + * forwarding it to the associated handling function, where the + * packet will be further processed and sent to kernel/upper layer + * if required. + */ +int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + struct rxpd *local_rx_pd; + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + + local_rx_pd = (struct rxpd *) (skb->data); + /* Get the BSS number from rxpd, get corresponding priv */ + priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num & + BSS_NUM_MASK, local_rx_pd->bss_type); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + + rx_info->bss_index = priv->bss_index; + + return mwifiex_process_sta_rx_packet(adapter, skb); +} +EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); + +/* + * This function sends a packet to device. + * + * It processes the packet to add the TxPD, checks condition and + * sends the processed packet to firmware for transmission. + * + * On successful completion, the function calls the completion callback + * and logs the time. + */ +int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, + struct mwifiex_tx_param *tx_param) +{ + int ret = -1; + struct mwifiex_adapter *adapter = priv->adapter; + u8 *head_ptr; + struct txpd *local_tx_pd = NULL; + + head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb); + if (head_ptr) { + 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->data, skb->len, tx_param); + } + + switch (ret) { + case -EBUSY: + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && + (adapter->pps_uapsd_mode) && + (adapter->tx_lock_flag)) { + priv->adapter->tx_lock_flag = false; + local_tx_pd->flags = 0; + } + dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); + break; + case -1: + adapter->data_sent = false; + dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n", + ret); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb, ret); + break; + case -EINPROGRESS: + adapter->data_sent = false; + break; + case 0: + mwifiex_write_data_complete(adapter, skb, ret); + break; + default: + break; + } + + return ret; +} + +/* + * Packet send completion callback handler. + * + * It either frees the buffer directly or forwards it to another + * completion callback which checks conditions, updates statistics, + * wakes up stalled traffic queue if required, and then frees the buffer. + */ +int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb, int status) +{ + struct mwifiex_private *priv, *tpriv; + struct mwifiex_txinfo *tx_info; + int i; + + if (!skb) + return 0; + + tx_info = MWIFIEX_SKB_TXCB(skb); + priv = mwifiex_bss_index_to_priv(adapter, tx_info->bss_index); + if (!priv) + goto done; + + priv->netdev->trans_start = jiffies; + if (!status) { + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + } else { + priv->stats.tx_errors++; + } + atomic_dec(&adapter->tx_pending); + + for (i = 0; i < adapter->priv_num; i++) { + + tpriv = adapter->priv[i]; + + if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA) + && (tpriv->media_connected)) { + if (netif_queue_stopped(tpriv->netdev)) + netif_wake_queue(tpriv->netdev); + } + } +done: + dev_kfree_skb_any(skb); + + return 0; +} + +/* + * Packet receive completion callback handler. + * + * This function calls another completion callback handler which + * updates the statistics, and optionally updates the parent buffer + * use count before freeing the received packet. + */ +int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb, int status) +{ + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + struct mwifiex_rxinfo *rx_info_parent; + struct mwifiex_private *priv; + struct sk_buff *skb_parent; + unsigned long flags; + + priv = adapter->priv[rx_info->bss_index]; + + if (priv && (status == -1)) + priv->stats.rx_dropped++; + + if (rx_info->parent) { + skb_parent = rx_info->parent; + rx_info_parent = MWIFIEX_SKB_RXCB(skb_parent); + + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + --rx_info_parent->use_count; + + if (!rx_info_parent->use_count) { + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + dev_kfree_skb_any(skb_parent); + } else { + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + } + } else { + dev_kfree_skb_any(skb); + } + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c new file mode 100644 index 000000000000..d41291529bc0 --- /dev/null +++ b/drivers/net/wireless/mwifiex/util.c @@ -0,0 +1,202 @@ +/* + * Marvell Wireless LAN device driver: utility functions + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * Firmware initialization complete callback handler. + * + * This function wakes up the function waiting on the init + * wait queue for the firmware initialization to complete. + */ +int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter) +{ + + adapter->init_wait_q_woken = true; + wake_up_interruptible(&adapter->init_wait_q); + return 0; +} + +/* + * Firmware shutdown complete callback handler. + * + * This function sets the hardware status to not ready and wakes up + * the function waiting on the init wait queue for the firmware + * shutdown to complete. + */ +int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter) +{ + adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY; + adapter->init_wait_q_woken = true; + wake_up_interruptible(&adapter->init_wait_q); + return 0; +} + +/* + * This function sends init/shutdown command + * to firmware. + */ +int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, + u32 func_init_shutdown) +{ + u16 cmd; + + if (func_init_shutdown == MWIFIEX_FUNC_INIT) { + cmd = HostCmd_CMD_FUNC_INIT; + } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) { + cmd = HostCmd_CMD_FUNC_SHUTDOWN; + } else { + dev_err(priv->adapter->dev, "unsupported parameter\n"); + return -1; + } + + return mwifiex_send_cmd_sync(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL); +} +EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw); + +/* + * IOCTL request handler to set/get debug information. + * + * This function collates/sets the information from/to different driver + * structures. + */ +int mwifiex_get_debug_info(struct mwifiex_private *priv, + struct mwifiex_debug_info *info) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + if (info) { + memcpy(info->packets_out, + priv->wmm.packets_out, + sizeof(priv->wmm.packets_out)); + info->max_tx_buf_size = (u32) adapter->max_tx_buf_size; + info->tx_buf_size = (u32) adapter->tx_buf_size; + info->rx_tbl_num = mwifiex_get_rx_reorder_tbl( + priv, info->rx_tbl); + info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl( + priv, info->tx_tbl); + info->ps_mode = adapter->ps_mode; + info->ps_state = adapter->ps_state; + info->is_deep_sleep = adapter->is_deep_sleep; + info->pm_wakeup_card_req = adapter->pm_wakeup_card_req; + info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try; + info->is_hs_configured = adapter->is_hs_configured; + info->hs_activated = adapter->hs_activated; + info->num_cmd_host_to_card_failure + = adapter->dbg.num_cmd_host_to_card_failure; + info->num_cmd_sleep_cfm_host_to_card_failure + = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure; + info->num_tx_host_to_card_failure + = adapter->dbg.num_tx_host_to_card_failure; + info->num_event_deauth = adapter->dbg.num_event_deauth; + info->num_event_disassoc = adapter->dbg.num_event_disassoc; + info->num_event_link_lost = adapter->dbg.num_event_link_lost; + info->num_cmd_deauth = adapter->dbg.num_cmd_deauth; + info->num_cmd_assoc_success = + adapter->dbg.num_cmd_assoc_success; + info->num_cmd_assoc_failure = + adapter->dbg.num_cmd_assoc_failure; + info->num_tx_timeout = adapter->dbg.num_tx_timeout; + info->num_cmd_timeout = adapter->dbg.num_cmd_timeout; + info->timeout_cmd_id = adapter->dbg.timeout_cmd_id; + info->timeout_cmd_act = adapter->dbg.timeout_cmd_act; + memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id, + sizeof(adapter->dbg.last_cmd_id)); + memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act, + sizeof(adapter->dbg.last_cmd_act)); + info->last_cmd_index = adapter->dbg.last_cmd_index; + memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id, + sizeof(adapter->dbg.last_cmd_resp_id)); + info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index; + memcpy(info->last_event, adapter->dbg.last_event, + sizeof(adapter->dbg.last_event)); + info->last_event_index = adapter->dbg.last_event_index; + info->data_sent = adapter->data_sent; + info->cmd_sent = adapter->cmd_sent; + info->cmd_resp_received = adapter->cmd_resp_received; + } + + return 0; +} + +/* + * This function processes the received packet before sending it to the + * kernel. + * + * It extracts the SKB from the received buffer and sends it to kernel. + * In case the received buffer does not contain the data in SKB format, + * the function creates a blank SKB, fills it with the data from the + * received buffer and then sends this new SKB to the kernel. + */ +int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) +{ + struct mwifiex_rxinfo *rx_info; + struct mwifiex_private *priv; + + if (!skb) + return -1; + + rx_info = MWIFIEX_SKB_RXCB(skb); + priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index); + if (!priv) + return -1; + + skb->dev = priv->netdev; + skb->protocol = eth_type_trans(skb, priv->netdev); + skb->ip_summed = CHECKSUM_NONE; + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); + + return 0; +} + +/* + * IOCTL completion callback handler. + * + * This function is called when a pending IOCTL is completed. + * + * If work queue support is enabled, the function wakes up the + * corresponding waiting function. Otherwise, it processes the + * IOCTL response and frees the response buffer. + */ +int mwifiex_complete_cmd(struct mwifiex_adapter *adapter) +{ + atomic_dec(&adapter->cmd_pending); + dev_dbg(adapter->dev, "cmd completed: status=%d\n", + adapter->cmd_wait_q.status); + + adapter->cmd_wait_q.condition = true; + + if (adapter->cmd_wait_q.status == -ETIMEDOUT) + dev_err(adapter->dev, "cmd timeout\n"); + else + wake_up_interruptible(&adapter->cmd_wait_q.wait); + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h new file mode 100644 index 000000000000..9506afc6c0e4 --- /dev/null +++ b/drivers/net/wireless/mwifiex/util.h @@ -0,0 +1,32 @@ +/* + * Marvell Wireless LAN device driver: utility functions + * + * Copyright (C) 2011, 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_UTIL_H_ +#define _MWIFIEX_UTIL_H_ + +static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) +{ + return (struct mwifiex_rxinfo *)skb->cb; +} + +static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb) +{ + return (struct mwifiex_txinfo *)skb->cb; +} +#endif /* !_MWIFIEX_UTIL_H_ */ diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c new file mode 100644 index 000000000000..faa09e32902e --- /dev/null +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -0,0 +1,1231 @@ +/* + * Marvell Wireless LAN device driver: WMM + * + * Copyright (C) 2011, 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 "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + + +/* Maximum value FW can accept for driver delay in packet transmission */ +#define DRV_PKT_DELAY_TO_FW_MAX 512 + + +#define WMM_QUEUED_PACKET_LOWER_LIMIT 180 + +#define WMM_QUEUED_PACKET_UPPER_LIMIT 200 + +/* Offset for TOS field in the IP header */ +#define IPTOS_OFFSET 5 + +/* WMM information IE */ +static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07, + 0x00, 0x50, 0xf2, 0x02, + 0x00, 0x01, 0x00 +}; + +static const u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE, + WMM_AC_BK, + WMM_AC_VI, + WMM_AC_VO +}; + +static u8 tos_to_tid[] = { + /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */ + 0x01, /* 0 1 0 AC_BK */ + 0x02, /* 0 0 0 AC_BK */ + 0x00, /* 0 0 1 AC_BE */ + 0x03, /* 0 1 1 AC_BE */ + 0x04, /* 1 0 0 AC_VI */ + 0x05, /* 1 0 1 AC_VI */ + 0x06, /* 1 1 0 AC_VO */ + 0x07 /* 1 1 1 AC_VO */ +}; + +/* + * This table inverses the tos_to_tid operation to get a priority + * which is in sequential order, and can be compared. + * Use this to compare the priority of two different TIDs. + */ +static u8 tos_to_tid_inv[] = { + 0x02, /* from tos_to_tid[2] = 0 */ + 0x00, /* from tos_to_tid[0] = 1 */ + 0x01, /* from tos_to_tid[1] = 2 */ + 0x03, + 0x04, + 0x05, + 0x06, + 0x07}; + +static u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} }; + +/* + * This function debug prints the priority parameters for a WMM AC. + */ +static void +mwifiex_wmm_ac_debug_print(const struct ieee_types_wmm_ac_parameters *ac_param) +{ + const char *ac_str[] = { "BK", "BE", "VI", "VO" }; + + pr_debug("info: WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, " + "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n", + ac_str[wmm_aci_to_qidx_map[(ac_param->aci_aifsn_bitmap + & MWIFIEX_ACI) >> 5]], + (ac_param->aci_aifsn_bitmap & MWIFIEX_ACI) >> 5, + (ac_param->aci_aifsn_bitmap & MWIFIEX_ACM) >> 4, + ac_param->aci_aifsn_bitmap & MWIFIEX_AIFSN, + ac_param->ecw_bitmap & MWIFIEX_ECW_MIN, + (ac_param->ecw_bitmap & MWIFIEX_ECW_MAX) >> 4, + le16_to_cpu(ac_param->tx_op_limit)); +} + +/* + * This function allocates a route address list. + * + * The function also initializes the list with the provided RA. + */ +static struct mwifiex_ra_list_tbl * +mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra) +{ + struct mwifiex_ra_list_tbl *ra_list; + + ra_list = kzalloc(sizeof(struct mwifiex_ra_list_tbl), GFP_ATOMIC); + + if (!ra_list) { + dev_err(adapter->dev, "%s: failed to alloc ra_list\n", + __func__); + return NULL; + } + INIT_LIST_HEAD(&ra_list->list); + skb_queue_head_init(&ra_list->skb_head); + + memcpy(ra_list->ra, ra, ETH_ALEN); + + ra_list->total_pkts_size = 0; + + dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list); + + return ra_list; +} + +/* + * This function allocates and adds a RA list for all TIDs + * with the given RA. + */ +void +mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra) +{ + int i; + struct mwifiex_ra_list_tbl *ra_list; + struct mwifiex_adapter *adapter = priv->adapter; + + for (i = 0; i < MAX_NUM_TID; ++i) { + ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra); + dev_dbg(adapter->dev, "info: created ra_list %p\n", ra_list); + + if (!ra_list) + break; + + if (!mwifiex_queuing_ra_based(priv)) + ra_list->is_11n_enabled = IS_11N_ENABLED(priv); + else + ra_list->is_11n_enabled = false; + + dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n", + ra_list, ra_list->is_11n_enabled); + + list_add_tail(&ra_list->list, + &priv->wmm.tid_tbl_ptr[i].ra_list); + + if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr) + priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list; + } +} + +/* + * This function sets the WMM queue priorities to their default values. + */ +static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv) +{ + /* Default queue priorities: VO->VI->BE->BK */ + priv->wmm.queue_priority[0] = WMM_AC_VO; + priv->wmm.queue_priority[1] = WMM_AC_VI; + priv->wmm.queue_priority[2] = WMM_AC_BE; + priv->wmm.queue_priority[3] = WMM_AC_BK; +} + +/* + * This function map ACs to TIDs. + */ +static void +mwifiex_wmm_queue_priorities_tid(u8 queue_priority[]) +{ + int i; + + for (i = 0; i < 4; ++i) { + tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1]; + tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0]; + } +} + +/* + * This function initializes WMM priority queues. + */ +void +mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, + struct ieee_types_wmm_parameter *wmm_ie) +{ + u16 cw_min, avg_back_off, tmp[4]; + u32 i, j, num_ac; + u8 ac_idx; + + if (!wmm_ie || !priv->wmm_enabled) { + /* WMM is not enabled, just set the defaults and return */ + mwifiex_wmm_default_queue_priorities(priv); + return; + } + + dev_dbg(priv->adapter->dev, "info: WMM Parameter IE: version=%d, " + "qos_info Parameter Set Count=%d, Reserved=%#x\n", + wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap & + IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK, + wmm_ie->reserved); + + for (num_ac = 0; num_ac < ARRAY_SIZE(wmm_ie->ac_params); num_ac++) { + cw_min = (1 << (wmm_ie->ac_params[num_ac].ecw_bitmap & + MWIFIEX_ECW_MIN)) - 1; + avg_back_off = (cw_min >> 1) + + (wmm_ie->ac_params[num_ac].aci_aifsn_bitmap & + MWIFIEX_AIFSN); + + ac_idx = wmm_aci_to_qidx_map[(wmm_ie->ac_params[num_ac]. + aci_aifsn_bitmap & + MWIFIEX_ACI) >> 5]; + priv->wmm.queue_priority[ac_idx] = ac_idx; + tmp[ac_idx] = avg_back_off; + + dev_dbg(priv->adapter->dev, "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n", + (1 << ((wmm_ie->ac_params[num_ac].ecw_bitmap & + MWIFIEX_ECW_MAX) >> 4)) - 1, + cw_min, avg_back_off); + mwifiex_wmm_ac_debug_print(&wmm_ie->ac_params[num_ac]); + } + + /* Bubble sort */ + for (i = 0; i < num_ac; i++) { + for (j = 1; j < num_ac - i; j++) { + if (tmp[j - 1] > tmp[j]) { + swap(tmp[j - 1], tmp[j]); + swap(priv->wmm.queue_priority[j - 1], + priv->wmm.queue_priority[j]); + } else if (tmp[j - 1] == tmp[j]) { + if (priv->wmm.queue_priority[j - 1] + < priv->wmm.queue_priority[j]) + swap(priv->wmm.queue_priority[j - 1], + priv->wmm.queue_priority[j]); + } + } + } + + mwifiex_wmm_queue_priorities_tid(priv->wmm.queue_priority); +} + +/* + * This function evaluates whether or not an AC is to be downgraded. + * + * In case the AC is not enabled, the highest AC is returned that is + * enabled and does not require admission control. + */ +static enum mwifiex_wmm_ac_e +mwifiex_wmm_eval_downgrade_ac(struct mwifiex_private *priv, + enum mwifiex_wmm_ac_e eval_ac) +{ + int down_ac; + enum mwifiex_wmm_ac_e ret_ac; + struct mwifiex_wmm_ac_status *ac_status; + + ac_status = &priv->wmm.ac_status[eval_ac]; + + if (!ac_status->disabled) + /* Okay to use this AC, its enabled */ + return eval_ac; + + /* Setup a default return value of the lowest priority */ + ret_ac = WMM_AC_BK; + + /* + * Find the highest AC that is enabled and does not require + * admission control. The spec disallows downgrading to an AC, + * which is enabled due to a completed admission control. + * Unadmitted traffic is not to be sent on an AC with admitted + * traffic. + */ + for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) { + ac_status = &priv->wmm.ac_status[down_ac]; + + if (!ac_status->disabled && !ac_status->flow_required) + /* AC is enabled and does not require admission + control */ + ret_ac = (enum mwifiex_wmm_ac_e) down_ac; + } + + return ret_ac; +} + +/* + * This function downgrades WMM priority queue. + */ +void +mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv) +{ + int ac_val; + + dev_dbg(priv->adapter->dev, "info: WMM: AC Priorities:" + "BK(0), BE(1), VI(2), VO(3)\n"); + + if (!priv->wmm_enabled) { + /* WMM is not enabled, default priorities */ + for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) + priv->wmm.ac_down_graded_vals[ac_val] = + (enum mwifiex_wmm_ac_e) ac_val; + } else { + for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) { + priv->wmm.ac_down_graded_vals[ac_val] + = mwifiex_wmm_eval_downgrade_ac(priv, + (enum mwifiex_wmm_ac_e) ac_val); + dev_dbg(priv->adapter->dev, "info: WMM: AC PRIO %d maps to %d\n", + ac_val, priv->wmm.ac_down_graded_vals[ac_val]); + } + } +} + +/* + * This function converts the IP TOS field to an WMM AC + * Queue assignment. + */ +static enum mwifiex_wmm_ac_e +mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos) +{ + /* Map of TOS UP values to WMM AC */ + const enum mwifiex_wmm_ac_e tos_to_ac[] = { WMM_AC_BE, + WMM_AC_BK, + WMM_AC_BK, + WMM_AC_BE, + WMM_AC_VI, + WMM_AC_VI, + WMM_AC_VO, + WMM_AC_VO + }; + + if (tos >= ARRAY_SIZE(tos_to_ac)) + return WMM_AC_BE; + + return tos_to_ac[tos]; +} + +/* + * This function evaluates a given TID and downgrades it to a lower + * TID if the WMM Parameter IE received from the AP indicates that the + * AP is disabled (due to call admission control (ACM bit). Mapping + * of TID to AC is taken care of internally. + */ +static u8 +mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid) +{ + enum mwifiex_wmm_ac_e ac, ac_down; + u8 new_tid; + + ac = mwifiex_wmm_convert_tos_to_ac(priv->adapter, tid); + ac_down = priv->wmm.ac_down_graded_vals[ac]; + + /* Send the index to tid array, picking from the array will be + * taken care by dequeuing function + */ + new_tid = ac_to_tid[ac_down][tid % 2]; + + return new_tid; +} + +/* + * This function initializes the WMM state information and the + * WMM data path queues. + */ +void +mwifiex_wmm_init(struct mwifiex_adapter *adapter) +{ + int i, j; + struct mwifiex_private *priv; + + for (j = 0; j < adapter->priv_num; ++j) { + priv = adapter->priv[j]; + if (!priv) + continue; + + for (i = 0; i < MAX_NUM_TID; ++i) { + priv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i]; + priv->aggr_prio_tbl[i].ampdu_ap = tos_to_tid_inv[i]; + priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i]; + priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL; + } + + priv->aggr_prio_tbl[6].amsdu + = priv->aggr_prio_tbl[6].ampdu_ap + = priv->aggr_prio_tbl[6].ampdu_user + = BA_STREAM_NOT_ALLOWED; + + priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap + = priv->aggr_prio_tbl[7].ampdu_user + = BA_STREAM_NOT_ALLOWED; + + priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT; + priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE; + priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE; + } +} + +/* + * This function checks if WMM Tx queue is empty. + */ +int +mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter) +{ + int i, j; + struct mwifiex_private *priv; + + for (j = 0; j < adapter->priv_num; ++j) { + priv = adapter->priv[j]; + if (priv) { + for (i = 0; i < MAX_NUM_TID; i++) + if (!mwifiex_wmm_is_ra_list_empty( + &priv->wmm.tid_tbl_ptr[i].ra_list)) + return false; + } + } + + return true; +} + +/* + * This function deletes all packets in an RA list node. + * + * The packet sent completion callback handler are called with + * status failure, after they are dequeued to ensure proper + * cleanup. The RA list node itself is freed at the end. + */ +static void +mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ra_list) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) + mwifiex_write_data_complete(adapter, skb, -1); +} + +/* + * This function deletes all packets in an RA list. + * + * Each nodes in the RA list are freed individually first, and then + * the RA list itself is freed. + */ +static void +mwifiex_wmm_del_pkts_in_ralist(struct mwifiex_private *priv, + struct list_head *ra_list_head) +{ + struct mwifiex_ra_list_tbl *ra_list; + + list_for_each_entry(ra_list, ra_list_head, list) + mwifiex_wmm_del_pkts_in_ralist_node(priv, ra_list); +} + +/* + * This function deletes all packets in all RA lists. + */ +static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv) +{ + int i; + + for (i = 0; i < MAX_NUM_TID; i++) + mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i]. + ra_list); +} + +/* + * This function deletes all route addresses from all RA lists. + */ +static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv) +{ + struct mwifiex_ra_list_tbl *ra_list, *tmp_node; + int i; + + for (i = 0; i < MAX_NUM_TID; ++i) { + dev_dbg(priv->adapter->dev, + "info: ra_list: freeing buf for tid %d\n", i); + list_for_each_entry_safe(ra_list, tmp_node, + &priv->wmm.tid_tbl_ptr[i].ra_list, list) { + list_del(&ra_list->list); + kfree(ra_list); + } + + INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[i].ra_list); + + priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL; + } +} + +/* + * This function cleans up the Tx and Rx queues. + * + * Cleanup includes - + * - All packets in RA lists + * - All entries in Rx reorder table + * - All entries in Tx BA stream table + * - MPA buffer (if required) + * - All RA lists + */ +void +mwifiex_clean_txrx(struct mwifiex_private *priv) +{ + unsigned long flags; + + mwifiex_11n_cleanup_reorder_tbl(priv); + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + mwifiex_wmm_cleanup_queues(priv); + mwifiex_11n_delete_all_tx_ba_stream_tbl(priv); + + if (priv->adapter->if_ops.cleanup_mpa_buf) + priv->adapter->if_ops.cleanup_mpa_buf(priv->adapter); + + mwifiex_wmm_delete_all_ralist(priv); + memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + +/* + * This function retrieves a particular RA list node, matching with the + * given TID and RA address. + */ +static struct mwifiex_ra_list_tbl * +mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, + u8 *ra_addr) +{ + struct mwifiex_ra_list_tbl *ra_list; + + list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[tid].ra_list, + list) { + if (!memcmp(ra_list->ra, ra_addr, ETH_ALEN)) + return ra_list; + } + + return NULL; +} + +/* + * This function retrieves an RA list node for a given TID and + * RA address pair. + * + * If no such node is found, a new node is added first and then + * retrieved. + */ +static struct mwifiex_ra_list_tbl * +mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr) +{ + struct mwifiex_ra_list_tbl *ra_list; + + ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra_addr); + if (ra_list) + return ra_list; + mwifiex_ralist_add(priv, ra_addr); + + return mwifiex_wmm_get_ralist_node(priv, tid, ra_addr); +} + +/* + * This function checks if a particular RA list node exists in a given TID + * table index. + */ +int +mwifiex_is_ralist_valid(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ra_list, int ptr_index) +{ + struct mwifiex_ra_list_tbl *rlist; + + list_for_each_entry(rlist, &priv->wmm.tid_tbl_ptr[ptr_index].ra_list, + list) { + if (rlist == ra_list) + return true; + } + + return false; +} + +/* + * This function adds a packet to WMM queue. + * + * In disconnected state the packet is immediately dropped and the + * packet send completion callback is called with status failure. + * + * Otherwise, the correct RA list node is located and the packet + * is queued at the list tail. + */ +void +mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); + struct mwifiex_private *priv = adapter->priv[tx_info->bss_index]; + u32 tid; + struct mwifiex_ra_list_tbl *ra_list; + u8 ra[ETH_ALEN], tid_down; + unsigned long flags; + + if (!priv->media_connected) { + dev_dbg(adapter->dev, "data: drop packet in disconnect\n"); + mwifiex_write_data_complete(adapter, skb, -1); + return; + } + + tid = skb->priority; + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + tid_down = mwifiex_wmm_downgrade_tid(priv, tid); + + /* In case of infra as we have already created the list during + association we just don't have to call get_queue_raptr, we will + have only 1 raptr for a tid in case of infra */ + if (!mwifiex_queuing_ra_based(priv)) { + if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list)) + ra_list = list_first_entry( + &priv->wmm.tid_tbl_ptr[tid_down].ra_list, + struct mwifiex_ra_list_tbl, list); + else + ra_list = NULL; + } else { + memcpy(ra, skb->data, ETH_ALEN); + ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); + } + + if (!ra_list) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); + mwifiex_write_data_complete(adapter, skb, -1); + return; + } + + skb_queue_tail(&ra_list->skb_head, skb); + + ra_list->total_pkts_size += skb->len; + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + +/* + * This function processes the get WMM status command response from firmware. + * + * The response may contain multiple TLVs - + * - AC Queue status TLVs + * - Current WMM Parameter IE TLV + * - Admission Control action frame TLVs + * + * This function parses the TLVs and then calls further specific functions + * to process any changes in the queue prioritize or state. + */ +int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, + const struct host_cmd_ds_command *resp) +{ + u8 *curr = (u8 *) &resp->params.get_wmm_status; + uint16_t resp_len = le16_to_cpu(resp->size), tlv_len; + int valid = true; + + struct mwifiex_ie_types_data *tlv_hdr; + struct mwifiex_ie_types_wmm_queue_status *tlv_wmm_qstatus; + struct ieee_types_wmm_parameter *wmm_param_ie = NULL; + struct mwifiex_wmm_ac_status *ac_status; + + dev_dbg(priv->adapter->dev, "info: WMM: WMM_GET_STATUS cmdresp received: %d\n", + resp_len); + + while ((resp_len >= sizeof(tlv_hdr->header)) && valid) { + tlv_hdr = (struct mwifiex_ie_types_data *) curr; + tlv_len = le16_to_cpu(tlv_hdr->header.len); + + switch (le16_to_cpu(tlv_hdr->header.type)) { + case TLV_TYPE_WMMQSTATUS: + tlv_wmm_qstatus = + (struct mwifiex_ie_types_wmm_queue_status *) + tlv_hdr; + dev_dbg(priv->adapter->dev, + "info: CMD_RESP: WMM_GET_STATUS:" + " QSTATUS TLV: %d, %d, %d\n", + tlv_wmm_qstatus->queue_index, + tlv_wmm_qstatus->flow_required, + tlv_wmm_qstatus->disabled); + + ac_status = &priv->wmm.ac_status[tlv_wmm_qstatus-> + queue_index]; + ac_status->disabled = tlv_wmm_qstatus->disabled; + ac_status->flow_required = + tlv_wmm_qstatus->flow_required; + ac_status->flow_created = tlv_wmm_qstatus->flow_created; + break; + + case WLAN_EID_VENDOR_SPECIFIC: + /* + * Point the regular IEEE IE 2 bytes into the Marvell IE + * and setup the IEEE IE type and length byte fields + */ + + wmm_param_ie = + (struct ieee_types_wmm_parameter *) (curr + + 2); + wmm_param_ie->vend_hdr.len = (u8) tlv_len; + wmm_param_ie->vend_hdr.element_id = + WLAN_EID_VENDOR_SPECIFIC; + + dev_dbg(priv->adapter->dev, + "info: CMD_RESP: WMM_GET_STATUS:" + " WMM Parameter Set Count: %d\n", + wmm_param_ie->qos_info_bitmap & + IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK); + + memcpy((u8 *) &priv->curr_bss_params.bss_descriptor. + wmm_ie, wmm_param_ie, + wmm_param_ie->vend_hdr.len + 2); + + break; + + default: + valid = false; + break; + } + + curr += (tlv_len + sizeof(tlv_hdr->header)); + resp_len -= (tlv_len + sizeof(tlv_hdr->header)); + } + + mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie); + mwifiex_wmm_setup_ac_downgrade(priv); + + return 0; +} + +/* + * Callback handler from the command module to allow insertion of a WMM TLV. + * + * If the BSS we are associating to supports WMM, this function adds the + * required WMM Information IE to the association request command buffer in + * the form of a Marvell extended IEEE IE. + */ +u32 +mwifiex_wmm_process_association_req(struct mwifiex_private *priv, + u8 **assoc_buf, + struct ieee_types_wmm_parameter *wmm_ie, + struct ieee80211_ht_cap *ht_cap) +{ + struct mwifiex_ie_types_wmm_param_set *wmm_tlv; + u32 ret_len = 0; + + /* Null checks */ + if (!assoc_buf) + return 0; + if (!(*assoc_buf)) + return 0; + + if (!wmm_ie) + return 0; + + dev_dbg(priv->adapter->dev, "info: WMM: process assoc req:" + "bss->wmmIe=0x%x\n", + wmm_ie->vend_hdr.element_id); + + if ((priv->wmm_required + || (ht_cap && (priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN)) + ) + && wmm_ie->vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) { + wmm_tlv = (struct mwifiex_ie_types_wmm_param_set *) *assoc_buf; + wmm_tlv->header.type = cpu_to_le16((u16) wmm_info_ie[0]); + wmm_tlv->header.len = cpu_to_le16((u16) wmm_info_ie[1]); + memcpy(wmm_tlv->wmm_ie, &wmm_info_ie[2], + le16_to_cpu(wmm_tlv->header.len)); + if (wmm_ie->qos_info_bitmap & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) + memcpy((u8 *) (wmm_tlv->wmm_ie + + le16_to_cpu(wmm_tlv->header.len) + - sizeof(priv->wmm_qosinfo)), + &priv->wmm_qosinfo, + sizeof(priv->wmm_qosinfo)); + + ret_len = sizeof(wmm_tlv->header) + + le16_to_cpu(wmm_tlv->header.len); + + *assoc_buf += ret_len; + } + + return ret_len; +} + +/* + * This function computes the time delay in the driver queues for a + * given packet. + * + * When the packet is received at the OS/Driver interface, the current + * time is set in the packet structure. The difference between the present + * time and that received time is computed in this function and limited + * based on pre-compiled limits in the driver. + */ +u8 +mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, + const struct sk_buff *skb) +{ + u8 ret_val; + struct timeval out_tstamp, in_tstamp; + u32 queue_delay; + + do_gettimeofday(&out_tstamp); + in_tstamp = ktime_to_timeval(skb->tstamp); + + queue_delay = (out_tstamp.tv_sec - in_tstamp.tv_sec) * 1000; + queue_delay += (out_tstamp.tv_usec - in_tstamp.tv_usec) / 1000; + + /* + * Queue delay is passed as a uint8 in units of 2ms (ms shifted + * by 1). Min value (other than 0) is therefore 2ms, max is 510ms. + * + * Pass max value if queue_delay is beyond the uint8 range + */ + ret_val = (u8) (min(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1); + + dev_dbg(priv->adapter->dev, "data: WMM: Pkt Delay: %d ms," + " %d ms sent to FW\n", queue_delay, ret_val); + + return ret_val; +} + +/* + * This function retrieves the highest priority RA list table pointer. + */ +static struct mwifiex_ra_list_tbl * +mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, + struct mwifiex_private **priv, int *tid) +{ + struct mwifiex_private *priv_tmp; + struct mwifiex_ra_list_tbl *ptr, *head; + struct mwifiex_bss_prio_node *bssprio_node, *bssprio_head; + struct mwifiex_tid_tbl *tid_ptr; + int is_list_empty; + unsigned long flags; + int i, j; + + for (j = adapter->priv_num - 1; j >= 0; --j) { + spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock, + flags); + is_list_empty = list_empty(&adapter->bss_prio_tbl[j] + .bss_prio_head); + spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock, + flags); + if (is_list_empty) + continue; + + if (adapter->bss_prio_tbl[j].bss_prio_cur == + (struct mwifiex_bss_prio_node *) + &adapter->bss_prio_tbl[j].bss_prio_head) { + bssprio_node = + list_first_entry(&adapter->bss_prio_tbl[j] + .bss_prio_head, + struct mwifiex_bss_prio_node, + list); + bssprio_head = bssprio_node; + } else { + bssprio_node = adapter->bss_prio_tbl[j].bss_prio_cur; + bssprio_head = bssprio_node; + } + + do { + priv_tmp = bssprio_node->priv; + + for (i = HIGH_PRIO_TID; i >= LOW_PRIO_TID; --i) { + + tid_ptr = &(priv_tmp)->wmm. + tid_tbl_ptr[tos_to_tid[i]]; + + spin_lock_irqsave(&tid_ptr->tid_tbl_lock, + flags); + is_list_empty = + list_empty(&adapter->bss_prio_tbl[j] + .bss_prio_head); + spin_unlock_irqrestore(&tid_ptr->tid_tbl_lock, + flags); + if (is_list_empty) + continue; + + /* + * Always choose the next ra we transmitted + * last time, this way we pick the ra's in + * round robin fashion. + */ + ptr = list_first_entry( + &tid_ptr->ra_list_curr->list, + struct mwifiex_ra_list_tbl, + list); + + head = ptr; + if (ptr == (struct mwifiex_ra_list_tbl *) + &tid_ptr->ra_list) { + /* Get next ra */ + ptr = list_first_entry(&ptr->list, + struct mwifiex_ra_list_tbl, list); + head = ptr; + } + + do { + is_list_empty = + skb_queue_empty(&ptr->skb_head); + if (!is_list_empty) { + *priv = priv_tmp; + *tid = tos_to_tid[i]; + return ptr; + } + /* Get next ra */ + ptr = list_first_entry(&ptr->list, + struct mwifiex_ra_list_tbl, + list); + if (ptr == + (struct mwifiex_ra_list_tbl *) + &tid_ptr->ra_list) + ptr = list_first_entry( + &ptr->list, + struct mwifiex_ra_list_tbl, + list); + } while (ptr != head); + } + + /* Get next bss priority node */ + bssprio_node = list_first_entry(&bssprio_node->list, + struct mwifiex_bss_prio_node, + list); + + if (bssprio_node == + (struct mwifiex_bss_prio_node *) + &adapter->bss_prio_tbl[j].bss_prio_head) + /* Get next bss priority node */ + bssprio_node = list_first_entry( + &bssprio_node->list, + struct mwifiex_bss_prio_node, + list); + } while (bssprio_node != bssprio_head); + } + return NULL; +} + +/* + * This function gets the number of packets in the Tx queue of a + * particular RA list. + */ +static int +mwifiex_num_pkts_in_txq(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int max_buf_size) +{ + int count = 0, total_size = 0; + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(&ptr->skb_head, skb, tmp) { + total_size += skb->len; + if (total_size < max_buf_size) + ++count; + else + break; + } + + return count; +} + +/* + * This function sends a single packet to firmware for transmission. + */ +static void +mwifiex_send_single_packet(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int ptr_index, + unsigned long ra_list_flags) + __releases(&priv->wmm.ra_list_spinlock) +{ + struct sk_buff *skb, *skb_next; + struct mwifiex_tx_param tx_param; + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_txinfo *tx_info; + + if (skb_queue_empty(&ptr->skb_head)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + dev_dbg(adapter->dev, "data: nothing to send\n"); + return; + } + + skb = skb_dequeue(&ptr->skb_head); + + tx_info = MWIFIEX_SKB_TXCB(skb); + dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb); + + ptr->total_pkts_size -= skb->len; + + if (!skb_queue_empty(&ptr->skb_head)) + skb_next = skb_peek(&ptr->skb_head); + else + skb_next = NULL; + + 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); + + if (mwifiex_process_tx(priv, skb, &tx_param) == -EBUSY) { + /* Queue the packet back at the head */ + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + + if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + mwifiex_write_data_complete(adapter, skb, -1); + return; + } + + skb_queue_tail(&ptr->skb_head, skb); + + ptr->total_pkts_size += skb->len; + tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + } else { + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + priv->wmm.packets_out[ptr_index]++; + priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr; + } + adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = + list_first_entry( + &adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_cur->list, + struct mwifiex_bss_prio_node, + list); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + } +} + +/* + * This function checks if the first packet in the given RA list + * is already processed or not. + */ +static int +mwifiex_is_ptr_processed(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr) +{ + struct sk_buff *skb; + struct mwifiex_txinfo *tx_info; + + if (skb_queue_empty(&ptr->skb_head)) + return false; + + skb = skb_peek(&ptr->skb_head); + + tx_info = MWIFIEX_SKB_TXCB(skb); + if (tx_info->flags & MWIFIEX_BUF_FLAG_REQUEUED_PKT) + return true; + + return false; +} + +/* + * This function sends a single processed packet to firmware for + * transmission. + */ +static void +mwifiex_send_processed_packet(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int ptr_index, + unsigned long ra_list_flags) + __releases(&priv->wmm.ra_list_spinlock) +{ + struct mwifiex_tx_param tx_param; + struct mwifiex_adapter *adapter = priv->adapter; + int ret = -1; + struct sk_buff *skb, *skb_next; + struct mwifiex_txinfo *tx_info; + + if (skb_queue_empty(&ptr->skb_head)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + return; + } + + skb = skb_dequeue(&ptr->skb_head); + + if (!skb_queue_empty(&ptr->skb_head)) + skb_next = skb_peek(&ptr->skb_head); + else + skb_next = NULL; + + 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->data, skb->len, &tx_param); + switch (ret) { + case -EBUSY: + dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + + if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + mwifiex_write_data_complete(adapter, skb, -1); + return; + } + + skb_queue_tail(&ptr->skb_head, skb); + + tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + break; + case -1: + adapter->data_sent = false; + dev_err(adapter->dev, "host_to_card failed: %#x\n", ret); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb, ret); + break; + case -EINPROGRESS: + adapter->data_sent = false; + default: + break; + } + if (ret != -EBUSY) { + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + priv->wmm.packets_out[ptr_index]++; + priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr; + } + adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = + list_first_entry( + &adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_cur->list, + struct mwifiex_bss_prio_node, + list); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + } +} + +/* + * This function dequeues a packet from the highest priority list + * and transmits it. + */ +static int +mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) +{ + struct mwifiex_ra_list_tbl *ptr; + struct mwifiex_private *priv = NULL; + int ptr_index = 0; + u8 ra[ETH_ALEN]; + int tid_del = 0, tid = 0; + unsigned long flags; + + ptr = mwifiex_wmm_get_highest_priolist_ptr(adapter, &priv, &ptr_index); + if (!ptr) + return -1; + + tid = mwifiex_get_tid(ptr); + + dev_dbg(adapter->dev, "data: tid=%d\n", tid); + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); + return -1; + } + + if (mwifiex_is_ptr_processed(priv, ptr)) { + mwifiex_send_processed_packet(priv, ptr, ptr_index, flags); + /* ra_list_spinlock has been freed in + mwifiex_send_processed_packet() */ + return 0; + } + + if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid) + || ((priv->sec_info.wpa_enabled + || priv->sec_info.wpa2_enabled) && !priv->wpa_is_gtk_set) + ) { + mwifiex_send_single_packet(priv, ptr, ptr_index, flags); + /* ra_list_spinlock has been freed in + mwifiex_send_single_packet() */ + } else { + if (mwifiex_is_ampdu_allowed(priv, tid)) { + if (mwifiex_space_avail_for_new_ba_stream(adapter)) { + mwifiex_11n_create_tx_ba_stream_tbl(priv, + ptr->ra, tid, + BA_STREAM_SETUP_INPROGRESS); + mwifiex_send_addba(priv, tid, ptr->ra); + } else if (mwifiex_find_stream_to_delete + (priv, tid, &tid_del, ra)) { + mwifiex_11n_create_tx_ba_stream_tbl(priv, + ptr->ra, tid, + BA_STREAM_SETUP_INPROGRESS); + mwifiex_send_delba(priv, tid_del, ra, 1); + } + } +/* Minimum number of AMSDU */ +#define MIN_NUM_AMSDU 2 + if (mwifiex_is_amsdu_allowed(priv, tid) && + (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >= + MIN_NUM_AMSDU)) + mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, + ptr_index, flags); + /* ra_list_spinlock has been freed in + mwifiex_11n_aggregate_pkt() */ + else + mwifiex_send_single_packet(priv, ptr, ptr_index, flags); + /* ra_list_spinlock has been freed in + mwifiex_send_single_packet() */ + } + return 0; +} + +/* + * This function transmits the highest priority packet awaiting in the + * WMM Queues. + */ +void +mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter) +{ + do { + /* Check if busy */ + if (adapter->data_sent || adapter->tx_lock_flag) + break; + + if (mwifiex_dequeue_tx_packet(adapter)) + break; + } while (true); +} diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h new file mode 100644 index 000000000000..fcea1f68792f --- /dev/null +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -0,0 +1,110 @@ +/* + * Marvell Wireless LAN device driver: WMM + * + * Copyright (C) 2011, 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_WMM_H_ +#define _MWIFIEX_WMM_H_ + +enum ieee_types_wmm_aciaifsn_bitmasks { + MWIFIEX_AIFSN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)), + MWIFIEX_ACM = BIT(4), + MWIFIEX_ACI = (BIT(5) | BIT(6)), +}; + +enum ieee_types_wmm_ecw_bitmasks { + MWIFIEX_ECW_MIN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)), + MWIFIEX_ECW_MAX = (BIT(4) | BIT(5) | BIT(6) | BIT(7)), +}; + +/* + * This function retrieves the TID of the given RA list. + */ +static inline int +mwifiex_get_tid(struct mwifiex_ra_list_tbl *ptr) +{ + struct sk_buff *skb; + + if (skb_queue_empty(&ptr->skb_head)) + return 0; + + skb = skb_peek(&ptr->skb_head); + + return skb->priority; +} + +/* + * This function gets the length of a list. + */ +static inline int +mwifiex_wmm_list_len(struct list_head *head) +{ + struct list_head *pos; + int count = 0; + + list_for_each(pos, head) + ++count; + + return count; +} + +/* + * This function checks if a RA list is empty or not. + */ +static inline u8 +mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead) +{ + struct mwifiex_ra_list_tbl *ra_list; + int is_list_empty; + + list_for_each_entry(ra_list, ra_list_hhead, list) { + is_list_empty = skb_queue_empty(&ra_list->skb_head); + if (!is_list_empty) + return false; + } + + return true; +} + +void mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, + struct sk_buff *skb); +void mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra); + +int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter); +void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter); +int mwifiex_is_ralist_valid(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ra_list, int tid); + +u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, + const struct sk_buff *skb); +void mwifiex_wmm_init(struct mwifiex_adapter *adapter); + +extern u32 mwifiex_wmm_process_association_req(struct mwifiex_private *priv, + u8 **assoc_buf, + struct ieee_types_wmm_parameter + *wmmie, + struct ieee80211_ht_cap + *htcap); + +void mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, + struct ieee_types_wmm_parameter + *wmm_ie); +void mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv); +extern int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, + const struct host_cmd_ds_command *resp); + +#endif /* !_MWIFIEX_WMM_H_ */ diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 36952274950e..32261189bcef 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -63,6 +63,7 @@ MODULE_PARM_DESC(ap_mode_default, #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c #define MWL8K_A2H_INT_DUMMY (1 << 20) +#define MWL8K_A2H_INT_BA_WATCHDOG (1 << 14) #define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) #define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) #define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) @@ -73,6 +74,14 @@ MODULE_PARM_DESC(ap_mode_default, #define MWL8K_A2H_INT_RX_READY (1 << 1) #define MWL8K_A2H_INT_TX_DONE (1 << 0) +/* HW micro second timer register + * located at offset 0xA600. This + * will be used to timestamp tx + * packets. + */ + +#define MWL8K_HW_TIMER_REGISTER 0x0000a600 + #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ MWL8K_A2H_INT_CHNL_SWITCHED | \ MWL8K_A2H_INT_QUEUE_EMPTY | \ @@ -82,10 +91,14 @@ MODULE_PARM_DESC(ap_mode_default, MWL8K_A2H_INT_MAC_EVENT | \ MWL8K_A2H_INT_OPC_DONE | \ MWL8K_A2H_INT_RX_READY | \ - MWL8K_A2H_INT_TX_DONE) + MWL8K_A2H_INT_TX_DONE | \ + MWL8K_A2H_INT_BA_WATCHDOG) #define MWL8K_RX_QUEUES 1 -#define MWL8K_TX_QUEUES 4 +#define MWL8K_TX_WMM_QUEUES 4 +#define MWL8K_MAX_AMPDU_QUEUES 8 +#define MWL8K_MAX_TX_QUEUES (MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES) +#define mwl8k_tx_queues(priv) (MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues) struct rxd_ops { int rxd_size; @@ -134,9 +147,25 @@ struct mwl8k_tx_queue { struct sk_buff **skb; }; +enum { + AMPDU_NO_STREAM, + AMPDU_STREAM_NEW, + AMPDU_STREAM_IN_PROGRESS, + AMPDU_STREAM_ACTIVE, +}; + +struct mwl8k_ampdu_stream { + struct ieee80211_sta *sta; + u8 tid; + u8 state; + u8 idx; + u8 txq_idx; /* index of this stream in priv->txq */ +}; + struct mwl8k_priv { struct ieee80211_hw *hw; struct pci_dev *pdev; + int irq; struct mwl8k_device_info *device_info; @@ -159,6 +188,12 @@ struct mwl8k_priv { u32 ap_macids_supported; u32 sta_macids_supported; + /* Ampdu stream information */ + u8 num_ampdu_queues; + spinlock_t stream_lock; + struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES]; + struct work_struct watchdog_ba_handle; + /* firmware access */ struct mutex fw_mutex; struct task_struct *fw_mutex_owner; @@ -190,7 +225,8 @@ struct mwl8k_priv { int pending_tx_pkts; struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; - struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; + struct mwl8k_tx_queue txq[MWL8K_MAX_TX_QUEUES]; + u32 txq_offset[MWL8K_MAX_TX_QUEUES]; bool radio_on; bool radio_short_preamble; @@ -223,7 +259,7 @@ struct mwl8k_priv { * preserve the queue configurations so they can be restored if/when * the firmware image is swapped. */ - struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES]; + struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_WMM_QUEUES]; /* async firmware loading state */ unsigned fw_state; @@ -261,9 +297,17 @@ struct mwl8k_vif { #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) #define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) +struct tx_traffic_info { + u32 start_time; + u32 pkts; +}; + +#define MWL8K_MAX_TID 8 struct mwl8k_sta { /* Index into station database. Returned by UPDATE_STADB. */ u8 peer_id; + u8 is_ampdu_allowed; + struct tx_traffic_info tx_stats[MWL8K_MAX_TID]; }; #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) @@ -351,10 +395,12 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 #define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 +#define MWL8K_CMD_GET_WATCHDOG_BITMAP 0x0205 #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ #define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ #define MWL8K_CMD_UPDATE_STADB 0x1123 +#define MWL8K_CMD_BASTREAM 0x1125 static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) { @@ -394,6 +440,8 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(SET_NEW_STN); MWL8K_CMDNAME(UPDATE_ENCRYPTION); MWL8K_CMDNAME(UPDATE_STADB); + MWL8K_CMDNAME(BASTREAM); + MWL8K_CMDNAME(GET_WATCHDOG_BITMAP); default: snprintf(buf, bufsize, "0x%x", cmd); } @@ -668,7 +716,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) "helper image\n", pci_name(priv->pdev)); return rc; } - msleep(5); + msleep(20); rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); } else { @@ -733,8 +781,11 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos) skb_pull(skb, sizeof(*tr) - hdrlen); } +#define REDUCED_TX_HEADROOM 8 + static void -mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) +mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, + int head_pad, int tail_pad) { struct ieee80211_hdr *wh; int hdrlen; @@ -750,7 +801,23 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) wh = (struct ieee80211_hdr *)skb->data; hdrlen = ieee80211_hdrlen(wh->frame_control); - reqd_hdrlen = sizeof(*tr); + + /* + * Check if skb_resize is required because of + * tx_headroom adjustment. + */ + if (priv->ap_fw && (hdrlen < (sizeof(struct ieee80211_cts) + + REDUCED_TX_HEADROOM))) { + if (pskb_expand_head(skb, REDUCED_TX_HEADROOM, 0, GFP_ATOMIC)) { + + wiphy_err(priv->hw->wiphy, + "Failed to reallocate TX buffer\n"); + return; + } + skb->truesize += REDUCED_TX_HEADROOM; + } + + reqd_hdrlen = sizeof(*tr) + head_pad; if (hdrlen != reqd_hdrlen) skb_push(skb, reqd_hdrlen - hdrlen); @@ -772,12 +839,14 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); } -static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) +static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, + struct sk_buff *skb) { struct ieee80211_hdr *wh; struct ieee80211_tx_info *tx_info; struct ieee80211_key_conf *key_conf; int data_pad; + int head_pad = 0; wh = (struct ieee80211_hdr *)skb->data; @@ -789,9 +858,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) /* * Make sure the packet header is in the DMA header format (4-address - * without QoS), the necessary crypto padding between the header and the - * payload has already been provided by mac80211, but it doesn't add tail - * padding when HW crypto is enabled. + * without QoS), and add head & tail padding when HW crypto is enabled. * * We have the following trailer padding requirements: * - WEP: 4 trailer bytes (ICV) @@ -800,6 +867,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) */ data_pad = 0; if (key_conf != NULL) { + head_pad = key_conf->iv_len; switch (key_conf->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: @@ -813,7 +881,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) break; } } - mwl8k_add_dma_header(skb, data_pad); + mwl8k_add_dma_header(priv, skb, head_pad, data_pad); } /* @@ -1126,6 +1194,9 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) struct mwl8k_rx_queue *rxq = priv->rxq + index; int i; + if (rxq->rxd == NULL) + return; + for (i = 0; i < MWL8K_RX_DESCS; i++) { if (rxq->buf[i].skb != NULL) { pci_unmap_single(priv->pdev, @@ -1318,7 +1389,7 @@ struct mwl8k_tx_desc { __le16 pkt_len; __u8 dest_MAC_addr[ETH_ALEN]; __le32 next_txd_phys_addr; - __le32 reserved; + __le32 timestamp; __le16 rate_info; __u8 peer_id; __u8 tx_frag_cnt; @@ -1382,7 +1453,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) struct mwl8k_priv *priv = hw->priv; int i; - for (i = 0; i < MWL8K_TX_QUEUES; i++) { + for (i = 0; i < mwl8k_tx_queues(priv); i++) { struct mwl8k_tx_queue *txq = priv->txq + i; int fw_owned = 0; int drv_owned = 0; @@ -1451,9 +1522,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) if (timeout) { WARN_ON(priv->pending_tx_pkts); - if (retry) { + if (retry) wiphy_notice(hw->wiphy, "tx rings drained\n"); - } break; } @@ -1483,6 +1553,41 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) MWL8K_TXD_STATUS_OK_RETRY | \ MWL8K_TXD_STATUS_OK_MORE_RETRY)) +static int mwl8k_tid_queue_mapping(u8 tid) +{ + BUG_ON(tid > 7); + + switch (tid) { + case 0: + case 3: + return IEEE80211_AC_BE; + break; + case 1: + case 2: + return IEEE80211_AC_BK; + break; + case 4: + case 5: + return IEEE80211_AC_VI; + break; + case 6: + case 7: + return IEEE80211_AC_VO; + break; + default: + return -1; + break; + } +} + +/* The firmware will fill in the rate information + * for each packet that gets queued in the hardware + * and these macros will interpret that info. + */ + +#define RI_FORMAT(a) (a & 0x0001) +#define RI_RATE_ID_MCS(a) ((a & 0x01f8) >> 3) + static int mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) { @@ -1499,6 +1604,10 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) struct sk_buff *skb; struct ieee80211_tx_info *info; u32 status; + struct ieee80211_sta *sta; + struct mwl8k_sta *sta_info = NULL; + u16 rate_info; + struct ieee80211_hdr *wh; tx = txq->head; tx_desc = txq->txd + tx; @@ -1527,18 +1636,40 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) mwl8k_remove_dma_header(skb, tx_desc->qos_control); + wh = (struct ieee80211_hdr *) skb->data; + /* Mark descriptor as unused */ tx_desc->pkt_phys_addr = 0; tx_desc->pkt_len = 0; info = IEEE80211_SKB_CB(skb); + if (ieee80211_is_data(wh->frame_control)) { + sta = info->control.sta; + if (sta) { + sta_info = MWL8K_STA(sta); + BUG_ON(sta_info == NULL); + rate_info = le16_to_cpu(tx_desc->rate_info); + /* If rate is < 6.5 Mpbs for an ht station + * do not form an ampdu. If the station is a + * legacy station (format = 0), do not form an + * ampdu + */ + if (RI_RATE_ID_MCS(rate_info) < 1 || + RI_FORMAT(rate_info) == 0) { + sta_info->is_ampdu_allowed = false; + } else { + sta_info->is_ampdu_allowed = true; + } + } + } + ieee80211_tx_info_clear_status(info); /* Rate control is happening in the firmware. * Ensure no tx rate is being reported. */ - info->status.rates[0].idx = -1; - info->status.rates[0].count = 1; + info->status.rates[0].idx = -1; + info->status.rates[0].count = 1; if (MWL8K_TXD_SUCCESS(status)) info->flags |= IEEE80211_TX_STAT_ACK; @@ -1548,9 +1679,6 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) processed++; } - if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) - ieee80211_wake_queue(hw, index); - return processed; } @@ -1560,6 +1688,9 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) struct mwl8k_priv *priv = hw->priv; struct mwl8k_tx_queue *txq = priv->txq + index; + if (txq->txd == NULL) + return; + mwl8k_txq_reclaim(hw, index, INT_MAX, 1); kfree(txq->skb); @@ -1571,12 +1702,116 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) txq->txd = NULL; } +/* caller must hold priv->stream_lock when calling the stream functions */ +static struct mwl8k_ampdu_stream * +mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) +{ + struct mwl8k_ampdu_stream *stream; + struct mwl8k_priv *priv = hw->priv; + int i; + + for (i = 0; i < priv->num_ampdu_queues; i++) { + stream = &priv->ampdu[i]; + if (stream->state == AMPDU_NO_STREAM) { + stream->sta = sta; + stream->state = AMPDU_STREAM_NEW; + stream->tid = tid; + stream->idx = i; + stream->txq_idx = MWL8K_TX_WMM_QUEUES + i; + wiphy_debug(hw->wiphy, "Added a new stream for %pM %d", + sta->addr, tid); + return stream; + } + } + return NULL; +} + +static int +mwl8k_start_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) +{ + int ret; + + /* if the stream has already been started, don't start it again */ + if (stream->state != AMPDU_STREAM_NEW) + return 0; + ret = ieee80211_start_tx_ba_session(stream->sta, stream->tid, 0); + if (ret) + wiphy_debug(hw->wiphy, "Failed to start stream for %pM %d: " + "%d\n", stream->sta->addr, stream->tid, ret); + else + wiphy_debug(hw->wiphy, "Started stream for %pM %d\n", + stream->sta->addr, stream->tid); + return ret; +} + +static void +mwl8k_remove_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) +{ + wiphy_debug(hw->wiphy, "Remove stream for %pM %d\n", stream->sta->addr, + stream->tid); + memset(stream, 0, sizeof(*stream)); +} + +static struct mwl8k_ampdu_stream * +mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid) +{ + struct mwl8k_priv *priv = hw->priv; + int i; + + for (i = 0 ; i < priv->num_ampdu_queues; i++) { + struct mwl8k_ampdu_stream *stream; + stream = &priv->ampdu[i]; + if (stream->state == AMPDU_NO_STREAM) + continue; + if (!memcmp(stream->sta->addr, addr, ETH_ALEN) && + stream->tid == tid) + return stream; + } + return NULL; +} + +#define MWL8K_AMPDU_PACKET_THRESHOLD 64 +static inline bool mwl8k_ampdu_allowed(struct ieee80211_sta *sta, u8 tid) +{ + struct mwl8k_sta *sta_info = MWL8K_STA(sta); + struct tx_traffic_info *tx_stats; + + BUG_ON(tid >= MWL8K_MAX_TID); + tx_stats = &sta_info->tx_stats[tid]; + + return sta_info->is_ampdu_allowed && + tx_stats->pkts > MWL8K_AMPDU_PACKET_THRESHOLD; +} + +static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid) +{ + struct mwl8k_sta *sta_info = MWL8K_STA(sta); + struct tx_traffic_info *tx_stats; + + BUG_ON(tid >= MWL8K_MAX_TID); + tx_stats = &sta_info->tx_stats[tid]; + + if (tx_stats->start_time == 0) + tx_stats->start_time = jiffies; + + /* reset the packet count after each second elapses. If the number of + * packets ever exceeds the ampdu_min_traffic threshold, we will allow + * an ampdu stream to be started. + */ + if (jiffies - tx_stats->start_time > HZ) { + tx_stats->pkts = 0; + tx_stats->start_time = 0; + } else + tx_stats->pkts++; +} + static void mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) { struct mwl8k_priv *priv = hw->priv; struct ieee80211_tx_info *tx_info; struct mwl8k_vif *mwl8k_vif; + struct ieee80211_sta *sta; struct ieee80211_hdr *wh; struct mwl8k_tx_queue *txq; struct mwl8k_tx_desc *tx; @@ -1584,6 +1819,12 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) u32 txstatus; u8 txdatarate; u16 qos; + int txpriority; + u8 tid = 0; + struct mwl8k_ampdu_stream *stream = NULL; + bool start_ba_session = false; + bool mgmtframe = false; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; wh = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_data_qos(wh->frame_control)) @@ -1591,14 +1832,18 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) else qos = 0; + if (ieee80211_is_mgmt(wh->frame_control)) + mgmtframe = true; + if (priv->ap_fw) - mwl8k_encapsulate_tx_frame(skb); + mwl8k_encapsulate_tx_frame(priv, skb); else - mwl8k_add_dma_header(skb, 0); + mwl8k_add_dma_header(priv, skb, 0, 0); wh = &((struct mwl8k_dma_data *)skb->data)->wh; tx_info = IEEE80211_SKB_CB(skb); + sta = tx_info->control.sta; mwl8k_vif = MWL8K_VIF(tx_info->control.vif); if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { @@ -1626,12 +1871,91 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) qos |= MWL8K_QOS_ACK_POLICY_NORMAL; } + /* Queue ADDBA request in the respective data queue. While setting up + * the ampdu stream, mac80211 queues further packets for that + * particular ra/tid pair. However, packets piled up in the hardware + * for that ra/tid pair will still go out. ADDBA request and the + * related data packets going out from different queues asynchronously + * will cause a shift in the receiver window which might result in + * ampdu packets getting dropped at the receiver after the stream has + * been setup. + */ + if (unlikely(ieee80211_is_action(wh->frame_control) && + mgmt->u.action.category == WLAN_CATEGORY_BACK && + mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ && + priv->ap_fw)) { + u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + index = mwl8k_tid_queue_mapping(tid); + } + + txpriority = index; + + if (ieee80211_is_data_qos(wh->frame_control) && + skb->protocol != cpu_to_be16(ETH_P_PAE) && + sta->ht_cap.ht_supported && priv->ap_fw) { + tid = qos & 0xf; + mwl8k_tx_count_packet(sta, tid); + spin_lock(&priv->stream_lock); + stream = mwl8k_lookup_stream(hw, sta->addr, tid); + if (stream != NULL) { + if (stream->state == AMPDU_STREAM_ACTIVE) { + txpriority = stream->txq_idx; + index = stream->txq_idx; + } else if (stream->state == AMPDU_STREAM_NEW) { + /* We get here if the driver sends us packets + * after we've initiated a stream, but before + * our ampdu_action routine has been called + * with IEEE80211_AMPDU_TX_START to get the SSN + * for the ADDBA request. So this packet can + * go out with no risk of sequence number + * mismatch. No special handling is required. + */ + } else { + /* Drop packets that would go out after the + * ADDBA request was sent but before the ADDBA + * response is received. If we don't do this, + * the recipient would probably receive it + * after the ADDBA request with SSN 0. This + * will cause the recipient's BA receive window + * to shift, which would cause the subsequent + * packets in the BA stream to be discarded. + * mac80211 queues our packets for us in this + * case, so this is really just a safety check. + */ + wiphy_warn(hw->wiphy, + "Cannot send packet while ADDBA " + "dialog is underway.\n"); + spin_unlock(&priv->stream_lock); + dev_kfree_skb(skb); + return; + } + } else { + /* Defer calling mwl8k_start_stream so that the current + * skb can go out before the ADDBA request. This + * prevents sequence number mismatch at the recepient + * as described above. + */ + if (mwl8k_ampdu_allowed(sta, tid)) { + stream = mwl8k_add_stream(hw, sta, tid); + if (stream != NULL) + start_ba_session = true; + } + } + spin_unlock(&priv->stream_lock); + } + dma = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(priv->pdev, dma)) { wiphy_debug(hw->wiphy, "failed to dma map skb, dropping TX frame.\n"); + if (start_ba_session) { + spin_lock(&priv->stream_lock); + mwl8k_remove_stream(hw, stream); + spin_unlock(&priv->stream_lock); + } dev_kfree_skb(skb); return; } @@ -1640,12 +1964,34 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) txq = priv->txq + index; + /* Mgmt frames that go out frequently are probe + * responses. Other mgmt frames got out relatively + * infrequently. Hence reserve 2 buffers so that + * other mgmt frames do not get dropped due to an + * already queued probe response in one of the + * reserved buffers. + */ + + if (txq->len >= MWL8K_TX_DESCS - 2) { + if (mgmtframe == false || + txq->len == MWL8K_TX_DESCS) { + if (start_ba_session) { + spin_lock(&priv->stream_lock); + mwl8k_remove_stream(hw, stream); + spin_unlock(&priv->stream_lock); + } + spin_unlock_bh(&priv->tx_lock); + dev_kfree_skb(skb); + return; + } + } + BUG_ON(txq->skb[txq->tail] != NULL); txq->skb[txq->tail] = skb; tx = txq->txd + txq->tail; tx->data_rate = txdatarate; - tx->tx_priority = index; + tx->tx_priority = txpriority; tx->qos_control = cpu_to_le16(qos); tx->pkt_phys_addr = cpu_to_le32(dma); tx->pkt_len = cpu_to_le16(skb->len); @@ -1654,6 +2000,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; else tx->peer_id = 0; + + if (priv->ap_fw) + tx->timestamp = cpu_to_le32(ioread32(priv->regs + + MWL8K_HW_TIMER_REGISTER)); + wmb(); tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); @@ -1664,12 +2015,17 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) if (txq->tail == MWL8K_TX_DESCS) txq->tail = 0; - if (txq->head == txq->tail) - ieee80211_stop_queue(hw, index); - mwl8k_tx_start(priv); spin_unlock_bh(&priv->tx_lock); + + /* Initiate the ampdu session here */ + if (start_ba_session) { + spin_lock(&priv->stream_lock); + if (mwl8k_start_stream(hw, stream)) + mwl8k_remove_stream(hw, stream); + spin_unlock(&priv->stream_lock); + } } @@ -1867,7 +2223,7 @@ struct mwl8k_cmd_get_hw_spec_sta { __u8 mcs_bitmap[16]; __le32 rx_queue_ptr; __le32 num_tx_queues; - __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; + __le32 tx_queue_ptrs[MWL8K_TX_WMM_QUEUES]; __le32 caps2; __le32 num_tx_desc_per_queue; __le32 total_rxd; @@ -1973,8 +2329,8 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); - cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); - for (i = 0; i < MWL8K_TX_QUEUES; i++) + cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); + for (i = 0; i < mwl8k_tx_queues(priv); i++) cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); @@ -2016,13 +2372,16 @@ struct mwl8k_cmd_get_hw_spec_ap { __le32 wcbbase2; __le32 wcbbase3; __le32 fw_api_version; + __le32 caps; + __le32 num_of_ampdu_queues; + __le32 wcbbase_ampdu[MWL8K_MAX_AMPDU_QUEUES]; } __packed; static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_get_hw_spec_ap *cmd; - int rc; + int rc, i; u32 api_version; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -2054,27 +2413,31 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; - mwl8k_setup_2ghz_band(hw); + mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); priv->ap_macids_supported = 0x000000ff; priv->sta_macids_supported = 0x00000000; - - off = le32_to_cpu(cmd->wcbbase0) & 0xffff; - iowrite32(priv->txq[0].txd_dma, priv->sram + off); - + priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); + if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { + wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" + " but we only support %d.\n", + priv->num_ampdu_queues, + MWL8K_MAX_AMPDU_QUEUES); + priv->num_ampdu_queues = MWL8K_MAX_AMPDU_QUEUES; + } off = le32_to_cpu(cmd->rxwrptr) & 0xffff; iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); off = le32_to_cpu(cmd->rxrdptr) & 0xffff; iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); - off = le32_to_cpu(cmd->wcbbase1) & 0xffff; - iowrite32(priv->txq[1].txd_dma, priv->sram + off); + priv->txq_offset[0] = le32_to_cpu(cmd->wcbbase0) & 0xffff; + priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff; + priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff; + priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff; - off = le32_to_cpu(cmd->wcbbase2) & 0xffff; - iowrite32(priv->txq[2].txd_dma, priv->sram + off); - - off = le32_to_cpu(cmd->wcbbase3) & 0xffff; - iowrite32(priv->txq[3].txd_dma, priv->sram + off); + for (i = 0; i < priv->num_ampdu_queues; i++) + priv->txq_offset[i + MWL8K_TX_WMM_QUEUES] = + le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff; } done: @@ -2097,12 +2460,20 @@ struct mwl8k_cmd_set_hw_spec { __le32 caps; __le32 rx_queue_ptr; __le32 num_tx_queues; - __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; + __le32 tx_queue_ptrs[MWL8K_MAX_TX_QUEUES]; __le32 flags; __le32 num_tx_desc_per_queue; __le32 total_rxd; } __packed; +/* If enabled, MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY will cause + * packets to expire 500 ms after the timestamp in the tx descriptor. That is, + * the packets that are queued for more than 500ms, will be dropped in the + * hardware. This helps minimizing the issues caused due to head-of-line + * blocking where a slow client can hog the bandwidth and affect traffic to a + * faster client. + */ +#define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400 #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 @@ -2123,7 +2494,7 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); - cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); + cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); /* * Mac80211 stack has Q0 as highest priority and Q3 as lowest in @@ -2131,14 +2502,15 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) * in that order. Map Q3 of mac80211 to Q0 of firmware so that the * priority is interpreted the right way in firmware. */ - for (i = 0; i < MWL8K_TX_QUEUES; i++) { - int j = MWL8K_TX_QUEUES - 1 - i; + for (i = 0; i < mwl8k_tx_queues(priv); i++) { + int j = mwl8k_tx_queues(priv) - 1 - i; cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma); } cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | - MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON); + MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON | + MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY); cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); @@ -2355,7 +2727,7 @@ struct mwl8k_cmd_tx_power { __le16 bw; __le16 sub_ch; __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; -} __attribute__((packed)); +} __packed; static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, struct ieee80211_conf *conf, @@ -3121,6 +3493,65 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) return rc; } +/* + * CMD_GET_WATCHDOG_BITMAP. + */ +struct mwl8k_cmd_get_watchdog_bitmap { + struct mwl8k_cmd_pkt header; + u8 bitmap; +} __packed; + +static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap) +{ + struct mwl8k_cmd_get_watchdog_bitmap *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_WATCHDOG_BITMAP); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + + rc = mwl8k_post_cmd(hw, &cmd->header); + if (!rc) + *bitmap = cmd->bitmap; + + kfree(cmd); + + return rc; +} + +#define INVALID_BA 0xAA +static void mwl8k_watchdog_ba_events(struct work_struct *work) +{ + int rc; + u8 bitmap = 0, stream_index; + struct mwl8k_ampdu_stream *streams; + struct mwl8k_priv *priv = + container_of(work, struct mwl8k_priv, watchdog_ba_handle); + + rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap); + if (rc) + return; + + if (bitmap == INVALID_BA) + return; + + /* the bitmap is the hw queue number. Map it to the ampdu queue. */ + stream_index = bitmap - MWL8K_TX_WMM_QUEUES; + + BUG_ON(stream_index >= priv->num_ampdu_queues); + + streams = &priv->ampdu[stream_index]; + + if (streams->state == AMPDU_STREAM_ACTIVE) + ieee80211_stop_tx_ba_session(streams->sta, streams->tid); + + return; +} + + /* * CMD_BSS_START. */ @@ -3149,6 +3580,152 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, return rc; } +/* + * CMD_BASTREAM. + */ + +/* + * UPSTREAM is tx direction + */ +#define BASTREAM_FLAG_DIRECTION_UPSTREAM 0x00 +#define BASTREAM_FLAG_IMMEDIATE_TYPE 0x01 + +enum ba_stream_action_type { + MWL8K_BA_CREATE, + MWL8K_BA_UPDATE, + MWL8K_BA_DESTROY, + MWL8K_BA_FLUSH, + MWL8K_BA_CHECK, +}; + + +struct mwl8k_create_ba_stream { + __le32 flags; + __le32 idle_thrs; + __le32 bar_thrs; + __le32 window_size; + u8 peer_mac_addr[6]; + u8 dialog_token; + u8 tid; + u8 queue_id; + u8 param_info; + __le32 ba_context; + u8 reset_seq_no_flag; + __le16 curr_seq_no; + u8 sta_src_mac_addr[6]; +} __packed; + +struct mwl8k_destroy_ba_stream { + __le32 flags; + __le32 ba_context; +} __packed; + +struct mwl8k_cmd_bastream { + struct mwl8k_cmd_pkt header; + __le32 action; + union { + struct mwl8k_create_ba_stream create_params; + struct mwl8k_destroy_ba_stream destroy_params; + }; +} __packed; + +static int +mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) +{ + struct mwl8k_cmd_bastream *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + + cmd->action = cpu_to_le32(MWL8K_BA_CHECK); + + cmd->create_params.queue_id = stream->idx; + memcpy(&cmd->create_params.peer_mac_addr[0], stream->sta->addr, + ETH_ALEN); + cmd->create_params.tid = stream->tid; + + cmd->create_params.flags = + cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) | + cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM); + + rc = mwl8k_post_cmd(hw, &cmd->header); + + kfree(cmd); + + return rc; +} + +static int +mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, + u8 buf_size) +{ + struct mwl8k_cmd_bastream *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + + cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + + cmd->action = cpu_to_le32(MWL8K_BA_CREATE); + + cmd->create_params.bar_thrs = cpu_to_le32((u32)buf_size); + cmd->create_params.window_size = cpu_to_le32((u32)buf_size); + cmd->create_params.queue_id = stream->idx; + + memcpy(cmd->create_params.peer_mac_addr, stream->sta->addr, ETH_ALEN); + cmd->create_params.tid = stream->tid; + cmd->create_params.curr_seq_no = cpu_to_le16(0); + cmd->create_params.reset_seq_no_flag = 1; + + cmd->create_params.param_info = + (stream->sta->ht_cap.ampdu_factor & + IEEE80211_HT_AMPDU_PARM_FACTOR) | + ((stream->sta->ht_cap.ampdu_density << 2) & + IEEE80211_HT_AMPDU_PARM_DENSITY); + + cmd->create_params.flags = + cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE | + BASTREAM_FLAG_DIRECTION_UPSTREAM); + + rc = mwl8k_post_cmd(hw, &cmd->header); + + wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n", + stream->sta->addr, stream->tid); + kfree(cmd); + + return rc; +} + +static void mwl8k_destroy_ba(struct ieee80211_hw *hw, + struct mwl8k_ampdu_stream *stream) +{ + struct mwl8k_cmd_bastream *cmd; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->action = cpu_to_le32(MWL8K_BA_DESTROY); + + cmd->destroy_params.ba_context = cpu_to_le32(stream->idx); + mwl8k_post_cmd(hw, &cmd->header); + + wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx); + + kfree(cmd); +} + /* * CMD_SET_NEW_STN. */ @@ -3273,7 +3850,7 @@ struct mwl8k_cmd_update_encryption { __u8 mac_addr[6]; __u8 encr_type; -} __attribute__((packed)); +} __packed; struct mwl8k_cmd_set_key { struct mwl8k_cmd_pkt header; @@ -3293,7 +3870,7 @@ struct mwl8k_cmd_set_key { __le16 tkip_tsc_low; __le32 tkip_tsc_high; __u8 mac_addr[6]; -} __attribute__((packed)); +} __packed; enum { MWL8K_ENCR_ENABLE, @@ -3421,7 +3998,7 @@ static int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw, mwl8k_vif->wep_key_conf[idx].enabled = 1; } - keymlen = 0; + keymlen = key->keylen; action = MWL8K_ENCR_SET_KEY; break; case WLAN_CIPHER_SUITE_TKIP: @@ -3495,7 +4072,6 @@ static int mwl8k_set_key(struct ieee80211_hw *hw, addr = sta->addr; if (cmd_param == SET_KEY) { - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key); if (rc) goto out; @@ -3670,6 +4246,11 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) tasklet_schedule(&priv->poll_rx_task); } + if (status & MWL8K_A2H_INT_BA_WATCHDOG) { + status &= ~MWL8K_A2H_INT_BA_WATCHDOG; + ieee80211_queue_work(hw, &priv->watchdog_ba_handle); + } + if (status) iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); @@ -3698,7 +4279,7 @@ static void mwl8k_tx_poll(unsigned long data) spin_lock_bh(&priv->tx_lock); - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) limit -= mwl8k_txq_reclaim(hw, i, limit, 0); if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { @@ -3761,9 +4342,11 @@ static int mwl8k_start(struct ieee80211_hw *hw) rc = request_irq(priv->pdev->irq, mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { + priv->irq = -1; wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); return -EIO; } + priv->irq = priv->pdev->irq; /* Enable TX reclaim and RX tasklets. */ tasklet_enable(&priv->poll_tx_task); @@ -3771,6 +4354,8 @@ static int mwl8k_start(struct ieee80211_hw *hw) /* Enable interrupts */ iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + iowrite32(MWL8K_A2H_EVENTS, + priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); rc = mwl8k_fw_lock(hw); if (!rc) { @@ -3800,6 +4385,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) if (rc) { iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); + priv->irq = -1; tasklet_disable(&priv->poll_tx_task); tasklet_disable(&priv->poll_rx_task); } @@ -3818,10 +4404,14 @@ static void mwl8k_stop(struct ieee80211_hw *hw) /* Disable interrupts */ iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - free_irq(priv->pdev->irq, hw); + if (priv->irq != -1) { + free_irq(priv->pdev->irq, hw); + priv->irq = -1; + } /* Stop finalize join worker */ cancel_work_sync(&priv->finalize_join_worker); + cancel_work_sync(&priv->watchdog_ba_handle); if (priv->beacon_skb != NULL) dev_kfree_skb(priv->beacon_skb); @@ -3830,7 +4420,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) tasklet_disable(&priv->poll_rx_task); /* Return all skbs to mac80211 */ - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_reclaim(hw, i, INT_MAX, 1); } @@ -3951,9 +4541,12 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) conf->power_level = 18; if (priv->ap_fw) { - rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); - if (rc) - goto out; + + if (conf->flags & IEEE80211_CONF_CHANGE_POWER) { + rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); + if (rc) + goto out; + } rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); if (rc) @@ -3980,7 +4573,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { struct mwl8k_priv *priv = hw->priv; - u32 ap_legacy_rates; + u32 ap_legacy_rates = 0; u8 ap_mcs_rates[16]; int rc; @@ -4305,6 +4898,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); if (ret >= 0) { MWL8K_STA(sta)->peer_id = ret; + if (sta->ht_cap.ht_supported) + MWL8K_STA(sta)->is_ampdu_allowed = true; ret = 0; } @@ -4328,14 +4923,14 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, rc = mwl8k_fw_lock(hw); if (!rc) { - BUG_ON(queue > MWL8K_TX_QUEUES - 1); + BUG_ON(queue > MWL8K_TX_WMM_QUEUES - 1); memcpy(&priv->wmm_params[queue], params, sizeof(*params)); if (!priv->wmm_enabled) rc = mwl8k_cmd_set_wmm_mode(hw, 1); if (!rc) { - int q = MWL8K_TX_QUEUES - 1 - queue; + int q = MWL8K_TX_WMM_QUEUES - 1 - queue; rc = mwl8k_cmd_set_edca_params(hw, q, params->cw_min, params->cw_max, @@ -4371,21 +4966,118 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, return 0; } +#define MAX_AMPDU_ATTEMPTS 5 + static int mwl8k_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 i, rc = 0; + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_ampdu_stream *stream; + u8 *addr = sta->addr; + + if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) + return -ENOTSUPP; + + spin_lock(&priv->stream_lock); + stream = mwl8k_lookup_stream(hw, addr, tid); + switch (action) { case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_STOP: - if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) - return -ENOTSUPP; - return 0; + break; + case IEEE80211_AMPDU_TX_START: + /* By the time we get here the hw queues may contain outgoing + * packets for this RA/TID that are not part of this BA + * session. The hw will assign sequence numbers to these + * packets as they go out. So if we query the hw for its next + * sequence number and use that for the SSN here, it may end up + * being wrong, which will lead to sequence number mismatch at + * the recipient. To avoid this, we reset the sequence number + * to O for the first MPDU in this BA stream. + */ + *ssn = 0; + if (stream == NULL) { + /* This means that somebody outside this driver called + * ieee80211_start_tx_ba_session. This is unexpected + * because we do our own rate control. Just warn and + * move on. + */ + wiphy_warn(hw->wiphy, "Unexpected call to %s. " + "Proceeding anyway.\n", __func__); + stream = mwl8k_add_stream(hw, sta, tid); + } + if (stream == NULL) { + wiphy_debug(hw->wiphy, "no free AMPDU streams\n"); + rc = -EBUSY; + break; + } + stream->state = AMPDU_STREAM_IN_PROGRESS; + + /* Release the lock before we do the time consuming stuff */ + spin_unlock(&priv->stream_lock); + for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) { + rc = mwl8k_check_ba(hw, stream); + + if (!rc) + break; + /* + * HW queues take time to be flushed, give them + * sufficient time + */ + + msleep(1000); + } + spin_lock(&priv->stream_lock); + if (rc) { + wiphy_err(hw->wiphy, "Stream for tid %d busy after %d" + " attempts\n", tid, MAX_AMPDU_ATTEMPTS); + mwl8k_remove_stream(hw, stream); + rc = -EBUSY; + break; + } + ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); + break; + case IEEE80211_AMPDU_TX_STOP: + if (stream == NULL) + break; + if (stream->state == AMPDU_STREAM_ACTIVE) { + spin_unlock(&priv->stream_lock); + mwl8k_destroy_ba(hw, stream); + spin_lock(&priv->stream_lock); + } + mwl8k_remove_stream(hw, stream); + ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + BUG_ON(stream == NULL); + BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS); + spin_unlock(&priv->stream_lock); + rc = mwl8k_create_ba(hw, stream, buf_size); + spin_lock(&priv->stream_lock); + if (!rc) + stream->state = AMPDU_STREAM_ACTIVE; + else { + spin_unlock(&priv->stream_lock); + mwl8k_destroy_ba(hw, stream); + spin_lock(&priv->stream_lock); + wiphy_debug(hw->wiphy, + "Failed adding stream for sta %pM tid %d\n", + addr, tid); + mwl8k_remove_stream(hw, stream); + } + break; + default: - return -ENOTSUPP; + rc = -ENOTSUPP; } + + spin_unlock(&priv->stream_lock); + return rc; } static const struct ieee80211_ops mwl8k_ops = { @@ -4434,7 +5126,7 @@ enum { MWL8366, }; -#define MWL8K_8366_AP_FW_API 1 +#define MWL8K_8366_AP_FW_API 2 #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) @@ -4600,6 +5292,23 @@ static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image, return rc; } +static int mwl8k_init_txqs(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + int rc = 0; + int i; + + for (i = 0; i < mwl8k_tx_queues(priv); i++) { + rc = mwl8k_txq_init(hw, i); + if (rc) + break; + if (priv->ap_fw) + iowrite32(priv->txq[i].txd_dma, + priv->sram + priv->txq_offset[i]); + } + return rc; +} + /* initialize hw after successfully loading a firmware image */ static int mwl8k_probe_hw(struct ieee80211_hw *hw) { @@ -4627,17 +5336,26 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) goto err_stop_firmware; rxq_refill(hw, 0, INT_MAX); - for (i = 0; i < MWL8K_TX_QUEUES; i++) { - rc = mwl8k_txq_init(hw, i); + /* For the sta firmware, we need to know the dma addresses of tx queues + * before sending MWL8K_CMD_GET_HW_SPEC. So we must initialize them + * prior to issuing this command. But for the AP case, we learn the + * total number of queues from the result CMD_GET_HW_SPEC, so for this + * case we must initialize the tx queues after. + */ + priv->num_ampdu_queues = 0; + if (!priv->ap_fw) { + rc = mwl8k_init_txqs(hw); if (rc) goto err_free_queues; } iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, + iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY| + MWL8K_A2H_INT_BA_WATCHDOG, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); - iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); + iowrite32(MWL8K_A2H_INT_OPC_DONE, + priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); rc = request_irq(priv->pdev->irq, mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); @@ -4646,6 +5364,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) goto err_free_queues; } + memset(priv->ampdu, 0, sizeof(priv->ampdu)); + /* * Temporarily enable interrupts. Initial firmware host * commands use interrupts and avoid polling. Disable @@ -4656,6 +5376,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) /* Get config data, mac addrs etc */ if (priv->ap_fw) { rc = mwl8k_cmd_get_hw_spec_ap(hw); + if (!rc) + rc = mwl8k_init_txqs(hw); if (!rc) rc = mwl8k_cmd_set_hw_spec(hw); } else { @@ -4698,7 +5420,7 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) free_irq(priv->pdev->irq, hw); err_free_queues: - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_deinit(hw, i); mwl8k_rxq_deinit(hw, 0); @@ -4720,7 +5442,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) mwl8k_stop(hw); mwl8k_rxq_deinit(hw, 0); - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_deinit(hw, i); rc = mwl8k_init_firmware(hw, fw_image, false); @@ -4739,7 +5461,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) if (rc) goto fail; - for (i = 0; i < MWL8K_TX_QUEUES; i++) { + for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); if (rc) goto fail; @@ -4771,9 +5493,11 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) hw->extra_tx_headroom = sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); + hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0; + hw->channel_change_time = 10; - hw->queues = MWL8K_TX_QUEUES; + hw->queues = MWL8K_TX_WMM_QUEUES; /* Set rssi values to dBm */ hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; @@ -4789,6 +5513,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) /* Finalize join worker */ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); + /* Handle watchdog ba events */ + INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events); /* TX reclaim and RX tasklets. */ tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); @@ -4808,6 +5534,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) spin_lock_init(&priv->tx_lock); + spin_lock_init(&priv->stream_lock); + priv->tx_wait = NULL; rc = mwl8k_probe_hw(hw); @@ -4829,7 +5557,7 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) return 0; err_unprobe_hw: - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_deinit(hw, i); mwl8k_rxq_deinit(hw, 0); @@ -4988,10 +5716,10 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) mwl8k_hw_reset(priv); /* Return all skbs to mac80211 */ - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_reclaim(hw, i, INT_MAX, 1); - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_deinit(hw, i); mwl8k_rxq_deinit(hw, 0); diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 13d750da9301..54cc0bba66b9 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -491,7 +491,7 @@ static int p54_parse_rssical(struct ieee80211_hw *dev, struct pda_rssi_cal_entry *cal = (void *) &data[offset]; for (i = 0; i < entries; i++) { - u16 freq; + u16 freq = 0; switch (i) { case IEEE80211_BAND_2GHZ: freq = 2437; diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 2fab7d20ffc2..b6a061cbbdec 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -727,3 +727,34 @@ int p54_fetch_statistics(struct p54_common *priv) p54_tx(priv, skb); return 0; } + +int p54_set_groupfilter(struct p54_common *priv) +{ + struct p54_group_address_table *grp; + struct sk_buff *skb; + bool on = false; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*grp), + P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + grp = (struct p54_group_address_table *)skb_put(skb, sizeof(*grp)); + + on = !(priv->filter_flags & FIF_ALLMULTI) && + (priv->mc_maclist_num > 0 && + priv->mc_maclist_num <= MC_FILTER_ADDRESS_NUM); + + if (on) { + grp->filter_enable = cpu_to_le16(1); + grp->num_address = cpu_to_le16(priv->mc_maclist_num); + memcpy(grp->mac_list, priv->mc_maclist, sizeof(grp->mac_list)); + } else { + grp->filter_enable = cpu_to_le16(0); + grp->num_address = cpu_to_le16(0); + memset(grp->mac_list, 0, sizeof(grp->mac_list)); + } + + p54_tx(priv, skb); + return 0; +} diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h index eb581abc1079..3d8d622bec55 100644 --- a/drivers/net/wireless/p54/lmac.h +++ b/drivers/net/wireless/p54/lmac.h @@ -540,6 +540,7 @@ int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set); int p54_setup_mac(struct p54_common *priv); int p54_set_ps(struct p54_common *priv); int p54_fetch_statistics(struct p54_common *priv); +int p54_set_groupfilter(struct p54_common *priv); /* e/v DCF setup */ int p54_set_edcf(struct p54_common *priv); diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index a946991989c6..a5a6d9e647bb 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -308,6 +308,31 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) return ret; } +static u64 p54_prepare_multicast(struct ieee80211_hw *dev, + struct netdev_hw_addr_list *mc_list) +{ + struct p54_common *priv = dev->priv; + struct netdev_hw_addr *ha; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(priv->mc_maclist) != + ARRAY_SIZE(((struct p54_group_address_table *)NULL)->mac_list)); + /* + * The first entry is reserved for the global broadcast MAC. + * Otherwise the firmware will drop it and ARP will no longer work. + */ + i = 1; + priv->mc_maclist_num = netdev_hw_addr_list_count(mc_list) + i; + netdev_hw_addr_list_for_each(ha, mc_list) { + memcpy(&priv->mc_maclist[i], ha->addr, ETH_ALEN); + i++; + if (i >= ARRAY_SIZE(priv->mc_maclist)) + break; + } + + return 1; /* update */ +} + static void p54_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, @@ -316,12 +341,16 @@ static void p54_configure_filter(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; *total_flags &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | FIF_OTHER_BSS; priv->filter_flags = *total_flags; if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) p54_setup_mac(priv); + + if (changed_flags & FIF_ALLMULTI || multicast) + p54_set_groupfilter(priv); } static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, @@ -591,6 +620,7 @@ static const struct ieee80211_ops p54_ops = { .config = p54_config, .flush = p54_flush, .bss_info_changed = p54_bss_info_changed, + .prepare_multicast = p54_prepare_multicast, .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, .get_stats = p54_get_stats, @@ -660,6 +690,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) init_completion(&priv->beacon_comp); INIT_DELAYED_WORK(&priv->work, p54_work); + memset(&priv->mc_maclist[0], ~0, ETH_ALEN); return dev; } EXPORT_SYMBOL_GPL(p54_init_common); diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 50730fc23fe5..799d05e12595 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -211,8 +211,10 @@ struct p54_common { /* BBP/MAC state */ u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; + u8 mc_maclist[4][ETH_ALEN]; u16 wakeup_timer; unsigned int filter_flags; + int mc_maclist_num; int mode; u32 tsf_low32, tsf_high32; u32 basic_rate_mask; diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 0494d7b102d4..1b753173680f 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -331,10 +331,9 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54p_ring_control *ring_control = priv->ring_control; struct p54p_desc *desc; dma_addr_t mapping; - u32 device_idx, idx, i; + u32 idx, i; spin_lock_irqsave(&priv->lock, flags); - device_idx = le32_to_cpu(ring_control->device_idx[1]); idx = le32_to_cpu(ring_control->host_idx[1]); i = idx % ARRAY_SIZE(ring_control->tx_data); diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 7834c26c2954..042842e704de 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -703,7 +703,7 @@ void p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_tx_info *p54info; struct p54_hdr *hdr; struct p54_tx_data *txhdr; - unsigned int padding, len, extra_len; + unsigned int padding, len, extra_len = 0; int i, j, ridx; u16 hdr_flags = 0, aid = 0; u8 rate, queue = 0, crypt_offset = 0; diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index f630552427b7..9def1e5369a1 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -59,7 +59,6 @@ config RT2800PCI select RT2800_LIB select RT2X00_LIB_PCI if PCI select RT2X00_LIB_SOC if RALINK_RT288X || RALINK_RT305X - select RT2X00_LIB_HT select RT2X00_LIB_FIRMWARE select RT2X00_LIB_CRYPTO select CRC_CCITT @@ -74,17 +73,13 @@ config RT2800PCI if RT2800PCI config RT2800PCI_RT33XX - bool "rt2800pci - Include support for rt33xx devices (EXPERIMENTAL)" - depends on EXPERIMENTAL - default n + bool "rt2800pci - Include support for rt33xx devices" + default y ---help--- This adds support for rt33xx wireless chipset family to the rt2800pci driver. Supported chips: RT3390 - Support for these devices is non-functional at the moment and is - intended for testers and developers. - config RT2800PCI_RT35XX bool "rt2800pci - Include support for rt35xx devices (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -98,17 +93,14 @@ config RT2800PCI_RT35XX intended for testers and developers. config RT2800PCI_RT53XX - bool "rt2800-pci - Include support for rt53xx devices (EXPERIMENTAL)" + bool "rt2800pci - Include support for rt53xx devices (EXPERIMENTAL)" depends on EXPERIMENTAL - default n + default y ---help--- This adds support for rt53xx wireless chipset family to the rt2800pci driver. Supported chips: RT5390 - Support for these devices is non-functional at the moment and is - intended for testers and developers. - endif config RT2500USB @@ -140,7 +132,6 @@ config RT2800USB depends on USB select RT2800_LIB select RT2X00_LIB_USB - select RT2X00_LIB_HT select RT2X00_LIB_FIRMWARE select RT2X00_LIB_CRYPTO select CRC_CCITT @@ -153,17 +144,13 @@ config RT2800USB if RT2800USB config RT2800USB_RT33XX - bool "rt2800usb - Include support for rt33xx devices (EXPERIMENTAL)" - depends on EXPERIMENTAL - default n + bool "rt2800usb - Include support for rt33xx devices" + default y ---help--- This adds support for rt33xx wireless chipset family to the rt2800usb driver. Supported chips: RT3370 - Support for these devices is non-functional at the moment and is - intended for testers and developers. - config RT2800USB_RT35XX bool "rt2800usb - Include support for rt35xx devices (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -176,6 +163,15 @@ config RT2800USB_RT35XX Support for these devices is non-functional at the moment and is intended for testers and developers. +config RT2800USB_RT53XX + bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)" + depends on EXPERIMENTAL + default y + ---help--- + This adds support for rt53xx wireless chipset family to the + rt2800pci driver. + Supported chips: RT5370 + config RT2800USB_UNKNOWN bool "rt2800usb - Include support for unknown (USB) devices" default n @@ -207,9 +203,6 @@ config RT2X00_LIB_USB config RT2X00_LIB tristate -config RT2X00_LIB_HT - boolean - config RT2X00_LIB_FIRMWARE boolean select FW_LOADER diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index 971339858297..349d5b8284a4 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -7,7 +7,6 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o -rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 329f3283697b..937f9e8bf05f 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1314,8 +1314,8 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, } } -static void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, - struct rt2x00_field32 irq_field) +static inline void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { u32 reg; @@ -1368,8 +1368,10 @@ static void rt2400pci_tbtt_tasklet(unsigned long data) static void rt2400pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - rt2x00pci_rxdone(rt2x00dev); - rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); + if (rt2x00pci_rxdone(rt2x00dev)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + else + rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); } static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) @@ -1534,13 +1536,13 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* * Check if the BBP tuning should be enabled. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING)) - __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); + __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); return 0; } @@ -1638,9 +1640,9 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires the atim queue and DMA-mapped skbs. */ - __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); + __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); /* * Set the rssi offset. @@ -1718,6 +1720,9 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .tx_last_beacon = rt2400pci_tx_last_beacon, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .set_antenna = rt2x00mac_set_antenna, + .get_antenna = rt2x00mac_get_antenna, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { @@ -1738,6 +1743,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .start_queue = rt2400pci_start_queue, .kick_queue = rt2400pci_kick_queue, .stop_queue = rt2400pci_stop_queue, + .flush_queue = rt2x00pci_flush_queue, .write_tx_desc = rt2400pci_write_tx_desc, .write_beacon = rt2400pci_write_beacon, .fill_rxdone = rt2400pci_fill_rxdone, @@ -1799,10 +1805,11 @@ static const struct rt2x00_ops rt2400pci_ops = { * RT2400pci module information. */ static DEFINE_PCI_DEVICE_TABLE(rt2400pci_device_table) = { - { PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) }, + { PCI_DEVICE(0x1814, 0x0101) }, { 0, } }; + MODULE_AUTHOR(DRV_PROJECT); MODULE_VERSION(DRV_VERSION); MODULE_DESCRIPTION("Ralink RT2400 PCI & PCMCIA Wireless LAN driver."); @@ -1810,10 +1817,16 @@ MODULE_SUPPORTED_DEVICE("Ralink RT2460 PCI & PCMCIA chipset based cards"); MODULE_DEVICE_TABLE(pci, rt2400pci_device_table); MODULE_LICENSE("GPL"); +static int rt2400pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id) +{ + return rt2x00pci_probe(pci_dev, &rt2400pci_ops); +} + static struct pci_driver rt2400pci_driver = { .name = KBUILD_MODNAME, .id_table = rt2400pci_device_table, - .probe = rt2x00pci_probe, + .probe = rt2400pci_probe, .remove = __devexit_p(rt2x00pci_remove), .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 58277878889e..d27d7b8ba3b6 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1446,8 +1446,8 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, } } -static void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, - struct rt2x00_field32 irq_field) +static inline void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { u32 reg; @@ -1500,8 +1500,10 @@ static void rt2500pci_tbtt_tasklet(unsigned long data) static void rt2500pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - rt2x00pci_rxdone(rt2x00dev); - rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); + if (rt2x00pci_rxdone(rt2x00dev)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + else + rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); } static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) @@ -1685,14 +1687,14 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* * Check if the BBP tuning should be enabled. */ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); if (!rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE)) - __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); + __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); /* * Read the RSSI <-> dBm offset information. @@ -1956,9 +1958,9 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires the atim queue and DMA-mapped skbs. */ - __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); + __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); /* * Set the rssi offset. @@ -2011,6 +2013,9 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .tx_last_beacon = rt2500pci_tx_last_beacon, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .set_antenna = rt2x00mac_set_antenna, + .get_antenna = rt2x00mac_get_antenna, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { @@ -2031,6 +2036,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .start_queue = rt2500pci_start_queue, .kick_queue = rt2500pci_kick_queue, .stop_queue = rt2500pci_stop_queue, + .flush_queue = rt2x00pci_flush_queue, .write_tx_desc = rt2500pci_write_tx_desc, .write_beacon = rt2500pci_write_beacon, .fill_rxdone = rt2500pci_fill_rxdone, @@ -2092,7 +2098,7 @@ static const struct rt2x00_ops rt2500pci_ops = { * RT2500pci module information. */ static DEFINE_PCI_DEVICE_TABLE(rt2500pci_device_table) = { - { PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) }, + { PCI_DEVICE(0x1814, 0x0201) }, { 0, } }; @@ -2103,10 +2109,16 @@ MODULE_SUPPORTED_DEVICE("Ralink RT2560 PCI & PCMCIA chipset based cards"); MODULE_DEVICE_TABLE(pci, rt2500pci_device_table); MODULE_LICENSE("GPL"); +static int rt2500pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id) +{ + return rt2x00pci_probe(pci_dev, &rt2500pci_ops); +} + static struct pci_driver rt2500pci_driver = { .name = KBUILD_MODNAME, .id_table = rt2500pci_device_table, - .probe = rt2x00pci_probe, + .probe = rt2500pci_probe, .remove = __devexit_p(rt2x00pci_remove), .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 979fe6596a2d..15237c275486 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1519,7 +1519,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* * Read the RSSI <-> dBm offset information. @@ -1790,14 +1790,14 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires the atim queue */ - __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); + __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags); if (!modparam_nohwcrypt) { - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_COPY_IV, &rt2x00dev->cap_flags); } - __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); + __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); /* * Set the rssi offset. @@ -1824,6 +1824,9 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .conf_tx = rt2x00mac_conf_tx, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .set_antenna = rt2x00mac_set_antenna, + .get_antenna = rt2x00mac_get_antenna, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { @@ -1905,58 +1908,54 @@ static const struct rt2x00_ops rt2500usb_ops = { */ static struct usb_device_id rt2500usb_device_table[] = { /* ASUS */ - { USB_DEVICE(0x0b05, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0b05, 0x1707), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0b05, 0x1706) }, + { USB_DEVICE(0x0b05, 0x1707) }, /* Belkin */ - { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x050d, 0x7050) }, + { USB_DEVICE(0x050d, 0x7051) }, /* Cisco Systems */ - { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) }, - /* CNet */ - { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x13b1, 0x000d) }, + { USB_DEVICE(0x13b1, 0x0011) }, + { USB_DEVICE(0x13b1, 0x001a) }, /* Conceptronic */ - { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c02) }, /* D-LINK */ - { USB_DEVICE(0x2001, 0x3c00), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x2001, 0x3c00) }, /* Gigabyte */ - { USB_DEVICE(0x1044, 0x8001), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x1044, 0x8007), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x1044, 0x8001) }, + { USB_DEVICE(0x1044, 0x8007) }, /* Hercules */ - { USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x06f8, 0xe000) }, /* Melco */ - { USB_DEVICE(0x0411, 0x005e), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0411, 0x005e) }, + { USB_DEVICE(0x0411, 0x0066) }, + { USB_DEVICE(0x0411, 0x0067) }, + { USB_DEVICE(0x0411, 0x008b) }, + { USB_DEVICE(0x0411, 0x0097) }, /* MSI */ - { USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0db0, 0x6869), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0db0, 0x6861) }, + { USB_DEVICE(0x0db0, 0x6865) }, + { USB_DEVICE(0x0db0, 0x6869) }, /* Ralink */ - { USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x148f, 0x1706) }, + { USB_DEVICE(0x148f, 0x2570) }, + { USB_DEVICE(0x148f, 0x9020) }, /* Sagem */ - { USB_DEVICE(0x079b, 0x004b), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x079b, 0x004b) }, /* Siemens */ - { USB_DEVICE(0x0681, 0x3c06), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0681, 0x3c06) }, /* SMC */ - { USB_DEVICE(0x0707, 0xee13), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0707, 0xee13) }, /* Spairon */ - { USB_DEVICE(0x114b, 0x0110), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x114b, 0x0110) }, /* SURECOM */ - { USB_DEVICE(0x0769, 0x11f3), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0769, 0x11f3) }, /* Trust */ - { USB_DEVICE(0x0eb0, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0eb0, 0x9020) }, /* VTech */ - { USB_DEVICE(0x0f88, 0x3012), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0f88, 0x3012) }, /* Zinwell */ - { USB_DEVICE(0x5a57, 0x0260), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x5a57, 0x0260) }, { 0, } }; @@ -1967,10 +1966,16 @@ MODULE_SUPPORTED_DEVICE("Ralink RT2570 USB chipset based cards"); MODULE_DEVICE_TABLE(usb, rt2500usb_device_table); MODULE_LICENSE("GPL"); +static int rt2500usb_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id) +{ + return rt2x00usb_probe(usb_intf, &rt2500usb_ops); +} + static struct usb_driver rt2500usb_driver = { .name = KBUILD_MODNAME, .id_table = rt2500usb_device_table, - .probe = rt2x00usb_probe, + .probe = rt2500usb_probe, .disconnect = rt2x00usb_disconnect, .suspend = rt2x00usb_suspend, .resume = rt2x00usb_resume, diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 8fbc5fa965e0..f67bc9b31b28 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -51,6 +51,7 @@ * RF3320 2.4G 1T1R(RT3350/RT3370/RT3390) * RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392) * RF3853 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662) + * RF5370 2.4G 1T1R * RF5390 2.4G 1T1R */ #define RF2820 0x0001 @@ -66,6 +67,7 @@ #define RF3320 0x000b #define RF3322 0x000c #define RF3853 0x000d +#define RF5370 0x5370 #define RF5390 0x5390 /* @@ -2103,6 +2105,59 @@ struct mac_iveiv_entry { #define EEPROM_TXPOWER_BG_1 FIELD16(0x00ff) #define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) +/* + * EEPROM temperature compensation boundaries 802.11BG + * MINUS4: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -4) + * MINUS3: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -3) + */ +#define EEPROM_TSSI_BOUND_BG1 0x0037 +#define EEPROM_TSSI_BOUND_BG1_MINUS4 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG1_MINUS3 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11BG + * MINUS2: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -2) + * MINUS1: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -1) + */ +#define EEPROM_TSSI_BOUND_BG2 0x0038 +#define EEPROM_TSSI_BOUND_BG2_MINUS2 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG2_MINUS1 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11BG + * REF: Reference TSSI value, no tx power changes needed + * PLUS1: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 1) + */ +#define EEPROM_TSSI_BOUND_BG3 0x0039 +#define EEPROM_TSSI_BOUND_BG3_REF FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG3_PLUS1 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11BG + * PLUS2: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 2) + * PLUS3: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 3) + */ +#define EEPROM_TSSI_BOUND_BG4 0x003a +#define EEPROM_TSSI_BOUND_BG4_PLUS2 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG4_PLUS3 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11BG + * PLUS4: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 4) + * AGC_STEP: Temperature compensation step. + */ +#define EEPROM_TSSI_BOUND_BG5 0x003b +#define EEPROM_TSSI_BOUND_BG5_PLUS4 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG5_AGC_STEP FIELD16(0xff00) + /* * EEPROM TXPOWER 802.11A */ @@ -2112,6 +2167,59 @@ struct mac_iveiv_entry { #define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) #define EEPROM_TXPOWER_A_2 FIELD16(0xff00) +/* + * EEPROM temperature compensation boundaries 802.11A + * MINUS4: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -4) + * MINUS3: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -3) + */ +#define EEPROM_TSSI_BOUND_A1 0x006a +#define EEPROM_TSSI_BOUND_A1_MINUS4 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A1_MINUS3 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11A + * MINUS2: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -2) + * MINUS1: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -1) + */ +#define EEPROM_TSSI_BOUND_A2 0x006b +#define EEPROM_TSSI_BOUND_A2_MINUS2 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A2_MINUS1 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11A + * REF: Reference TSSI value, no tx power changes needed + * PLUS1: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 1) + */ +#define EEPROM_TSSI_BOUND_A3 0x006c +#define EEPROM_TSSI_BOUND_A3_REF FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A3_PLUS1 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11A + * PLUS2: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 2) + * PLUS3: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 3) + */ +#define EEPROM_TSSI_BOUND_A4 0x006d +#define EEPROM_TSSI_BOUND_A4_PLUS2 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A4_PLUS3 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11A + * PLUS4: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 4) + * AGC_STEP: Temperature compensation step. + */ +#define EEPROM_TSSI_BOUND_A5 0x006e +#define EEPROM_TSSI_BOUND_A5_PLUS4 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A5_AGC_STEP FIELD16(0xff00) + /* * EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode */ diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index dbf74d07d947..2a6aa85cc6c9 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -687,6 +687,9 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status) mcs = real_mcs; } + if (aggr == 1 || ampdu == 1) + __set_bit(TXDONE_AMPDU, &txdesc.flags); + /* * Ralink has a retry mechanism using a global fallback * table. We setup this fallback table to try the immediate @@ -727,34 +730,20 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; struct queue_entry *entry; u32 reg; - u8 pid; - int i; + u8 qid; - /* - * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO - * at most X times and also stop processing once the TX_STA_FIFO_VALID - * flag is not set anymore. - * - * The legacy drivers use X=TX_RING_SIZE but state in a comment - * that the TX_STA_FIFO stack has a size of 16. We stick to our - * tx ring size for now. - */ - for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) { - rt2800_register_read(rt2x00dev, TX_STA_FIFO, ®); - if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID)) - break; + while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { - /* - * Skip this entry when it contains an invalid - * queue identication number. + /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus + * qid is guaranteed to be one of the TX QIDs */ - pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); - if (pid >= QID_RX) - continue; - - queue = rt2x00queue_get_tx_queue(rt2x00dev, pid); - if (unlikely(!queue)) + qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); + queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); + if (unlikely(!queue)) { + WARNING(rt2x00dev, "Got TX status for an unavailable " + "queue %u, dropping\n", qid); continue; + } /* * Inside each queue, we process each entry in a chronological @@ -946,25 +935,49 @@ static void rt2800_brightness_set(struct led_classdev *led_cdev, unsigned int ledmode = rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, EEPROM_FREQ_LED_MODE); + u32 reg; - if (led->type == LED_TYPE_RADIO) { - rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, - enabled ? 0x20 : 0); - } else if (led->type == LED_TYPE_ASSOC) { - rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, - enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); - } else if (led->type == LED_TYPE_QUALITY) { - /* - * The brightness is divided into 6 levels (0 - 5), - * The specs tell us the following levels: - * 0, 1 ,3, 7, 15, 31 - * to determine the level in a simple way we can simply - * work with bitshifting: - * (1 << level) - 1 - */ - rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, - (1 << brightness / (LED_FULL / 6)) - 1, - polarity); + /* Check for SoC (SOC devices don't support MCU requests) */ + if (rt2x00_is_soc(led->rt2x00dev)) { + rt2800_register_read(led->rt2x00dev, LED_CFG, ®); + + /* Set LED Polarity */ + rt2x00_set_field32(®, LED_CFG_LED_POLAR, polarity); + + /* Set LED Mode */ + if (led->type == LED_TYPE_RADIO) { + rt2x00_set_field32(®, LED_CFG_G_LED_MODE, + enabled ? 3 : 0); + } else if (led->type == LED_TYPE_ASSOC) { + rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, + enabled ? 3 : 0); + } else if (led->type == LED_TYPE_QUALITY) { + rt2x00_set_field32(®, LED_CFG_R_LED_MODE, + enabled ? 3 : 0); + } + + rt2800_register_write(led->rt2x00dev, LED_CFG, reg); + + } else { + if (led->type == LED_TYPE_RADIO) { + rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + enabled ? 0x20 : 0); + } else if (led->type == LED_TYPE_ASSOC) { + rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); + } else if (led->type == LED_TYPE_QUALITY) { + /* + * The brightness is divided into 6 levels (0 - 5), + * The specs tell us the following levels: + * 0, 1 ,3, 7, 15, 31 + * to determine the level in a simple way we can simply + * work with bitshifting: + * (1 << level) - 1 + */ + rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, + (1 << brightness / (LED_FULL / 6)) - 1, + polarity); + } } } @@ -1218,6 +1231,25 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + + if (conf->sync == TSF_SYNC_AP_NONE) { + /* + * Tune beacon queue transmit parameters for AP mode + */ + rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, ®); + rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 0); + rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 1); + rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32); + rt2x00_set_field32(®, TBTT_SYNC_CFG_TBTT_ADJUST, 0); + rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg); + } else { + rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, ®); + rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 4); + rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 2); + rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32); + rt2x00_set_field32(®, TBTT_SYNC_CFG_TBTT_ADJUST, 16); + rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg); + } } if (flags & CONFIG_UPDATE_MAC) { @@ -1608,7 +1640,6 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, struct channel_info *info) { u8 rfcsr; - u16 eeprom; rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); @@ -1638,11 +1669,10 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); if (rf->channel <= 14) { int idx = rf->channel-1; - if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) { + if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) { /* r55/r59 value array of channel 1~14 */ static const char r55_bt_rev[] = {0x83, 0x83, @@ -1721,7 +1751,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_rf(rt2x00dev, RF3052) || rt2x00_rf(rt2x00dev, RF3320)) rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info); - else if (rt2x00_rf(rt2x00dev, RF5390)) + else if (rt2x00_rf(rt2x00dev, RF5370) || + rt2x00_rf(rt2x00dev, RF5390)) rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info); else rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info); @@ -1736,8 +1767,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, if (rf->channel <= 14) { if (!rt2x00_rt(rt2x00dev, RT5390)) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, - &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, + &rt2x00dev->cap_flags)) { rt2800_bbp_write(rt2x00dev, 82, 0x62); rt2800_bbp_write(rt2x00dev, 75, 0x46); } else { @@ -1748,7 +1779,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, } else { rt2800_bbp_write(rt2x00dev, 82, 0xf2); - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) rt2800_bbp_write(rt2x00dev, 75, 0x46); else rt2800_bbp_write(rt2x00dev, 75, 0x50); @@ -1813,17 +1844,131 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, ®); } +static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) +{ + u8 tssi_bounds[9]; + u8 current_tssi; + u16 eeprom; + u8 step; + int i; + + /* + * Read TSSI boundaries for temperature compensation from + * the EEPROM. + * + * Array idx 0 1 2 3 4 5 6 7 8 + * Matching Delta value -4 -3 -2 -1 0 +1 +2 +3 +4 + * Example TSSI bounds 0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00 + */ + if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom); + tssi_bounds[0] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG1_MINUS4); + tssi_bounds[1] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG1_MINUS3); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom); + tssi_bounds[2] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG2_MINUS2); + tssi_bounds[3] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG2_MINUS1); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom); + tssi_bounds[4] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG3_REF); + tssi_bounds[5] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG3_PLUS1); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom); + tssi_bounds[6] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG4_PLUS2); + tssi_bounds[7] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG4_PLUS3); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom); + tssi_bounds[8] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG5_PLUS4); + + step = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG5_AGC_STEP); + } else { + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom); + tssi_bounds[0] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A1_MINUS4); + tssi_bounds[1] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A1_MINUS3); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom); + tssi_bounds[2] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A2_MINUS2); + tssi_bounds[3] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A2_MINUS1); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom); + tssi_bounds[4] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A3_REF); + tssi_bounds[5] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A3_PLUS1); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom); + tssi_bounds[6] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A4_PLUS2); + tssi_bounds[7] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A4_PLUS3); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom); + tssi_bounds[8] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A5_PLUS4); + + step = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A5_AGC_STEP); + } + + /* + * Check if temperature compensation is supported. + */ + if (tssi_bounds[4] == 0xff) + return 0; + + /* + * Read current TSSI (BBP 49). + */ + rt2800_bbp_read(rt2x00dev, 49, ¤t_tssi); + + /* + * Compare TSSI value (BBP49) with the compensation boundaries + * from the EEPROM and increase or decrease tx power. + */ + for (i = 0; i <= 3; i++) { + if (current_tssi > tssi_bounds[i]) + break; + } + + if (i == 4) { + for (i = 8; i >= 5; i--) { + if (current_tssi < tssi_bounds[i]) + break; + } + } + + return (i - 4) * step; +} + static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, enum ieee80211_band band) { u16 eeprom; u8 comp_en; u8 comp_type; - int comp_value; + int comp_value = 0; rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom); - if (eeprom == 0xffff) + /* + * HT40 compensation not required. + */ + if (eeprom == 0xffff || + !test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) return 0; if (band == IEEE80211_BAND_2GHZ) { @@ -1853,11 +1998,9 @@ static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, return comp_value; } -static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, - int is_rate_b, - enum ieee80211_band band, - int power_level, - u8 txpower) +static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, + enum ieee80211_band band, int power_level, + u8 txpower, int delta) { u32 reg; u16 eeprom; @@ -1865,15 +2008,11 @@ static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, u8 eirp_txpower; u8 eirp_txpower_criterion; u8 reg_limit; - int bw_comp = 0; if (!((band == IEEE80211_BAND_5GHZ) && is_rate_b)) return txpower; - if (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) - bw_comp = rt2800_get_txpower_bw_comp(rt2x00dev, band); - - if (test_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags)) { /* * Check if eirp txpower exceed txpower_limit. * We use OFDM 6M as criterion and its eirp txpower @@ -1895,18 +2034,19 @@ static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, EEPROM_EIRP_MAX_TX_POWER_5GHZ); eirp_txpower = eirp_txpower_criterion + (txpower - criterion) + - (is_rate_b ? 4 : 0) + bw_comp; + (is_rate_b ? 4 : 0) + delta; reg_limit = (eirp_txpower > power_level) ? (eirp_txpower - power_level) : 0; } else reg_limit = 0; - return txpower + bw_comp - reg_limit; + return txpower + delta - reg_limit; } static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf) + enum ieee80211_band band, + int power_level) { u8 txpower; u16 eeprom; @@ -1914,8 +2054,17 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, u32 reg; u8 r1; u32 offset; - enum ieee80211_band band = conf->channel->band; - int power_level = conf->power_level; + int delta; + + /* + * Calculate HT40 compensation delta + */ + delta = rt2800_get_txpower_bw_comp(rt2x00dev, band); + + /* + * calculate temperature compensation delta + */ + delta += rt2800_get_gain_calibration_delta(rt2x00dev); /* * set to normal bbp tx power control mode: +/- 0dBm @@ -1944,8 +2093,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE0, txpower); /* @@ -1955,8 +2104,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE1, txpower); /* @@ -1966,8 +2115,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE2, txpower); /* @@ -1977,8 +2126,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE3, txpower); /* read the next four txpower values */ @@ -1993,8 +2142,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE4, txpower); /* @@ -2004,8 +2153,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE5, txpower); /* @@ -2015,8 +2164,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE6, txpower); /* @@ -2026,8 +2175,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE7, txpower); rt2800_register_write(rt2x00dev, offset, reg); @@ -2037,6 +2186,13 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, } } +void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev) +{ + rt2800_config_txpower(rt2x00dev, rt2x00dev->curr_band, + rt2x00dev->tx_power); +} +EXPORT_SYMBOL_GPL(rt2800_gain_calibration); + static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -2090,10 +2246,12 @@ void rt2800_config(struct rt2x00_dev *rt2x00dev, if (flags & IEEE80211_CONF_CHANGE_CHANNEL) { rt2800_config_channel(rt2x00dev, libconf->conf, &libconf->rf, &libconf->channel); - rt2800_config_txpower(rt2x00dev, libconf->conf); + rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band, + libconf->conf->power_level); } if (flags & IEEE80211_CONF_CHANGE_POWER) - rt2800_config_txpower(rt2x00dev, libconf->conf); + rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band, + libconf->conf->power_level); if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) rt2800_config_retry_limit(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) @@ -2254,7 +2412,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) } else if (rt2800_is_305x_soc(rt2x00dev)) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); - rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000001f); + rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000030); } else if (rt2x00_rt(rt2x00dev, RT5390)) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); @@ -2758,8 +2916,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) ant = (div_mode == 3) ? 1 : 0; /* check if this is a Bluetooth combo card */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); - if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) { + if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { u32 reg; rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); @@ -3155,8 +3312,8 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) || rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) { - if (!test_bit(CONFIG_EXTERNAL_LNA_BG, - &rt2x00dev->flags)) + if (!test_bit(CAPABILITY_EXTERNAL_LNA_BG, + &rt2x00dev->cap_flags)) rt2x00_set_field8(&rfcsr, RFCSR17_R, 1); } rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &eeprom); @@ -3530,6 +3687,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) !rt2x00_rf(rt2x00dev, RF3022) && !rt2x00_rf(rt2x00dev, RF3052) && !rt2x00_rf(rt2x00dev, RF3320) && + !rt2x00_rf(rt2x00dev, RF5370) && !rt2x00_rf(rt2x00dev, RF5390)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; @@ -3568,26 +3726,30 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) } /* - * Read frequency offset and RF programming sequence. + * Determine external LNA informations. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); - rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); - - /* - * Read external LNA informations. - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); - if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G)) - __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G)) - __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); /* * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_HW_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); + + /* + * Detect if this device has Bluetooth co-existence. + */ + if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) + __set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags); + + /* + * Read frequency offset and RF programming sequence. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); /* * Store led settings, for correct led behaviour. @@ -3597,7 +3759,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg); + rt2x00dev->led_mcu_reg = eeprom; #endif /* CONFIG_RT2X00_LIB_LEDS */ /* @@ -3607,7 +3769,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) if (rt2x00_get_field16(eeprom, EEPROM_EIRP_MAX_TX_POWER_2GHZ) < EIRP_MAX_TX_POWER_LIMIT) - __set_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags); + __set_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags); return 0; } @@ -3828,6 +3990,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00_rf(rt2x00dev, RF3021) || rt2x00_rf(rt2x00dev, RF3022) || rt2x00_rf(rt2x00dev, RF3320) || + rt2x00_rf(rt2x00dev, RF5370) || rt2x00_rf(rt2x00dev, RF5390)) { spec->num_channels = 14; spec->channels = rf_vals_3x; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 0c92d86a36f4..f2d15941c71a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -181,6 +181,7 @@ void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, const u32 count); +void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev); int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev); void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 808073aa9dcc..cc4a54f571b8 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -66,7 +66,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) return; for (i = 0; i < 200; i++) { - rt2800_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); + rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) || (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) || @@ -80,8 +80,8 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) if (i == 200) ERROR(rt2x00dev, "MCU request failed, no response from hardware\n"); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); } #if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) @@ -105,7 +105,7 @@ static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) struct rt2x00_dev *rt2x00dev = eeprom->data; u32 reg; - rt2800_register_read(rt2x00dev, E2PROM_CSR, ®); + rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); @@ -127,7 +127,7 @@ static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom) rt2x00_set_field32(®, E2PROM_CSR_CHIP_SELECT, !!eeprom->reg_chip_select); - rt2800_register_write(rt2x00dev, E2PROM_CSR, reg); + rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg); } static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) @@ -135,7 +135,7 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) struct eeprom_93cx6 eeprom; u32 reg; - rt2800_register_read(rt2x00dev, E2PROM_CSR, ®); + rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); eeprom.data = rt2x00dev; eeprom.register_read = rt2800pci_eepromregister_read; @@ -195,9 +195,9 @@ static void rt2800pci_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: /* @@ -207,15 +207,15 @@ static void rt2800pci_start_queue(struct data_queue *queue) tasklet_enable(&rt2x00dev->tbtt_tasklet); tasklet_enable(&rt2x00dev->pretbtt_tasklet); - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); - rt2800_register_read(rt2x00dev, INT_TIMER_EN, ®); + rt2x00pci_register_read(rt2x00dev, INT_TIMER_EN, ®); rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 1); - rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg); + rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg); break; default: break; @@ -233,11 +233,13 @@ static void rt2800pci_kick_queue(struct data_queue *queue) case QID_AC_BE: case QID_AC_BK: entry = rt2x00queue_get_entry(queue, Q_INDEX); - rt2800_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), entry->entry_idx); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), + entry->entry_idx); break; case QID_MGMT: entry = rt2x00queue_get_entry(queue, Q_INDEX); - rt2800_register_write(rt2x00dev, TX_CTX_IDX(5), entry->entry_idx); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(5), + entry->entry_idx); break; default: break; @@ -251,20 +253,20 @@ static void rt2800pci_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); - rt2800_register_read(rt2x00dev, INT_TIMER_EN, ®); + rt2x00pci_register_read(rt2x00dev, INT_TIMER_EN, ®); rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 0); - rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg); + rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg); /* * Wait for tbtt tasklets to finish. @@ -295,19 +297,19 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev, */ reg = 0; rt2x00_set_field32(®, PBF_SYS_CTRL_HOST_RAM_WRITE, 1); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, reg); /* * Write firmware to device. */ - rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, - data, len); + rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, + data, len); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); - rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); return 0; } @@ -351,7 +353,7 @@ static void rt2800pci_clear_entry(struct queue_entry *entry) * Set RX IDX in register to inform hardware that we have * handled this entry and it is available for reuse again. */ - rt2800_register_write(rt2x00dev, RX_CRX_IDX, + rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx); } else { rt2x00_desc_read(entry_priv->desc, 1, &word); @@ -369,45 +371,51 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) * Initialize registers. */ entry_priv = rt2x00dev->tx[0].entries[0].priv_data; - rt2800_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma); - rt2800_register_write(rt2x00dev, TX_MAX_CNT0, rt2x00dev->tx[0].limit); - rt2800_register_write(rt2x00dev, TX_CTX_IDX0, 0); - rt2800_register_write(rt2x00dev, TX_DTX_IDX0, 0); + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT0, + rt2x00dev->tx[0].limit); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX0, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX0, 0); entry_priv = rt2x00dev->tx[1].entries[0].priv_data; - rt2800_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma); - rt2800_register_write(rt2x00dev, TX_MAX_CNT1, rt2x00dev->tx[1].limit); - rt2800_register_write(rt2x00dev, TX_CTX_IDX1, 0); - rt2800_register_write(rt2x00dev, TX_DTX_IDX1, 0); + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT1, + rt2x00dev->tx[1].limit); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX1, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX1, 0); entry_priv = rt2x00dev->tx[2].entries[0].priv_data; - rt2800_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma); - rt2800_register_write(rt2x00dev, TX_MAX_CNT2, rt2x00dev->tx[2].limit); - rt2800_register_write(rt2x00dev, TX_CTX_IDX2, 0); - rt2800_register_write(rt2x00dev, TX_DTX_IDX2, 0); + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT2, + rt2x00dev->tx[2].limit); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX2, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX2, 0); entry_priv = rt2x00dev->tx[3].entries[0].priv_data; - rt2800_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma); - rt2800_register_write(rt2x00dev, TX_MAX_CNT3, rt2x00dev->tx[3].limit); - rt2800_register_write(rt2x00dev, TX_CTX_IDX3, 0); - rt2800_register_write(rt2x00dev, TX_DTX_IDX3, 0); + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT3, + rt2x00dev->tx[3].limit); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX3, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX3, 0); entry_priv = rt2x00dev->rx->entries[0].priv_data; - rt2800_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma); - rt2800_register_write(rt2x00dev, RX_MAX_CNT, rt2x00dev->rx[0].limit); - rt2800_register_write(rt2x00dev, RX_CRX_IDX, rt2x00dev->rx[0].limit - 1); - rt2800_register_write(rt2x00dev, RX_DRX_IDX, 0); + rt2x00pci_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, RX_MAX_CNT, + rt2x00dev->rx[0].limit); + rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, + rt2x00dev->rx[0].limit - 1); + rt2x00pci_register_write(rt2x00dev, RX_DRX_IDX, 0); /* * Enable global DMA configuration */ - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + 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); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - rt2800_register_write(rt2x00dev, DELAY_INT_CFG, 0); + rt2x00pci_register_write(rt2x00dev, DELAY_INT_CFG, 0); return 0; } @@ -427,8 +435,8 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, * should clear the register to assure a clean state. */ if (state == STATE_RADIO_IRQ_ON) { - rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); - rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); /* * Enable tasklets. The beacon related tasklets are @@ -440,7 +448,7 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, } spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); rt2x00_set_field32(®, INT_MASK_CSR_RXDELAYINT, 0); rt2x00_set_field32(®, INT_MASK_CSR_TXDELAYINT, 0); rt2x00_set_field32(®, INT_MASK_CSR_RX_DONE, mask); @@ -459,7 +467,7 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, INT_MASK_CSR_GPTIMER, 0); rt2x00_set_field32(®, INT_MASK_CSR_RX_COHERENT, 0); rt2x00_set_field32(®, INT_MASK_CSR_TX_COHERENT, 0); - rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); if (state == STATE_RADIO_IRQ_OFF) { @@ -480,7 +488,7 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) /* * Reset DMA indexes */ - rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, ®); + rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, ®); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1); @@ -488,26 +496,26 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1); - rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg); + rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); if (rt2x00_rt(rt2x00dev, RT5390)) { - rt2800_register_read(rt2x00dev, AUX_CTRL, ®); + rt2x00pci_register_read(rt2x00dev, AUX_CTRL, ®); rt2x00_set_field32(®, AUX_CTRL_FORCE_PCIE_CLK, 1); rt2x00_set_field32(®, AUX_CTRL_WAKE_PCIE_EN, 1); - rt2800_register_write(rt2x00dev, AUX_CTRL, reg); + rt2x00pci_register_write(rt2x00dev, AUX_CTRL, reg); } - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); return 0; } @@ -525,8 +533,8 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) { if (rt2x00_is_soc(rt2x00dev)) { rt2800_disable_radio(rt2x00dev); - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); - rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); + rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0); + rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, 0); } } @@ -537,8 +545,10 @@ static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02); rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP); } else if (state == STATE_SLEEP) { - rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, 0xffffffff); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, 0xffffffff); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, + 0xffffffff); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, + 0xffffffff); rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01); } @@ -717,12 +727,13 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev) rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); } -static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) +static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; struct queue_entry *entry; u32 status; u8 qid; + int max_tx_done = 16; while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) { qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); @@ -759,11 +770,16 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); rt2800_txdone_entry(entry, status); + + if (--max_tx_done == 0) + break; } + + return !max_tx_done; } -static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, - struct rt2x00_field32 irq_field) +static inline void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { u32 reg; @@ -772,15 +788,17 @@ static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, * access needs locking. */ spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); rt2x00_set_field32(®, irq_field, 1); - rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); spin_unlock_irq(&rt2x00dev->irqmask_lock); } static void rt2800pci_txstatus_tasklet(unsigned long data) { - rt2800pci_txdone((struct rt2x00_dev *)data); + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + if (rt2800pci_txdone(rt2x00dev)) + tasklet_schedule(&rt2x00dev->txstatus_tasklet); /* * No need to enable the tx status interrupt here as we always @@ -806,8 +824,10 @@ static void rt2800pci_tbtt_tasklet(unsigned long data) static void rt2800pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - rt2x00pci_rxdone(rt2x00dev); - rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); + if (rt2x00pci_rxdone(rt2x00dev)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + else + rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); } static void rt2800pci_autowake_tasklet(unsigned long data) @@ -841,7 +861,7 @@ static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) * need to lock the kfifo. */ for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) { - rt2800_register_read(rt2x00dev, TX_STA_FIFO, &status); + rt2x00pci_register_read(rt2x00dev, TX_STA_FIFO, &status); if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID)) break; @@ -863,8 +883,8 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) u32 reg, mask; /* Read status and ACK all interrupts */ - rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); - rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); if (!reg) return IRQ_NONE; @@ -904,9 +924,9 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) * the tasklet will reenable the appropriate interrupts. */ spin_lock(&rt2x00dev->irqmask_lock); - rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); reg &= mask; - rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); spin_unlock(&rt2x00dev->irqmask_lock); return IRQ_HANDLED; @@ -956,28 +976,28 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) * This device has multiple filters for control frames * and has a separate filter for PS Poll frames. */ - __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags); + __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags); /* * This device has a pre tbtt interrupt and thus fetches * a new beacon directly prior to transmission. */ - __set_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags); + __set_bit(CAPABILITY_PRE_TBTT_INTERRUPT, &rt2x00dev->cap_flags); /* * This device requires firmware. */ if (!rt2x00_is_soc(rt2x00dev)) - __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags); + __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags); if (!modparam_nohwcrypt) - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); /* * Set the rssi offset. @@ -1008,6 +1028,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = { .ampdu_action = rt2800_ampdu_action, .flush = rt2x00mac_flush, .get_survey = rt2800_get_survey, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2800_ops rt2800pci_rt2800_ops = { @@ -1043,9 +1064,11 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .link_stats = rt2800_link_stats, .reset_tuner = rt2800_reset_tuner, .link_tuner = rt2800_link_tuner, + .gain_calibration = rt2800_gain_calibration, .start_queue = rt2800pci_start_queue, .kick_queue = rt2800pci_kick_queue, .stop_queue = rt2800pci_stop_queue, + .flush_queue = rt2x00pci_flush_queue, .write_tx_desc = rt2800pci_write_tx_desc, .write_tx_data = rt2800_write_tx_data, .write_beacon = rt2800_write_beacon, @@ -1105,36 +1128,36 @@ static const struct rt2x00_ops rt2800pci_ops = { */ #ifdef CONFIG_PCI static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { - { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7738), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0601) }, + { PCI_DEVICE(0x1814, 0x0681) }, + { PCI_DEVICE(0x1814, 0x0701) }, + { PCI_DEVICE(0x1814, 0x0781) }, + { PCI_DEVICE(0x1814, 0x3090) }, + { PCI_DEVICE(0x1814, 0x3091) }, + { PCI_DEVICE(0x1814, 0x3092) }, + { PCI_DEVICE(0x1432, 0x7708) }, + { PCI_DEVICE(0x1432, 0x7727) }, + { PCI_DEVICE(0x1432, 0x7728) }, + { PCI_DEVICE(0x1432, 0x7738) }, + { PCI_DEVICE(0x1432, 0x7748) }, + { PCI_DEVICE(0x1432, 0x7758) }, + { PCI_DEVICE(0x1432, 0x7768) }, + { PCI_DEVICE(0x1462, 0x891a) }, + { PCI_DEVICE(0x1a3b, 0x1059) }, #ifdef CONFIG_RT2800PCI_RT33XX - { PCI_DEVICE(0x1814, 0x3390), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3390) }, #endif #ifdef CONFIG_RT2800PCI_RT35XX - { PCI_DEVICE(0x1432, 0x7711), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7722), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3593), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1432, 0x7711) }, + { PCI_DEVICE(0x1432, 0x7722) }, + { PCI_DEVICE(0x1814, 0x3060) }, + { PCI_DEVICE(0x1814, 0x3062) }, + { PCI_DEVICE(0x1814, 0x3562) }, + { PCI_DEVICE(0x1814, 0x3592) }, + { PCI_DEVICE(0x1814, 0x3593) }, #endif #ifdef CONFIG_RT2800PCI_RT53XX - { PCI_DEVICE(0x1814, 0x5390), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x5390) }, #endif { 0, } }; @@ -1170,10 +1193,16 @@ static struct platform_driver rt2800soc_driver = { #endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ #ifdef CONFIG_PCI +static int rt2800pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id) +{ + return rt2x00pci_probe(pci_dev, &rt2800pci_ops); +} + static struct pci_driver rt2800pci_driver = { .name = KBUILD_MODNAME, .id_table = rt2800pci_device_table, - .probe = rt2x00pci_probe, + .probe = rt2800pci_probe, .remove = __devexit_p(rt2x00pci_remove), .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 37509d019910..ba82c972703a 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -59,16 +59,16 @@ static void rt2800usb_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); break; default: break; @@ -82,22 +82,79 @@ static void rt2800usb_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); break; default: break; } } +/* + * test if there is an entry in any TX queue for which DMA is done + * but the TX status has not been returned yet + */ +static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + + tx_queue_for_each(rt2x00dev, queue) { + if (rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE) != + rt2x00queue_get_entry(queue, Q_INDEX_DONE)) + return true; + } + return false; +} + +static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, + int urb_status, u32 tx_status) +{ + if (urb_status) { + WARNING(rt2x00dev, "rt2x00usb_register_read_async failed: %d\n", urb_status); + return false; + } + + /* try to read all TX_STA_FIFO entries before scheduling txdone_work */ + if (rt2x00_get_field32(tx_status, TX_STA_FIFO_VALID)) { + if (!kfifo_put(&rt2x00dev->txstatus_fifo, &tx_status)) { + WARNING(rt2x00dev, "TX status FIFO overrun, " + "drop tx status report.\n"); + queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); + } else + return true; + } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) { + queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); + } else if (rt2800usb_txstatus_pending(rt2x00dev)) { + mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); + } + + return false; +} + +static void rt2800usb_tx_dma_done(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + + rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO, + rt2800usb_tx_sta_fifo_read_completed); +} + +static void rt2800usb_tx_sta_fifo_timeout(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + + rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO, + rt2800usb_tx_sta_fifo_read_completed); +} + /* * Firmware functions */ @@ -129,11 +186,11 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev, /* * Write firmware to device. */ - rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, - data + offset, length); + rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, + data + offset, length); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); /* * Send firmware request to device to load firmware, @@ -148,7 +205,7 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev, } msleep(10); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); return 0; } @@ -166,22 +223,22 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2800_wait_csr_ready(rt2x00dev)) return -EBUSY; - rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); + rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + rt2x00usb_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); + rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, USB_MODE_RESET, REGISTER_TIMEOUT); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); return 0; } @@ -193,7 +250,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev))) return -EIO; - rt2800_register_read(rt2x00dev, USB_DMA_CFG, ®); + rt2x00usb_register_read(rt2x00dev, USB_DMA_CFG, ®); rt2x00_set_field32(®, USB_DMA_CFG_PHY_CLEAR, 0); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, 0); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128); @@ -206,7 +263,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) / 1024) - 3); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_EN, 1); rt2x00_set_field32(®, USB_DMA_CFG_TX_BULK_EN, 1); - rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg); + rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, reg); return rt2800_enable_radio(rt2x00dev); } @@ -282,12 +339,12 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev) unsigned int i; u32 reg; - rt2800_register_read(rt2x00dev, TXRXQ_PCNT, ®); + rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, ®); if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q)) { WARNING(rt2x00dev, "TX HW queue 0 timed out," " invoke forced kick\n"); - rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40012); + rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40012); for (i = 0; i < 10; i++) { udelay(10); @@ -295,15 +352,15 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev) break; } - rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); + rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006); } - rt2800_register_read(rt2x00dev, TXRXQ_PCNT, ®); + rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, ®); if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q)) { WARNING(rt2x00dev, "TX HW queue 1 timed out," " invoke forced kick\n"); - rt2800_register_write(rt2x00dev, PBF_CFG, 0xf4000a); + rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf4000a); for (i = 0; i < 10; i++) { udelay(10); @@ -311,7 +368,7 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev) break; } - rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); + rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006); } rt2x00usb_watchdog(rt2x00dev); @@ -420,13 +477,24 @@ static void rt2800usb_work_txdone(struct work_struct *work) while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || - !test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) + if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + break; + if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) + rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); + else if (rt2x00queue_status_timeout(entry)) + rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); + else break; - - rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); } } + + /* + * The hw may delay sending the packet after DMA complete + * if the medium is busy, thus the TX_STA_FIFO entry is + * also delayed -> use a timer to retrieve it. + */ + if (rt2800usb_txstatus_pending(rt2x00dev)) + mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); } /* @@ -553,19 +621,24 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) * This device has multiple filters for control frames * and has a separate filter for PS Poll frames. */ - __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags); + __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags); /* * This device requires firmware. */ - __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); + __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags); if (!modparam_nohwcrypt) - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); + + setup_timer(&rt2x00dev->txstatus_timer, + rt2800usb_tx_sta_fifo_timeout, + (unsigned long) rt2x00dev); /* * Set the rssi offset. @@ -602,6 +675,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { .ampdu_action = rt2800_ampdu_action, .flush = rt2x00mac_flush, .get_survey = rt2800_get_survey, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2800_ops rt2800usb_rt2800_ops = { @@ -630,11 +704,13 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .link_stats = rt2800_link_stats, .reset_tuner = rt2800_reset_tuner, .link_tuner = rt2800_link_tuner, + .gain_calibration = rt2800_gain_calibration, .watchdog = rt2800usb_watchdog, .start_queue = rt2800usb_start_queue, .kick_queue = rt2x00usb_kick_queue, .stop_queue = rt2800usb_stop_queue, .flush_queue = rt2x00usb_flush_queue, + .tx_dma_done = rt2800usb_tx_dma_done, .write_tx_desc = rt2800usb_write_tx_desc, .write_tx_data = rt2800usb_write_tx_data, .write_beacon = rt2800_write_beacon, @@ -695,294 +771,340 @@ static const struct rt2x00_ops rt2800usb_ops = { */ static struct usb_device_id rt2800usb_device_table[] = { /* Abocom */ - { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x2870) }, + { USB_DEVICE(0x07b8, 0x2770) }, + { USB_DEVICE(0x07b8, 0x3070) }, + { USB_DEVICE(0x07b8, 0x3071) }, + { USB_DEVICE(0x07b8, 0x3072) }, + { USB_DEVICE(0x1482, 0x3c09) }, /* AirTies */ - { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1eda, 0x2012) }, + { USB_DEVICE(0x1eda, 0x2310) }, /* Allwin */ - { USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x2070) }, + { USB_DEVICE(0x8516, 0x2770) }, + { USB_DEVICE(0x8516, 0x2870) }, + { USB_DEVICE(0x8516, 0x3070) }, + { USB_DEVICE(0x8516, 0x3071) }, + { USB_DEVICE(0x8516, 0x3072) }, + /* Alpha Networks */ + { USB_DEVICE(0x14b2, 0x3c06) }, + { USB_DEVICE(0x14b2, 0x3c07) }, + { USB_DEVICE(0x14b2, 0x3c09) }, + { USB_DEVICE(0x14b2, 0x3c12) }, + { USB_DEVICE(0x14b2, 0x3c23) }, + { USB_DEVICE(0x14b2, 0x3c25) }, + { USB_DEVICE(0x14b2, 0x3c27) }, + { USB_DEVICE(0x14b2, 0x3c28) }, + { USB_DEVICE(0x14b2, 0x3c2c) }, /* Amit */ - { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x15c5, 0x0008) }, /* Askey */ - { USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1690, 0x0740) }, /* ASUS */ - { USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1731) }, + { USB_DEVICE(0x0b05, 0x1732) }, + { USB_DEVICE(0x0b05, 0x1742) }, + { USB_DEVICE(0x0b05, 0x1784) }, + { USB_DEVICE(0x1761, 0x0b05) }, /* AzureWave */ - { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3307), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3321), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3247) }, + { USB_DEVICE(0x13d3, 0x3273) }, + { USB_DEVICE(0x13d3, 0x3305) }, + { USB_DEVICE(0x13d3, 0x3307) }, + { USB_DEVICE(0x13d3, 0x3321) }, /* Belkin */ - { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x050d, 0x825b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x050d, 0x935a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x050d, 0x935b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x8053) }, + { USB_DEVICE(0x050d, 0x805c) }, + { USB_DEVICE(0x050d, 0x815c) }, + { USB_DEVICE(0x050d, 0x825b) }, + { USB_DEVICE(0x050d, 0x935a) }, + { USB_DEVICE(0x050d, 0x935b) }, /* Buffalo */ - { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x016f), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Conceptronic */ - { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c28), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x00e8) }, + { USB_DEVICE(0x0411, 0x016f) }, + { USB_DEVICE(0x0411, 0x01a2) }, /* Corega */ - { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x002f) }, + { USB_DEVICE(0x07aa, 0x003c) }, + { USB_DEVICE(0x07aa, 0x003f) }, + { USB_DEVICE(0x18c5, 0x0012) }, /* D-Link */ - { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c09) }, + { USB_DEVICE(0x07d1, 0x3c0a) }, + { USB_DEVICE(0x07d1, 0x3c0d) }, + { USB_DEVICE(0x07d1, 0x3c0e) }, + { USB_DEVICE(0x07d1, 0x3c0f) }, + { USB_DEVICE(0x07d1, 0x3c11) }, + { USB_DEVICE(0x07d1, 0x3c16) }, /* Draytek */ - { USB_DEVICE(0x07fa, 0x7712), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07fa, 0x7712) }, /* Edimax */ - { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x7711) }, + { USB_DEVICE(0x7392, 0x7717) }, + { USB_DEVICE(0x7392, 0x7718) }, /* Encore */ - { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x203d, 0x1480) }, + { USB_DEVICE(0x203d, 0x14a9) }, /* EnGenius */ - { USB_DEVICE(0x1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9701) }, + { USB_DEVICE(0x1740, 0x9702) }, + { USB_DEVICE(0x1740, 0x9703) }, + { USB_DEVICE(0x1740, 0x9705) }, + { USB_DEVICE(0x1740, 0x9706) }, + { USB_DEVICE(0x1740, 0x9707) }, + { USB_DEVICE(0x1740, 0x9708) }, + { USB_DEVICE(0x1740, 0x9709) }, + /* Gemtek */ + { USB_DEVICE(0x15a9, 0x0012) }, /* Gigabyte */ - { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1044, 0x800b) }, + { USB_DEVICE(0x1044, 0x800d) }, /* Hawking */ - { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0013), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0018), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0001) }, + { USB_DEVICE(0x0e66, 0x0003) }, + { USB_DEVICE(0x0e66, 0x0009) }, + { USB_DEVICE(0x0e66, 0x000b) }, + { USB_DEVICE(0x0e66, 0x0013) }, + { USB_DEVICE(0x0e66, 0x0017) }, + { USB_DEVICE(0x0e66, 0x0018) }, /* I-O DATA */ - { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x04bb, 0x0945) }, + { USB_DEVICE(0x04bb, 0x0947) }, + { USB_DEVICE(0x04bb, 0x0948) }, /* Linksys */ - { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13b1, 0x0031) }, + { USB_DEVICE(0x1737, 0x0070) }, + { USB_DEVICE(0x1737, 0x0071) }, /* Logitec */ - { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0789, 0x0166), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0162) }, + { USB_DEVICE(0x0789, 0x0163) }, + { USB_DEVICE(0x0789, 0x0164) }, + { USB_DEVICE(0x0789, 0x0166) }, /* Motorola */ - { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x100d, 0x9031) }, /* MSI */ - { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x822b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x822c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x871b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x871c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x3820) }, + { USB_DEVICE(0x0db0, 0x3821) }, + { USB_DEVICE(0x0db0, 0x3822) }, + { USB_DEVICE(0x0db0, 0x3870) }, + { USB_DEVICE(0x0db0, 0x3871) }, + { USB_DEVICE(0x0db0, 0x6899) }, + { USB_DEVICE(0x0db0, 0x821a) }, + { USB_DEVICE(0x0db0, 0x822a) }, + { USB_DEVICE(0x0db0, 0x822b) }, + { USB_DEVICE(0x0db0, 0x822c) }, + { USB_DEVICE(0x0db0, 0x870a) }, + { USB_DEVICE(0x0db0, 0x871a) }, + { USB_DEVICE(0x0db0, 0x871b) }, + { USB_DEVICE(0x0db0, 0x871c) }, + { USB_DEVICE(0x0db0, 0x899a) }, /* Para */ - { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x20b8, 0x8888) }, /* Pegatron */ - { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x000c) }, + { USB_DEVICE(0x1d4d, 0x000e) }, + { USB_DEVICE(0x1d4d, 0x0011) }, /* Philips */ - { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0471, 0x200f) }, /* Planex */ - { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x2019, 0xab25) }, + { USB_DEVICE(0x2019, 0xed06) }, /* Quanta */ - { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1a32, 0x0304) }, /* Ralink */ - { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2070) }, + { USB_DEVICE(0x148f, 0x2770) }, + { USB_DEVICE(0x148f, 0x2870) }, + { USB_DEVICE(0x148f, 0x3070) }, + { USB_DEVICE(0x148f, 0x3071) }, + { USB_DEVICE(0x148f, 0x3072) }, /* Samsung */ - { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x04e8, 0x2018) }, /* Siemens */ - { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x129b, 0x1828) }, /* Sitecom */ - { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0017) }, + { USB_DEVICE(0x0df6, 0x002b) }, + { USB_DEVICE(0x0df6, 0x002c) }, + { USB_DEVICE(0x0df6, 0x002d) }, + { USB_DEVICE(0x0df6, 0x0039) }, + { USB_DEVICE(0x0df6, 0x003b) }, + { USB_DEVICE(0x0df6, 0x003d) }, + { USB_DEVICE(0x0df6, 0x003e) }, + { USB_DEVICE(0x0df6, 0x003f) }, + { USB_DEVICE(0x0df6, 0x0040) }, + { USB_DEVICE(0x0df6, 0x0042) }, + { USB_DEVICE(0x0df6, 0x0047) }, + { USB_DEVICE(0x0df6, 0x0048) }, + { USB_DEVICE(0x0df6, 0x0051) }, + { USB_DEVICE(0x0df6, 0x005f) }, /* SMC */ - { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xa703), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x6618) }, + { USB_DEVICE(0x083a, 0x7511) }, + { USB_DEVICE(0x083a, 0x7512) }, + { USB_DEVICE(0x083a, 0x7522) }, + { USB_DEVICE(0x083a, 0x8522) }, + { USB_DEVICE(0x083a, 0xa618) }, + { USB_DEVICE(0x083a, 0xa701) }, + { USB_DEVICE(0x083a, 0xa702) }, + { USB_DEVICE(0x083a, 0xa703) }, + { USB_DEVICE(0x083a, 0xb522) }, /* Sparklan */ - { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x15a9, 0x0006) }, /* Sweex */ - { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* U-Media*/ - { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x177f, 0x0302) }, + /* U-Media */ + { USB_DEVICE(0x157e, 0x300e) }, + { USB_DEVICE(0x157e, 0x3013) }, /* ZCOM */ - { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0cde, 0x0022) }, + { USB_DEVICE(0x0cde, 0x0025) }, /* Zinwell */ - { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0280) }, + { USB_DEVICE(0x5a57, 0x0282) }, + { USB_DEVICE(0x5a57, 0x0283) }, + { USB_DEVICE(0x5a57, 0x5257) }, /* Zyxel */ - { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0586, 0x3416) }, + { USB_DEVICE(0x0586, 0x3418) }, + { USB_DEVICE(0x0586, 0x341e) }, + { USB_DEVICE(0x0586, 0x343e) }, #ifdef CONFIG_RT2800USB_RT33XX /* Ralink */ - { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3370) }, + { USB_DEVICE(0x148f, 0x8070) }, /* Sitecom */ - { USB_DEVICE(0x0df6, 0x0050), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0050) }, #endif #ifdef CONFIG_RT2800USB_RT35XX /* Allwin */ - { USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x3572) }, /* Askey */ - { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1690, 0x0744) }, /* Cisco */ - { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x167b, 0x4001) }, /* EnGenius */ - { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9801) }, /* I-O DATA */ - { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x04bb, 0x0944) }, + /* Linksys */ + { USB_DEVICE(0x13b1, 0x002f) }, + { USB_DEVICE(0x1737, 0x0079) }, /* Ralink */ - { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3572) }, /* Sitecom */ - { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0041) }, /* Toshiba */ - { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0930, 0x0a07) }, /* Zinwell */ - { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0284) }, +#endif +#ifdef CONFIG_RT2800USB_RT53XX + /* Azurewave */ + { USB_DEVICE(0x13d3, 0x3329) }, + { USB_DEVICE(0x13d3, 0x3365) }, + /* Ralink */ + { USB_DEVICE(0x148f, 0x5370) }, + { USB_DEVICE(0x148f, 0x5372) }, #endif #ifdef CONFIG_RT2800USB_UNKNOWN /* * Unclear what kind of devices these are (they aren't supported by the * vendor linux driver). */ + /* Abocom */ + { USB_DEVICE(0x07b8, 0x3073) }, + { USB_DEVICE(0x07b8, 0x3074) }, + /* Alpha Networks */ + { USB_DEVICE(0x14b2, 0x3c08) }, + { USB_DEVICE(0x14b2, 0x3c11) }, /* Amigo */ - { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e0b, 0x9031) }, + { USB_DEVICE(0x0e0b, 0x9041) }, /* ASUS */ - { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x166a) }, + { USB_DEVICE(0x0b05, 0x1760) }, + { USB_DEVICE(0x0b05, 0x1761) }, + { USB_DEVICE(0x0b05, 0x1790) }, + { USB_DEVICE(0x0b05, 0x179d) }, /* AzureWave */ - { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3322), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3262) }, + { USB_DEVICE(0x13d3, 0x3284) }, + { USB_DEVICE(0x13d3, 0x3322) }, /* Belkin */ - { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x1003) }, + { USB_DEVICE(0x050d, 0x825a) }, /* Buffalo */ - { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x0148), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x0150), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x015d), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Conceptronic */ - { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x012e) }, + { USB_DEVICE(0x0411, 0x0148) }, + { USB_DEVICE(0x0411, 0x0150) }, + { USB_DEVICE(0x0411, 0x015d) }, /* Corega */ - { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x0041) }, + { USB_DEVICE(0x07aa, 0x0042) }, + { USB_DEVICE(0x18c5, 0x0008) }, /* D-Link */ - { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c17), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0b) }, + { USB_DEVICE(0x07d1, 0x3c13) }, + { USB_DEVICE(0x07d1, 0x3c15) }, + { USB_DEVICE(0x07d1, 0x3c17) }, + { USB_DEVICE(0x2001, 0x3c17) }, /* Edimax */ - { USB_DEVICE(0x7392, 0x4085), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x4085) }, + { USB_DEVICE(0x7392, 0x7722) }, /* Encore */ - { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x203d, 0x14a1) }, /* Gemtek */ - { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x15a9, 0x0010) }, /* Gigabyte */ - { USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1044, 0x800c) }, + /* Huawei */ + { USB_DEVICE(0x148f, 0xf101) }, + /* I-O DATA */ + { USB_DEVICE(0x04bb, 0x094b) }, /* LevelOne */ - { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x0605) }, + { USB_DEVICE(0x1740, 0x0615) }, /* Linksys */ - { USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1737, 0x0078), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1737, 0x0077) }, + { USB_DEVICE(0x1737, 0x0078) }, + /* Logitec */ + { USB_DEVICE(0x0789, 0x0168) }, + { USB_DEVICE(0x0789, 0x0169) }, /* Motorola */ - { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x100d, 0x9032) }, /* Ovislink */ - { USB_DEVICE(0x1b75, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1b75, 0x3071) }, + { USB_DEVICE(0x1b75, 0x3072) }, /* Pegatron */ - { USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x05a6, 0x0101) }, + { USB_DEVICE(0x1d4d, 0x0002) }, + { USB_DEVICE(0x1d4d, 0x0010) }, /* Planex */ - { USB_DEVICE(0x2019, 0x5201), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x2019, 0x5201) }, + { USB_DEVICE(0x2019, 0xab24) }, /* Qcom */ - { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x18e8, 0x6259) }, + /* RadioShack */ + { USB_DEVICE(0x08b9, 0x1197) }, + /* Sitecom */ + { USB_DEVICE(0x0df6, 0x003c) }, + { USB_DEVICE(0x0df6, 0x004a) }, + { USB_DEVICE(0x0df6, 0x004d) }, + { USB_DEVICE(0x0df6, 0x0053) }, + { USB_DEVICE(0x0df6, 0x0060) }, + { USB_DEVICE(0x0df6, 0x0062) }, /* SMC */ - { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xd522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xf511), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xa512) }, + { USB_DEVICE(0x083a, 0xc522) }, + { USB_DEVICE(0x083a, 0xd522) }, + { USB_DEVICE(0x083a, 0xf511) }, /* Sweex */ - { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x177f, 0x0153) }, + { USB_DEVICE(0x177f, 0x0313) }, /* Zyxel */ - { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0586, 0x341a) }, #endif { 0, } }; @@ -995,10 +1117,16 @@ MODULE_DEVICE_TABLE(usb, rt2800usb_device_table); MODULE_FIRMWARE(FIRMWARE_RT2870); MODULE_LICENSE("GPL"); +static int rt2800usb_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id) +{ + return rt2x00usb_probe(usb_intf, &rt2800usb_ops); +} + static struct usb_driver rt2800usb_driver = { .name = KBUILD_MODNAME, .id_table = rt2800usb_device_table, - .probe = rt2x00usb_probe, + .probe = rt2800usb_probe, .disconnect = rt2x00usb_disconnect, .suspend = rt2x00usb_suspend, .resume = rt2x00usb_resume, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 7f10239f56a8..c446db69bd3c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -348,6 +349,11 @@ struct link { * to bring the device/driver back into the desired state. */ struct delayed_work watchdog_work; + + /* + * Work structure for scheduling periodic AGC adjustments. + */ + struct delayed_work agc_work; }; enum rt2x00_delayed_flags { @@ -556,6 +562,7 @@ struct rt2x00lib_ops { struct link_qual *qual); void (*link_tuner) (struct rt2x00_dev *rt2x00dev, struct link_qual *qual, const u32 count); + void (*gain_calibration) (struct rt2x00_dev *rt2x00dev); /* * Data queue handlers. @@ -564,7 +571,8 @@ struct rt2x00lib_ops { void (*start_queue) (struct data_queue *queue); void (*kick_queue) (struct data_queue *queue); void (*stop_queue) (struct data_queue *queue); - void (*flush_queue) (struct data_queue *queue); + void (*flush_queue) (struct data_queue *queue, bool drop); + void (*tx_dma_done) (struct queue_entry *entry); /* * TX control handlers @@ -637,11 +645,11 @@ struct rt2x00_ops { }; /* - * rt2x00 device flags + * rt2x00 state flags */ -enum rt2x00_flags { +enum rt2x00_state_flags { /* - * Device state flags + * Device flags */ DEVICE_STATE_PRESENT, DEVICE_STATE_REGISTERED_HW, @@ -650,41 +658,48 @@ enum rt2x00_flags { DEVICE_STATE_ENABLED_RADIO, DEVICE_STATE_SCANNING, - /* - * Driver requirements - */ - DRIVER_REQUIRE_FIRMWARE, - DRIVER_REQUIRE_BEACON_GUARD, - DRIVER_REQUIRE_ATIM_QUEUE, - DRIVER_REQUIRE_DMA, - DRIVER_REQUIRE_COPY_IV, - DRIVER_REQUIRE_L2PAD, - DRIVER_REQUIRE_TXSTATUS_FIFO, - DRIVER_REQUIRE_TASKLET_CONTEXT, - DRIVER_REQUIRE_SW_SEQNO, - DRIVER_REQUIRE_HT_TX_DESC, - - /* - * Driver features - */ - CONFIG_SUPPORT_HW_BUTTON, - CONFIG_SUPPORT_HW_CRYPTO, - CONFIG_SUPPORT_POWER_LIMIT, - DRIVER_SUPPORT_CONTROL_FILTERS, - DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, - DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, - DRIVER_SUPPORT_LINK_TUNING, - DRIVER_SUPPORT_WATCHDOG, - /* * Driver configuration */ - CONFIG_FRAME_TYPE, - CONFIG_RF_SEQUENCE, - CONFIG_EXTERNAL_LNA_A, - CONFIG_EXTERNAL_LNA_BG, - CONFIG_DOUBLE_ANTENNA, CONFIG_CHANNEL_HT40, + CONFIG_POWERSAVING, +}; + +/* + * rt2x00 capability flags + */ +enum rt2x00_capability_flags { + /* + * Requirements + */ + REQUIRE_FIRMWARE, + REQUIRE_BEACON_GUARD, + REQUIRE_ATIM_QUEUE, + REQUIRE_DMA, + REQUIRE_COPY_IV, + REQUIRE_L2PAD, + REQUIRE_TXSTATUS_FIFO, + REQUIRE_TASKLET_CONTEXT, + REQUIRE_SW_SEQNO, + REQUIRE_HT_TX_DESC, + REQUIRE_PS_AUTOWAKE, + + /* + * Capabilities + */ + CAPABILITY_HW_BUTTON, + CAPABILITY_HW_CRYPTO, + CAPABILITY_POWER_LIMIT, + CAPABILITY_CONTROL_FILTERS, + CAPABILITY_CONTROL_FILTER_PSPOLL, + CAPABILITY_PRE_TBTT_INTERRUPT, + CAPABILITY_LINK_TUNING, + CAPABILITY_FRAME_TYPE, + CAPABILITY_RF_SEQUENCE, + CAPABILITY_EXTERNAL_LNA_A, + CAPABILITY_EXTERNAL_LNA_BG, + CAPABILITY_DOUBLE_ANTENNA, + CAPABILITY_BT_COEXIST, }; /* @@ -733,12 +748,19 @@ struct rt2x00_dev { #endif /* CONFIG_RT2X00_LIB_LEDS */ /* - * Device flags. - * In these flags the current status and some - * of the device capabilities are stored. + * Device state flags. + * In these flags the current status is stored. + * Access to these flags should occur atomically. */ unsigned long flags; + /* + * Device capabiltiy flags. + * In these flags the device/driver capabilities are stored. + * Access to these flags should occur non-atomically. + */ + unsigned long cap_flags; + /* * Device information, Bus IRQ and name (PCI, SoC) */ @@ -854,11 +876,21 @@ struct rt2x00_dev { */ u8 calibration[2]; + /* + * Association id. + */ + u16 aid; + /* * Beacon interval. */ u16 beacon_int; + /** + * Timestamp of last received beacon + */ + unsigned long last_beacon; + /* * Low level statistics which will have * to be kept up to date while device is running. @@ -886,6 +918,11 @@ struct rt2x00_dev { struct work_struct rxdone_work; struct work_struct txdone_work; + /* + * Powersaving work + */ + struct delayed_work autowakeup_work; + /* * Data queue arrays for RX, TX, Beacon and ATIM. */ @@ -905,6 +942,11 @@ struct rt2x00_dev { */ DECLARE_KFIFO_PTR(txstatus_fifo, u32); + /* + * Timer to ensure tx status reports are read (rt2800usb). + */ + struct timer_list txstatus_timer; + /* * Tasklet for processing tx status reports (rt2800pci). */ @@ -1230,6 +1272,10 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop); +int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); +int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); +void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, + u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); /* * Driver allocation handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 9416e36de29e..555180d8f4aa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -100,6 +100,10 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.basic_rates = bss_conf->basic_rates; erp.beacon_int = bss_conf->beacon_int; + /* Update the AID, this is needed for dynamic PS support */ + rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0; + rt2x00dev->last_beacon = bss_conf->timestamp; + /* Update global beacon interval time, this is needed for PS support */ rt2x00dev->beacon_int = bss_conf->beacon_int; @@ -109,15 +113,6 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp, changed); } -static inline -enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant, - enum antenna default_ant) -{ - if (current_ant != ANTENNA_SW_DIVERSITY) - return current_ant; - return (default_ant != ANTENNA_SW_DIVERSITY) ? default_ant : ANTENNA_B; -} - void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, struct antenna_setup config) { @@ -126,19 +121,35 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, struct antenna_setup *active = &rt2x00dev->link.ant.active; /* - * Failsafe: Make sure we are not sending the - * ANTENNA_SW_DIVERSITY state to the driver. - * If that happens, fallback to hardware defaults, - * or our own default. + * When the caller tries to send the SW diversity, + * we must update the ANTENNA_RX_DIVERSITY flag to + * enable the antenna diversity in the link tuner. + * + * Secondly, we must guarentee we never send the + * software antenna diversity command to the driver. */ - if (!(ant->flags & ANTENNA_RX_DIVERSITY)) - config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx); - else if (config.rx == ANTENNA_SW_DIVERSITY) + if (!(ant->flags & ANTENNA_RX_DIVERSITY)) { + if (config.rx == ANTENNA_SW_DIVERSITY) { + ant->flags |= ANTENNA_RX_DIVERSITY; + + if (def->rx == ANTENNA_SW_DIVERSITY) + config.rx = ANTENNA_B; + else + config.rx = def->rx; + } + } else if (config.rx == ANTENNA_SW_DIVERSITY) config.rx = active->rx; - if (!(ant->flags & ANTENNA_TX_DIVERSITY)) - config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx); - else if (config.tx == ANTENNA_SW_DIVERSITY) + if (!(ant->flags & ANTENNA_TX_DIVERSITY)) { + if (config.tx == ANTENNA_SW_DIVERSITY) { + ant->flags |= ANTENNA_TX_DIVERSITY; + + if (def->tx == ANTENNA_SW_DIVERSITY) + config.tx = ANTENNA_B; + else + config.tx = def->tx; + } + } else if (config.tx == ANTENNA_SW_DIVERSITY) config.tx = active->tx; /* @@ -163,12 +174,43 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, rt2x00queue_start_queue(rt2x00dev->rx); } +static u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + int center_channel; + u16 i; + + /* + * Initialize center channel to current channel. + */ + center_channel = spec->channels[conf->channel->hw_value].channel; + + /* + * Adjust center channel to HT40+ and HT40- operation. + */ + if (conf_is_ht40_plus(conf)) + center_channel += 2; + else if (conf_is_ht40_minus(conf)) + center_channel -= (center_channel == 14) ? 1 : 2; + + for (i = 0; i < spec->num_channels; i++) + if (spec->channels[i].channel == center_channel) + return i; + + WARN_ON(1); + return conf->channel->hw_value; +} + void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, unsigned int ieee80211_flags) { struct rt2x00lib_conf libconf; u16 hw_value; + u16 autowake_timeout; + u16 beacon_int; + u16 beacon_diff; memset(&libconf, 0, sizeof(libconf)); @@ -176,10 +218,10 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { if (conf_is_ht40(conf)) { - __set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); + set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); hw_value = rt2x00ht_center_channel(rt2x00dev, conf); } else { - __clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); + clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); hw_value = conf->channel->hw_value; } @@ -192,6 +234,10 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, sizeof(libconf.channel)); } + if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && + (ieee80211_flags & IEEE80211_CONF_CHANGE_PS)) + cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); + /* * Start configuration. */ @@ -204,6 +250,26 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2x00link_reset_tuner(rt2x00dev, false); + if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && + (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) && + (conf->flags & IEEE80211_CONF_PS)) { + beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon; + beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int); + + if (beacon_diff > beacon_int) + beacon_diff = 0; + + autowake_timeout = (conf->max_sleep_period * beacon_int) - beacon_diff; + queue_delayed_work(rt2x00dev->workqueue, + &rt2x00dev->autowakeup_work, + autowake_timeout - 15); + } + + if (conf->flags & IEEE80211_CONF_PS) + set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); + else + clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); + rt2x00dev->curr_band = conf->channel->band; rt2x00dev->curr_freq = conf->channel->center_freq; rt2x00dev->tx_power = conf->power_level; diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 3f5688fbf3f7..1bb9d46077ff 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -52,7 +52,7 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; - if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key) + if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !hw_key) return; __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); @@ -80,7 +80,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev, struct ieee80211_key_conf *key = tx_info->control.hw_key; unsigned int overhead = 0; - if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key) + if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !key) return overhead; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index c92db3264741..78787fcc919e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -63,7 +63,8 @@ struct rt2x00debug_intf { * - driver folder * - driver file * - chipset file - * - device flags file + * - device state flags file + * - device capability flags file * - register folder * - csr offset/value files * - eeprom offset/value files @@ -78,6 +79,7 @@ struct rt2x00debug_intf { struct dentry *driver_entry; struct dentry *chipset_entry; struct dentry *dev_flags; + struct dentry *cap_flags; struct dentry *register_folder; struct dentry *csr_off_entry; struct dentry *csr_val_entry; @@ -553,6 +555,35 @@ static const struct file_operations rt2x00debug_fop_dev_flags = { .llseek = default_llseek, }; +static ssize_t rt2x00debug_read_cap_flags(struct file *file, + char __user *buf, + size_t length, + loff_t *offset) +{ + struct rt2x00debug_intf *intf = file->private_data; + char line[16]; + size_t size; + + if (*offset) + return 0; + + size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->cap_flags); + + if (copy_to_user(buf, line, size)) + return -EFAULT; + + *offset += size; + return size; +} + +static const struct file_operations rt2x00debug_fop_cap_flags = { + .owner = THIS_MODULE, + .read = rt2x00debug_read_cap_flags, + .open = rt2x00debug_file_open, + .release = rt2x00debug_file_release, + .llseek = default_llseek, +}; + static struct dentry *rt2x00debug_create_file_driver(const char *name, struct rt2x00debug_intf *intf, @@ -568,7 +599,6 @@ static struct dentry *rt2x00debug_create_file_driver(const char *name, blob->data = data; data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name); data += sprintf(data, "version:\t%s\n", DRV_VERSION); - data += sprintf(data, "compiled:\t%s %s\n", __DATE__, __TIME__); blob->size = strlen(blob->data); return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob); @@ -653,6 +683,12 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) if (IS_ERR(intf->dev_flags) || !intf->dev_flags) goto exit; + intf->cap_flags = debugfs_create_file("cap_flags", S_IRUSR, + intf->driver_folder, intf, + &rt2x00debug_fop_cap_flags); + if (IS_ERR(intf->cap_flags) || !intf->cap_flags) + goto exit; + intf->register_folder = debugfs_create_dir("register", intf->driver_folder); if (IS_ERR(intf->register_folder) || !intf->register_folder) @@ -706,7 +742,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) intf, &rt2x00debug_fop_queue_stats); #ifdef CONFIG_RT2X00_LIB_CRYPTO - if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) intf->crypto_stats_entry = debugfs_create_file("crypto", S_IRUGO, intf->queue_folder, intf, &rt2x00debug_fop_crypto_stats); @@ -744,6 +780,7 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) debugfs_remove(intf->csr_off_entry); debugfs_remove(intf->register_folder); debugfs_remove(intf->dev_flags); + debugfs_remove(intf->cap_flags); debugfs_remove(intf->chipset_entry); debugfs_remove(intf->driver_entry); debugfs_remove(intf->driver_folder); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 84eb6ad36377..c018d67aab8e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "rt2x00.h" #include "rt2x00lib.h" @@ -70,6 +71,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) */ rt2x00queue_start_queues(rt2x00dev); rt2x00link_start_tuner(rt2x00dev); + rt2x00link_start_agc(rt2x00dev); /* * Start watchdog monitoring. @@ -92,6 +94,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) /* * Stop all queues */ + rt2x00link_stop_agc(rt2x00dev); rt2x00link_stop_tuner(rt2x00dev); rt2x00queue_stop_queues(rt2x00dev); rt2x00queue_flush_queues(rt2x00dev, true); @@ -138,6 +141,16 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) rt2x00dev); } +static void rt2x00lib_autowakeup(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, autowakeup_work.work); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + ERROR(rt2x00dev, "Device failed to wakeup.\n"); + clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); +} + /* * Interrupt context handlers. */ @@ -197,7 +210,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) * here as they will fetch the next beacon directly prior to * transmission. */ - if (test_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_PRE_TBTT_INTERRUPT, &rt2x00dev->cap_flags)) return; /* fetch next beacon */ @@ -222,7 +235,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); void rt2x00lib_dmastart(struct queue_entry *entry) { set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - rt2x00queue_index_inc(entry->queue, Q_INDEX); + rt2x00queue_index_inc(entry, Q_INDEX); } EXPORT_SYMBOL_GPL(rt2x00lib_dmastart); @@ -230,7 +243,7 @@ void rt2x00lib_dmadone(struct queue_entry *entry) { set_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags); clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE); + rt2x00queue_index_inc(entry, Q_INDEX_DMA_DONE); } EXPORT_SYMBOL_GPL(rt2x00lib_dmadone); @@ -268,7 +281,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, /* * Remove L2 padding which was added during */ - if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) + if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags)) rt2x00queue_remove_l2pad(entry->skb, header_length); /* @@ -277,7 +290,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, * mac80211 will expect the same data to be present it the * frame as it was passed to us. */ - if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) rt2x00crypto_tx_insert_iv(entry->skb, header_length); /* @@ -350,10 +363,14 @@ void rt2x00lib_txdone(struct queue_entry *entry, * which would allow the rc algorithm to better decide on * which rates are suitable. */ - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { + if (test_bit(TXDONE_AMPDU, &txdesc->flags) || + tx_info->flags & IEEE80211_TX_CTL_AMPDU) { 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; } if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { @@ -370,7 +387,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, * send the status report back. */ if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) { - if (test_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags)) + if (test_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags)) ieee80211_tx_status(rt2x00dev->hw, entry->skb); else ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb); @@ -385,7 +402,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->ops->lib->clear_entry(entry); - rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); + rt2x00queue_index_inc(entry, Q_INDEX_DONE); /* * If the data queue was below the threshold before the txdone @@ -409,6 +426,77 @@ void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status) } EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo); +static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return NULL; + + if (pos[0] == ie) + return pos; + + pos += 2 + pos[1]; + } + + return NULL; +} + +static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, + struct rxdone_entry_desc *rxdesc) +{ + struct ieee80211_hdr *hdr = (void *) skb->data; + struct ieee80211_tim_ie *tim_ie; + u8 *tim; + u8 tim_len; + bool cam; + + /* If this is not a beacon, or if mac80211 has no powersaving + * configured, or if the device is already in powersaving mode + * we can exit now. */ + if (likely(!ieee80211_is_beacon(hdr->frame_control) || + !(rt2x00dev->hw->conf.flags & IEEE80211_CONF_PS))) + return; + + /* min. beacon length + FCS_LEN */ + if (skb->len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (!(rxdesc->dev_flags & RXDONE_MY_BSS) || + !rt2x00dev->aid) + return; + + rt2x00dev->last_beacon = jiffies; + + tim = rt2x00lib_find_ie(skb->data, skb->len - FCS_LEN, WLAN_EID_TIM); + if (!tim) + return; + + if (tim[1] < sizeof(*tim_ie)) + return; + + tim_len = tim[1]; + tim_ie = (struct ieee80211_tim_ie *) &tim[2]; + + /* Check whenever the PHY can be turned off again. */ + + /* 1. What about buffered unicast traffic for our AID? */ + cam = ieee80211_check_tim(tim_ie, tim_len, rt2x00dev->aid); + + /* 2. Maybe the AP wants to send multicast/broadcast data? */ + cam |= (tim_ie->bitmap_ctrl & 0x01); + + if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) + rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, + IEEE80211_CONF_CHANGE_PS); +} + static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, struct rxdone_entry_desc *rxdesc) { @@ -511,8 +599,6 @@ void rt2x00lib_rxdone(struct queue_entry *entry) (rxdesc.size > header_length) && (rxdesc.dev_flags & RXDONE_L2PAD)) rt2x00queue_remove_l2pad(entry->skb, header_length); - else - rt2x00queue_align_payload(entry->skb, header_length); /* Trim buffer to correct size */ skb_trim(entry->skb, rxdesc.size); @@ -525,6 +611,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry) rxdesc.rate_mode == RATE_MODE_HT_GREENFIELD) rxdesc.flags |= RX_FLAG_HT; + /* + * Check if this is a beacon, and more frames have been + * buffered while we were in powersaving mode. + */ + rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc); + /* * Update extra components */ @@ -554,7 +646,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry) submit_entry: entry->flags = 0; - rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); + rt2x00queue_index_inc(entry, Q_INDEX_DONE); if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00dev->ops->lib->clear_entry(entry); @@ -801,23 +893,28 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Take TX headroom required for alignment into account. */ - if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) + if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags)) rt2x00dev->hw->extra_tx_headroom += RT2X00_L2PAD_SIZE; - else if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) + else if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE; /* * Allocate tx status FIFO for driver use. */ - if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) { + if (test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags)) { /* - * Allocate txstatus fifo and tasklet, we use a size of 512 - * for the kfifo which is big enough to store 512/4=128 tx - * status reports. In the worst case (tx status for all tx - * queues gets reported before we've got a chance to handle - * them) 24*4=384 tx status reports need to be cached. + * Allocate the txstatus fifo. In the worst case the tx + * status fifo has to hold the tx status of all entries + * in all tx queues. Hence, calculate the kfifo size as + * tx_queues * entry_num and round up to the nearest + * power of 2. */ - status = kfifo_alloc(&rt2x00dev->txstatus_fifo, 512, + int kfifo_size = + roundup_pow_of_two(rt2x00dev->ops->tx_queues * + rt2x00dev->ops->tx->entry_num * + sizeof(u32)); + + status = kfifo_alloc(&rt2x00dev->txstatus_fifo, kfifo_size, GFP_KERNEL); if (status) return status; @@ -1007,6 +1104,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) } INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); + INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); /* * Let the driver probe the device to detect the capabilities. @@ -1063,6 +1161,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) */ cancel_work_sync(&rt2x00dev->intf_work); if (rt2x00_is_usb(rt2x00dev)) { + del_timer_sync(&rt2x00dev->txstatus_timer); cancel_work_sync(&rt2x00dev->rxdone_work); cancel_work_sync(&rt2x00dev->txdone_work); } diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c index be0ff78c1b16..f316aad30612 100644 --- a/drivers/net/wireless/rt2x00/rt2x00firmware.c +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c @@ -99,7 +99,7 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) { int retval; - if (!test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) + if (!test_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags)) return 0; if (!rt2x00dev->fw) { diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c deleted file mode 100644 index ae1219dffaae..000000000000 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - Copyright (C) 2004 - 2009 Ivo van Doorn - - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - Module: rt2x00lib - Abstract: rt2x00 HT specific routines. - */ - -#include -#include - -#include "rt2x00.h" -#include "rt2x00lib.h" - -void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, - struct txentry_desc *txdesc, - const struct rt2x00_rate *hwrate) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); - struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; - - if (tx_info->control.sta) - txdesc->u.ht.mpdu_density = - tx_info->control.sta->ht_cap.ampdu_density; - - txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ - - txdesc->u.ht.stbc = - (tx_info->flags & IEEE80211_TX_CTL_STBC) >> IEEE80211_TX_CTL_STBC_SHIFT; - - /* - * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the - * mcs rate to be used - */ - if (txrate->flags & IEEE80211_TX_RC_MCS) { - txdesc->u.ht.mcs = txrate->idx; - - /* - * MIMO PS should be set to 1 for STA's using dynamic SM PS - * when using more then one tx stream (>MCS7). - */ - if (tx_info->control.sta && txdesc->u.ht.mcs > 7 && - ((tx_info->control.sta->ht_cap.cap & - IEEE80211_HT_CAP_SM_PS) >> - IEEE80211_HT_CAP_SM_PS_SHIFT) == - WLAN_HT_CAP_SM_PS_DYNAMIC) - __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); - } else { - txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); - if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - txdesc->u.ht.mcs |= 0x08; - } - - /* - * This frame is eligible for an AMPDU, however, don't aggregate - * frames that are intended to probe a specific tx rate. - */ - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU && - !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) - __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags); - - /* - * Set 40Mhz mode if necessary (for legacy rates this will - * duplicate the frame to both channels). - */ - if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH || - txrate->flags & IEEE80211_TX_RC_DUP_DATA) - __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags); - if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) - __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags); - - /* - * Determine IFS values - * - Use TXOP_BACKOFF for management frames - * - Use TXOP_SIFS for fragment bursts - * - Use TXOP_HTTXOP for everything else - * - * Note: rt2800 devices won't use CTS protection (if used) - * for frames not transmitted with TXOP_HTTXOP - */ - if (ieee80211_is_mgmt(hdr->frame_control)) - txdesc->u.ht.txop = TXOP_BACKOFF; - else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)) - txdesc->u.ht.txop = TXOP_SIFS; - else - txdesc->u.ht.txop = TXOP_HTTXOP; -} - -u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf) -{ - struct hw_mode_spec *spec = &rt2x00dev->spec; - int center_channel; - u16 i; - - /* - * Initialize center channel to current channel. - */ - center_channel = spec->channels[conf->channel->hw_value].channel; - - /* - * Adjust center channel to HT40+ and HT40- operation. - */ - if (conf_is_ht40_plus(conf)) - center_channel += 2; - else if (conf_is_ht40_minus(conf)) - center_channel -= (center_channel == 14) ? 1 : 2; - - for (i = 0; i < spec->num_channels; i++) - if (spec->channels[i].channel == center_channel) - return i; - - WARN_ON(1); - return conf->channel->hw_value; -} diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 2d94cbaf5f4a..322cc4f3de5d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -32,6 +32,7 @@ */ #define WATCHDOG_INTERVAL round_jiffies_relative(HZ) #define LINK_TUNE_INTERVAL round_jiffies_relative(HZ) +#define AGC_INTERVAL round_jiffies_relative(4 * HZ) /* * rt2x00_rate: Per rate device information @@ -118,16 +119,6 @@ void rt2x00queue_free_skb(struct queue_entry *entry); */ void rt2x00queue_align_frame(struct sk_buff *skb); -/** - * rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary - * @skb: The skb to align - * @header_length: Length of 802.11 header - * - * Align the 802.11 payload to a 4-byte boundary, this could - * mean the header is not aligned properly though. - */ -void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length); - /** * rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary * @skb: The skb to align @@ -184,14 +175,14 @@ int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev, /** * rt2x00queue_index_inc - Index incrementation function - * @queue: Queue (&struct data_queue) to perform the action on. + * @entry: Queue entry (&struct queue_entry) to perform the action on. * @index: Index type (&enum queue_index) to perform the action on. * - * This function will increase the requested index on the queue, + * This function will increase the requested index on the entry's queue, * it will grab the appropriate locks and handle queue overflow events by * resetting the index to the start of the queue. */ -void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); +void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index); /** * rt2x00queue_init_queues - Initialize all data queues @@ -280,6 +271,18 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev); */ void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev); +/** + * rt2x00link_start_agc - Start periodic gain calibration + * @rt2x00dev: Pointer to &struct rt2x00_dev. + */ +void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev); + +/** + * rt2x00link_stop_agc - Stop periodic gain calibration + * @rt2x00dev: Pointer to &struct rt2x00_dev. + */ +void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev); + /** * rt2x00link_register - Initialize link tuning & watchdog functionality * @rt2x00dev: Pointer to &struct rt2x00_dev. @@ -384,42 +387,18 @@ static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, } #endif /* CONFIG_RT2X00_LIB_CRYPTO */ -/* - * HT handlers. - */ -#ifdef CONFIG_RT2X00_LIB_HT -void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, - struct txentry_desc *txdesc, - const struct rt2x00_rate *hwrate); - -u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf); -#else -static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, - struct txentry_desc *txdesc, - const struct rt2x00_rate *hwrate) -{ -} - -static inline u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf) -{ - return conf->channel->hw_value; -} -#endif /* CONFIG_RT2X00_LIB_HT */ - /* * RFkill handlers. */ static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { - if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags)) wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy); } static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) { - if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags)) wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy); } diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 29abfdeb0b65..ea10b0068f82 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -192,17 +192,7 @@ static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) /* * Determine if software diversity is enabled for * either the TX or RX antenna (or both). - * Always perform this check since within the link - * tuner interval the configuration might have changed. */ - ant->flags &= ~ANTENNA_RX_DIVERSITY; - ant->flags &= ~ANTENNA_TX_DIVERSITY; - - if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) - ant->flags |= ANTENNA_RX_DIVERSITY; - if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) - ant->flags |= ANTENNA_TX_DIVERSITY; - if (!(ant->flags & ANTENNA_RX_DIVERSITY) && !(ant->flags & ANTENNA_TX_DIVERSITY)) { ant->flags = 0; @@ -383,7 +373,7 @@ static void rt2x00link_tuner(struct work_struct *work) * do not support link tuning at all, while other devices can disable * the feature from the EEPROM. */ - if (test_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags)) rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count); /* @@ -413,12 +403,11 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev) { struct link *link = &rt2x00dev->link; - if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || - !test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags)) - return; - - ieee80211_queue_delayed_work(rt2x00dev->hw, - &link->watchdog_work, WATCHDOG_INTERVAL); + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + rt2x00dev->ops->lib->watchdog) + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->watchdog_work, + WATCHDOG_INTERVAL); } void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev) @@ -447,8 +436,46 @@ static void rt2x00link_watchdog(struct work_struct *work) WATCHDOG_INTERVAL); } +void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev) +{ + struct link *link = &rt2x00dev->link; + + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + rt2x00dev->ops->lib->gain_calibration) + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->agc_work, + AGC_INTERVAL); +} + +void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev) +{ + cancel_delayed_work_sync(&rt2x00dev->link.agc_work); +} + +static void rt2x00link_agc(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, link.agc_work.work); + struct link *link = &rt2x00dev->link; + + /* + * When the radio is shutting down we should + * immediately cease the watchdog monitoring. + */ + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + rt2x00dev->ops->lib->gain_calibration(rt2x00dev); + + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->agc_work, + AGC_INTERVAL); +} + void rt2x00link_register(struct rt2x00_dev *rt2x00dev) { + INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc); INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog); INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner); } diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 661c6baad2b9..93bec140e598 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -119,7 +119,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * Use the ATIM queue if appropriate and present. */ if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && - test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) + test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) qid = QID_ATIM; queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); @@ -158,7 +158,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return; exit_fail: - ieee80211_stop_queue(rt2x00dev->hw, qid); + rt2x00queue_pause_queue(queue); dev_kfree_skb_any(skb); } EXPORT_SYMBOL_GPL(rt2x00mac_tx); @@ -411,11 +411,11 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, * of different types, but has no a separate filter for PS Poll frames, * FIF_CONTROL flag implies FIF_PSPOLL. */ - if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags)) { + if (!test_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags)) { if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL) *total_flags |= FIF_CONTROL | FIF_PSPOLL; } - if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags)) { + if (!test_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags)) { if (*total_flags & FIF_CONTROL) *total_flags |= FIF_PSPOLL; } @@ -496,7 +496,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; - else if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + else if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) return -EOPNOTSUPP; else if (key->keylen > 32) return -ENOSPC; @@ -562,7 +562,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_set_key); void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - __set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); + set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); rt2x00link_stop_tuner(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start); @@ -570,7 +570,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start); void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - __clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); + clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); rt2x00link_start_tuner(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_complete); @@ -737,3 +737,84 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop) rt2x00queue_flush_queue(queue, drop); } EXPORT_SYMBOL_GPL(rt2x00mac_flush); + +int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct link_ant *ant = &rt2x00dev->link.ant; + struct antenna_setup *def = &rt2x00dev->default_ant; + struct antenna_setup setup; + + // The antenna value is not supposed to be 0, + // or exceed the maximum number of antenna's. + if (!tx_ant || (tx_ant & ~3) || !rx_ant || (rx_ant & ~3)) + return -EINVAL; + + // When the client tried to configure the antenna to or from + // diversity mode, we must reset the default antenna as well + // as that controls the diversity switch. + if (ant->flags & ANTENNA_TX_DIVERSITY && tx_ant != 3) + ant->flags &= ~ANTENNA_TX_DIVERSITY; + if (ant->flags & ANTENNA_RX_DIVERSITY && rx_ant != 3) + ant->flags &= ~ANTENNA_RX_DIVERSITY; + + // If diversity is being enabled, check if we need hardware + // or software diversity. In the latter case, reset the value, + // and make sure we update the antenna flags to have the + // link tuner pick up the diversity tuning. + if (tx_ant == 3 && def->tx == ANTENNA_SW_DIVERSITY) { + tx_ant = ANTENNA_SW_DIVERSITY; + ant->flags |= ANTENNA_TX_DIVERSITY; + } + + if (rx_ant == 3 && def->rx == ANTENNA_SW_DIVERSITY) { + rx_ant = ANTENNA_SW_DIVERSITY; + ant->flags |= ANTENNA_RX_DIVERSITY; + } + + setup.tx = tx_ant; + setup.rx = rx_ant; + + rt2x00lib_config_antenna(rt2x00dev, setup); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_set_antenna); + +int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct link_ant *ant = &rt2x00dev->link.ant; + struct antenna_setup *active = &rt2x00dev->link.ant.active; + + // When software diversity is active, we must report this to the + // client and not the current active antenna state. + if (ant->flags & ANTENNA_TX_DIVERSITY) + *tx_ant = ANTENNA_HW_DIVERSITY; + else + *tx_ant = active->tx; + + if (ant->flags & ANTENNA_RX_DIVERSITY) + *rx_ant = ANTENNA_HW_DIVERSITY; + else + *rx_ant = active->rx; + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_get_antenna); + +void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, + u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + + tx_queue_for_each(rt2x00dev, queue) { + *tx += queue->length; + *tx_max += queue->limit; + } + + *rx = rt2x00dev->rx->length; + *rx_max = rt2x00dev->rx->limit; +} +EXPORT_SYMBOL_GPL(rt2x00mac_get_ringparam); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 4dd82b0b0520..17148bb24426 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -60,14 +60,15 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); -void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) +bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue = rt2x00dev->rx; struct queue_entry *entry; struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; + int max_rx = 16; - while (1) { + while (--max_rx) { entry = rt2x00queue_get_entry(queue, Q_INDEX); entry_priv = entry->priv_data; @@ -93,9 +94,20 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) */ rt2x00lib_rxdone(entry); } + + return !max_rx; } EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); +void rt2x00pci_flush_queue(struct data_queue *queue, bool drop) +{ + unsigned int i; + + for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++) + msleep(10); +} +EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue); + /* * Device initialization handlers. */ @@ -239,9 +251,8 @@ static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev) return -ENOMEM; } -int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) +int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops) { - struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data; struct ieee80211_hw *hw; struct rt2x00_dev *rt2x00dev; int retval; diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 746ce8fe8cf4..e2c99f2b9a14 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -101,8 +101,21 @@ struct queue_entry_priv_pci { /** * rt2x00pci_rxdone - Handle RX done events * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * + * Returns true if there are still rx frames pending and false if all + * pending rx frames were processed. */ -void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); +bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); + +/** + * rt2x00pci_flush_queue - Flush data queue + * @queue: Data queue to stop + * @drop: True to drop all pending frames. + * + * This will wait for a maximum of 100ms, waiting for the queues + * to become empty. + */ +void rt2x00pci_flush_queue(struct data_queue *queue, bool drop); /* * Device initialization handlers. @@ -113,7 +126,7 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev); /* * PCI driver handlers. */ -int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id); +int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops); void rt2x00pci_remove(struct pci_dev *pci_dev); #ifdef CONFIG_PM int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 4358051bfe1a..ab8c16f8bcaf 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -60,7 +60,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry) * at least 8 bytes bytes available in headroom for IV/EIV * and 8 bytes for ICV data as tailroon. */ - if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) { head_size += 8; tail_size += 8; } @@ -86,7 +86,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry) memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->entry = entry; - if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) { + if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) { skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len, @@ -148,19 +148,6 @@ void rt2x00queue_align_frame(struct sk_buff *skb) skb_trim(skb, frame_length); } -void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length) -{ - unsigned int frame_length = skb->len; - unsigned int align = ALIGN_SIZE(skb, header_length); - - if (!align) - return; - - skb_push(skb, align); - memmove(skb->data, skb->data + align, frame_length); - skb_trim(skb, frame_length); -} - void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) { unsigned int payload_length = skb->len - header_length; @@ -226,7 +213,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); - if (!test_bit(DRIVER_REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->flags)) + if (!test_bit(REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->cap_flags)) return; /* @@ -315,6 +302,85 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry, } } +static void rt2x00queue_create_tx_descriptor_ht(struct queue_entry *entry, + struct txentry_desc *txdesc, + const struct rt2x00_rate *hwrate) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; + + if (tx_info->control.sta) + txdesc->u.ht.mpdu_density = + tx_info->control.sta->ht_cap.ampdu_density; + + 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 + */ + if (txrate->flags & IEEE80211_TX_RC_MCS) { + txdesc->u.ht.mcs = txrate->idx; + + /* + * MIMO PS should be set to 1 for STA's using dynamic SM PS + * when using more then one tx stream (>MCS7). + */ + if (tx_info->control.sta && txdesc->u.ht.mcs > 7 && + ((tx_info->control.sta->ht_cap.cap & + IEEE80211_HT_CAP_SM_PS) >> + IEEE80211_HT_CAP_SM_PS_SHIFT) == + WLAN_HT_CAP_SM_PS_DYNAMIC) + __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); + } else { + txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); + if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + txdesc->u.ht.mcs |= 0x08; + } + + /* + * This frame is eligible for an AMPDU, however, don't aggregate + * frames that are intended to probe a specific tx rate. + */ + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU && + !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) + __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags); + + /* + * Set 40Mhz mode if necessary (for legacy rates this will + * duplicate the frame to both channels). + */ + if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH || + txrate->flags & IEEE80211_TX_RC_DUP_DATA) + __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags); + if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) + __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags); + + /* + * Determine IFS values + * - Use TXOP_BACKOFF for management frames except beacons + * - Use TXOP_SIFS for fragment bursts + * - Use TXOP_HTTXOP for everything else + * + * Note: rt2800 devices won't use CTS protection (if used) + * for frames not transmitted with TXOP_HTTXOP + */ + if (ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_beacon(hdr->frame_control)) + txdesc->u.ht.txop = TXOP_BACKOFF; + else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)) + txdesc->u.ht.txop = TXOP_SIFS; + else + txdesc->u.ht.txop = TXOP_HTTXOP; +} + static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, struct txentry_desc *txdesc) { @@ -409,8 +475,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, rt2x00crypto_create_tx_descriptor(entry, txdesc); rt2x00queue_create_tx_descriptor_seq(entry, txdesc); - if (test_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags)) - rt2x00ht_create_tx_descriptor(entry, txdesc, hwrate); + if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags)) + rt2x00queue_create_tx_descriptor_ht(entry, txdesc, hwrate); else rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate); } @@ -449,7 +515,7 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry, /* * Map the skb to DMA. */ - if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) + if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) rt2x00queue_map_txskb(entry); return 0; @@ -495,8 +561,11 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, struct skb_frame_desc *skbdesc; u8 rate_idx, rate_flags; - if (unlikely(rt2x00queue_full(queue))) + if (unlikely(rt2x00queue_full(queue))) { + ERROR(queue->rt2x00dev, + "Dropping frame due to full tx queue %d.\n", queue->qid); return -ENOBUFS; + } if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))) { @@ -539,7 +608,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, */ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { - if (test_bit(DRIVER_REQUIRE_COPY_IV, &queue->rt2x00dev->flags)) + if (test_bit(REQUIRE_COPY_IV, &queue->rt2x00dev->cap_flags)) rt2x00crypto_tx_copy_iv(skb, &txdesc); else rt2x00crypto_tx_remove_iv(skb, &txdesc); @@ -553,9 +622,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, * PCI and USB devices, while header alignment only is valid * for PCI devices. */ - if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) + if (test_bit(REQUIRE_L2PAD, &queue->rt2x00dev->cap_flags)) rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length); - else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) + else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags)) rt2x00queue_align_frame(entry->skb); /* @@ -571,7 +640,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, set_bit(ENTRY_DATA_PENDING, &entry->flags); - rt2x00queue_index_inc(queue, Q_INDEX); + rt2x00queue_index_inc(entry, Q_INDEX); rt2x00queue_write_tx_descriptor(entry, &txdesc); rt2x00queue_kick_tx_queue(queue, &txdesc); @@ -660,10 +729,12 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, return ret; } -void rt2x00queue_for_each_entry(struct data_queue *queue, +bool rt2x00queue_for_each_entry(struct data_queue *queue, enum queue_index start, enum queue_index end, - void (*fn)(struct queue_entry *entry)) + void *data, + bool (*fn)(struct queue_entry *entry, + void *data)) { unsigned long irqflags; unsigned int index_start; @@ -674,7 +745,7 @@ void rt2x00queue_for_each_entry(struct data_queue *queue, ERROR(queue->rt2x00dev, "Entry requested from invalid index range (%d - %d)\n", start, end); - return; + return true; } /* @@ -693,15 +764,23 @@ void rt2x00queue_for_each_entry(struct data_queue *queue, * send out all frames in the correct order. */ if (index_start < index_end) { - for (i = index_start; i < index_end; i++) - fn(&queue->entries[i]); + for (i = index_start; i < index_end; i++) { + if (fn(&queue->entries[i], data)) + return true; + } } else { - for (i = index_start; i < queue->limit; i++) - fn(&queue->entries[i]); + for (i = index_start; i < queue->limit; i++) { + if (fn(&queue->entries[i], data)) + return true; + } - for (i = 0; i < index_end; i++) - fn(&queue->entries[i]); + for (i = 0; i < index_end; i++) { + if (fn(&queue->entries[i], data)) + return true; + } } + + return false; } EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry); @@ -727,8 +806,9 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, } EXPORT_SYMBOL_GPL(rt2x00queue_get_entry); -void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) +void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index) { + struct data_queue *queue = entry->queue; unsigned long irqflags; if (unlikely(index >= Q_INDEX_MAX)) { @@ -743,7 +823,7 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) if (queue->index[index] >= queue->limit) queue->index[index] = 0; - queue->last_action[index] = jiffies; + entry->last_action = jiffies; if (index == Q_INDEX) { queue->length++; @@ -848,7 +928,6 @@ EXPORT_SYMBOL_GPL(rt2x00queue_stop_queue); void rt2x00queue_flush_queue(struct data_queue *queue, bool drop) { - unsigned int i; bool started; bool tx_queue = (queue->qid == QID_AC_VO) || @@ -883,20 +962,12 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop) } /* - * Check if driver supports flushing, we can only guarantee - * full support for flushing if the driver is able - * to cancel all pending frames (drop = true). + * Check if driver supports flushing, if that is the case we can + * defer the flushing to the driver. Otherwise we must use the + * alternative which just waits for the queue to become empty. */ - if (drop && queue->rt2x00dev->ops->lib->flush_queue) - queue->rt2x00dev->ops->lib->flush_queue(queue); - - /* - * When we don't want to drop any frames, or when - * the driver doesn't fully flush the queue correcly, - * we must wait for the queue to become empty. - */ - for (i = 0; !rt2x00queue_empty(queue) && i < 100; i++) - msleep(10); + if (likely(queue->rt2x00dev->ops->lib->flush_queue)) + queue->rt2x00dev->ops->lib->flush_queue(queue, drop); /* * The queue flush has failed... @@ -969,10 +1040,8 @@ static void rt2x00queue_reset(struct data_queue *queue) queue->count = 0; queue->length = 0; - for (i = 0; i < Q_INDEX_MAX; i++) { + for (i = 0; i < Q_INDEX_MAX; i++) queue->index[i] = 0; - queue->last_action[i] = jiffies; - } spin_unlock_irqrestore(&queue->index_lock, irqflags); } @@ -1079,7 +1148,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev) if (status) goto exit; - if (test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) { + if (test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) { status = rt2x00queue_alloc_entries(rt2x00dev->atim, rt2x00dev->ops->atim); if (status) @@ -1131,7 +1200,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; enum data_queue_qid qid; unsigned int req_atim = - !!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); + !!test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); /* * We need the following queues: diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 217861f8d95f..167d45873dca 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -217,6 +217,7 @@ enum txdone_entry_desc_flags { TXDONE_FALLBACK, TXDONE_FAILURE, TXDONE_EXCESSIVE_RETRY, + TXDONE_AMPDU, }; /** @@ -363,6 +364,7 @@ enum queue_entry_flags { * struct queue_entry: Entry inside the &struct data_queue * * @flags: Entry flags, see &enum queue_entry_flags. + * @last_action: Timestamp of last change. * @queue: The data queue (&struct data_queue) to which this entry belongs. * @skb: The buffer which is currently being transmitted (for TX queue), * or used to directly receive data in (for RX queue). @@ -372,6 +374,7 @@ enum queue_entry_flags { */ struct queue_entry { unsigned long flags; + unsigned long last_action; struct data_queue *queue; @@ -462,7 +465,6 @@ struct data_queue { unsigned short threshold; unsigned short length; unsigned short index[Q_INDEX_MAX]; - unsigned long last_action[Q_INDEX_MAX]; unsigned short txop; unsigned short aifs; @@ -579,16 +581,22 @@ struct data_queue_desc { * @queue: Pointer to @data_queue * @start: &enum queue_index Pointer to start index * @end: &enum queue_index Pointer to end index + * @data: Data to pass to the callback function * @fn: The function to call for each &struct queue_entry * * This will walk through all entries in the queue, in chronological * order. This means it will start at the current @start pointer * and will walk through the queue until it reaches the @end pointer. + * + * If fn returns true for an entry rt2x00queue_for_each_entry will stop + * processing and return true as well. */ -void rt2x00queue_for_each_entry(struct data_queue *queue, +bool rt2x00queue_for_each_entry(struct data_queue *queue, enum queue_index start, enum queue_index end, - void (*fn)(struct queue_entry *entry)); + void *data, + bool (*fn)(struct queue_entry *entry, + void *data)); /** * rt2x00queue_empty - Check if the queue is empty. @@ -628,22 +636,24 @@ static inline int rt2x00queue_threshold(struct data_queue *queue) /** * rt2x00queue_status_timeout - Check if a timeout occurred for STATUS reports - * @queue: Queue to check. + * @entry: Queue entry to check. */ -static inline int rt2x00queue_status_timeout(struct data_queue *queue) +static inline int rt2x00queue_status_timeout(struct queue_entry *entry) { - return time_after(queue->last_action[Q_INDEX_DMA_DONE], - queue->last_action[Q_INDEX_DONE] + (HZ / 10)); + if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) + return false; + return time_after(jiffies, entry->last_action + msecs_to_jiffies(100)); } /** - * rt2x00queue_timeout - Check if a timeout occurred for DMA transfers - * @queue: Queue to check. + * rt2x00queue_dma_timeout - Check if a timeout occurred for DMA transfers + * @entry: Queue entry to check. */ -static inline int rt2x00queue_dma_timeout(struct data_queue *queue) +static inline int rt2x00queue_dma_timeout(struct queue_entry *entry) { - return time_after(queue->last_action[Q_INDEX], - queue->last_action[Q_INDEX_DMA_DONE] + (HZ / 10)); + if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + return false; + return time_after(jiffies, entry->last_action + msecs_to_jiffies(100)); } /** diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 36f388f97d65..8f90f6268077 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -165,6 +165,59 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read); + +struct rt2x00_async_read_data { + __le32 reg; + struct usb_ctrlrequest cr; + struct rt2x00_dev *rt2x00dev; + bool (*callback)(struct rt2x00_dev *, int, u32); +}; + +static void rt2x00usb_register_read_async_cb(struct urb *urb) +{ + struct rt2x00_async_read_data *rd = urb->context; + if (rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg))) { + if (usb_submit_urb(urb, GFP_ATOMIC) < 0) + kfree(rd); + } else + kfree(rd); +} + +void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + bool (*callback)(struct rt2x00_dev*, int, u32)) +{ + struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); + struct urb *urb; + struct rt2x00_async_read_data *rd; + + rd = kmalloc(sizeof(*rd), GFP_ATOMIC); + if (!rd) + return; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + kfree(rd); + return; + } + + rd->rt2x00dev = rt2x00dev; + rd->callback = callback; + rd->cr.bRequestType = USB_VENDOR_REQUEST_IN; + rd->cr.bRequest = USB_MULTI_READ; + rd->cr.wValue = 0; + rd->cr.wIndex = cpu_to_le16(offset); + rd->cr.wLength = cpu_to_le16(sizeof(u32)); + + usb_fill_control_urb(urb, usb_dev, usb_rcvctrlpipe(usb_dev, 0), + (unsigned char *)(&rd->cr), &rd->reg, sizeof(rd->reg), + rt2x00usb_register_read_async_cb, rd); + if (usb_submit_urb(urb, GFP_ATOMIC) < 0) + kfree(rd); + usb_free_urb(urb); +} +EXPORT_SYMBOL_GPL(rt2x00usb_register_read_async); + /* * TX data handlers. */ @@ -212,6 +265,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; + if (rt2x00dev->ops->lib->tx_dma_done) + rt2x00dev->ops->lib->tx_dma_done(entry); + /* * Report the frame as DMA done */ @@ -227,10 +283,12 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * Schedule the delayed work for reading the TX status * from the device. */ - queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); + if (!test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags) || + !kfifo_is_empty(&rt2x00dev->txstatus_fifo)) + queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } -static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) +static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); @@ -240,7 +298,7 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags) || test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) - return; + return false; /* * USB devices cannot blindly pass the skb->len as the @@ -261,6 +319,8 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); rt2x00lib_dmadone(entry); } + + return false; } /* @@ -323,7 +383,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work); } -static void rt2x00usb_kick_rx_entry(struct queue_entry *entry) +static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void* data) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); @@ -332,7 +392,7 @@ static void rt2x00usb_kick_rx_entry(struct queue_entry *entry) if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) - return; + return false; rt2x00lib_dmastart(entry); @@ -348,6 +408,8 @@ static void rt2x00usb_kick_rx_entry(struct queue_entry *entry) set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); rt2x00lib_dmadone(entry); } + + return false; } void rt2x00usb_kick_queue(struct data_queue *queue) @@ -358,12 +420,18 @@ void rt2x00usb_kick_queue(struct data_queue *queue) case QID_AC_BE: case QID_AC_BK: if (!rt2x00queue_empty(queue)) - rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, + rt2x00queue_for_each_entry(queue, + Q_INDEX_DONE, + Q_INDEX, + NULL, rt2x00usb_kick_tx_entry); break; case QID_RX: if (!rt2x00queue_full(queue)) - rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, + rt2x00queue_for_each_entry(queue, + Q_INDEX_DONE, + Q_INDEX, + NULL, rt2x00usb_kick_rx_entry); break; default: @@ -372,14 +440,14 @@ void rt2x00usb_kick_queue(struct data_queue *queue) } EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue); -static void rt2x00usb_flush_entry(struct queue_entry *entry) +static bool rt2x00usb_flush_entry(struct queue_entry *entry, void* data) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) - return; + return false; usb_kill_urb(entry_priv->urb); @@ -387,17 +455,20 @@ static void rt2x00usb_flush_entry(struct queue_entry *entry) * Kill guardian urb (if required by driver). */ if ((entry->queue->qid == QID_BEACON) && - (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))) + (test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))) usb_kill_urb(bcn_priv->guardian_urb); + + return false; } -void rt2x00usb_flush_queue(struct data_queue *queue) +void rt2x00usb_flush_queue(struct data_queue *queue, bool drop) { struct work_struct *completion; unsigned int i; - rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, - rt2x00usb_flush_entry); + if (drop) + rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL, + rt2x00usb_flush_entry); /* * Obtain the queue completion handler @@ -416,7 +487,7 @@ void rt2x00usb_flush_queue(struct data_queue *queue) return; } - for (i = 0; i < 20; i++) { + for (i = 0; i < 10; i++) { /* * Check if the driver is already done, otherwise we * have to sleep a little while to give the driver/hw @@ -456,15 +527,31 @@ static void rt2x00usb_watchdog_tx_status(struct data_queue *queue) queue_work(queue->rt2x00dev->workqueue, &queue->rt2x00dev->txdone_work); } +static int rt2x00usb_status_timeout(struct data_queue *queue) +{ + struct queue_entry *entry; + + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + return rt2x00queue_status_timeout(entry); +} + +static int rt2x00usb_dma_timeout(struct data_queue *queue) +{ + struct queue_entry *entry; + + entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE); + return rt2x00queue_dma_timeout(entry); +} + void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; tx_queue_for_each(rt2x00dev, queue) { if (!rt2x00queue_empty(queue)) { - if (rt2x00queue_dma_timeout(queue)) + if (rt2x00usb_dma_timeout(queue)) rt2x00usb_watchdog_tx_dma(queue); - if (rt2x00queue_status_timeout(queue)) + if (rt2x00usb_status_timeout(queue)) rt2x00usb_watchdog_tx_status(queue); } } @@ -489,7 +576,7 @@ void rt2x00usb_clear_entry(struct queue_entry *entry) entry->flags = 0; if (entry->queue->qid == QID_RX) - rt2x00usb_kick_rx_entry(entry); + rt2x00usb_kick_rx_entry(entry, NULL); } EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); @@ -583,7 +670,7 @@ static int rt2x00usb_alloc_entries(struct data_queue *queue) * then we are done. */ if (queue->qid != QID_BEACON || - !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) + !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)) return 0; for (i = 0; i < queue->limit; i++) { @@ -618,7 +705,7 @@ static void rt2x00usb_free_entries(struct data_queue *queue) * then we are done. */ if (queue->qid != QID_BEACON || - !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) + !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)) return; for (i = 0; i < queue->limit; i++) { @@ -707,10 +794,9 @@ static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev) } int rt2x00usb_probe(struct usb_interface *usb_intf, - const struct usb_device_id *id) + const struct rt2x00_ops *ops) { struct usb_device *usb_dev = interface_to_usbdev(usb_intf); - struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_info; struct ieee80211_hw *hw; struct rt2x00_dev *rt2x00dev; int retval; @@ -735,6 +821,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone); INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone); + init_timer(&rt2x00dev->txstatus_timer); retval = rt2x00usb_alloc_reg(rt2x00dev); if (retval) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index e11c759ac9ed..323ca7b2b095 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -34,12 +34,6 @@ interface_to_usbdev(intf); \ }) -/* - * This variable should be used with the - * usb_driver structure initialization. - */ -#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) - /* * For USB vendor requests we need to pass a timeout * time in ms, for this we use the REGISTER_TIMEOUT, @@ -345,6 +339,23 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, const struct rt2x00_field32 field, u32 *reg); +/** + * rt2x00usb_register_read_async - Asynchronously read 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @callback: Functon to call when read completes. + * + * Submit a control URB to read a 32bit register. This safe to + * be called from atomic context. The callback will be called + * when the URB completes. Otherwise the function is similar + * to rt2x00usb_register_read(). + * When the callback function returns false, the memory will be cleaned up, + * when it returns true, the urb will be fired again. + */ +void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + bool (*callback)(struct rt2x00_dev*, int, u32)); + /* * Radio handlers */ @@ -389,11 +400,13 @@ void rt2x00usb_kick_queue(struct data_queue *queue); /** * rt2x00usb_flush_queue - Flush data queue * @queue: Data queue to stop + * @drop: True to drop all pending frames. * - * This will walk through all entries of the queue and kill all - * URB's which were send to the device. + * This will walk through all entries of the queue and will optionally + * kill all URB's which were send to the device, or at least wait until + * they have been returned from the device.. */ -void rt2x00usb_flush_queue(struct data_queue *queue); +void rt2x00usb_flush_queue(struct data_queue *queue, bool drop); /** * rt2x00usb_watchdog - Watchdog for USB communication @@ -416,7 +429,7 @@ void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev); * USB driver handlers. */ int rt2x00usb_probe(struct usb_interface *usb_intf, - const struct usb_device_id *id); + const struct rt2x00_ops *ops); void rt2x00usb_disconnect(struct usb_interface *usb_intf); #ifdef CONFIG_PM int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 77e8113b91e1..9d35ec16a3a5 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -683,7 +683,7 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529)); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, - !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); + !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags)); /* * Configure the RX antenna. @@ -811,10 +811,10 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { sel = antenna_sel_a; - lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + lna = test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); } else { sel = antenna_sel_bg; - lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + lna = test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); } for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) @@ -834,7 +834,7 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, else if (rt2x00_rf(rt2x00dev, RF2527)) rt61pci_config_antenna_2x(rt2x00dev, ant); else if (rt2x00_rf(rt2x00dev, RF2529)) { - if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags)) rt61pci_config_antenna_2x(rt2x00dev, ant); else rt61pci_config_antenna_2529(rt2x00dev, ant); @@ -848,13 +848,13 @@ static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, short lna_gain = 0; if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) lna_gain += 14; rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); } else { - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) lna_gain += 14; rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); @@ -1050,14 +1050,14 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev, if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { low_bound = 0x28; up_bound = 0x48; - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) { low_bound += 0x10; up_bound += 0x10; } } else { low_bound = 0x20; up_bound = 0x40; - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) { low_bound += 0x10; up_bound += 0x10; } @@ -2260,8 +2260,8 @@ static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev) rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); } -static void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, - struct rt2x00_field32 irq_field) +static inline void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { u32 reg; @@ -2313,8 +2313,10 @@ static void rt61pci_tbtt_tasklet(unsigned long data) static void rt61pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - rt2x00pci_rxdone(rt2x00dev); - rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); + if (rt2x00pci_rxdone(rt2x00dev)) + rt2x00pci_rxdone(rt2x00dev); + else + rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); } static void rt61pci_autowake_tasklet(unsigned long data) @@ -2535,7 +2537,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Determine number of antennas. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) - __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags); + __set_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags); /* * Identify default antenna configuration. @@ -2549,20 +2551,20 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Read the Frame type. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE)) - __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); + __set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags); /* * Detect if this device has a hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* * Read frequency offset and RF programming sequence. */ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ)) - __set_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags); + __set_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags); rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); @@ -2572,9 +2574,9 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) - __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) - __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); /* * When working with a RF2529 chip without double antenna, @@ -2582,7 +2584,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * eeprom word. */ if (rt2x00_rf(rt2x00dev, RF2529) && - !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) { + !test_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags)) { rt2x00dev->default_ant.rx = ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED); rt2x00dev->default_ant.tx = @@ -2797,7 +2799,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) { + if (!test_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags)) { spec->num_channels = 14; spec->channels = rf_vals_noseq; } else { @@ -2867,16 +2869,16 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) * This device has multiple filters for control frames, * but has no a separate filter for PS Poll frames. */ - __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); + __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); /* * This device requires firmware and DMA mapped skbs. */ - __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); + __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); if (!modparam_nohwcrypt) - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); /* * Set the rssi offset. @@ -2977,6 +2979,9 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .get_tsf = rt61pci_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .set_antenna = rt2x00mac_set_antenna, + .get_antenna = rt2x00mac_get_antenna, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { @@ -3001,6 +3006,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .start_queue = rt61pci_start_queue, .kick_queue = rt61pci_kick_queue, .stop_queue = rt61pci_stop_queue, + .flush_queue = rt2x00pci_flush_queue, .write_tx_desc = rt61pci_write_tx_desc, .write_beacon = rt61pci_write_beacon, .clear_beacon = rt61pci_clear_beacon, @@ -3058,11 +3064,11 @@ static const struct rt2x00_ops rt61pci_ops = { */ static DEFINE_PCI_DEVICE_TABLE(rt61pci_device_table) = { /* RT2561s */ - { PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) }, + { PCI_DEVICE(0x1814, 0x0301) }, /* RT2561 v2 */ - { PCI_DEVICE(0x1814, 0x0302), PCI_DEVICE_DATA(&rt61pci_ops) }, + { PCI_DEVICE(0x1814, 0x0302) }, /* RT2661 */ - { PCI_DEVICE(0x1814, 0x0401), PCI_DEVICE_DATA(&rt61pci_ops) }, + { PCI_DEVICE(0x1814, 0x0401) }, { 0, } }; @@ -3077,10 +3083,16 @@ MODULE_FIRMWARE(FIRMWARE_RT2561s); MODULE_FIRMWARE(FIRMWARE_RT2661); MODULE_LICENSE("GPL"); +static int rt61pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id) +{ + return rt2x00pci_probe(pci_dev, &rt61pci_ops); +} + static struct pci_driver rt61pci_driver = { .name = KBUILD_MODNAME, .id_table = rt61pci_device_table, - .probe = rt2x00pci_probe, + .probe = rt61pci_probe, .remove = __devexit_p(rt2x00pci_remove), .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 02f1148c577e..ad20953cbf05 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -595,7 +595,7 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, switch (ant->rx) { case ANTENNA_HW_DIVERSITY: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); - temp = !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags) + temp = !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags) && (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, temp); break; @@ -636,7 +636,7 @@ static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, - !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); + !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags)); /* * Configure the RX antenna. @@ -709,10 +709,10 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev, if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { sel = antenna_sel_a; - lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + lna = test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); } else { sel = antenna_sel_bg; - lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + lna = test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); } for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) @@ -740,7 +740,7 @@ static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, short lna_gain = 0; if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) lna_gain += 14; rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); @@ -930,7 +930,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev, low_bound = 0x28; up_bound = 0x48; - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) { low_bound += 0x10; up_bound += 0x10; } @@ -946,7 +946,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev, up_bound = 0x1c; } - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) { low_bound += 0x14; up_bound += 0x10; } @@ -1661,7 +1661,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) } if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) { if (lna == 3 || lna == 2) offset += 10; } else { @@ -1899,13 +1899,13 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Read the Frame type. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE)) - __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); + __set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags); /* * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* * Read frequency offset. @@ -1919,8 +1919,8 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA)) { - __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); - __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); } /* @@ -2200,16 +2200,16 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) * This device has multiple filters for control frames, * but has no a separate filter for PS Poll frames. */ - __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); + __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); /* * This device requires firmware. */ - __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); + __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); if (!modparam_nohwcrypt) - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); /* * Set the rssi offset. @@ -2311,6 +2311,9 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .get_tsf = rt73usb_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .set_antenna = rt2x00mac_set_antenna, + .get_antenna = rt2x00mac_get_antenna, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { @@ -2389,114 +2392,113 @@ static const struct rt2x00_ops rt73usb_ops = { */ static struct usb_device_id rt73usb_device_table[] = { /* AboCom */ - { USB_DEVICE(0x07b8, 0xb21b), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07b8, 0xb21c), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07b8, 0xb21e), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07b8, 0xb21f), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x07b8, 0xb21b) }, + { USB_DEVICE(0x07b8, 0xb21c) }, + { USB_DEVICE(0x07b8, 0xb21d) }, + { USB_DEVICE(0x07b8, 0xb21e) }, + { USB_DEVICE(0x07b8, 0xb21f) }, /* AL */ - { USB_DEVICE(0x14b2, 0x3c10), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c10) }, /* Amigo */ - { USB_DEVICE(0x148f, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0eb0, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x148f, 0x9021) }, + { USB_DEVICE(0x0eb0, 0x9021) }, /* AMIT */ - { USB_DEVICE(0x18c5, 0x0002), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x18c5, 0x0002) }, /* Askey */ - { USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1690, 0x0722) }, /* ASUS */ - { USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0b05, 0x1723) }, + { USB_DEVICE(0x0b05, 0x1724) }, /* Belkin */ - { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x050d, 0x905c), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x050d, 0x705a) }, + { USB_DEVICE(0x050d, 0x905b) }, + { USB_DEVICE(0x050d, 0x905c) }, /* Billionton */ - { USB_DEVICE(0x1631, 0xc019), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1631, 0xc019) }, + { USB_DEVICE(0x08dd, 0x0120) }, /* Buffalo */ - { USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0411, 0x00d9), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0411, 0x0137), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0411, 0x00d8) }, + { USB_DEVICE(0x0411, 0x00d9) }, + { USB_DEVICE(0x0411, 0x00f4) }, + { USB_DEVICE(0x0411, 0x0116) }, + { USB_DEVICE(0x0411, 0x0119) }, + { USB_DEVICE(0x0411, 0x0137) }, /* CEIVA */ - { USB_DEVICE(0x178d, 0x02be), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x178d, 0x02be) }, /* CNet */ - { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1371, 0x9022) }, + { USB_DEVICE(0x1371, 0x9032) }, /* Conceptronic */ - { USB_DEVICE(0x14b2, 0x3c22), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c22) }, /* Corega */ - { USB_DEVICE(0x07aa, 0x002e), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x07aa, 0x002e) }, /* D-Link */ - { USB_DEVICE(0x07d1, 0x3c03), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c06), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c07), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c03) }, + { USB_DEVICE(0x07d1, 0x3c04) }, + { USB_DEVICE(0x07d1, 0x3c06) }, + { USB_DEVICE(0x07d1, 0x3c07) }, /* Edimax */ - { USB_DEVICE(0x7392, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x7392, 0x7618), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x7392, 0x7318) }, + { USB_DEVICE(0x7392, 0x7618) }, /* EnGenius */ - { USB_DEVICE(0x1740, 0x3701), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1740, 0x3701) }, /* Gemtek */ - { USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x15a9, 0x0004) }, /* Gigabyte */ - { USB_DEVICE(0x1044, 0x8008), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x1044, 0x800a), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1044, 0x8008) }, + { USB_DEVICE(0x1044, 0x800a) }, /* Huawei-3Com */ - { USB_DEVICE(0x1472, 0x0009), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1472, 0x0009) }, /* Hercules */ - { USB_DEVICE(0x06f8, 0xe002), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x06f8, 0xe010), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x06f8, 0xe020), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x06f8, 0xe002) }, + { USB_DEVICE(0x06f8, 0xe010) }, + { USB_DEVICE(0x06f8, 0xe020) }, /* Linksys */ - { USB_DEVICE(0x13b1, 0x0020), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x13b1, 0x0028), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x13b1, 0x0020) }, + { USB_DEVICE(0x13b1, 0x0023) }, + { USB_DEVICE(0x13b1, 0x0028) }, /* MSI */ - { USB_DEVICE(0x0db0, 0x4600), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0db0, 0x4600) }, + { USB_DEVICE(0x0db0, 0x6877) }, + { USB_DEVICE(0x0db0, 0x6874) }, + { USB_DEVICE(0x0db0, 0xa861) }, + { USB_DEVICE(0x0db0, 0xa874) }, /* Ovislink */ - { USB_DEVICE(0x1b75, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1b75, 0x7318) }, /* Ralink */ - { USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0812, 0x3101), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x04bb, 0x093d) }, + { USB_DEVICE(0x148f, 0x2573) }, + { USB_DEVICE(0x148f, 0x2671) }, + { USB_DEVICE(0x0812, 0x3101) }, /* Qcom */ - { USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x18e8, 0x6238), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x18e8, 0x6196) }, + { USB_DEVICE(0x18e8, 0x6229) }, + { USB_DEVICE(0x18e8, 0x6238) }, /* Samsung */ - { USB_DEVICE(0x04e8, 0x4471), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x04e8, 0x4471) }, /* Senao */ - { USB_DEVICE(0x1740, 0x7100), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1740, 0x7100) }, /* Sitecom */ - { USB_DEVICE(0x0df6, 0x0024), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0df6, 0x0027), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0df6, 0x002f), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0df6, 0x90ac), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0df6, 0x0024) }, + { USB_DEVICE(0x0df6, 0x0027) }, + { USB_DEVICE(0x0df6, 0x002f) }, + { USB_DEVICE(0x0df6, 0x90ac) }, + { USB_DEVICE(0x0df6, 0x9712) }, /* Surecom */ - { USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0769, 0x31f3) }, /* Tilgin */ - { USB_DEVICE(0x6933, 0x5001), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x6933, 0x5001) }, /* Philips */ - { USB_DEVICE(0x0471, 0x200a), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0471, 0x200a) }, /* Planex */ - { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x2019, 0xab01) }, + { USB_DEVICE(0x2019, 0xab50) }, /* WideTell */ - { USB_DEVICE(0x7167, 0x3840), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x7167, 0x3840) }, /* Zcom */ - { USB_DEVICE(0x0cde, 0x001c), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0cde, 0x001c) }, /* ZyXEL */ - { USB_DEVICE(0x0586, 0x3415), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0586, 0x3415) }, { 0, } }; @@ -2508,10 +2510,16 @@ MODULE_DEVICE_TABLE(usb, rt73usb_device_table); MODULE_FIRMWARE(FIRMWARE_RT2571); MODULE_LICENSE("GPL"); +static int rt73usb_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id) +{ + return rt2x00usb_probe(usb_intf, &rt73usb_ops); +} + static struct usb_driver rt73usb_driver = { .name = KBUILD_MODNAME, .id_table = rt73usb_device_table, - .probe = rt2x00usb_probe, + .probe = rt73usb_probe, .disconnect = rt2x00usb_disconnect, .suspend = rt2x00usb_suspend, .resume = rt2x00usb_resume, diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig index ce49e0ce7cad..5aee8b22d74e 100644 --- a/drivers/net/wireless/rtlwifi/Kconfig +++ b/drivers/net/wireless/rtlwifi/Kconfig @@ -10,6 +10,17 @@ config RTL8192CE If you choose to build it as a module, it will be called rtl8192ce +config RTL8192SE + tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter" + depends on MAC80211 && EXPERIMENTAL + select FW_LOADER + select RTLWIFI + ---help--- + This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe + wireless network adapters. + + If you choose to build it as a module, it will be called rtl8192se + config RTL8192CU tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter" depends on MAC80211 && USB && EXPERIMENTAL @@ -24,10 +35,10 @@ config RTL8192CU config RTLWIFI tristate - depends on RTL8192CE || RTL8192CU + depends on RTL8192CE || RTL8192CU || RTL8192SE default m config RTL8192C_COMMON tristate - depends on RTL8192CE || RTL8192CU + depends on RTL8192CE || RTL8192CU || RTL8192SE default m diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile index ec9393f24799..7acce83c3785 100644 --- a/drivers/net/wireless/rtlwifi/Makefile +++ b/drivers/net/wireless/rtlwifi/Makefile @@ -22,5 +22,6 @@ endif obj-$(CONFIG_RTL8192C_COMMON) += rtl8192c/ obj-$(CONFIG_RTL8192CE) += rtl8192ce/ obj-$(CONFIG_RTL8192CU) += rtl8192cu/ +obj-$(CONFIG_RTL8192SE) += rtl8192se/ ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 0d7d93e1d398..ccb6da38fe22 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -50,8 +50,9 @@ *3) functions called by core.c *4) wq & timer callback functions *5) frame process functions - *6) sysfs functions - *7) ... + *6) IOT functions + *7) sysfs functions + *8) ... */ /********************************************************* @@ -59,7 +60,7 @@ * mac80211 init functions * *********************************************************/ -static struct ieee80211_channel rtl_channeltable[] = { +static struct ieee80211_channel rtl_channeltable_2g[] = { {.center_freq = 2412, .hw_value = 1,}, {.center_freq = 2417, .hw_value = 2,}, {.center_freq = 2422, .hw_value = 3,}, @@ -76,7 +77,34 @@ static struct ieee80211_channel rtl_channeltable[] = { {.center_freq = 2484, .hw_value = 14,}, }; -static struct ieee80211_rate rtl_ratetable[] = { +static struct ieee80211_channel rtl_channeltable_5g[] = { + {.center_freq = 5180, .hw_value = 36,}, + {.center_freq = 5200, .hw_value = 40,}, + {.center_freq = 5220, .hw_value = 44,}, + {.center_freq = 5240, .hw_value = 48,}, + {.center_freq = 5260, .hw_value = 52,}, + {.center_freq = 5280, .hw_value = 56,}, + {.center_freq = 5300, .hw_value = 60,}, + {.center_freq = 5320, .hw_value = 64,}, + {.center_freq = 5500, .hw_value = 100,}, + {.center_freq = 5520, .hw_value = 104,}, + {.center_freq = 5540, .hw_value = 108,}, + {.center_freq = 5560, .hw_value = 112,}, + {.center_freq = 5580, .hw_value = 116,}, + {.center_freq = 5600, .hw_value = 120,}, + {.center_freq = 5620, .hw_value = 124,}, + {.center_freq = 5640, .hw_value = 128,}, + {.center_freq = 5660, .hw_value = 132,}, + {.center_freq = 5680, .hw_value = 136,}, + {.center_freq = 5700, .hw_value = 140,}, + {.center_freq = 5745, .hw_value = 149,}, + {.center_freq = 5765, .hw_value = 153,}, + {.center_freq = 5785, .hw_value = 157,}, + {.center_freq = 5805, .hw_value = 161,}, + {.center_freq = 5825, .hw_value = 165,}, +}; + +static struct ieee80211_rate rtl_ratetable_2g[] = { {.bitrate = 10, .hw_value = 0x00,}, {.bitrate = 20, .hw_value = 0x01,}, {.bitrate = 55, .hw_value = 0x02,}, @@ -91,18 +119,57 @@ static struct ieee80211_rate rtl_ratetable[] = { {.bitrate = 540, .hw_value = 0x0b,}, }; +static struct ieee80211_rate rtl_ratetable_5g[] = { + {.bitrate = 60, .hw_value = 0x04,}, + {.bitrate = 90, .hw_value = 0x05,}, + {.bitrate = 120, .hw_value = 0x06,}, + {.bitrate = 180, .hw_value = 0x07,}, + {.bitrate = 240, .hw_value = 0x08,}, + {.bitrate = 360, .hw_value = 0x09,}, + {.bitrate = 480, .hw_value = 0x0a,}, + {.bitrate = 540, .hw_value = 0x0b,}, +}; + static const struct ieee80211_supported_band rtl_band_2ghz = { .band = IEEE80211_BAND_2GHZ, - .channels = rtl_channeltable, - .n_channels = ARRAY_SIZE(rtl_channeltable), + .channels = rtl_channeltable_2g, + .n_channels = ARRAY_SIZE(rtl_channeltable_2g), - .bitrates = rtl_ratetable, - .n_bitrates = ARRAY_SIZE(rtl_ratetable), + .bitrates = rtl_ratetable_2g, + .n_bitrates = ARRAY_SIZE(rtl_ratetable_2g), .ht_cap = {0}, }; +static struct ieee80211_supported_band rtl_band_5ghz = { + .band = IEEE80211_BAND_5GHZ, + + .channels = rtl_channeltable_5g, + .n_channels = ARRAY_SIZE(rtl_channeltable_5g), + + .bitrates = rtl_ratetable_5g, + .n_bitrates = ARRAY_SIZE(rtl_ratetable_5g), + + .ht_cap = {0}, +}; + +static const u8 tid_to_ac[] = { + 2, /* IEEE80211_AC_BE */ + 3, /* IEEE80211_AC_BK */ + 3, /* IEEE80211_AC_BK */ + 2, /* IEEE80211_AC_BE */ + 1, /* IEEE80211_AC_VI */ + 1, /* IEEE80211_AC_VI */ + 0, /* IEEE80211_AC_VO */ + 0, /* IEEE80211_AC_VO */ +}; + +u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid) +{ + return tid_to_ac[tid]; +} + static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, struct ieee80211_sta_ht_cap *ht_cap) { @@ -115,6 +182,9 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU; + if (rtlpriv->rtlhal.disable_amsdu_8k) + ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; + /* *Maximum length of AMPDU that the STA can receive. *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) @@ -159,37 +229,99 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, static void _rtl_init_mac80211(struct ieee80211_hw *hw) { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct ieee80211_supported_band *sband; - /* <1> use mac->bands as mem for hw->wiphy->bands */ - sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); - /* - * <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] - * to default value(1T1R) - */ - memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz, - sizeof(struct ieee80211_supported_band)); + if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && rtlhal->bandset == + BAND_ON_BOTH) { + /* 1: 2.4 G bands */ + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); - /* <3> init ht cap base on ant_num */ - _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz, + sizeof(struct ieee80211_supported_band)); - /* <4> set mac->sband to wiphy->sband */ - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + + /* 2: 5 G bands */ + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), &rtl_band_5ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; + } else { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), + &rtl_band_2ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + } else if (rtlhal->current_bandtype == BAND_ON_5G) { + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), + &rtl_band_5ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("Err BAND %d\n", + rtlhal->current_bandtype)); + } + } /* <5> set hw caps */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_AMPDU_AGGREGATION | /*PS*/ - /*IEEE80211_HW_SUPPORTS_PS | */ - /*IEEE80211_HW_PS_NULLFUNC_STACK | */ - /*IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ + IEEE80211_HW_BEACON_FILTER | + IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0; + /* swlps or hwlps has been set in diff chip in init_sw_vars */ + if (rtlpriv->psc.swctrl_lps) + hw->flags |= IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK | + /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ + 0; + hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->rts_threshold = 2347; @@ -199,9 +331,10 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) /* TODO: Correct this value for our hw */ /* TODO: define these hard code value */ hw->channel_change_time = 100; - hw->max_listen_interval = 5; + hw->max_listen_interval = 10; hw->max_rate_tries = 4; /* hw->max_rates = 1; */ + hw->sta_data_size = sizeof(struct rtl_sta_info); /* <6> mac address */ if (is_valid_ether_addr(rtlefuse->dev_addr)) { @@ -230,6 +363,10 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw) (void *)rtl_watchdog_wq_callback); INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, (void *)rtl_ips_nic_off_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ps_work, + (void *)rtl_swlps_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq, + (void *)rtl_swlps_rfon_wq_callback); } @@ -241,6 +378,8 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw) cancel_delayed_work(&rtlpriv->works.watchdog_wq); cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); + cancel_delayed_work(&rtlpriv->works.ps_work); + cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); } void rtl_init_rfkill(struct ieee80211_hw *hw) @@ -251,14 +390,16 @@ void rtl_init_rfkill(struct ieee80211_hw *hw) bool blocked; u8 valid = 0; + /*set init state to on */ + rtlpriv->rfkill.rfkill_state = 1; + wiphy_rfkill_set_hw_state(hw->wiphy, 0); + radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); - /*set init state to that of switch */ - rtlpriv->rfkill.rfkill_state = radio_state; - printk(KERN_INFO "rtlwifi: wireless switch is %s\n", - rtlpriv->rfkill.rfkill_state ? "on" : "off"); - if (valid) { + printk(KERN_INFO "rtlwifi: wireless switch is %s\n", + rtlpriv->rfkill.rfkill_state ? "on" : "off"); + rtlpriv->rfkill.rfkill_state = radio_state; blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1; @@ -308,6 +449,8 @@ int rtl_init_core(struct ieee80211_hw *hw) spin_lock_init(&rtlpriv->locks.rf_ps_lock); spin_lock_init(&rtlpriv->locks.rf_lock); spin_lock_init(&rtlpriv->locks.lps_lock); + spin_lock_init(&rtlpriv->locks.waitq_lock); + spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock); rtlmac->link_state = MAC80211_NOLINK; @@ -327,12 +470,6 @@ void rtl_init_rx_config(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf)); - rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MGT_FILTER, - (u8 *) (&mac->rx_mgt_filter)); - rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CTRL_FILTER, - (u8 *) (&mac->rx_ctrl_filter)); - rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_DATA_FILTER, - (u8 *) (&mac->rx_data_filter)); } /********************************************************* @@ -359,28 +496,40 @@ static void _rtl_qurey_shortpreamble_mode(struct ieee80211_hw *hw, } static void _rtl_query_shortgi(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, struct rtl_tcb_desc *tcb_desc, struct ieee80211_tx_info *info) { struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); u8 rate_flag = info->control.rates[0].flags; - + u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0; tcb_desc->use_shortgi = false; - if (!mac->ht_enable) + if (sta == NULL) return; - if (!mac->sgi_40 && !mac->sgi_20) + sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + + if (!(sta->ht_cap.ht_supported)) return; - if ((mac->bw_40 == true) && mac->sgi_40) + if (!sgi_40 && !sgi_20) + return; + + if (mac->opmode == NL80211_IFTYPE_STATION) + bw_40 = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + if ((bw_40 == true) && sgi_40) tcb_desc->use_shortgi = true; - else if ((mac->bw_40 == false) && mac->sgi_20) + else if ((bw_40 == false) && sgi_20) tcb_desc->use_shortgi = true; if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI)) tcb_desc->use_shortgi = false; - } static void _rtl_query_protection_mode(struct ieee80211_hw *hw, @@ -408,19 +557,25 @@ static void _rtl_query_protection_mode(struct ieee80211_hw *hw, tcb_desc->rts_enable = true; tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M]; } - } static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u8 ratr_index = 7; + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + ratr_index = sta_entry->ratr_index; + } if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) { - if (mac->opmode == NL80211_IFTYPE_STATION) + if (mac->opmode == NL80211_IFTYPE_STATION) { tcb_desc->ratr_index = 0; - else if (mac->opmode == NL80211_IFTYPE_ADHOC) { + } else if (mac->opmode == NL80211_IFTYPE_ADHOC) { if (tcb_desc->multicast || tcb_desc->broadcast) { tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M]; @@ -428,36 +583,61 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, } else { /* TODO */ } + tcb_desc->ratr_index = ratr_index; + } else if (mac->opmode == NL80211_IFTYPE_AP) { + tcb_desc->ratr_index = ratr_index; } } if (rtlpriv->dm.useramask) { /* TODO we will differentiate adhoc and station futrue */ - tcb_desc->mac_id = 0; + if (mac->opmode == NL80211_IFTYPE_STATION) { + tcb_desc->mac_id = 0; - if ((mac->mode == WIRELESS_MODE_N_24G) || - (mac->mode == WIRELESS_MODE_N_5G)) { - tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB; - } else if (mac->mode & WIRELESS_MODE_G) { - tcb_desc->ratr_index = RATR_INX_WIRELESS_GB; - } else if (mac->mode & WIRELESS_MODE_B) { - tcb_desc->ratr_index = RATR_INX_WIRELESS_B; + if (mac->mode == WIRELESS_MODE_N_24G) + tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB; + else if (mac->mode == WIRELESS_MODE_N_5G) + tcb_desc->ratr_index = RATR_INX_WIRELESS_NG; + else if (mac->mode & WIRELESS_MODE_G) + tcb_desc->ratr_index = RATR_INX_WIRELESS_GB; + else if (mac->mode & WIRELESS_MODE_B) + tcb_desc->ratr_index = RATR_INX_WIRELESS_B; + else if (mac->mode & WIRELESS_MODE_A) + tcb_desc->ratr_index = RATR_INX_WIRELESS_G; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (NULL != sta) { + if (sta->aid > 0) + tcb_desc->mac_id = sta->aid + 1; + else + tcb_desc->mac_id = 1; + } else { + tcb_desc->mac_id = 0; + } } } } static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); tcb_desc->packet_bw = false; - - if (!mac->bw_40 || !mac->ht_enable) + if (!sta) return; - + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (!(sta->ht_cap.ht_supported) || + !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + return; + } else if (mac->opmode == NL80211_IFTYPE_STATION) { + if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) + return; + } if (tcb_desc->multicast || tcb_desc->broadcast) return; @@ -484,22 +664,21 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw) void rtl_get_tcb_desc(struct ieee80211_hw *hw, struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); struct ieee80211_rate *txrate; __le16 fc = hdr->frame_control; - memset(tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + txrate = ieee80211_get_tx_rate(hw, info); + tcb_desc->hw_rate = txrate->hw_value; if (ieee80211_is_data(fc)) { - txrate = ieee80211_get_tx_rate(hw, info); - tcb_desc->hw_rate = txrate->hw_value; - /* - *we set data rate RTL_RC_CCK_RATE1M + *we set data rate INX 0 *in rtl_rc.c if skb is special data or *mgt which need low data rate. */ @@ -508,12 +687,11 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, *So tcb_desc->hw_rate is just used for *special data and mgt frames */ - if (tcb_desc->hw_rate < rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]) { + if (info->control.rates[0].idx == 0 && + ieee80211_is_nullfunc(fc)) { tcb_desc->use_driver_rate = true; - tcb_desc->ratr_index = 7; + tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; - tcb_desc->hw_rate = - rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; tcb_desc->disable_ratefallback = 1; } else { /* @@ -523,7 +701,7 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, *and N rate will all be controlled by FW *when tcb_desc->use_driver_rate = false */ - if (rtlmac->ht_enable) { + if (sta && (sta->ht_cap.ht_supported)) { tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw); } else { if (rtlmac->mode == WIRELESS_MODE_B) { @@ -541,43 +719,25 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr))) tcb_desc->broadcast = 1; - _rtl_txrate_selectmode(hw, tcb_desc); - _rtl_query_bandwidth_mode(hw, tcb_desc); + _rtl_txrate_selectmode(hw, sta, tcb_desc); + _rtl_query_bandwidth_mode(hw, sta, tcb_desc); _rtl_qurey_shortpreamble_mode(hw, tcb_desc, info); - _rtl_query_shortgi(hw, tcb_desc, info); + _rtl_query_shortgi(hw, sta, tcb_desc, info); _rtl_query_protection_mode(hw, tcb_desc, info); } else { tcb_desc->use_driver_rate = true; - tcb_desc->ratr_index = 7; + tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; tcb_desc->disable_ratefallback = 1; tcb_desc->mac_id = 0; - - tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; + tcb_desc->packet_bw = false; } } EXPORT_SYMBOL(rtl_get_tcb_desc); -bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); - __le16 fc = hdr->frame_control; - - if (ieee80211_is_auth(fc)) { - RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); - rtl_ips_nic_on(hw); - - mac->link_state = MAC80211_LINKING; - } - - return true; -} - bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) { struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); struct rtl_priv *rtlpriv = rtl_priv(hw); __le16 fc = hdr->frame_control; u8 *act = (u8 *) (((u8 *) skb->data + MAC80211_3ADDR_LEN)); @@ -622,22 +782,20 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - __le16 fc = hdr->frame_control; + __le16 fc = rtl_get_fc(skb); u16 ether_type; u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb); const struct iphdr *ip; if (!ieee80211_is_data(fc)) - goto end; + return false; - if (ieee80211_is_nullfunc(fc)) - return true; ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len + SNAP_SIZE + PROTOC_TYPE_SIZE); ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE); + /* ether_type = ntohs(ether_type); */ if (ETH_P_IP == ether_type) { if (IPPROTO_UDP == ip->protocol) { @@ -686,7 +844,6 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) return true; } -end: return false; } @@ -695,61 +852,92 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) * functions called by core.c * *********************************************************/ -int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, u16 tid, u16 *ssn) +int rtl_tx_agg_start(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid, u16 *ssn) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_tid_data *tid_data; struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; - RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, - ("on ra = %pM tid = %d\n", ra, tid)); + if (sta == NULL) + return -EINVAL; if (unlikely(tid >= MAX_TID_COUNT)) return -EINVAL; - if (mac->tids[tid].agg.agg_state != RTL_AGG_OFF) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("Start AGG when state is not RTL_AGG_OFF !\n")); + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + if (!sta_entry) return -ENXIO; - } - - tid_data = &mac->tids[tid]; - *ssn = SEQ_TO_SN(tid_data->seq_number); + tid_data = &sta_entry->tids[tid]; RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, - ("HW queue is empty tid:%d\n", tid)); - tid_data->agg.agg_state = RTL_AGG_ON; + ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid, + tid_data->seq_number)); - ieee80211_start_tx_ba_cb_irqsafe(mac->vif, ra, tid); + *ssn = tid_data->seq_number; + tid_data->agg.agg_state = RTL_AGG_START; + + ieee80211_start_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid); return 0; } -int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 * ra, u16 tid) +int rtl_tx_agg_stop(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) { - int ssn = -1; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; - if (!ra) { + if (sta == NULL) + return -EINVAL; + + if (!sta->addr) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n")); return -EINVAL; } + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + ("on ra = %pM tid = %d\n", sta->addr, tid)); + if (unlikely(tid >= MAX_TID_COUNT)) return -EINVAL; - if (mac->tids[tid].agg.agg_state != RTL_AGG_ON) - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("Stopping AGG while state not ON or starting\n")); + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid_data = &sta_entry->tids[tid]; + sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP; - tid_data = &mac->tids[tid]; - ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; + ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid); - mac->tids[tid].agg.agg_state = RTL_AGG_OFF; + return 0; +} - ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, ra, tid); +int rtl_tx_agg_oper(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; + + if (sta == NULL) + return -EINVAL; + + if (!sta->addr) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n")); + return -EINVAL; + } + + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + ("on ra = %pM tid = %d\n", sta->addr, tid)); + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid_data = &sta_entry->tids[tid]; + sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL; return 0; } @@ -768,18 +956,16 @@ void rtl_watchdog_wq_callback(void *data) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - bool busytraffic = false; bool higher_busytraffic = false; bool higher_busyrxtraffic = false; - bool higher_busytxtraffic = false; - - u8 idx = 0; + u8 idx, tid; u32 rx_cnt_inp4eriod = 0; u32 tx_cnt_inp4eriod = 0; u32 aver_rx_cnt_inperiod = 0; u32 aver_tx_cnt_inperiod = 0; - + u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0}; + u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0}; bool enter_ps = false; if (is_hal_stop(rtlhal)) @@ -793,9 +979,6 @@ void rtl_watchdog_wq_callback(void *data) mac->cnt_after_linked = 0; } - /* <2> DM */ - rtlpriv->cfg->ops->dm_watchdog(hw); - /* *<3> to check if traffic busy, if * busytraffic we don't change channel @@ -834,8 +1017,27 @@ void rtl_watchdog_wq_callback(void *data) /* Extremely high Rx data. */ if (aver_rx_cnt_inperiod > 5000) higher_busyrxtraffic = true; + } + + /* check every tid's tx traffic */ + for (tid = 0; tid <= 7; tid++) { + for (idx = 0; idx <= 2; idx++) + rtlpriv->link_info.tidtx_in4period[tid][idx] = + rtlpriv->link_info.tidtx_in4period[tid] + [idx + 1]; + rtlpriv->link_info.tidtx_in4period[tid][3] = + rtlpriv->link_info.tidtx_inperiod[tid]; + + for (idx = 0; idx <= 3; idx++) + tidtx_inp4eriod[tid] += + rtlpriv->link_info.tidtx_in4period[tid][idx]; + aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4; + if (aver_tidtx_inperiod[tid] > 5000) + rtlpriv->link_info.higher_busytxtraffic[tid] = + true; else - higher_busytxtraffic = false; + rtlpriv->link_info.higher_busytxtraffic[tid] = + false; } if (((rtlpriv->link_info.num_rx_inperiod + @@ -854,11 +1056,15 @@ void rtl_watchdog_wq_callback(void *data) rtlpriv->link_info.num_rx_inperiod = 0; rtlpriv->link_info.num_tx_inperiod = 0; + for (tid = 0; tid <= 7; tid++) + rtlpriv->link_info.tidtx_inperiod[tid] = 0; rtlpriv->link_info.busytraffic = busytraffic; rtlpriv->link_info.higher_busytraffic = higher_busytraffic; rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic; + /* <3> DM */ + rtlpriv->cfg->ops->dm_watchdog(hw); } void rtl_watch_dog_timer_callback(unsigned long data) @@ -873,6 +1079,268 @@ void rtl_watch_dog_timer_callback(unsigned long data) jiffies + MSECS(RTL_WATCH_DOG_TIME)); } +/********************************************************* + * + * frame process functions + * + *********************************************************/ +u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return NULL; + + if (pos[0] == ie) + return pos; + + pos += 2 + pos[1]; + } + return NULL; +} + +/* when we use 2 rx ants we send IEEE80211_SMPS_OFF */ +/* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */ +static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw, + enum ieee80211_smps_mode smps, u8 *da, u8 *bssid) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct sk_buff *skb; + struct ieee80211_mgmt *action_frame; + + /* 27 = header + category + action + smps mode */ + skb = dev_alloc_skb(27 + hw->extra_tx_headroom); + if (!skb) + return NULL; + + skb_reserve(skb, hw->extra_tx_headroom); + action_frame = (void *)skb_put(skb, 27); + memset(action_frame, 0, 27); + memcpy(action_frame->da, da, ETH_ALEN); + memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN); + memcpy(action_frame->bssid, bssid, ETH_ALEN); + action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); + action_frame->u.action.category = WLAN_CATEGORY_HT; + action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS; + switch (smps) { + case IEEE80211_SMPS_AUTOMATIC:/* 0 */ + case IEEE80211_SMPS_NUM_MODES:/* 4 */ + WARN_ON(1); + case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */ + break; + case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */ + break; + case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */ + break; + } + + return skb; +} + +int rtl_send_smps_action(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 *da, u8 *bssid, + enum ieee80211_smps_mode smps) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct sk_buff *skb = rtl_make_smps_action(hw, smps, da, bssid); + struct rtl_tcb_desc tcb_desc; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + if (rtlpriv->mac80211.act_scanning) + goto err_free; + + if (!sta) + goto err_free; + + if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) + goto err_free; + + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + goto err_free; + + /* this is a type = mgmt * stype = action frame */ + if (skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl_sta_info *sta_entry = + (struct rtl_sta_info *) sta->drv_priv; + sta_entry->mimo_ps = smps; + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); + + info->control.rates[0].idx = 0; + info->control.sta = sta; + info->band = hw->conf.channel->band; + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); + } +err_free: + return 0; +} + +/********************************************************* + * + * IOT functions + * + *********************************************************/ +static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw, + struct octet_string vendor_ie) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool matched = false; + static u8 athcap_1[] = { 0x00, 0x03, 0x7F }; + static u8 athcap_2[] = { 0x00, 0x13, 0x74 }; + static u8 broadcap_1[] = { 0x00, 0x10, 0x18 }; + static u8 broadcap_2[] = { 0x00, 0x0a, 0xf7 }; + static u8 broadcap_3[] = { 0x00, 0x05, 0xb5 }; + static u8 racap[] = { 0x00, 0x0c, 0x43 }; + static u8 ciscocap[] = { 0x00, 0x40, 0x96 }; + static u8 marvcap[] = { 0x00, 0x50, 0x43 }; + + if (memcmp(vendor_ie.octet, athcap_1, 3) == 0 || + memcmp(vendor_ie.octet, athcap_2, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_ATH; + matched = true; + } else if (memcmp(vendor_ie.octet, broadcap_1, 3) == 0 || + memcmp(vendor_ie.octet, broadcap_2, 3) == 0 || + memcmp(vendor_ie.octet, broadcap_3, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_BROAD; + matched = true; + } else if (memcmp(vendor_ie.octet, racap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_RAL; + matched = true; + } else if (memcmp(vendor_ie.octet, ciscocap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_CISCO; + matched = true; + } else if (memcmp(vendor_ie.octet, marvcap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_MARV; + matched = true; + } + + return matched; +} + +static bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data, + unsigned int len) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + struct octet_string vendor_ie; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos[0] == 221) { + vendor_ie.length = pos[1]; + vendor_ie.octet = &pos[2]; + if (rtl_chk_vendor_ouisub(hw, vendor_ie)) + return true; + } + + if (pos + 2 + pos[1] > end) + return false; + + pos += 2 + pos[1]; + } + return false; +} + +void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = (void *)data; + u32 vendor = PEER_UNKNOWN; + + static u8 ap3_1[3] = { 0x00, 0x14, 0xbf }; + static u8 ap3_2[3] = { 0x00, 0x1a, 0x70 }; + static u8 ap3_3[3] = { 0x00, 0x1d, 0x7e }; + static u8 ap4_1[3] = { 0x00, 0x90, 0xcc }; + static u8 ap4_2[3] = { 0x00, 0x0e, 0x2e }; + static u8 ap4_3[3] = { 0x00, 0x18, 0x02 }; + static u8 ap4_4[3] = { 0x00, 0x17, 0x3f }; + static u8 ap4_5[3] = { 0x00, 0x1c, 0xdf }; + static u8 ap5_1[3] = { 0x00, 0x1c, 0xf0 }; + static u8 ap5_2[3] = { 0x00, 0x21, 0x91 }; + static u8 ap5_3[3] = { 0x00, 0x24, 0x01 }; + static u8 ap5_4[3] = { 0x00, 0x15, 0xe9 }; + static u8 ap5_5[3] = { 0x00, 0x17, 0x9A }; + static u8 ap5_6[3] = { 0x00, 0x18, 0xE7 }; + static u8 ap6_1[3] = { 0x00, 0x17, 0x94 }; + static u8 ap7_1[3] = { 0x00, 0x14, 0xa4 }; + + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + + if (mac->link_state == MAC80211_NOLINK) { + mac->vendor = PEER_UNKNOWN; + return; + } + + if (mac->cnt_after_linked > 2) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control)) + return; + + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + if (rtl_find_221_ie(hw, data, len)) + vendor = mac->vendor; + + if ((memcmp(mac->bssid, ap5_1, 3) == 0) || + (memcmp(mac->bssid, ap5_2, 3) == 0) || + (memcmp(mac->bssid, ap5_3, 3) == 0) || + (memcmp(mac->bssid, ap5_4, 3) == 0) || + (memcmp(mac->bssid, ap5_5, 3) == 0) || + (memcmp(mac->bssid, ap5_6, 3) == 0) || + vendor == PEER_ATH) { + vendor = PEER_ATH; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ath find\n")); + } else if ((memcmp(mac->bssid, ap4_4, 3) == 0) || + (memcmp(mac->bssid, ap4_5, 3) == 0) || + (memcmp(mac->bssid, ap4_1, 3) == 0) || + (memcmp(mac->bssid, ap4_2, 3) == 0) || + (memcmp(mac->bssid, ap4_3, 3) == 0) || + vendor == PEER_RAL) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ral findn\n")); + vendor = PEER_RAL; + } else if (memcmp(mac->bssid, ap6_1, 3) == 0 || + vendor == PEER_CISCO) { + vendor = PEER_CISCO; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>cisco find\n")); + } else if ((memcmp(mac->bssid, ap3_1, 3) == 0) || + (memcmp(mac->bssid, ap3_2, 3) == 0) || + (memcmp(mac->bssid, ap3_3, 3) == 0) || + vendor == PEER_BROAD) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>broad find\n")); + vendor = PEER_BROAD; + } else if (memcmp(mac->bssid, ap7_1, 3) == 0 || + vendor == PEER_MARV) { + vendor = PEER_MARV; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>marv find\n")); + } + + mac->vendor = vendor; +} + /********************************************************* * * sysfs functions @@ -940,12 +1408,13 @@ static int __init rtl_core_module_init(void) if (rtl_rate_control_register()) printk(KERN_ERR "rtlwifi: Unable to register rtl_rc," "use default RC !!\n"); + return 0; } static void __exit rtl_core_module_exit(void) { - /*RC*/ + /*RC*/ rtl_rate_control_unregister(); } diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index 043045342bc7..a91f3eee59c8 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -24,13 +24,26 @@ * Hsinchu 300, Taiwan. * * Larry Finger + * *****************************************************************************/ #ifndef __RTL_BASE_H__ #define __RTL_BASE_H__ +enum ap_peer { + PEER_UNKNOWN = 0, + PEER_RTL = 1, + PEER_RTL_92SE = 2, + PEER_BROAD = 3, + PEER_RAL = 4, + PEER_ATH = 5, + PEER_CISCO = 6, + PEER_MARV = 7, + PEER_AIRGO = 9, + PEER_MAX = 10, +} ; + #define RTL_DUMMY_OFFSET 0 -#define RTL_RX_DESC_SIZE 24 #define RTL_DUMMY_UNIT 8 #define RTL_TX_DUMMY_SIZE (RTL_DUMMY_OFFSET * RTL_DUMMY_UNIT) #define RTL_TX_DESC_SIZE 32 @@ -53,6 +66,14 @@ #define FRAME_OFFSET_SEQUENCE 22 #define FRAME_OFFSET_ADDRESS4 24 +#define SET_80211_HDR_FRAME_CONTROL(_hdr, _val) \ + WRITEEF2BYTE(_hdr, _val) +#define SET_80211_HDR_TYPE_AND_SUBTYPE(_hdr, _val) \ + WRITEEF1BYTE(_hdr, _val) +#define SET_80211_HDR_PWR_MGNT(_hdr, _val) \ + SET_BITS_TO_LE_2BYTE(_hdr, 12, 1, _val) +#define SET_80211_HDR_TO_DS(_hdr, _val) \ + SET_BITS_TO_LE_2BYTE(_hdr, 8, 1, _val) #define SET_80211_PS_POLL_AID(_hdr, _val) \ (*(u16 *)((u8 *)(_hdr) + 2) = le16_to_cpu(_val)) @@ -64,11 +85,27 @@ #define SET_80211_HDR_DURATION(_hdr, _val) \ (*(u16 *)((u8 *)(_hdr) + FRAME_OFFSET_DURATION) = le16_to_cpu(_val)) #define SET_80211_HDR_ADDRESS1(_hdr, _val) \ - memcpy((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8*)(_val), ETH_ALEN) + CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8 *)(_val)) #define SET_80211_HDR_ADDRESS2(_hdr, _val) \ - memcpy((u8 *)(_hdr) + FRAME_OFFSET_ADDRESS2, (u8 *)(_val), ETH_ALEN) + CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS2, (u8 *)(_val)) #define SET_80211_HDR_ADDRESS3(_hdr, _val) \ - memcpy((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val), ETH_ALEN) + CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val)) +#define SET_80211_HDR_FRAGMENT_SEQUENCE(_hdr, _val) \ + WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_SEQUENCE, _val) + +#define SET_BEACON_PROBE_RSP_TIME_STAMP_LOW(__phdr, __val) \ + WRITEEF4BYTE(((u8 *)(__phdr)) + 24, __val) +#define SET_BEACON_PROBE_RSP_TIME_STAMP_HIGH(__phdr, __val) \ + WRITEEF4BYTE(((u8 *)(__phdr)) + 28, __val) +#define SET_BEACON_PROBE_RSP_BEACON_INTERVAL(__phdr, __val) \ + WRITEEF2BYTE(((u8 *)(__phdr)) + 32, __val) +#define GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) \ + READEF2BYTE(((u8 *)(__phdr)) + 34) +#define SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ + WRITEEF2BYTE(((u8 *)(__phdr)) + 34, __val) +#define MASK_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ + SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \ + (GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val)))) int rtl_init_core(struct ieee80211_hw *hw); void rtl_deinit_core(struct ieee80211_hw *hw); @@ -80,18 +117,27 @@ void rtl_watch_dog_timer_callback(unsigned long data); void rtl_deinit_deferred_work(struct ieee80211_hw *hw); bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); -bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); void rtl_watch_dog_timer_callback(unsigned long data); -int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, +int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid, u16 *ssn); -int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid); +int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + u16 tid); +int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + u16 tid); void rtl_watchdog_wq_callback(void *data); void rtl_get_tcb_desc(struct ieee80211_hw *hw, struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc); +int rtl_send_smps_action(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 *da, u8 *bssid, + enum ieee80211_smps_mode smps); +u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie); +void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); +u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid); extern struct attribute_group rtl_attribute_group; #endif diff --git a/drivers/net/wireless/rtlwifi/cam.c b/drivers/net/wireless/rtlwifi/cam.c index 52c9c1367cac..7295af0536b7 100644 --- a/drivers/net/wireless/rtlwifi/cam.c +++ b/drivers/net/wireless/rtlwifi/cam.c @@ -23,6 +23,8 @@ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, * Hsinchu 300, Taiwan. * + * Larry Finger + * *****************************************************************************/ #include "wifi.h" @@ -49,7 +51,7 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, u32 target_content = 0; u8 entry_i; - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("key_cont_128:\n %x:%x:%x:%x:%x:%x\n", key_cont_128[0], key_cont_128[1], key_cont_128[2], key_cont_128[3], @@ -68,15 +70,13 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], target_command); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): " - "WRITE %x: %x\n", + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE %x: %x\n", rtlpriv->cfg->maps[WCAMI], target_content)); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("The Key ID is %d\n", entry_no)); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): " - "WRITE %x: %x\n", + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE %x: %x\n", rtlpriv->cfg->maps[RWCAM], target_command)); } else if (entry_i == 1) { @@ -91,12 +91,10 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], target_command); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): WRITE A4: %x\n", - target_content)); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): WRITE A0: %x\n", - target_command)); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE A4: %x\n", target_content)); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE A0: %x\n", target_command)); } else { @@ -113,16 +111,14 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, target_command); udelay(100); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): WRITE A4: %x\n", - target_content)); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): WRITE A0: %x\n", - target_command)); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE A4: %x\n", target_content)); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE A0: %x\n", target_command)); } } - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("after set key, usconfig:%x\n", us_config)); } @@ -289,3 +285,71 @@ void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index) } EXPORT_SYMBOL(rtl_cam_empty_entry); + +u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4; + u8 entry_idx = 0; + u8 i, *addr; + + if (NULL == sta_addr) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, + ("sta_addr is NULL.\n")); + return TOTAL_CAM_ENTRY; + } + /* Does STA already exist? */ + for (i = 4; i < TOTAL_CAM_ENTRY; i++) { + addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; + if (memcmp(addr, sta_addr, ETH_ALEN) == 0) + return i; + } + /* Get a free CAM entry. */ + for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) { + if ((bitmap & BIT(0)) == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, + ("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n", + rtlpriv->sec.hwsec_cam_bitmap, entry_idx)); + rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx; + memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx], + sta_addr, ETH_ALEN); + return entry_idx; + } + bitmap = bitmap >> 1; + } + return TOTAL_CAM_ENTRY; +} +EXPORT_SYMBOL(rtl_cam_get_free_entry); + +void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 bitmap; + u8 i, *addr; + + if (NULL == 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) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, + ("sta_addr is 00:00:00:00:00:00.\n")); + return; + } + /* Does STA already exist? */ + for (i = 4; i < TOTAL_CAM_ENTRY; i++) { + addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; + bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i; + if (((bitmap & BIT(0)) == BIT(0)) && + (memcmp(addr, sta_addr, ETH_ALEN) == 0)) { + /* Remove from HW Security CAM */ + memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN); + rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i); + printk(KERN_INFO "&&&&&&&&&del entry %d\n", i); + } + } + return; +} +EXPORT_SYMBOL(rtl_cam_del_entry); diff --git a/drivers/net/wireless/rtlwifi/cam.h b/drivers/net/wireless/rtlwifi/cam.h index dd82f057d53d..c62da4eefc75 100644 --- a/drivers/net/wireless/rtlwifi/cam.h +++ b/drivers/net/wireless/rtlwifi/cam.h @@ -23,12 +23,13 @@ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, * Hsinchu 300, Taiwan. * + * Larry Finger + * *****************************************************************************/ #ifndef __RTL_CAM_H_ #define __RTL_CAM_H_ -#define TOTAL_CAM_ENTRY 32 #define CAM_CONTENT_COUNT 8 #define CFG_DEFAULT_KEY BIT(5) @@ -49,5 +50,7 @@ int rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index); void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index); void rtl_cam_reset_sec_info(struct ieee80211_hw *hw); +u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr); +void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr); #endif diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index e4f4aee8f298..fc89cd8c8320 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -24,6 +24,7 @@ * Hsinchu 300, Taiwan. * * Larry Finger + * *****************************************************************************/ #include "wifi.h" @@ -35,7 +36,7 @@ /*mutex for start & stop is must here. */ static int rtl_op_start(struct ieee80211_hw *hw) { - int err = 0; + int err; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -45,10 +46,8 @@ static int rtl_op_start(struct ieee80211_hw *hw) return 0; mutex_lock(&rtlpriv->locks.conf_mutex); err = rtlpriv->intf_ops->adapter_start(hw); - if (err) - goto out; - rtl_watch_dog_timer_callback((unsigned long)hw); -out: + if (!err) + rtl_watch_dog_timer_callback((unsigned long)hw); mutex_unlock(&rtlpriv->locks.conf_mutex); return err; } @@ -72,6 +71,7 @@ static void rtl_op_stop(struct ieee80211_hw *hw) mac->link_state = MAC80211_NOLINK; memset(mac->bssid, 0, 6); + mac->vendor = PEER_UNKNOWN; /*reset sec info */ rtl_cam_reset_sec_info(hw); @@ -87,6 +87,8 @@ static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_tcb_desc tcb_desc; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) goto err_free; @@ -94,8 +96,8 @@ static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) goto err_free; - - rtlpriv->intf_ops->adapter_tx(hw, skb); + if (!rtlpriv->intf_ops->waitq_insert(hw, skb)) + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); return; @@ -136,10 +138,26 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw, mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg(hw); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + mac->basic_rates = 0xfff; + else + mac->basic_rates = 0xff0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *) (&mac->basic_rates)); + break; case NL80211_IFTYPE_AP: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_AP\n")); + + mac->link_state = MAC80211_LINKED; + rtlpriv->cfg->ops->set_bcn_reg(hw); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + mac->basic_rates = 0xfff; + else + mac->basic_rates = 0xff0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *) (&mac->basic_rates)); break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, @@ -186,13 +204,12 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw, mac->vif = NULL; mac->link_state = MAC80211_NOLINK; memset(mac->bssid, 0, 6); + mac->vendor = PEER_UNKNOWN; mac->opmode = NL80211_IFTYPE_UNSPECIFIED; rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); - mutex_unlock(&rtlpriv->locks.conf_mutex); } - static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -224,10 +241,25 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) /*For LPS */ if (changed & IEEE80211_CONF_CHANGE_PS) { - if (conf->flags & IEEE80211_CONF_PS) - rtl_lps_enter(hw); - else - rtl_lps_leave(hw); + cancel_delayed_work(&rtlpriv->works.ps_work); + cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); + if (conf->flags & IEEE80211_CONF_PS) { + rtlpriv->psc.sw_ps_enabled = true; + /* sleep here is must, or we may recv the beacon and + * cause mac80211 into wrong ps state, this will cause + * power save nullfunc send fail, and further cause + * pkt loss, So sleep must quickly but not immediatly + * because that will cause nullfunc send by mac80211 + * fail, and cause pkt loss, we have tested that 5mA + * is worked very well */ + if (!rtlpriv->psc.multi_buffered) + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.ps_work, + MSECS(5)); + } else { + rtl_swlps_rf_awake(hw); + rtlpriv->psc.sw_ps_enabled = false; + } } if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { @@ -259,7 +291,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) case NL80211_CHAN_NO_HT: /* SC */ mac->cur_40_prime_sc = - PRIME_CHNL_OFFSET_DONT_CARE; + PRIME_CHNL_OFFSET_DONT_CARE; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20; mac->bw_40 = false; break; @@ -267,7 +299,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER; rtlphy->current_chan_bw = - HT_CHANNEL_WIDTH_20_40; + HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ @@ -278,7 +310,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER; rtlphy->current_chan_bw = - HT_CHANNEL_WIDTH_20_40; + HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ @@ -288,16 +320,29 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) default: mac->bw_40 = false; RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("switch case not processed\n")); + ("switch case not processed\n")); break; } if (wide_chan <= 0) wide_chan = 1; + + /* In scanning, before we go offchannel we may send a ps=1 null + * to AP, and then we may send a ps = 0 null to AP quickly, but + * first null may have caused AP to put lots of packet to hw tx + * buffer. These packets must be tx'd before we go off channel + * so we must delay more time to let AP flush these packets + * before going offchannel, or dis-association or delete BA will + * happen by AP + */ + if (rtlpriv->mac80211.offchan_deley) { + rtlpriv->mac80211.offchan_deley = false; + mdelay(50); + } rtlphy->current_channel = wide_chan; - rtlpriv->cfg->ops->set_channel_access(hw); rtlpriv->cfg->ops->switch_channel(hw); + rtlpriv->cfg->ops->set_channel_access(hw); rtlpriv->cfg->ops->set_bw_mode(hw, hw->conf.channel_type); } @@ -345,27 +390,28 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, } } - if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - /* - *TODO: BIT(5) is probe response BIT(8) is beacon - *TODO: Use define for BIT(5) and BIT(8) - */ - if (*new_flags & FIF_BCN_PRBRESP_PROMISC) - mac->rx_mgt_filter |= (BIT(5) | BIT(8)); - else - mac->rx_mgt_filter &= ~(BIT(5) | BIT(8)); + /* if ssid not set to hw don't check bssid + * here just used for linked scanning, & linked + * and nolink check bssid is set in set network_type */ + if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) && + (mac->link_state >= MAC80211_LINKED)) { + if (mac->opmode != NL80211_IFTYPE_AP) { + if (*new_flags & FIF_BCN_PRBRESP_PROMISC) { + rtlpriv->cfg->ops->set_chk_bssid(hw, false); + } else { + rtlpriv->cfg->ops->set_chk_bssid(hw, true); + } + } } if (changed_flags & FIF_CONTROL) { if (*new_flags & FIF_CONTROL) { mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF]; - mac->rx_ctrl_filter |= RTL_SUPPORTED_CTRL_FILTER; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("Enable receive control frame.\n")); } else { mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; - mac->rx_ctrl_filter &= ~RTL_SUPPORTED_CTRL_FILTER; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("Disable receive control frame.\n")); } @@ -382,14 +428,54 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, ("Disable receive other BSS's frame.\n")); } } - - rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf)); - rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MGT_FILTER, - (u8 *) (&mac->rx_mgt_filter)); - rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CTRL_FILTER, - (u8 *) (&mac->rx_ctrl_filter)); } +static int rtl_op_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry; + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + sta_entry->wireless_mode = WIRELESS_MODE_G; + if (sta->supp_rates[0] <= 0xf) + sta_entry->wireless_mode = WIRELESS_MODE_B; + if (sta->ht_cap.ht_supported == true) + sta_entry->wireless_mode = WIRELESS_MODE_N_24G; + } else if (rtlhal->current_bandtype == BAND_ON_5G) { + sta_entry->wireless_mode = WIRELESS_MODE_A; + if (sta->ht_cap.ht_supported == true) + sta_entry->wireless_mode = WIRELESS_MODE_N_24G; + } + + /* I found some times mac80211 give wrong supp_rates for adhoc*/ + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) + sta_entry->wireless_mode = WIRELESS_MODE_G; + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + ("Add sta addr is "MAC_FMT"\n", MAC_ARG(sta->addr))); + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); + } + return 0; +} +static int rtl_op_sta_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *sta_entry; + if (sta) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + ("Remove sta addr is "MAC_FMT"\n", MAC_ARG(sta->addr))); + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + sta_entry->wireless_mode = 0; + sta_entry->ratr_index = 0; + } + return 0; +} static int _rtl_get_hal_qnum(u16 queue) { int qnum; @@ -446,19 +532,18 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changed) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct ieee80211_sta *sta = NULL; mutex_lock(&rtlpriv->locks.conf_mutex); - if ((vif->type == NL80211_IFTYPE_ADHOC) || (vif->type == NL80211_IFTYPE_AP) || (vif->type == NL80211_IFTYPE_MESH_POINT)) { - if ((changed & BSS_CHANGED_BEACON) || (changed & BSS_CHANGED_BEACON_ENABLED && bss_conf->enable_beacon)) { - if (mac->beacon_enabled == 0) { RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ("BSS_CHANGED_BEACON_ENABLED\n")); @@ -470,8 +555,13 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, rtlpriv->cfg->maps [RTL_IBSS_INT_MASKS], 0); + + if (rtlpriv->cfg->ops->linked_set_reg) + rtlpriv->cfg->ops->linked_set_reg(hw); } - } else { + } + if ((changed & BSS_CHANGED_BEACON_ENABLED && + !bss_conf->enable_beacon)) { if (mac->beacon_enabled == 1) { RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ("ADHOC DISABLE BEACON\n")); @@ -482,7 +572,6 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, [RTL_IBSS_INT_MASKS]); } } - if (changed & BSS_CHANGED_BEACON_INT) { RT_TRACE(rtlpriv, COMP_BEACON, DBG_TRACE, ("BSS_CHANGED_BEACON_INT\n")); @@ -494,11 +583,25 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, /*TODO: reference to enum ieee80211_bss_change */ if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { + /* we should reset all sec info & cam + * before set cam after linked, we should not + * reset in disassoc, that will cause tkip->wep + * fail because some flag will be wrong */ + /* reset sec info */ + rtl_cam_reset_sec_info(hw); + /* reset cam to fix wep fail issue + * when change from wpa to wep */ + rtl_cam_reset_all_entry(hw); + mac->link_state = MAC80211_LINKED; mac->cnt_after_linked = 0; mac->assoc_id = bss_conf->aid; memcpy(mac->bssid, bss_conf->bssid, 6); + if (rtlpriv->cfg->ops->linked_set_reg) + rtlpriv->cfg->ops->linked_set_reg(hw); + if (mac->opmode == NL80211_IFTYPE_STATION && sta) + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ("BSS_CHANGED_ASSOC\n")); } else { @@ -507,9 +610,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, mac->link_state = MAC80211_NOLINK; memset(mac->bssid, 0, 6); - - /* reset sec info */ - rtl_cam_reset_sec_info(hw); + mac->vendor = PEER_UNKNOWN; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ("BSS_CHANGED_UN_ASSOC\n")); @@ -546,14 +647,10 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_HT) { - struct ieee80211_sta *sta = NULL; - RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, ("BSS_CHANGED_HT\n")); - rcu_read_lock(); - sta = ieee80211_find_sta(mac->vif, mac->bssid); - + sta = get_sta(hw, vif, (u8 *)bss_conf->bssid); if (sta) { if (sta->ht_cap.ampdu_density > mac->current_ampdu_density) @@ -575,9 +672,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BSSID) { - struct ieee80211_sta *sta = NULL; u32 basic_rates; - u8 i; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID, (u8 *) bss_conf->bssid); @@ -585,96 +680,65 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, (MAC_FMT "\n", MAC_ARG(bss_conf->bssid))); + mac->vendor = PEER_UNKNOWN; memcpy(mac->bssid, bss_conf->bssid, 6); - if (is_valid_ether_addr(bss_conf->bssid)) { - switch (vif->type) { - case NL80211_IFTYPE_UNSPECIFIED: - break; - case NL80211_IFTYPE_ADHOC: - break; - case NL80211_IFTYPE_STATION: - break; - case NL80211_IFTYPE_AP: - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("switch case not process\n")); - break; - } - rtlpriv->cfg->ops->set_network_type(hw, vif->type); - } else - rtlpriv->cfg->ops->set_network_type(hw, - NL80211_IFTYPE_UNSPECIFIED); - - memset(mac->mcs, 0, 16); - mac->ht_enable = false; - mac->sgi_40 = false; - mac->sgi_20 = false; - - if (!bss_conf->use_short_slot) - mac->mode = WIRELESS_MODE_B; - else - mac->mode = WIRELESS_MODE_G; + rtlpriv->cfg->ops->set_network_type(hw, vif->type); rcu_read_lock(); - sta = ieee80211_find_sta(mac->vif, mac->bssid); - - if (sta) { - if (sta->ht_cap.ht_supported) { - mac->mode = WIRELESS_MODE_N_24G; - mac->ht_enable = true; - } - - if (mac->ht_enable) { - u16 ht_cap = sta->ht_cap.cap; - memcpy(mac->mcs, (u8 *) (&sta->ht_cap.mcs), 16); - - for (i = 0; i < 16; i++) - RT_TRACE(rtlpriv, COMP_MAC80211, - DBG_LOUD, ("%x ", - mac->mcs[i])); - RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, - ("\n")); - - if (ht_cap & IEEE80211_HT_CAP_SGI_40) - mac->sgi_40 = true; - - if (ht_cap & IEEE80211_HT_CAP_SGI_20) - mac->sgi_20 = true; - - /* - * for cisco 1252 bw20 it's wrong - * if (ht_cap & - * IEEE80211_HT_CAP_SUP_WIDTH_20_40) { - * mac->bw_40 = true; - * } - */ - } + sta = get_sta(hw, vif, (u8 *)bss_conf->bssid); + if (!sta) { + rcu_read_unlock(); + goto out; } - rcu_read_unlock(); - /*mac80211 just give us CCK rates any time - *So we add G rate in basic rates when - not in B mode*/ - if (changed & BSS_CHANGED_BASIC_RATES) { - if (mac->mode == WIRELESS_MODE_B) - basic_rates = bss_conf->basic_rates | 0x00f; + if (rtlhal->current_bandtype == BAND_ON_5G) { + mac->mode = WIRELESS_MODE_A; + } else { + if (sta->supp_rates[0] <= 0xf) + mac->mode = WIRELESS_MODE_B; else - basic_rates = bss_conf->basic_rates | 0xff0; + mac->mode = WIRELESS_MODE_G; + } - if (!vif) - goto out; + if (sta->ht_cap.ht_supported) { + if (rtlhal->current_bandtype == BAND_ON_2_4G) + mac->mode = WIRELESS_MODE_N_24G; + else + mac->mode = WIRELESS_MODE_N_5G; + } + + /* just station need it, because ibss & ap mode will + * set in sta_add, and will be NULL here */ + if (mac->opmode == NL80211_IFTYPE_STATION) { + struct rtl_sta_info *sta_entry; + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + sta_entry->wireless_mode = mac->mode; + } + + if (sta->ht_cap.ht_supported) { + mac->ht_enable = true; + + /* + * for cisco 1252 bw20 it's wrong + * if (ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { + * mac->bw_40 = true; + * } + * */ + } + + if (changed & BSS_CHANGED_BASIC_RATES) { + /* for 5G must << RATE_6M_INDEX=4, + * because 5G have no cck rate*/ + if (rtlhal->current_bandtype == BAND_ON_5G) + basic_rates = sta->supp_rates[1] << 4; + else + basic_rates = sta->supp_rates[0]; mac->basic_rates = basic_rates; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&basic_rates)); - - if (rtlpriv->dm.useramask) - rtlpriv->cfg->ops->update_rate_mask(hw, 0); - else - rtlpriv->cfg->ops->update_rate_table(hw); - } + rcu_read_unlock(); } /* @@ -760,16 +824,17 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_START: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, ("IEEE80211_AMPDU_TX_START: TID:%d\n", tid)); - return rtl_tx_agg_start(hw, sta->addr, tid, ssn); + return rtl_tx_agg_start(hw, sta, tid, ssn); break; case IEEE80211_AMPDU_TX_STOP: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, ("IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid)); - return rtl_tx_agg_stop(hw, sta->addr, tid); + return rtl_tx_agg_stop(hw, sta, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, ("IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid)); + rtl_tx_agg_oper(hw, sta, tid); break; case IEEE80211_AMPDU_RX_START: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, @@ -799,8 +864,12 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw) if (mac->link_state == MAC80211_LINKED) { rtl_lps_leave(hw); mac->link_state = MAC80211_LINKED_SCANNING; - } else + } else { rtl_ips_nic_on(hw); + } + + /* Dual mac */ + rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false; rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY); rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP); @@ -812,22 +881,19 @@ static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("\n")); - - rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE); mac->act_scanning = false; + /* Dual mac */ + rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false; + if (mac->link_state == MAC80211_LINKED_SCANNING) { mac->link_state = MAC80211_LINKED; - - /* fix fwlps issue */ - rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); - - if (rtlpriv->dm.useramask) - rtlpriv->cfg->ops->update_rate_mask(hw, 0); - else - rtlpriv->cfg->ops->update_rate_table(hw); - + if (mac->opmode == NL80211_IFTYPE_STATION) { + /* fix fwlps issue */ + rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); + } } + rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE); } static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, @@ -858,49 +924,73 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, rtl_ips_nic_on(hw); mutex_lock(&rtlpriv->locks.conf_mutex); /* <1> get encryption alg */ + switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: key_type = WEP40_ENCRYPTION; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP40\n")); - rtlpriv->sec.use_defaultkey = true; break; case WLAN_CIPHER_SUITE_WEP104: RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP104\n")); key_type = WEP104_ENCRYPTION; - rtlpriv->sec.use_defaultkey = true; break; case WLAN_CIPHER_SUITE_TKIP: key_type = TKIP_ENCRYPTION; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:TKIP\n")); - if (mac->opmode == NL80211_IFTYPE_ADHOC) - rtlpriv->sec.use_defaultkey = true; break; case WLAN_CIPHER_SUITE_CCMP: key_type = AESCCMP_ENCRYPTION; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:CCMP\n")); - if (mac->opmode == NL80211_IFTYPE_ADHOC) - rtlpriv->sec.use_defaultkey = true; break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("alg_err:%x!!!!:\n", key->cipher)); goto out_unlock; } + if (key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION || + mac->opmode == NL80211_IFTYPE_ADHOC) + rtlpriv->sec.use_defaultkey = true; + /* <2> get key_idx */ key_idx = (u8) (key->keyidx); if (key_idx > 3) goto out_unlock; /* <3> if pairwise key enable_hw_sec */ group_key = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE); - if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) || - rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) { - if (rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION && - (key_type == WEP40_ENCRYPTION || - key_type == WEP104_ENCRYPTION)) - wep_only = true; - rtlpriv->sec.pairwise_enc_algorithm = key_type; - rtlpriv->cfg->ops->enable_hw_sec(hw); + + /* wep always be group key, but there are two conditions: + * 1) wep only: is just for wep enc, in this condition + * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION + * will be true & enable_hw_sec will be set when wep + * ke setting. + * 2) wep(group) + AES(pairwise): some AP like cisco + * may use it, in this condition enable_hw_sec will not + * be set when wep key setting */ + /* we must reset sec_info after lingked before set key, + * or some flag will be wrong*/ + if (mac->opmode == NL80211_IFTYPE_AP) { + if (!group_key || key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION) { + if (group_key) + wep_only = true; + rtlpriv->cfg->ops->enable_hw_sec(hw); + } + } else { + if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) || + rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) { + if (rtlpriv->sec.pairwise_enc_algorithm == + NO_ENCRYPTION && + (key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION)) + wep_only = true; + rtlpriv->sec.pairwise_enc_algorithm = key_type; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1" + " TKIP:2 AES:4 WEP104:5)\n", key_type)); + rtlpriv->cfg->ops->enable_hw_sec(hw); + } } /* <4> set key based on cmd */ switch (cmd) { @@ -932,6 +1022,7 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!sta) { RT_ASSERT(false, ("pairwise key withnot" "mac_addr\n")); + err = -EOPNOTSUPP; goto out_unlock; } @@ -959,6 +1050,10 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("disable key delete one entry\n")); /*set local buf about wep key. */ + if (mac->opmode == NL80211_IFTYPE_AP) { + if (sta) + rtl_cam_del_entry(hw, sta->addr); + } memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen); rtlpriv->sec.key_len[key_idx] = 0; memcpy(mac_addr, zero_addr, ETH_ALEN); @@ -1011,6 +1106,18 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw) mutex_unlock(&rtlpriv->locks.conf_mutex); } +/* this function is called by mac80211 to flush tx buffer + * before switch channle or power save, or tx buffer packet + * maybe send after offchannel or rf sleep, this may cause + * dis-association by AP */ +static void rtl_op_flush(struct ieee80211_hw *hw, bool drop) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->intf_ops->flush) + rtlpriv->intf_ops->flush(hw, drop); +} + const struct ieee80211_ops rtl_ops = { .start = rtl_op_start, .stop = rtl_op_stop, @@ -1019,6 +1126,8 @@ const struct ieee80211_ops rtl_ops = { .remove_interface = rtl_op_remove_interface, .config = rtl_op_config, .configure_filter = rtl_op_configure_filter, + .sta_add = rtl_op_sta_add, + .sta_remove = rtl_op_sta_remove, .set_key = rtl_op_set_key, .conf_tx = rtl_op_conf_tx, .bss_info_changed = rtl_op_bss_info_changed, @@ -1030,4 +1139,5 @@ const struct ieee80211_ops rtl_ops = { .sw_scan_start = rtl_op_sw_scan_start, .sw_scan_complete = rtl_op_sw_scan_complete, .rfkill_poll = rtl_op_rfkill_poll, + .flush = rtl_op_flush, }; diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h index 0ef31c3c6196..4b247db2861d 100644 --- a/drivers/net/wireless/rtlwifi/core.h +++ b/drivers/net/wireless/rtlwifi/core.h @@ -24,6 +24,7 @@ * Hsinchu 300, Taiwan. * * Larry Finger + * *****************************************************************************/ #ifndef __RTL_CORE_H__ diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 590f14f45a89..50de6f5d8a56 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -52,8 +52,6 @@ static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = { {11, 0, 0, 28} }; -static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, - u8 *pbuf); static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset, u8 *value); static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset, @@ -79,7 +77,7 @@ static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata, u8 *targetdata); static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, u16 efuse_addr, u8 word_en, u8 *data); -static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, +static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate); static u16 efuse_get_current_size(struct ieee80211_hw *hw); static u8 efuse_calculate_word_cnts(u8 word_en); @@ -115,8 +113,10 @@ u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address) u8 bytetemp; u8 temp; u32 k = 0; + const u32 efuse_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; - if (address < EFUSE_REAL_CONTENT_LEN) { + if (address < efuse_len) { temp = address & 0xFF; rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, temp); @@ -158,11 +158,13 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) u8 bytetemp; u8 temp; u32 k = 0; + const u32 efuse_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("Addr=%x Data =%x\n", address, value)); - if (address < EFUSE_REAL_CONTENT_LEN) { + if (address < efuse_len) { rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value); temp = address & 0xFF; @@ -198,7 +200,7 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) } -static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) +void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 value32; @@ -233,26 +235,45 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - u8 efuse_tbl[EFUSE_MAP_LEN]; + u8 *efuse_tbl; u8 rtemp8[1]; u16 efuse_addr = 0; u8 offset, wren; u16 i; u16 j; - u16 efuse_word[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT]; + const u16 efuse_max_section = + rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP]; + const u32 efuse_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + u16 **efuse_word; u16 efuse_utilized = 0; u8 efuse_usage; - if ((_offset + _size_byte) > EFUSE_MAP_LEN) { + if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) { RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("read_efuse(): Invalid offset(%#x) with read " "bytes(%#x)!!\n", _offset, _size_byte)); return; } - for (i = 0; i < EFUSE_MAX_SECTION; i++) + /* allocate memory for efuse_tbl and efuse_word */ + efuse_tbl = kmalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE] * + sizeof(u8), GFP_ATOMIC); + if (!efuse_tbl) + return; + efuse_word = kmalloc(EFUSE_MAX_WORD_UNIT * sizeof(u16 *), GFP_ATOMIC); + if (!efuse_word) + goto done; + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { + efuse_word[i] = kmalloc(efuse_max_section * sizeof(u16), + GFP_ATOMIC); + if (!efuse_word[i]) + goto done; + } + + for (i = 0; i < efuse_max_section; i++) for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) - efuse_word[i][j] = 0xFFFF; + efuse_word[j][i] = 0xFFFF; read_efuse_byte(hw, efuse_addr, rtemp8); if (*rtemp8 != 0xFF) { @@ -262,10 +283,10 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) efuse_addr++; } - while ((*rtemp8 != 0xFF) && (efuse_addr < EFUSE_REAL_CONTENT_LEN)) { + while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) { offset = ((*rtemp8 >> 4) & 0x0f); - if (offset < EFUSE_MAX_SECTION) { + if (offset < efuse_max_section) { wren = (*rtemp8 & 0x0f); RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, ("offset-%d Worden=%x\n", offset, wren)); @@ -279,9 +300,10 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) read_efuse_byte(hw, efuse_addr, rtemp8); efuse_addr++; efuse_utilized++; - efuse_word[offset][i] = (*rtemp8 & 0xff); + efuse_word[i][offset] = + (*rtemp8 & 0xff); - if (efuse_addr >= EFUSE_REAL_CONTENT_LEN) + if (efuse_addr >= efuse_len) break; RTPRINT(rtlpriv, FEEPROM, @@ -291,10 +313,10 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) read_efuse_byte(hw, efuse_addr, rtemp8); efuse_addr++; efuse_utilized++; - efuse_word[offset][i] |= + efuse_word[i][offset] |= (((u16)*rtemp8 << 8) & 0xff00); - if (efuse_addr >= EFUSE_REAL_CONTENT_LEN) + if (efuse_addr >= efuse_len) break; } @@ -305,18 +327,18 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, ("Addr=%d\n", efuse_addr)); read_efuse_byte(hw, efuse_addr, rtemp8); - if (*rtemp8 != 0xFF && (efuse_addr < 512)) { + if (*rtemp8 != 0xFF && (efuse_addr < efuse_len)) { efuse_utilized++; efuse_addr++; } } - for (i = 0; i < EFUSE_MAX_SECTION; i++) { + for (i = 0; i < efuse_max_section; i++) { for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { efuse_tbl[(i * 8) + (j * 2)] = - (efuse_word[i][j] & 0xff); + (efuse_word[j][i] & 0xff); efuse_tbl[(i * 8) + ((j * 2) + 1)] = - ((efuse_word[i][j] >> 8) & 0xff); + ((efuse_word[j][i] >> 8) & 0xff); } } @@ -324,12 +346,17 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) pbuf[i] = efuse_tbl[_offset + i]; rtlefuse->efuse_usedbytes = efuse_utilized; - efuse_usage = (u8)((efuse_utilized * 100) / EFUSE_REAL_CONTENT_LEN); + efuse_usage = (u8) ((efuse_utilized * 100) / efuse_len); rtlefuse->efuse_usedpercentage = efuse_usage; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_utilized); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE, (u8 *)&efuse_usage); +done: + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) + kfree(efuse_word[i]); + kfree(efuse_word); + kfree(efuse_tbl); } bool efuse_shadow_update_chk(struct ieee80211_hw *hw) @@ -338,11 +365,11 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw) struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 section_idx, i, Base; u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used; - bool bwordchanged, bresult = true; + bool wordchanged, result = true; for (section_idx = 0; section_idx < 16; section_idx++) { Base = section_idx * 8; - bwordchanged = false; + wordchanged = false; for (i = 0; i < 8; i = i + 2) { if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i] != @@ -351,11 +378,11 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw) rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i + 1])) { words_need++; - bwordchanged = true; + wordchanged = true; } } - if (bwordchanged == true) + if (wordchanged == true) hdr_num++; } @@ -364,14 +391,14 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw) if ((totalbytes + efuse_used) >= (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) - bresult = false; + result = false; RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("efuse_shadow_update_chk(): totalbytes(%#x), " "hdr_num(%#x), words_need(%#x), efuse_used(%d)\n", totalbytes, hdr_num, words_need, efuse_used)); - return bresult; + return result; } void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, @@ -394,7 +421,7 @@ void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset, else if (type == 2) efuse_shadow_write_2byte(hw, offset, (u16) value); else if (type == 4) - efuse_shadow_write_4byte(hw, offset, (u32) value); + efuse_shadow_write_4byte(hw, offset, value); } @@ -478,9 +505,10 @@ void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - if (rtlefuse->autoload_failflag == true) { - memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, 128); - } else + if (rtlefuse->autoload_failflag == true) + memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, + rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + else efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], @@ -572,7 +600,7 @@ static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 tmpidx = 0; - int bresult; + int result; rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (u8) (addr & 0xff)); @@ -592,19 +620,18 @@ static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) if (tmpidx < 100) { *data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); - bresult = true; + result = true; } else { *data = 0xff; - bresult = false; + result = false; } - return bresult; + return result; } static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 tmpidx = 0; - bool bresult; RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("Addr = %x Data=%x\n", addr, data)); @@ -626,17 +653,16 @@ static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) } if (tmpidx < 100) - bresult = true; - else - bresult = false; + return true; - return bresult; + return false; } static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse) { + struct rtl_priv *rtlpriv = rtl_priv(hw); efuse_power_switch(hw, false, true); - read_efuse(hw, 0, 128, efuse); + read_efuse(hw, 0, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], efuse); efuse_power_switch(hw, false, false); } @@ -644,7 +670,7 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, u8 efuse_data, u8 offset, u8 *tmpdata, u8 *readstate) { - bool bdataempty = true; + bool dataempty = true; u8 hoffset; u8 tmpidx; u8 hworden; @@ -660,13 +686,13 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, &efuse_data)) { tmpdata[tmpidx] = efuse_data; if (efuse_data != 0xff) - bdataempty = true; + dataempty = true; } } - if (bdataempty == true) + if (dataempty == true) { *readstate = PG_STATE_DATA; - else { + } else { *efuse_addr = *efuse_addr + (word_cnts * 2) + 1; *readstate = PG_STATE_HEADER; } @@ -680,12 +706,9 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) { u8 readstate = PG_STATE_HEADER; - - bool bcontinual = true; - + bool continual = true; u8 efuse_data, word_cnts = 0; u16 efuse_addr = 0; - u8 hworden = 0; u8 tmpdata[8]; if (data == NULL) @@ -696,7 +719,7 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); - while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) { + while (continual && (efuse_addr < EFUSE_MAX_SIZE)) { if (readstate & PG_STATE_HEADER) { if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) && (efuse_data != 0xFF)) @@ -705,9 +728,9 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) offset, tmpdata, &readstate); else - bcontinual = false; + continual = false; } else if (readstate & PG_STATE_DATA) { - efuse_word_enable_data_read(hworden, tmpdata, data); + efuse_word_enable_data_read(0, tmpdata, data); efuse_addr = efuse_addr + (word_cnts * 2) + 1; readstate = PG_STATE_HEADER; } @@ -725,13 +748,13 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) } static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, - u8 efuse_data, u8 offset, int *bcontinual, + u8 efuse_data, u8 offset, int *continual, u8 *write_state, struct pgpkt_struct *target_pkt, - int *repeat_times, int *bresult, u8 word_en) + int *repeat_times, int *result, u8 word_en) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct pgpkt_struct tmp_pkt; - int bdataempty = true; + bool dataempty = true; u8 originaldata[8 * sizeof(u8)]; u8 badworden = 0x0F; u8 match_word_en, tmp_word_en; @@ -751,10 +774,10 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, u16 address = *efuse_addr + 1 + tmpindex; if (efuse_one_byte_read(hw, address, &efuse_data) && (efuse_data != 0xFF)) - bdataempty = false; + dataempty = false; } - if (bdataempty == false) { + if (dataempty == false) { *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; *write_state = PG_STATE_HEADER; } else { @@ -799,24 +822,25 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, tmp_word_en &= (~BIT(1)); if ((target_pkt->word_en & BIT(2)) ^ - (match_word_en & BIT(2))) + (match_word_en & BIT(2))) tmp_word_en &= (~BIT(2)); if ((target_pkt->word_en & BIT(3)) ^ - (match_word_en & BIT(3))) + (match_word_en & BIT(3))) tmp_word_en &= (~BIT(3)); if ((tmp_word_en & 0x0F) != 0x0F) { *efuse_addr = efuse_get_current_size(hw); target_pkt->offset = offset; target_pkt->word_en = tmp_word_en; - } else - *bcontinual = false; + } else { + *continual = false; + } *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { - *bcontinual = false; - *bresult = false; + *continual = false; + *result = false; } } else { *efuse_addr += (2 * tmp_word_cnts) + 1; @@ -830,9 +854,9 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, } static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, - int *bcontinual, u8 *write_state, + int *continual, u8 *write_state, struct pgpkt_struct target_pkt, - int *repeat_times, int *bresult) + int *repeat_times, int *result) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct pgpkt_struct tmp_pkt; @@ -846,14 +870,14 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, efuse_one_byte_write(hw, *efuse_addr, pg_header); efuse_one_byte_read(hw, *efuse_addr, &tmp_header); - if (tmp_header == pg_header) + if (tmp_header == pg_header) { *write_state = PG_STATE_DATA; - else if (tmp_header == 0xFF) { + } else if (tmp_header == 0xFF) { *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { - *bcontinual = false; - *bresult = false; + *continual = false; + *result = false; } } else { tmp_pkt.offset = (tmp_header >> 4) & 0x0F; @@ -875,17 +899,19 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, reorg_worden, originaldata); *efuse_addr = efuse_get_current_size(hw); - } else + } else { *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; - } else + } + } else { *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; + } *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { - *bcontinual = false; - *bresult = false; + *continual = false; + *result = false; } RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, @@ -899,7 +925,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct pgpkt_struct target_pkt; u8 write_state = PG_STATE_HEADER; - int bcontinual = true, bdataempty = true, bresult = true; + int continual = true, dataempty = true, result = true; u16 efuse_addr = 0; u8 efuse_data; u8 target_word_cnts = 0; @@ -923,11 +949,11 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse Power ON\n")); - while (bcontinual && (efuse_addr < + while (continual && (efuse_addr < (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) { if (write_state == PG_STATE_HEADER) { - bdataempty = true; + dataempty = true; badworden = 0x0F; RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse PG_STATE_HEADER\n")); @@ -936,32 +962,30 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, (efuse_data != 0xFF)) efuse_write_data_case1(hw, &efuse_addr, efuse_data, offset, - &bcontinual, + &continual, &write_state, &target_pkt, - &repeat_times, &bresult, + &repeat_times, &result, word_en); else efuse_write_data_case2(hw, &efuse_addr, - &bcontinual, + &continual, &write_state, target_pkt, &repeat_times, - &bresult); + &result); } else if (write_state == PG_STATE_DATA) { RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse PG_STATE_DATA\n")); - badworden = 0x0f; badworden = efuse_word_enable_data_write(hw, efuse_addr + 1, target_pkt.word_en, target_pkt.data); if ((badworden & 0x0F) == 0x0F) { - bcontinual = false; + continual = false; } else { - efuse_addr = - efuse_addr + (2 * target_word_cnts) + 1; + efuse_addr += (2 * target_word_cnts) + 1; target_pkt.offset = offset; target_pkt.word_en = badworden; @@ -971,8 +995,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, write_state = PG_STATE_HEADER; repeat_times++; if (repeat_times > EFUSE_REPEAT_THRESHOLD_) { - bcontinual = false; - bresult = false; + continual = false; + result = false; } RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse PG_STATE_HEADER-3\n")); @@ -1072,13 +1096,15 @@ static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, return badworden; } -static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) +static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u8 tempval; u16 tmpV16; - if (pwrstate == true) { + if (pwrstate && (rtlhal->hw_type != + HARDWARE_TYPE_RTL8192SE)) { tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL]); if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { @@ -1106,20 +1132,29 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) } } - if (pwrstate == true) { - if (bwrite == true) { + if (pwrstate) { + if (write) { tempval = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); - tempval &= 0x0F; - tempval |= (VOLTAGE_V25 << 4); + + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) { + tempval &= 0x0F; + tempval |= (VOLTAGE_V25 << 4); + } + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, (tempval | 0x80)); } + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], + 0x03); + } + } else { - if (bwrite == true) { + if (write) { tempval = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); @@ -1128,18 +1163,23 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) (tempval & 0x7F)); } + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], + 0x02); + } + } } static u16 efuse_get_current_size(struct ieee80211_hw *hw) { - int bcontinual = true; + int continual = true; u16 efuse_addr = 0; u8 hoffset, hworden; u8 efuse_data, word_cnts; - while (bcontinual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) + while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) && (efuse_addr < EFUSE_MAX_SIZE)) { if (efuse_data != 0xFF) { hoffset = (efuse_data >> 4) & 0x0F; @@ -1147,7 +1187,7 @@ static u16 efuse_get_current_size(struct ieee80211_hw *hw) word_cnts = efuse_calculate_word_cnts(hworden); efuse_addr = efuse_addr + (word_cnts * 2) + 1; } else { - bcontinual = false; + continual = false; } } diff --git a/drivers/net/wireless/rtlwifi/efuse.h b/drivers/net/wireless/rtlwifi/efuse.h index 47774dd4c2a6..164dabaa7615 100644 --- a/drivers/net/wireless/rtlwifi/efuse.h +++ b/drivers/net/wireless/rtlwifi/efuse.h @@ -30,9 +30,10 @@ #ifndef __RTL_EFUSE_H_ #define __RTL_EFUSE_H_ +#define EFUSE_IC_ID_OFFSET 506 + #define EFUSE_REAL_CONTENT_LEN 512 #define EFUSE_MAP_LEN 128 -#define EFUSE_MAX_SECTION 16 #define EFUSE_MAX_WORD_UNIT 4 #define EFUSE_INIT_MAP 0 @@ -52,6 +53,7 @@ #define _PRE_EXECUTE_READ_CMD_ #define EFUSE_REPEAT_THRESHOLD_ 3 +#define EFUSE_ERROE_HANDLE 1 struct efuse_map { u8 offset; @@ -103,6 +105,7 @@ struct efuse_priv { u8 tx_power_g[14]; }; +extern void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf); extern void efuse_initialize(struct ieee80211_hw *hw); extern u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address); extern void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value); diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 5938f6ee21e4..a40952845436 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -32,6 +32,7 @@ #include "pci.h" #include "base.h" #include "ps.h" +#include "efuse.h" static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { INTEL_VENDOR_ID, @@ -40,6 +41,31 @@ static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { SIS_VENDOR_ID }; +static const u8 ac_to_hwq[] = { + VO_QUEUE, + VI_QUEUE, + BE_QUEUE, + BK_QUEUE +}; + +static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + __le16 fc = rtl_get_fc(skb); + u8 queue_index = skb_get_queue_mapping(skb); + + if (unlikely(ieee80211_is_beacon(fc))) + return BEACON_QUEUE; + if (ieee80211_is_mgmt(fc)) + return MGNT_QUEUE; + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) + if (ieee80211_is_nullfunc(fc)) + return HIGH_QUEUE; + + return ac_to_hwq[queue_index]; +} + /* Update PCI dependent default settings*/ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) { @@ -48,6 +74,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; + u8 init_aspm; ppsc->reg_rfps_level = 0; ppsc->support_aspm = 0; @@ -125,7 +152,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) bool support_backdoor = true; ppsc->support_aspm = support_aspm; - /*if(priv->oem_id == RT_CID_TOSHIBA && + /*if (priv->oem_id == RT_CID_TOSHIBA && !priv->ndis_adapter.amd_l1_patch) support_backdoor = false; */ @@ -145,6 +172,13 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) ("switch case not process\n")); break; } + + /* toshiba aspm issue, toshiba will set aspm selfly + * so we should not set aspm in driver */ + pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm); + if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE && + init_aspm == 0x43) + ppsc->support_aspm = false; } static bool _rtl_pci_platform_switch_device_pci_aspm( @@ -152,28 +186,28 @@ static bool _rtl_pci_platform_switch_device_pci_aspm( u8 value) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - bool bresult = false; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - value |= 0x40; + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) + value |= 0x40; pci_write_config_byte(rtlpci->pdev, 0x80, value); - return bresult; + return false; } /*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/ static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - u8 buffer; - bool bresult = false; - - buffer = value; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); pci_write_config_byte(rtlpci->pdev, 0x81, value); - bresult = true; - return bresult; + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) + udelay(100); + + return true; } /*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/ @@ -191,6 +225,10 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter. pcibridge_linkctrlreg; u16 aspmlevel = 0; + u8 tmp_u1b = 0; + + if (!ppsc->support_aspm) + return; if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, @@ -204,11 +242,8 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) _rtl_pci_switch_clk_req(hw, 0x0); } - if (1) { - /*for promising device will in L0 state after an I/O. */ - u8 tmp_u1b; - pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); - } + /*for promising device will in L0 state after an I/O. */ + pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); /*Set corresponding value. */ aspmlevel |= BIT(0) | BIT(1); @@ -224,7 +259,6 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg); udelay(50); - } /* @@ -249,6 +283,9 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) u8 u_pcibridge_aspmsetting; u8 u_device_aspmsetting; + if (!ppsc->support_aspm) + return; + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, ("PCI(Bridge) UNKNOWN.\n")); @@ -293,7 +330,7 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0); RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ); } - udelay(200); + udelay(100); } static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) @@ -330,13 +367,13 @@ static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; u8 linkctrl_reg; - u8 num4bBytes; + u8 num4bbytes; - num4bBytes = (capabilityoffset + 0x10) / 4; + num4bbytes = (capabilityoffset + 0x10) / 4; /*Read Link Control Register */ rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, - pcicfg_addrport + (num4bBytes << 2)); + pcicfg_addrport + (num4bbytes << 2)); rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg); pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg; @@ -369,7 +406,7 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev, pci_write_config_byte(pdev, 0x70f, tmp); } -static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw) +static void rtl_pci_init_aspm(struct ieee80211_hw *hw) { struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); @@ -383,52 +420,6 @@ static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw) } -static void rtl_pci_init_aspm(struct ieee80211_hw *hw) -{ - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - - /* - * ASPM PS mode. - * 0 - Disable ASPM, - * 1 - Enable ASPM without Clock Req, - * 2 - Enable ASPM with Clock Req, - * 3 - Always Enable ASPM with Clock Req, - * 4 - Always Enable ASPM without Clock Req. - * set defult to RTL8192CE:3 RTL8192E:2 - * */ - rtlpci->const_pci_aspm = 3; - - /*Setting for PCI-E device */ - rtlpci->const_devicepci_aspm_setting = 0x03; - - /*Setting for PCI-E bridge */ - rtlpci->const_hostpci_aspm_setting = 0x02; - - /* - * In Hw/Sw Radio Off situation. - * 0 - Default, - * 1 - From ASPM setting without low Mac Pwr, - * 2 - From ASPM setting with low Mac Pwr, - * 3 - Bus D3 - * set default to RTL8192CE:0 RTL8192SE:2 - */ - rtlpci->const_hwsw_rfoff_d3 = 0; - - /* - * This setting works for those device with - * backdoor ASPM setting such as EPHY setting. - * 0 - Not support ASPM, - * 1 - Support ASPM, - * 2 - According to chipset. - */ - rtlpci->const_support_pciaspm = 1; - - _rtl_pci_initialize_adapter_common(hw); -} - static void _rtl_pci_io_handler_init(struct device *dev, struct ieee80211_hw *hw) { @@ -450,6 +441,90 @@ static void _rtl_pci_io_handler_release(struct ieee80211_hw *hw) { } +static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw, + struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc, u8 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + u8 additionlen = FCS_LEN; + struct sk_buff *next_skb; + + /* here open is 4, wep/tkip is 8, aes is 12*/ + if (info->control.hw_key) + additionlen += info->control.hw_key->icv_len; + + /* The most skb num is 6 */ + tcb_desc->empkt_num = 0; + spin_lock_bh(&rtlpriv->locks.waitq_lock); + skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) { + struct ieee80211_tx_info *next_info; + + next_info = IEEE80211_SKB_CB(next_skb); + if (next_info->flags & IEEE80211_TX_CTL_AMPDU) { + tcb_desc->empkt_len[tcb_desc->empkt_num] = + next_skb->len + additionlen; + tcb_desc->empkt_num++; + } else { + break; + } + + if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid], + next_skb)) + break; + + if (tcb_desc->empkt_num >= 5) + break; + } + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + + return true; +} + +/* just for early mode now */ +static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct sk_buff *skb = NULL; + struct ieee80211_tx_info *info = NULL; + int tid; /* should be int */ + + if (!rtlpriv->rtlhal.earlymode_enable) + return; + + /* we juse use em for BE/BK/VI/VO */ + for (tid = 7; tid >= 0; tid--) { + u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)]; + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; + while (!mac->act_scanning && + rtlpriv->psc.rfpwr_state == ERFON) { + struct rtl_tcb_desc tcb_desc; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + spin_lock_bh(&rtlpriv->locks.waitq_lock); + if (!skb_queue_empty(&mac->skb_waitq[tid]) && + (ring->entries - skb_queue_len(&ring->queue) > 5)) { + skb = skb_dequeue(&mac->skb_waitq[tid]); + } else { + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + break; + } + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + + /* Some macaddr can't do early mode. like + * multicast/broadcast/no_qos data */ + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) + _rtl_update_earlymode_info(hw, skb, + &tcb_desc, tid); + + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); + } + } +} + + static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -461,6 +536,8 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) struct rtl_tx_desc *entry = &ring->desc[ring->idx]; struct sk_buff *skb; struct ieee80211_tx_info *info; + __le16 fc; + u8 tid; u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true, HW_DESC_OWN); @@ -481,6 +558,10 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) HW_DESC_TXBUFF_ADDR), skb->len, PCI_DMA_TODEVICE); + /* remove early mode header */ + if (rtlpriv->rtlhal.earlymode_enable) + skb_pull(skb, EM_HDR_LEN); + RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_TRACE, ("new ring->idx:%d, " "free: skb_queue_len:%d, free: seq:%x\n", @@ -488,6 +569,30 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) skb_queue_len(&ring->queue), *(u16 *) (skb->data + 22))); + if (prio == TXCMD_QUEUE) { + dev_kfree_skb(skb); + goto tx_status_ok; + + } + + /* for sw LPS, just after NULL skb send out, we can + * sure AP kown we are sleeped, our we should not let + * rf to sleep*/ + fc = rtl_get_fc(skb); + if (ieee80211_is_nullfunc(fc)) { + if (ieee80211_has_pm(fc)) { + rtlpriv->mac80211.offchan_deley = true; + rtlpriv->psc.state_inap = 1; + } else { + rtlpriv->psc.state_inap = 0; + } + } + + /* update tid tx pkt num */ + tid = rtl_get_tid(skb); + if (tid <= 7) + rtlpriv->link_info.tidtx_inperiod[tid]++; + info = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(info); @@ -510,7 +615,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) skb_get_queue_mapping (skb)); } - +tx_status_ok: skb = NULL; } @@ -582,23 +687,21 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) *skb_trim(skb, skb->len - 4); */ - hdr = (struct ieee80211_hdr *)(skb->data); - fc = hdr->frame_control; + hdr = rtl_get_hdr(skb); + fc = rtl_get_fc(skb); - if (!stats.crc) { + if (!stats.crc || !stats.hwerror) { memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); - if (is_broadcast_ether_addr(hdr->addr1)) + if (is_broadcast_ether_addr(hdr->addr1)) { ;/*TODO*/ - else { - if (is_multicast_ether_addr(hdr->addr1)) - ;/*TODO*/ - else { - unicast = true; - rtlpriv->stats.rxbytesunicast += - skb->len; - } + } else if (is_multicast_ether_addr(hdr->addr1)) { + ;/*TODO*/ + } else { + unicast = true; + rtlpriv->stats.rxbytesunicast += + skb->len; } rtl_is_special_data(hw, skb, false); @@ -612,28 +715,38 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) num_rx_inperiod++; } - if (unlikely(!rtl_action_proc(hw, skb, - false))) { + /* for sw lps */ + rtl_swlps_beacon(hw, (void *)skb->data, + skb->len); + rtl_recognize_peer(hw, (void *)skb->data, + skb->len); + if ((rtlpriv->mac80211.opmode == + NL80211_IFTYPE_AP) && + (rtlpriv->rtlhal.current_bandtype == + BAND_ON_2_4G) && + (ieee80211_is_beacon(fc) || + ieee80211_is_probe_resp(fc))) { dev_kfree_skb_any(skb); } else { - struct sk_buff *uskb = NULL; - u8 *pdata; - uskb = dev_alloc_skb(skb->len + 128); - if (!uskb) { - RT_TRACE(rtlpriv, - (COMP_INTR | COMP_RECV), - DBG_EMERG, - ("can't alloc rx skb\n")); - goto done; - } - memcpy(IEEE80211_SKB_RXCB(uskb), - &rx_status, - sizeof(rx_status)); - pdata = (u8 *)skb_put(uskb, skb->len); - memcpy(pdata, skb->data, skb->len); - dev_kfree_skb_any(skb); + if (unlikely(!rtl_action_proc(hw, skb, + false))) { + dev_kfree_skb_any(skb); + } else { + struct sk_buff *uskb = NULL; + u8 *pdata; + uskb = dev_alloc_skb(skb->len + + 128); + memcpy(IEEE80211_SKB_RXCB(uskb), + &rx_status, + sizeof(rx_status)); + pdata = (u8 *)skb_put(uskb, + skb->len); + memcpy(pdata, skb->data, + skb->len); + dev_kfree_skb_any(skb); - ieee80211_rx_irqsafe(hw, uskb); + ieee80211_rx_irqsafe(hw, uskb); + } } } else { dev_kfree_skb_any(skb); @@ -648,7 +761,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) new_skb = dev_alloc_skb(rtlpci->rxbuffersize); if (unlikely(!new_skb)) { RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), - DBG_EMERG, + DBG_DMESG, ("can't alloc skb for rx\n")); goto done; } @@ -666,7 +779,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) } done: - bufferaddress = (u32)(*((dma_addr_t *) skb->cb)); + bufferaddress = (*((dma_addr_t *)skb->cb)); tmp_one = 1; rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, HW_DESC_RXBUFF_ADDR, @@ -695,6 +808,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) struct ieee80211_hw *hw = dev_id; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); unsigned long flags; u32 inta = 0; u32 intb = 0; @@ -781,23 +895,36 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) _rtl_pci_tx_isr(hw, VO_QUEUE); } + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + if (inta & rtlpriv->cfg->maps[RTL_IMR_COMDOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + ("CMD TX OK interrupt!\n")); + _rtl_pci_tx_isr(hw, TXCMD_QUEUE); + } + } + /*<2> Rx related */ if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) { RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n")); - tasklet_schedule(&rtlpriv->works.irq_tasklet); + _rtl_pci_rx_interrupt(hw); } if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx descriptor unavailable!\n")); - tasklet_schedule(&rtlpriv->works.irq_tasklet); + _rtl_pci_rx_interrupt(hw); } if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx overflow !\n")); - tasklet_schedule(&rtlpriv->works.irq_tasklet); + _rtl_pci_rx_interrupt(hw); } + if (rtlpriv->rtlhal.earlymode_enable) + tasklet_schedule(&rtlpriv->works.irq_tasklet); + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); return IRQ_HANDLED; @@ -808,7 +935,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) { - _rtl_pci_rx_interrupt(hw); + _rtl_pci_tx_chk_waitq(hw); } static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) @@ -816,14 +943,15 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; + struct rtl8192_tx_ring *ring = NULL; struct ieee80211_hdr *hdr = NULL; struct ieee80211_tx_info *info = NULL; struct sk_buff *pskb = NULL; struct rtl_tx_desc *pdesc = NULL; - unsigned int queue_index; + struct rtl_tcb_desc tcb_desc; u8 temp_one = 1; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); ring = &rtlpci->tx_ring[BEACON_QUEUE]; pskb = __skb_dequeue(&ring->queue); if (pskb) @@ -833,14 +961,11 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) pskb = ieee80211_beacon_get(hw, mac->vif); if (pskb == NULL) return; - hdr = (struct ieee80211_hdr *)(pskb->data); + hdr = rtl_get_hdr(pskb); info = IEEE80211_SKB_CB(pskb); - - queue_index = BEACON_QUEUE; - pdesc = &ring->desc[0]; rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, - info, pskb, queue_index); + info, pskb, BEACON_QUEUE, &tcb_desc); __skb_queue_tail(&ring->queue, pskb); @@ -882,7 +1007,6 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); rtlpci->up_first_time = true; rtlpci->being_init_adapter = false; @@ -890,31 +1014,20 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw, rtlhal->hw = hw; rtlpci->pdev = pdev; - ppsc->inactiveps = false; - ppsc->leisure_ps = true; - ppsc->fwctrl_lps = true; - ppsc->reg_fwctrl_lps = 3; - ppsc->reg_max_lps_awakeintvl = 5; - - if (ppsc->reg_fwctrl_lps == 1) - ppsc->fwctrl_psmode = FW_PS_MIN_MODE; - else if (ppsc->reg_fwctrl_lps == 2) - ppsc->fwctrl_psmode = FW_PS_MAX_MODE; - else if (ppsc->reg_fwctrl_lps == 3) - ppsc->fwctrl_psmode = FW_PS_DTIM_MODE; - /*Tx/Rx related var */ _rtl_pci_init_trx_var(hw); - /*IBSS*/ mac->beacon_interval = 100; + /*IBSS*/ mac->beacon_interval = 100; - /*AMPDU*/ mac->min_space_cfg = 0; + /*AMPDU*/ + mac->min_space_cfg = 0; mac->max_mss_density = 0; /*set sane AMPDU defaults */ mac->current_ampdu_density = 7; mac->current_ampdu_factor = 3; - /*QOS*/ rtlpci->acm_method = eAcmWay2_SW; + /*QOS*/ + rtlpci->acm_method = eAcmWay2_SW; /*task */ tasklet_init(&rtlpriv->works.irq_tasklet, @@ -955,7 +1068,8 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, ("queue:%d, ring_addr:%p\n", prio, ring)); for (i = 0; i < entries; i++) { - nextdescaddress = (u32) dma + ((i + 1) % entries) * + nextdescaddress = (u32) dma + + ((i + 1) % entries) * sizeof(*ring); rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]), @@ -1020,7 +1134,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw) rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); - bufferaddress = (u32)(*((dma_addr_t *)skb->cb)); + bufferaddress = (*((dma_addr_t *)skb->cb)); rtlpriv->cfg->ops->set_desc((u8 *)entry, false, HW_DESC_RXBUFF_ADDR, (u8 *)&bufferaddress); @@ -1203,72 +1317,73 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) return 0; } -static unsigned int _rtl_mac_to_hwqueue(__le16 fc, - unsigned int mac80211_queue_index) -{ - unsigned int hw_queue_index; - - if (unlikely(ieee80211_is_beacon(fc))) { - hw_queue_index = BEACON_QUEUE; - goto out; - } - - if (ieee80211_is_mgmt(fc)) { - hw_queue_index = MGNT_QUEUE; - goto out; - } - - switch (mac80211_queue_index) { - case 0: - hw_queue_index = VO_QUEUE; - break; - case 1: - hw_queue_index = VI_QUEUE; - break; - case 2: - hw_queue_index = BE_QUEUE;; - break; - case 3: - hw_queue_index = BK_QUEUE; - break; - default: - hw_queue_index = BE_QUEUE; - RT_ASSERT(false, ("QSLT_BE queue, skb_queue:%d\n", - mac80211_queue_index)); - break; - } - -out: - return hw_queue_index; -} - -static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, + struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->control.sta; + struct rtl_sta_info *sta_entry = NULL; + u8 tid = rtl_get_tid(skb); + + if (!sta) + return false; + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + + if (!rtlpriv->rtlhal.earlymode_enable) + return false; + if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL) + return false; + if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE) + return false; + if (tid > 7) + return false; + + /* maybe every tid should be checked */ + if (!rtlpriv->link_info.higher_busytxtraffic[tid]) + return false; + + spin_lock_bh(&rtlpriv->locks.waitq_lock); + skb_queue_tail(&rtlpriv->mac80211.skb_waitq[tid], skb); + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + + return true; +} + +static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct rtl_tcb_desc *ptcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *sta_entry = NULL; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->control.sta; struct rtl8192_tx_ring *ring; struct rtl_tx_desc *pdesc; u8 idx; - unsigned int queue_index, hw_queue; + u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb); unsigned long flags; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); - __le16 fc = hdr->frame_control; + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + __le16 fc = rtl_get_fc(skb); u8 *pda_addr = hdr->addr1; struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); /*ssn */ - u8 *qc = NULL; u8 tid = 0; u16 seq_number = 0; u8 own; u8 temp_one = 1; - if (ieee80211_is_mgmt(fc)) - rtl_tx_mgmt_proc(hw, skb); - rtl_action_proc(hw, skb, true); + if (ieee80211_is_auth(fc)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); + rtl_ips_nic_on(hw); + } - queue_index = skb_get_queue_mapping(skb); - hw_queue = _rtl_mac_to_hwqueue(fc, queue_index); + if (rtlpriv->psc.sw_ps_enabled) { + if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && + !ieee80211_has_pm(fc)) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + } + + rtl_action_proc(hw, skb, true); if (is_multicast_ether_addr(pda_addr)) rtlpriv->stats.txbytesmulticast += skb->len; @@ -1278,7 +1393,6 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) rtlpriv->stats.txbytesunicast += skb->len; spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); - ring = &rtlpci->tx_ring[hw_queue]; if (hw_queue != BEACON_QUEUE) idx = (ring->idx + skb_queue_len(&ring->queue)) % @@ -1301,43 +1415,30 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return skb->len; } - /* - *if(ieee80211_is_nullfunc(fc)) { - * spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); - * return 1; - *} - */ - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + tid = rtl_get_tid(skb); + if (sta) { + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + seq_number = (le16_to_cpu(hdr->seq_ctrl) & + IEEE80211_SCTL_SEQ) >> 4; + seq_number += 1; - seq_number = mac->tids[tid].seq_number; - seq_number &= IEEE80211_SCTL_SEQ; - /* - *hdr->seq_ctrl = hdr->seq_ctrl & - *cpu_to_le16(IEEE80211_SCTL_FRAG); - *hdr->seq_ctrl |= cpu_to_le16(seq_number); - */ - - seq_number += 1; + if (!ieee80211_has_morefrags(hdr->frame_control)) + sta_entry->tids[tid].seq_number = seq_number; + } } if (ieee80211_is_data(fc)) rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); - rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, - info, skb, hw_queue); + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, + info, skb, hw_queue, ptcb_desc); __skb_queue_tail(&ring->queue, skb); - rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, + rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true, HW_DESC_OWN, (u8 *)&temp_one); - if (!ieee80211_has_morefrags(hdr->frame_control)) { - if (qc) - mac->tids[tid].seq_number = seq_number; - } if ((ring->entries - skb_queue_len(&ring->queue)) < 2 && hw_queue != BEACON_QUEUE) { @@ -1359,6 +1460,35 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return 0; } +static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u16 i = 0; + int queue_id; + struct rtl8192_tx_ring *ring; + + for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) { + u32 queue_len; + ring = &pcipriv->dev.tx_ring[queue_id]; + queue_len = skb_queue_len(&ring->queue); + if (queue_len == 0 || queue_id == BEACON_QUEUE || + queue_id == TXCMD_QUEUE) { + queue_id--; + continue; + } else { + msleep(20); + i++; + } + + /* we just wait 1s for all queues */ + if (rtlpriv->psc.rfpwr_state == ERFOFF || + is_hal_stop(rtlhal) || i >= 200) + return; + } +} + static void rtl_pci_deinit(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1477,11 +1607,14 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, struct pci_dev *bridge_pdev = pdev->bus->self; u16 venderid; u16 deviceid; + u8 revisionid; u16 irqline; u8 tmp; + pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN; venderid = pdev->vendor; deviceid = pdev->device; + pci_read_config_byte(pdev, 0x8, &revisionid); pci_read_config_word(pdev, 0x3C, &irqline); if (deviceid == RTL_PCI_8192_DID || @@ -1492,7 +1625,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, deviceid == RTL_PCI_8173_DID || deviceid == RTL_PCI_8172_DID || deviceid == RTL_PCI_8171_DID) { - switch (pdev->revision) { + switch (revisionid) { case RTL_PCI_REVISION_ID_8192PCIE: RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("8192 PCI-E is found - " @@ -1521,6 +1654,12 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("8192C PCI-E is found - " "vid/did=%x/%x\n", venderid, deviceid)); + } else if (deviceid == RTL_PCI_8192DE_DID || + deviceid == RTL_PCI_8192DE_DID2) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8192DE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + ("8192D PCI-E is found - " + "vid/did=%x/%x\n", venderid, deviceid)); } else { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("Err: Unknown device -" @@ -1529,6 +1668,25 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE; } + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) { + if (revisionid == 0 || revisionid == 1) { + if (revisionid == 0) { + RT_TRACE(rtlpriv, COMP_INIT, + DBG_LOUD, ("Find 92DE MAC0.\n")); + rtlhal->interfaceindex = 0; + } else if (revisionid == 1) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Find 92DE MAC1.\n")); + rtlhal->interfaceindex = 1; + } + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Unknown device - " + "VendorID/DeviceID=%x/%x, Revision=%x\n", + venderid, deviceid, revisionid)); + rtlhal->interfaceindex = 0; + } + } /*find bus info */ pcipriv->ndis_adapter.busnumber = pdev->bus->number; pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn); @@ -1554,12 +1712,12 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, PCI_SLOT(bridge_pdev->devfn); pcipriv->ndis_adapter.pcibridge_funcnum = PCI_FUNC(bridge_pdev->devfn); - pcipriv->ndis_adapter.pcibridge_pciehdr_offset = - pci_pcie_cap(bridge_pdev); pcipriv->ndis_adapter.pcicfg_addrport = (pcipriv->ndis_adapter.pcibridge_busnum << 16) | (pcipriv->ndis_adapter.pcibridge_devnum << 11) | (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31); + pcipriv->ndis_adapter.pcibridge_pciehdr_offset = + pci_pcie_cap(bridge_pdev); pcipriv->ndis_adapter.num4bytes = (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4; @@ -1642,6 +1800,11 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, pcipriv = (void *)rtlpriv->priv; pcipriv->dev.pdev = pdev; + /* init cfg & intf_ops */ + rtlpriv->rtlhal.interface = INTF_PCI; + rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); + rtlpriv->intf_ops = &rtl_pci_ops; + /* *init dbgp flags before all *other functions, because we will @@ -1659,13 +1822,14 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, return err; } - pmem_start = pci_resource_start(pdev, 2); - pmem_len = pci_resource_len(pdev, 2); - pmem_flags = pci_resource_flags(pdev, 2); + pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id); + pmem_len = pci_resource_len(pdev, rtlpriv->cfg->bar_id); + pmem_flags = pci_resource_flags(pdev, rtlpriv->cfg->bar_id); /*shared mem start */ rtlpriv->io.pci_mem_start = - (unsigned long)pci_iomap(pdev, 2, pmem_len); + (unsigned long)pci_iomap(pdev, + rtlpriv->cfg->bar_id, pmem_len); if (rtlpriv->io.pci_mem_start == 0) { RT_ASSERT(false, ("Can't map PCI mem\n")); goto fail2; @@ -1684,11 +1848,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, pci_write_config_byte(pdev, 0x04, 0x06); pci_write_config_byte(pdev, 0x04, 0x07); - /* init cfg & intf_ops */ - rtlpriv->rtlhal.interface = INTF_PCI; - rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); - rtlpriv->intf_ops = &rtl_pci_ops; - /* find adapter */ _rtl_pci_find_adapter(pdev, hw); @@ -1806,7 +1965,6 @@ void rtl_pci_disconnect(struct pci_dev *pdev) rtl_pci_deinit(hw); rtl_deinit_core(hw); - rtlpriv->cfg->ops->deinit_sw_leds(hw); _rtl_pci_io_handler_release(hw); rtlpriv->cfg->ops->deinit_sw_vars(hw); @@ -1821,6 +1979,9 @@ void rtl_pci_disconnect(struct pci_dev *pdev) } pci_disable_device(pdev); + + rtl_pci_disable_aspm(hw); + pci_set_drvdata(pdev, NULL); ieee80211_free_hw(hw); @@ -1844,10 +2005,15 @@ no need to call hw_disable here. ****************************************/ int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state) { + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->cfg->ops->hw_suspend(hw); + rtl_deinit_rfkill(hw); + pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); - return 0; } EXPORT_SYMBOL(rtl_pci_suspend); @@ -1855,6 +2021,8 @@ EXPORT_SYMBOL(rtl_pci_suspend); int rtl_pci_resume(struct pci_dev *pdev) { int ret; + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtl_priv *rtlpriv = rtl_priv(hw); pci_set_power_state(pdev, PCI_D0); ret = pci_enable_device(pdev); @@ -1865,15 +2033,20 @@ int rtl_pci_resume(struct pci_dev *pdev) pci_restore_state(pdev); + rtlpriv->cfg->ops->hw_resume(hw); + rtl_init_rfkill(hw); return 0; } EXPORT_SYMBOL(rtl_pci_resume); struct rtl_intf_ops rtl_pci_ops = { + .read_efuse_byte = read_efuse_byte, .adapter_start = rtl_pci_start, .adapter_stop = rtl_pci_stop, .adapter_tx = rtl_pci_tx, + .flush = rtl_pci_flush, .reset_trx_ring = rtl_pci_reset_trx_ring, + .waitq_insert = rtl_pci_tx_chk_waitq_insert, .disable_aspm = rtl_pci_disable_aspm, .enable_aspm = rtl_pci_enable_aspm, diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 0caa81429726..671b1f5aa0cf 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -102,8 +102,8 @@ #define RTL_PCI_8191CE_DID 0x8177 /*8192ce */ #define RTL_PCI_8188CE_DID 0x8176 /*8192ce */ #define RTL_PCI_8192CU_DID 0x8191 /*8192ce */ -#define RTL_PCI_8192DE_DID 0x092D /*8192ce */ -#define RTL_PCI_8192DU_DID 0x092D /*8192ce */ +#define RTL_PCI_8192DE_DID 0x8193 /*8192de */ +#define RTL_PCI_8192DE_DID2 0x002B /*92DE*/ /*8192 support 16 pages of IO registers*/ #define RTL_MEM_MAPPED_IO_RANGE_8190PCI 0x1000 @@ -129,6 +129,11 @@ enum pci_bridge_vendor { PCI_BRIDGE_VENDOR_MAX, }; +struct rtl_pci_capabilities_header { + u8 capability_id; + u8 next; +}; + struct rtl_rx_desc { u32 dword[8]; } __packed; @@ -161,7 +166,9 @@ struct rtl_pci { bool driver_is_goingto_unload; bool up_first_time; + bool first_init; bool being_init_adapter; + bool init_ready; bool irq_enabled; /*Tx */ @@ -192,11 +199,14 @@ struct rtl_pci { u8 const_devicepci_aspm_setting; /*If it supports ASPM, Offset[560h] = 0x40, otherwise Offset[560h] = 0x00. */ - bool b_support_aspm; - bool b_support_backdoor; + bool support_aspm; + bool support_backdoor; /*QOS & EDCA */ enum acm_method acm_method; + + u16 shortretry_limit; + u16 longretry_limit; }; struct mp_adapter { @@ -227,6 +237,7 @@ struct rtl_pci_priv { struct rtl_pci dev; struct mp_adapter ndis_adapter; struct rtl_led_ctl ledctl; + struct bt_coexist_info bt_coexist; }; #define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv)) diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index 6b7e217b6b89..2bb71195e976 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -36,7 +36,6 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - bool init_status = true; /*<1> reset trx ring */ if (rtlhal->interface == INTF_PCI) @@ -49,7 +48,6 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw) /*<2> Enable Adapter */ rtlpriv->cfg->ops->hw_init(hw); RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); - /*init_status = false; */ /*<3> Enable Interrupt */ rtlpriv->cfg->ops->enable_interrupt(hw); @@ -57,13 +55,12 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw) /* */ rtl_watch_dog_timer_callback((unsigned long)hw); - return init_status; + return true; } EXPORT_SYMBOL(rtl_ps_enable_nic); bool rtl_ps_disable_nic(struct ieee80211_hw *hw) { - bool status = true; struct rtl_priv *rtlpriv = rtl_priv(hw); /*<1> Stop all timer */ @@ -75,7 +72,7 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw) /*<3> Disable Adapter */ rtlpriv->cfg->ops->hw_disable(hw); - return status; + return true; } EXPORT_SYMBOL(rtl_ps_disable_nic); @@ -193,12 +190,13 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) ppsc->swrf_processing = true; - if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) { + if (ppsc->inactive_pwrstate == ERFOFF && + rtlhal->interface == INTF_PCI) { if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && - RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM) && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && rtlhal->interface == INTF_PCI) { rtlpriv->intf_ops->disable_aspm(hw); - RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } } @@ -207,9 +205,10 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) if (ppsc->inactive_pwrstate == ERFOFF && rtlhal->interface == INTF_PCI) { - if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && + !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { rtlpriv->intf_ops->enable_aspm(hw); - RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); + RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } } @@ -233,6 +232,9 @@ void rtl_ips_nic_off_wq_callback(void *data) return; } + if (mac->link_state > MAC80211_NOLINK) + return; + if (is_hal_stop(rtlhal)) return; @@ -284,10 +286,14 @@ void rtl_ips_nic_off(struct ieee80211_hw *hw) void rtl_ips_nic_on(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); enum rf_pwrstate rtstate; unsigned long flags; + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags); if (ppsc->inactiveps) { @@ -370,8 +376,7 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) * mode and set RPWM to turn RF on. */ - if ((ppsc->fwctrl_lps) && (ppsc->leisure_ps) && - ppsc->report_linked) { + if ((ppsc->fwctrl_lps) && ppsc->report_linked) { bool fw_current_inps; if (ppsc->dot11_psmode == EACTIVE) { RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, @@ -425,7 +430,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); unsigned long flag; - if (!(ppsc->fwctrl_lps && ppsc->leisure_ps)) + if (!ppsc->fwctrl_lps) return; if (rtlpriv->sec.being_setkey) @@ -446,17 +451,16 @@ void rtl_lps_enter(struct ieee80211_hw *hw) spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); - if (ppsc->leisure_ps) { - /* Idle for a while if we connect to AP a while ago. */ - if (mac->cnt_after_linked >= 2) { - if (ppsc->dot11_psmode == EACTIVE) { - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + /* Idle for a while if we connect to AP a while ago. */ + if (mac->cnt_after_linked >= 2) { + if (ppsc->dot11_psmode == EACTIVE) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("Enter 802.11 power save mode...\n")); - rtl_lps_set_psmode(hw, EAUTOPS); - } + rtl_lps_set_psmode(hw, EAUTOPS); } } + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); } @@ -470,17 +474,17 @@ void rtl_lps_leave(struct ieee80211_hw *hw) spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); - if (ppsc->fwctrl_lps && ppsc->leisure_ps) { + if (ppsc->fwctrl_lps) { if (ppsc->dot11_psmode != EACTIVE) { /*FIX ME */ rtlpriv->cfg->ops->enable_interrupt(hw); if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && - RT_IN_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM) && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && rtlhal->interface == INTF_PCI) { rtlpriv->intf_ops->disable_aspm(hw); - RT_CLEAR_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, @@ -491,3 +495,214 @@ void rtl_lps_leave(struct ieee80211_hw *hw) } spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); } + +/* For sw LPS*/ +void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = (void *) data; + struct ieee80211_tim_ie *tim_ie; + u8 *tim; + u8 tim_len; + bool u_buffed; + bool m_buffed; + + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + + if (!rtlpriv->psc.swctrl_lps) + return; + + if (rtlpriv->mac80211.link_state != MAC80211_LINKED) + return; + + if (!rtlpriv->psc.sw_ps_enabled) + return; + + if (rtlpriv->psc.fwctrl_lps) + return; + + if (likely(!(hw->conf.flags & IEEE80211_CONF_PS))) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control)) + return; + + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + rtlpriv->psc.last_beacon = jiffies; + + tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM); + if (!tim) + return; + + if (tim[1] < sizeof(*tim_ie)) + return; + + tim_len = tim[1]; + tim_ie = (struct ieee80211_tim_ie *) &tim[2]; + + if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period)) + rtlpriv->psc.dtim_counter = tim_ie->dtim_count; + + /* Check whenever the PHY can be turned off again. */ + + /* 1. What about buffered unicast traffic for our AID? */ + u_buffed = ieee80211_check_tim(tim_ie, tim_len, + rtlpriv->mac80211.assoc_id); + + /* 2. Maybe the AP wants to send multicast/broadcast data? */ + m_buffed = tim_ie->bitmap_ctrl & 0x01; + rtlpriv->psc.multi_buffered = m_buffed; + + /* unicast will process by mac80211 through + * set ~IEEE80211_CONF_PS, So we just check + * multicast frames here */ + if (!m_buffed) { + /* back to low-power land. and delay is + * prevent null power save frame tx fail */ + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.ps_work, MSECS(5)); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ("u_bufferd: %x, " + "m_buffered: %x\n", u_buffed, m_buffed)); + } +} + +void rtl_swlps_rf_awake(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + unsigned long flag; + + if (!rtlpriv->psc.swctrl_lps) + return; + if (mac->link_state != MAC80211_LINKED) + return; + + if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->disable_aspm(hw); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false); + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); +} + +void rtl_swlps_rfon_wq_callback(void *data) +{ + struct rtl_works *rtlworks = + container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq); + struct ieee80211_hw *hw = rtlworks->hw; + + rtl_swlps_rf_awake(hw); +} + +void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + unsigned long flag; + u8 sleep_intv; + + if (!rtlpriv->psc.sw_ps_enabled) + return; + + if ((rtlpriv->sec.being_setkey) || + (mac->opmode == NL80211_IFTYPE_ADHOC)) + return; + + /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ + if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5)) + return; + + if (rtlpriv->link_info.busytraffic) + return; + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + if (rtlpriv->psc.rfchange_inprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + return; + } + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS, false); + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && + !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->enable_aspm(hw); + RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + /* here is power save alg, when this beacon is DTIM + * we will set sleep time to dtim_period * n; + * when this beacon is not DTIM, we will set sleep + * time to sleep_intv = rtlpriv->psc.dtim_counter or + * MAX_SW_LPS_SLEEP_INTV(default set to 5) */ + + if (rtlpriv->psc.dtim_counter == 0) { + if (hw->conf.ps_dtim_period == 1) + sleep_intv = hw->conf.ps_dtim_period * 2; + else + sleep_intv = hw->conf.ps_dtim_period; + } else { + sleep_intv = rtlpriv->psc.dtim_counter; + } + + if (sleep_intv > MAX_SW_LPS_SLEEP_INTV) + sleep_intv = MAX_SW_LPS_SLEEP_INTV; + + /* this print should always be dtim_conter = 0 & + * sleep = dtim_period, that meaons, we should + * awake before every dtim */ + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + ("dtim_counter:%x will sleep :%d" + " beacon_intv\n", rtlpriv->psc.dtim_counter, sleep_intv)); + + /* we tested that 40ms is enough for sw & hw sw delay */ + queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq, + MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40)); +} + + +void rtl_swlps_wq_callback(void *data) +{ + struct rtl_works *rtlworks = container_of_dwork_rtl(data, + struct rtl_works, + ps_work); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool ps = false; + + ps = (hw->conf.flags & IEEE80211_CONF_PS); + + /* we can sleep after ps null send ok */ + if (rtlpriv->psc.state_inap) { + rtl_swlps_rf_sleep(hw); + + if (rtlpriv->psc.state && !ps) { + rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies - + rtlpriv->psc.last_action); + } + + if (ps) + rtlpriv->psc.last_slept = jiffies; + + rtlpriv->psc.last_action = jiffies; + rtlpriv->psc.state = ps; + } +} diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h index ae56da801a23..e3bf89840370 100644 --- a/drivers/net/wireless/rtlwifi/ps.h +++ b/drivers/net/wireless/rtlwifi/ps.h @@ -30,6 +30,8 @@ #ifndef __REALTEK_RTL_PCI_PS_H__ #define __REALTEK_RTL_PCI_PS_H__ +#define MAX_SW_LPS_SLEEP_INTV 5 + bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, enum rf_pwrstate state_toset, u32 changesource, bool protect_or_not); @@ -40,4 +42,11 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw); void rtl_ips_nic_off_wq_callback(void *data); void rtl_lps_enter(struct ieee80211_hw *hw); void rtl_lps_leave(struct ieee80211_hw *hw); + +void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len); +void rtl_swlps_wq_callback(void *data); +void rtl_swlps_rfon_wq_callback(void *data); +void rtl_swlps_rf_awake(struct ieee80211_hw *hw); +void rtl_swlps_rf_sleep(struct ieee80211_hw *hw); + #endif diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c index 91634107434a..30da68a77786 100644 --- a/drivers/net/wireless/rtlwifi/rc.c +++ b/drivers/net/wireless/rtlwifi/rc.c @@ -38,17 +38,14 @@ *CCK11M or OFDM_54M based on wireless mode. */ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta, struct sk_buff *skb, bool not_data) { struct rtl_mac *rtlmac = rtl_mac(rtlpriv); - - /* - *mgt use 1M, although we have check it - *before this function use rate_control_send_low, - *we still check it here - */ - if (not_data) - return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_sta_info *sta_entry = NULL; + u8 wireless_mode = 0; /* *this rate is no use for true rate, firmware @@ -57,35 +54,78 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, *2.in rtl_get_tcb_desc when we check rate is * 1M we will not use FW rate but user rate. */ - if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true)) { - return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; + if (rtlmac->opmode == NL80211_IFTYPE_AP || + rtlmac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + wireless_mode = sta_entry->wireless_mode; + } else { + return 0; + } } else { - if (rtlmac->mode == WIRELESS_MODE_B) - return rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]; - else - return rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]; + wireless_mode = rtlmac->mode; + } + + if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true) || + not_data) { + return 0; + } else { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + if (wireless_mode == WIRELESS_MODE_B) { + return B_MODE_MAX_RIX; + } else if (wireless_mode == WIRELESS_MODE_G) { + return G_MODE_MAX_RIX; + } else { + if (get_rf_type(rtlphy) != RF_2T2R) + return N_MODE_MCS7_RIX; + else + return N_MODE_MCS15_RIX; + } + } else { + if (wireless_mode == WIRELESS_MODE_A) { + return A_MODE_MAX_RIX; + } else { + if (get_rf_type(rtlphy) != RF_2T2R) + return N_MODE_MCS7_RIX; + else + return N_MODE_MCS15_RIX; + } + } } } static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta, struct ieee80211_tx_rate *rate, struct ieee80211_tx_rate_control *txrc, - u8 tries, u8 rix, int rtsctsenable, + u8 tries, char rix, int rtsctsenable, bool not_data) { struct rtl_mac *mac = rtl_mac(rtlpriv); + u8 sgi_20 = 0, sgi_40 = 0; + if (sta) { + sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + } rate->count = tries; - rate->idx = (rix > 0x2) ? rix : 0x2; + rate->idx = rix >= 0x00 ? rix : 0x00; if (!not_data) { if (txrc->short_preamble) rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; - if (mac->bw_40) - rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - if (mac->sgi_20 || mac->sgi_40) + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta && (sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + } else { + if (mac->bw_40) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + } + if (sgi_20 || sgi_40) rate->flags |= IEEE80211_TX_RC_SHORT_GI; - if (mac->ht_enable) + if (sta && sta->ht_cap.ht_supported) rate->flags |= IEEE80211_TX_RC_MCS; } } @@ -97,39 +137,39 @@ static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta, struct sk_buff *skb = txrc->skb; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rates = tx_info->control.rates; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc = hdr->frame_control; + __le16 fc = rtl_get_fc(skb); u8 try_per_rate, i, rix; bool not_data = !ieee80211_is_data(fc); if (rate_control_send_low(sta, priv_sta, txrc)) return; - rix = _rtl_rc_get_highest_rix(rtlpriv, skb, not_data); - + rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data); try_per_rate = 1; - _rtl_rc_rate_set_series(rtlpriv, &rates[0], txrc, + _rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc, try_per_rate, rix, 1, not_data); if (!not_data) { for (i = 1; i < 4; i++) - _rtl_rc_rate_set_series(rtlpriv, &rates[i], + _rtl_rc_rate_set_series(rtlpriv, sta, &rates[i], txrc, i, (rix - i), 1, not_data); } } -static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, u16 tid) +static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, + struct rtl_sta_info *sta_entry, u16 tid) { struct rtl_mac *mac = rtl_mac(rtlpriv); if (mac->act_scanning) return false; - if (mac->cnt_after_linked < 3) + if (mac->opmode == NL80211_IFTYPE_STATION && + mac->cnt_after_linked < 3) return false; - if (mac->tids[tid].agg.agg_state == RTL_AGG_OFF) + if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP) return true; return false; @@ -143,11 +183,9 @@ static void rtl_tx_status(void *ppriv, { struct rtl_priv *rtlpriv = ppriv; struct rtl_mac *mac = rtl_mac(rtlpriv); - struct ieee80211_hdr *hdr; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + __le16 fc = rtl_get_fc(skb); + struct rtl_sta_info *sta_entry; if (!priv_sta || !ieee80211_is_data(fc)) return; @@ -159,17 +197,21 @@ static void rtl_tx_status(void *ppriv, || is_broadcast_ether_addr(ieee80211_get_DA(hdr))) return; - /* Check if aggregation has to be enabled for this tid */ - if (conf_is_ht(&mac->hw->conf) && - !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { - if (ieee80211_is_data_qos(fc)) { - u8 *qc, tid; - - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - - if (_rtl_tx_aggr_check(rtlpriv, tid)) - ieee80211_start_tx_ba_session(sta, tid, 5000); + if (sta) { + /* Check if aggregation has to be enabled for this tid */ + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + if ((sta->ht_cap.ht_supported == true) && + !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { + if (ieee80211_is_data_qos(fc)) { + u8 tid = rtl_get_tid(skb); + if (_rtl_tx_aggr_check(rtlpriv, sta_entry, + tid)) { + sta_entry->tids[tid].agg.agg_state = + RTL_AGG_PROGRESS; + ieee80211_start_tx_ba_session(sta, + tid, 5000); + } + } } } } @@ -178,43 +220,6 @@ static void rtl_rate_init(void *ppriv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta) { - struct rtl_priv *rtlpriv = ppriv; - struct rtl_mac *mac = rtl_mac(rtlpriv); - u8 is_ht = conf_is_ht(&mac->hw->conf); - - if ((mac->opmode == NL80211_IFTYPE_STATION) || - (mac->opmode == NL80211_IFTYPE_MESH_POINT) || - (mac->opmode == NL80211_IFTYPE_ADHOC)) { - - switch (sband->band) { - case IEEE80211_BAND_2GHZ: - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_G; - if (is_ht) - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - case IEEE80211_BAND_5GHZ: - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_A; - if (is_ht) - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("Invalid band\n")); - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - } - - RT_TRACE(rtlpriv, COMP_RATE, DBG_DMESG, - ("Choosing rate table index: %d\n", - rtlpriv->rate_priv->cur_ratetab_idx)); - - } - } static void rtl_rate_update(void *ppriv, @@ -223,49 +228,6 @@ static void rtl_rate_update(void *ppriv, u32 changed, enum nl80211_channel_type oper_chan_type) { - struct rtl_priv *rtlpriv = ppriv; - struct rtl_mac *mac = rtl_mac(rtlpriv); - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); - bool oper_cw40 = false, oper_sgi40; - bool local_cw40 = mac->bw_40; - bool local_sgi40 = mac->sgi_40; - u8 is_ht = conf_is_ht(&mac->hw->conf); - - if (changed & IEEE80211_RC_HT_CHANGED) { - if (mac->opmode != NL80211_IFTYPE_STATION) - return; - - if (rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40MINUS || - rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40PLUS) - oper_cw40 = true; - - oper_sgi40 = mac->sgi_40; - - if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) { - switch (sband->band) { - case IEEE80211_BAND_2GHZ: - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_G; - if (is_ht) - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - case IEEE80211_BAND_5GHZ: - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_A; - if (is_ht) - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("Invalid band\n")); - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - } - } - } } static void *rtl_rate_alloc(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rtlwifi/rc.h b/drivers/net/wireless/rtlwifi/rc.h index b4667c035f0b..4afa2c20adcf 100644 --- a/drivers/net/wireless/rtlwifi/rc.h +++ b/drivers/net/wireless/rtlwifi/rc.h @@ -30,8 +30,15 @@ #ifndef __RTL_RC_H__ #define __RTL_RC_H__ +#define B_MODE_MAX_RIX 3 +#define G_MODE_MAX_RIX 11 +#define A_MODE_MAX_RIX 7 + +/* in mac80211 mcs0-mcs15 is idx0-idx15*/ +#define N_MODE_MCS7_RIX 7 +#define N_MODE_MCS15_RIX 15 + struct rtl_rate_priv { - u8 cur_ratetab_idx; u8 ht_cap; }; diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c index d26f957981ad..8f6718f163e5 100644 --- a/drivers/net/wireless/rtlwifi/regd.c +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -66,31 +66,83 @@ static struct country_code_to_enum_rd allCountries[] = { NL80211_RRF_PASSIVE_SCAN | \ NL80211_RRF_NO_OFDM) +/* 5G chan 36 - chan 64*/ +#define RTL819x_5GHZ_5150_5350 \ + REG_RULE(5150-10, 5350+10, 40, 0, 30, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +/* 5G chan 100 - chan 165*/ +#define RTL819x_5GHZ_5470_5850 \ + REG_RULE(5470-10, 5850+10, 40, 0, 30, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +/* 5G chan 149 - chan 165*/ +#define RTL819x_5GHZ_5725_5850 \ + REG_RULE(5725-10, 5850+10, 40, 0, 30, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +#define RTL819x_5GHZ_ALL \ + (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850) + static const struct ieee80211_regdomain rtl_regdom_11 = { .n_reg_rules = 1, .alpha2 = "99", .reg_rules = { RTL819x_2GHZ_CH01_11, - } + } }; -static const struct ieee80211_regdomain rtl_regdom_global = { - .n_reg_rules = 3, - .alpha2 = "99", - .reg_rules = { - RTL819x_2GHZ_CH01_11, - RTL819x_2GHZ_CH12_13, - RTL819x_2GHZ_CH14, - } -}; - -static const struct ieee80211_regdomain rtl_regdom_world = { +static const struct ieee80211_regdomain rtl_regdom_12_13 = { .n_reg_rules = 2, .alpha2 = "99", .reg_rules = { RTL819x_2GHZ_CH01_11, - RTL819x_2GHZ_CH12_13, - } + RTL819x_2GHZ_CH12_13, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_no_midband = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_5GHZ_5150_5350, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_60_64 = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_14_60_64 = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_2GHZ_CH14, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_14 = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_2GHZ_CH14, + } }; static bool _rtl_is_radar_freq(u16 center_freq) @@ -162,6 +214,8 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, u32 bandwidth = 0; int r; + if (!wiphy->bands[IEEE80211_BAND_2GHZ]) + return; sband = wiphy->bands[IEEE80211_BAND_2GHZ]; /* @@ -292,25 +346,26 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select( { switch (reg->country_code) { case COUNTRY_CODE_FCC: + return &rtl_regdom_no_midband; case COUNTRY_CODE_IC: return &rtl_regdom_11; case COUNTRY_CODE_ETSI: + case COUNTRY_CODE_TELEC_NETGEAR: + return &rtl_regdom_60_64; case COUNTRY_CODE_SPAIN: case COUNTRY_CODE_FRANCE: case COUNTRY_CODE_ISRAEL: - case COUNTRY_CODE_TELEC_NETGEAR: - return &rtl_regdom_world; + case COUNTRY_CODE_WORLD_WIDE_13: + return &rtl_regdom_12_13; case COUNTRY_CODE_MKK: case COUNTRY_CODE_MKK1: case COUNTRY_CODE_TELEC: case COUNTRY_CODE_MIC: - return &rtl_regdom_global; + return &rtl_regdom_14_60_64; case COUNTRY_CODE_GLOBAL_DOMAIN: - return &rtl_regdom_global; - case COUNTRY_CODE_WORLD_WIDE_13: - return &rtl_regdom_world; + return &rtl_regdom_14; default: - return &rtl_regdom_world; + return &rtl_regdom_no_midband; } } @@ -323,9 +378,11 @@ static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg, const struct ieee80211_regdomain *regd; wiphy->reg_notifier = reg_notifier; + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY; wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS; + regd = _rtl_regdomain_select(reg); wiphy_apply_custom_regulatory(wiphy, regd); _rtl_reg_apply_radar_flags(wiphy); @@ -355,8 +412,8 @@ int rtl_regd_init(struct ieee80211_hw *hw, if (wiphy == NULL || &rtlpriv->regd == NULL) return -EINVAL; - /* force the channel plan to world wide 13 */ - rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13; + /* init country_code from efuse channel plan */ + rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan; RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE, (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n", @@ -373,8 +430,8 @@ int rtl_regd_init(struct ieee80211_hw *hw, country = _rtl_regd_find_country(rtlpriv->regd.country_code); if (country) { - rtlpriv->regd.alpha2[0] = country->isoName[0]; - rtlpriv->regd.alpha2[1] = country->isoName[1]; + rtlpriv->regd.alpha2[0] = country->iso_name[0]; + rtlpriv->regd.alpha2[1] = country->iso_name[1]; } else { rtlpriv->regd.alpha2[0] = '0'; rtlpriv->regd.alpha2[1] = '0'; diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h index 4cdbc4ae76d4..d23118938fac 100644 --- a/drivers/net/wireless/rtlwifi/regd.h +++ b/drivers/net/wireless/rtlwifi/regd.h @@ -32,7 +32,7 @@ struct country_code_to_enum_rd { u16 countrycode; - const char *isoName; + const char *iso_name; }; enum country_code_type_t { diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index bb023274414c..97183829b9be 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -28,10 +28,26 @@ *****************************************************************************/ #include "dm_common.h" +#include "phy_common.h" +#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) +#define BT_RSSI_STATE_BG_EDCA_LOW BIT_OFFSET_LEN_MASK_32(3, 1) +#define BT_RSSI_STATE_TXPOWER_LOW BIT_OFFSET_LEN_MASK_32(4, 1) + +#define RTLPRIV (struct rtl_priv *) +#define GET_UNDECORATED_AVERAGE_RSSI(_priv) \ + ((RTLPRIV(_priv))->mac80211.opmode == \ + NL80211_IFTYPE_ADHOC) ? \ + ((RTLPRIV(_priv))->dm.entry_min_undecoratedsmoothed_pwdb) : \ + ((RTLPRIV(_priv))->dm.undecorated_smoothed_pwdb) + static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = { 0x7f8001fe, 0x788001e2, @@ -304,7 +320,7 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw) static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) { - static u8 binitialized; /* initialized to false */ + static u8 initialized; /* initialized to false */ struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; @@ -315,11 +331,11 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) if ((multi_sta == false) || (dm_digtable.cursta_connectctate != DIG_STA_DISCONNECT)) { - binitialized = false; + initialized = false; dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; return; - } else if (binitialized == false) { - binitialized = true; + } else if (initialized == false) { + initialized = true; dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; dm_digtable.cur_igvalue = 0x20; rtl92c_dm_write_dig(hw); @@ -461,10 +477,7 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw) if (mac->act_scanning == true) return; - if ((mac->link_state > MAC80211_NOLINK) && - (mac->link_state < MAC80211_LINKED)) - dm_digtable.cursta_connectctate = DIG_STA_BEFORE_CONNECT; - else if (mac->link_state >= MAC80211_LINKED) + if (mac->link_state >= MAC80211_LINKED) dm_digtable.cursta_connectctate = DIG_STA_CONNECT; else dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT; @@ -562,23 +575,42 @@ EXPORT_SYMBOL(rtl92c_dm_init_edca_turbo); static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + static u64 last_txok_cnt; static u64 last_rxok_cnt; - u64 cur_txok_cnt; - u64 cur_rxok_cnt; + static u32 last_bt_edca_ul; + static u32 last_bt_edca_dl; + u64 cur_txok_cnt = 0; + u64 cur_rxok_cnt = 0; u32 edca_be_ul = 0x5ea42b; u32 edca_be_dl = 0x5ea42b; + bool bt_change_edca = false; - if (mac->opmode == NL80211_IFTYPE_ADHOC) - goto dm_checkedcaturbo_exit; + if ((last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) || + (last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) { + rtlpriv->dm.current_turbo_edca = false; + last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul; + last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl; + } + + if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) { + edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul; + bt_change_edca = true; + } + + if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) { + edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl; + bt_change_edca = true; + } if (mac->link_state != MAC80211_LINKED) { rtlpriv->dm.current_turbo_edca = false; return; } - if (!mac->ht_enable) { /*FIX MERGE */ + if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) { if (!(edca_be_ul & 0xffff0000)) edca_be_ul |= 0x005e0000; @@ -586,10 +618,12 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw) edca_be_dl |= 0x005e0000; } - if ((!rtlpriv->dm.is_any_nonbepkts) && - (!rtlpriv->dm.disable_framebursting)) { + if ((bt_change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) && + (!rtlpriv->dm.disable_framebursting))) { + cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; + if (cur_rxok_cnt > 4 * cur_txok_cnt) { if (!rtlpriv->dm.is_cur_rdlstate || !rtlpriv->dm.current_turbo_edca) { @@ -618,7 +652,6 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw) } } -dm_checkedcaturbo_exit: rtlpriv->dm.is_any_nonbepkts = false; last_txok_cnt = rtlpriv->stats.txbytesunicast; last_rxok_cnt = rtlpriv->stats.rxbytesunicast; @@ -633,14 +666,14 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 thermalvalue, delta, delta_lck, delta_iqk; long ele_a, ele_d, temp_cck, val_x, value32; - long val_y, ele_c; - u8 ofdm_index[2], cck_index, ofdm_index_old[2], cck_index_old; + long val_y, ele_c = 0; + u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0; int i; bool is2t = IS_92C_SERIAL(rtlhal->version); u8 txpwr_level[2] = {0, 0}; u8 ofdm_min_index = 6, rf; - rtlpriv->dm.txpower_trackingInit = true; + rtlpriv->dm.txpower_trackinginit = true; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, ("rtl92c_dm_txpower_tracking_callback_thermalmeter\n")); @@ -683,7 +716,6 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw for (i = 0; i < OFDM_TABLE_LENGTH; i++) { if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) { - ofdm_index_old[1] = (u8) i; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, @@ -1062,7 +1094,7 @@ static void rtl92c_dm_initialize_txpower_tracking_thermalmeter( struct rtl_priv *rtlpriv = rtl_priv(hw); rtlpriv->dm.txpower_tracking = true; - rtlpriv->dm.txpower_trackingInit = false; + rtlpriv->dm.txpower_trackinginit = false; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, ("pMgntInfo->txpower_tracking = %d\n", @@ -1132,6 +1164,7 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rate_adaptive *p_ra = &(rtlpriv->ra); u32 low_rssithresh_for_ra, high_rssithresh_for_ra; + struct ieee80211_sta *sta = NULL; if (is_hal_stop(rtlhal)) { RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, @@ -1145,8 +1178,8 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) return; } - if (mac->link_state == MAC80211_LINKED) { - + if (mac->link_state == MAC80211_LINKED && + mac->opmode == NL80211_IFTYPE_STATION) { switch (p_ra->pre_ratr_state) { case DM_RATR_STA_HIGH: high_rssithresh_for_ra = 50; @@ -1185,10 +1218,13 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) ("PreState = %d, CurState = %d\n", p_ra->pre_ratr_state, p_ra->ratr_state)); - rtlpriv->cfg->ops->update_rate_mask(hw, + rcu_read_lock(); + sta = ieee80211_find_sta(mac->vif, mac->bssid); + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, p_ra->ratr_state); p_ra->pre_ratr_state = p_ra->ratr_state; + rcu_read_unlock(); } } } @@ -1202,51 +1238,6 @@ static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw) dm_pstable.rssi_val_min = 0; } -static void rtl92c_dm_1r_cca(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &(rtlpriv->phy); - - if (dm_pstable.rssi_val_min != 0) { - if (dm_pstable.pre_ccastate == CCA_2R) { - if (dm_pstable.rssi_val_min >= 35) - dm_pstable.cur_ccasate = CCA_1R; - else - dm_pstable.cur_ccasate = CCA_2R; - } else { - if (dm_pstable.rssi_val_min <= 30) - dm_pstable.cur_ccasate = CCA_2R; - else - dm_pstable.cur_ccasate = CCA_1R; - } - } else { - dm_pstable.cur_ccasate = CCA_MAX; - } - - if (dm_pstable.pre_ccastate != dm_pstable.cur_ccasate) { - if (dm_pstable.cur_ccasate == CCA_1R) { - if (get_rf_type(rtlphy) == RF_2T2R) { - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, - MASKBYTE0, 0x13); - rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x20); - } else { - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, - MASKBYTE0, 0x23); - rtl_set_bbreg(hw, 0xe70, 0x7fc00000, 0x10c); - } - } else { - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, - 0x33); - rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x63); - } - dm_pstable.pre_ccastate = dm_pstable.cur_ccasate; - } - - RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, ("CCAStage = %s\n", - (dm_pstable.cur_ccasate == - 0) ? "1RCCA" : "2RCCA")); -} - void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal) { static u8 initialize; @@ -1352,7 +1343,9 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw) } if (IS_92C_SERIAL(rtlhal->version)) - rtl92c_dm_1r_cca(hw); + ;/* rtl92c_dm_1r_cca(hw); */ + else + rtl92c_dm_rf_saving(hw, false); } void rtl92c_dm_init(struct ieee80211_hw *hw) @@ -1369,6 +1362,84 @@ void rtl92c_dm_init(struct ieee80211_hw *hw) } EXPORT_SYMBOL(rtl92c_dm_init); +void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + + if (!rtlpriv->dm.dynamic_txpower_enable) + return; + + if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + ("Not connected to any\n")); + + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("AP Client PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("STA Default Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("AP Ext Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } + + if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n")); + } else if ((undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && + (undecorated_smoothed_pwdb >= + TX_POWER_NEAR_FIELD_THRESH_LVL1)) { + + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n")); + } else if (undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("TXHIGHPWRLEVEL_NORMAL\n")); + } + + if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("PHY_SetTxPowerLevel8192S() Channel = %d\n", + rtlphy->current_channel)); + rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); + } + + rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} + void rtl92c_dm_watchdog(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1388,11 +1459,321 @@ void rtl92c_dm_watchdog(struct ieee80211_hw *hw) rtl92c_dm_dig(hw); rtl92c_dm_false_alarm_counter_statistics(hw); rtl92c_dm_dynamic_bb_powersaving(hw); - rtlpriv->cfg->ops->dm_dynamic_txpower(hw); + rtl92c_dm_dynamic_txpower(hw); rtl92c_dm_check_txpower_tracking(hw); rtl92c_dm_refresh_rate_adaptive_mask(hw); + rtl92c_dm_bt_coexist(hw); rtl92c_dm_check_edca_turbo(hw); - } } EXPORT_SYMBOL(rtl92c_dm_watchdog); + +u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + long undecorated_smoothed_pwdb; + u8 curr_bt_rssi_state = 0x00; + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + undecorated_smoothed_pwdb = + GET_UNDECORATED_AVERAGE_RSSI(rtlpriv); + } else { + if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0) + undecorated_smoothed_pwdb = 100; + else + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + } + + /* Check RSSI to determine HighPower/NormalPower state for + * BT coexistence. */ + if (undecorated_smoothed_pwdb >= 67) + curr_bt_rssi_state &= (~BT_RSSI_STATE_NORMAL_POWER); + else if (undecorated_smoothed_pwdb < 62) + curr_bt_rssi_state |= BT_RSSI_STATE_NORMAL_POWER; + + /* Check RSSI to determine AMPDU setting for BT coexistence. */ + if (undecorated_smoothed_pwdb >= 40) + curr_bt_rssi_state &= (~BT_RSSI_STATE_AMDPU_OFF); + else if (undecorated_smoothed_pwdb <= 32) + curr_bt_rssi_state |= BT_RSSI_STATE_AMDPU_OFF; + + /* Marked RSSI state. It will be used to determine BT coexistence + * setting later. */ + if (undecorated_smoothed_pwdb < 35) + curr_bt_rssi_state |= BT_RSSI_STATE_SPECIAL_LOW; + else + curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW); + + /* Set Tx Power according to BT status. */ + if (undecorated_smoothed_pwdb >= 30) + curr_bt_rssi_state |= BT_RSSI_STATE_TXPOWER_LOW; + else if (undecorated_smoothed_pwdb < 25) + curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW); + + /* Check BT state related to BT_Idle in B/G mode. */ + if (undecorated_smoothed_pwdb < 15) + curr_bt_rssi_state |= BT_RSSI_STATE_BG_EDCA_LOW; + else + curr_bt_rssi_state &= (~BT_RSSI_STATE_BG_EDCA_LOW); + + if (curr_bt_rssi_state != rtlpcipriv->bt_coexist.bt_rssi_state) { + rtlpcipriv->bt_coexist.bt_rssi_state = curr_bt_rssi_state; + return true; + } else { + return false; + } +} +EXPORT_SYMBOL(rtl92c_bt_rssi_state_change); + +static bool rtl92c_bt_state_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + u32 polling, ratio_tx, ratio_pri; + u32 bt_tx, bt_pri; + u8 bt_state; + u8 cur_service_type; + + if (rtlpriv->mac80211.link_state < MAC80211_LINKED) + return false; + + bt_state = rtl_read_byte(rtlpriv, 0x4fd); + bt_tx = rtl_read_dword(rtlpriv, 0x488); + bt_tx = bt_tx & 0x00ffffff; + bt_pri = rtl_read_dword(rtlpriv, 0x48c); + bt_pri = bt_pri & 0x00ffffff; + polling = rtl_read_dword(rtlpriv, 0x490); + + if (bt_tx == 0xffffffff && bt_pri == 0xffffffff && + polling == 0xffffffff && bt_state == 0xff) + return false; + + bt_state &= BIT_OFFSET_LEN_MASK_32(0, 1); + if (bt_state != rtlpcipriv->bt_coexist.bt_cur_state) { + rtlpcipriv->bt_coexist.bt_cur_state = bt_state; + + if (rtlpcipriv->bt_coexist.reg_bt_sco == 3) { + rtlpcipriv->bt_coexist.bt_service = BT_IDLE; + + bt_state = bt_state | + ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? + 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | + BIT_OFFSET_LEN_MASK_32(2, 1); + rtl_write_byte(rtlpriv, 0x4fd, bt_state); + } + return true; + } + + ratio_tx = bt_tx * 1000 / polling; + ratio_pri = bt_pri * 1000 / polling; + rtlpcipriv->bt_coexist.ratio_tx = ratio_tx; + rtlpcipriv->bt_coexist.ratio_pri = ratio_pri; + + if (bt_state && rtlpcipriv->bt_coexist.reg_bt_sco == 3) { + + if ((ratio_tx < 30) && (ratio_pri < 30)) + cur_service_type = BT_IDLE; + else if ((ratio_pri > 110) && (ratio_pri < 250)) + cur_service_type = BT_SCO; + else if ((ratio_tx >= 200) && (ratio_pri >= 200)) + cur_service_type = BT_BUSY; + else if ((ratio_tx >= 350) && (ratio_tx < 500)) + cur_service_type = BT_OTHERBUSY; + else if (ratio_tx >= 500) + cur_service_type = BT_PAN; + else + cur_service_type = BT_OTHER_ACTION; + + if (cur_service_type != rtlpcipriv->bt_coexist.bt_service) { + rtlpcipriv->bt_coexist.bt_service = cur_service_type; + bt_state = bt_state | + ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? + 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | + ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) ? + 0 : BIT_OFFSET_LEN_MASK_32(2, 1)); + + /* Add interrupt migration when bt is not ini + * idle state (no traffic). */ + if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { + rtl_write_word(rtlpriv, 0x504, 0x0ccc); + rtl_write_byte(rtlpriv, 0x506, 0x54); + rtl_write_byte(rtlpriv, 0x507, 0x54); + } else { + rtl_write_byte(rtlpriv, 0x506, 0x00); + rtl_write_byte(rtlpriv, 0x507, 0x00); + } + + rtl_write_byte(rtlpriv, 0x4fd, bt_state); + return true; + } + } + + return false; + +} + +static bool rtl92c_bt_wifi_connect_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + static bool media_connect; + + if (rtlpriv->mac80211.link_state < MAC80211_LINKED) { + media_connect = false; + } else { + if (!media_connect) { + media_connect = true; + return true; + } + media_connect = true; + } + + return false; +} + +static void rtl92c_bt_set_normal(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + + if (rtlpcipriv->bt_coexist.bt_service == BT_OTHERBUSY) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72b; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72b; + } else if (rtlpcipriv->bt_coexist.bt_service == BT_BUSY) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82f; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82f; + } else if (rtlpcipriv->bt_coexist.bt_service == BT_SCO) { + if (rtlpcipriv->bt_coexist.ratio_tx > 160) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72f; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72f; + } else { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea32b; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea42b; + } + } else { + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + } + + if ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) && + (rtlpriv->mac80211.mode == WIRELESS_MODE_G || + (rtlpriv->mac80211.mode == (WIRELESS_MODE_G | WIRELESS_MODE_B))) && + (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_BG_EDCA_LOW)) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82b; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82b; + } +} + +static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + + /* Only enable HW BT coexist when BT in "Busy" state. */ + if (rtlpriv->mac80211.vendor == PEER_CISCO && + rtlpcipriv->bt_coexist.bt_service == BT_OTHER_ACTION) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + } else { + if ((rtlpcipriv->bt_coexist.bt_service == BT_BUSY) && + (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_NORMAL_POWER)) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + } else if ((rtlpcipriv->bt_coexist.bt_service == + BT_OTHER_ACTION) && (rtlpriv->mac80211.mode < + WIRELESS_MODE_N_24G) && + (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_SPECIAL_LOW)) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + } else if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); + } else { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); + } + } + + if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x10100); + else + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x0); + + if (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_NORMAL_POWER) { + rtl92c_bt_set_normal(hw); + } else { + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + } + + if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { + rtlpriv->cfg->ops->set_rfreg(hw, + RF90_PATH_A, + 0x1e, + 0xf0, 0xf); + } else { + rtlpriv->cfg->ops->set_rfreg(hw, + RF90_PATH_A, 0x1e, 0xf0, + rtlpcipriv->bt_coexist.bt_rfreg_origin_1e); + } + + if (!rtlpriv->dm.dynamic_txpower_enable) { + if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { + if (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_TXPOWER_LOW) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_BT2; + } else { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_BT1; + } + } else { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_NORMAL; + } + rtl92c_phy_set_txpower_level(hw, + rtlpriv->phy.current_channel); + } +} + +static void rtl92c_check_bt_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + if (rtlpcipriv->bt_coexist.bt_cur_state) { + if (rtlpcipriv->bt_coexist.bt_ant_isolation) + rtl92c_bt_ant_isolation(hw); + } else { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); + rtlpriv->cfg->ops->set_rfreg(hw, RF90_PATH_A, 0x1e, 0xf0, + rtlpcipriv->bt_coexist.bt_rfreg_origin_1e); + + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + } +} + +void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + bool wifi_connect_change; + bool bt_state_change; + bool rssi_state_change; + + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) { + + wifi_connect_change = rtl92c_bt_wifi_connect_change(hw); + bt_state_change = rtl92c_bt_state_change(hw); + rssi_state_change = rtl92c_bt_rssi_state_change(hw); + + if (wifi_connect_change || bt_state_change || rssi_state_change) + rtl92c_check_bt_change(hw); + } +} +EXPORT_SYMBOL(rtl92c_dm_bt_coexist); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h index b9cbb0a3c03f..b9736d3e9a39 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h @@ -200,5 +200,7 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery); +void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw); +void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 28a6ce3bc239..50303e1adff1 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -171,7 +171,6 @@ static void _rtl92c_write_fw(struct ieee80211_hw *hw, static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - int err = -EIO; u32 counter = 0; u32 value32; @@ -184,7 +183,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("chksum report faill ! REG_MCUFWDL:0x%08x .\n", value32)); - goto exit; + return -EIO; } RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, @@ -204,8 +203,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) ("Polling FW ready success!!" " REG_MCUFWDL:0x%08x .\n", value32)); - err = 0; - goto exit; + return 0; } mdelay(FW_8192C_POLLING_DELAY); @@ -214,9 +212,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32)); - -exit: - return err; + return -EIO; } int rtl92c_download_fw(struct ieee80211_hw *hw) @@ -226,32 +222,16 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) struct rtl92c_firmware_header *pfwheader; u8 *pfwdata; u32 fwsize; - int err; enum version_8192c version = rtlhal->version; - const struct firmware *firmware; - printk(KERN_INFO "rtl8192cu: Loading firmware file %s\n", + printk(KERN_INFO "rtl8192c: Loading firmware file %s\n", rtlpriv->cfg->fw_name); - err = request_firmware(&firmware, rtlpriv->cfg->fw_name, - rtlpriv->io.dev); - if (err) { - printk(KERN_ERR "rtl8192cu: Firmware loading failed\n"); + if (!rtlhal->pfirmware) return 1; - } - - if (firmware->size > 0x4000) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("Firmware is too big!\n")); - release_firmware(firmware); - return 1; - } - - memcpy(rtlhal->pfirmware, firmware->data, firmware->size); - fwsize = firmware->size; - release_firmware(firmware); pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; pfwdata = (u8 *) rtlhal->pfirmware; + fwsize = rtlhal->fwsize; if (IS_FW_HEADER_EXIST(pfwheader)) { RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, @@ -267,8 +247,7 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) _rtl92c_write_fw(hw, version, pfwdata, fwsize); _rtl92c_enable_fw_download(hw, false); - err = _rtl92c_fw_free_to_go(hw); - if (err) { + if (_rtl92c_fw_free_to_go(hw)) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Firmware is not ready to run!\n")); } else { @@ -300,10 +279,9 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u8 boxnum; - u16 box_reg, box_extreg; + u16 box_reg = 0, box_extreg = 0; u8 u1b_tmp; bool isfw_read = false; - u8 buf_index = 0; bool bwrite_sucess = false; u8 wait_h2c_limmit = 100; u8 wait_writeh2c_limmit = 100; @@ -414,7 +392,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 1: boxcontent[0] &= ~(BIT(7)); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index, 1); + p_cmdbuffer, 1); for (idx = 0; idx < 4; idx++) { rtl_write_byte(rtlpriv, box_reg + idx, @@ -424,7 +402,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 2: boxcontent[0] &= ~(BIT(7)); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index, 2); + p_cmdbuffer, 2); for (idx = 0; idx < 4; idx++) { rtl_write_byte(rtlpriv, box_reg + idx, @@ -434,7 +412,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 3: boxcontent[0] &= ~(BIT(7)); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index, 3); + p_cmdbuffer, 3); for (idx = 0; idx < 4; idx++) { rtl_write_byte(rtlpriv, box_reg + idx, @@ -444,9 +422,9 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 4: boxcontent[0] |= (BIT(7)); memcpy((u8 *) (boxextcontent), - p_cmdbuffer + buf_index, 2); + p_cmdbuffer, 2); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index + 2, 2); + p_cmdbuffer + 2, 2); for (idx = 0; idx < 2; idx++) { rtl_write_byte(rtlpriv, box_extreg + idx, @@ -461,9 +439,9 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 5: boxcontent[0] |= (BIT(7)); memcpy((u8 *) (boxextcontent), - p_cmdbuffer + buf_index, 2); + p_cmdbuffer, 2); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index + 2, 3); + p_cmdbuffer + 2, 3); for (idx = 0; idx < 2; idx++) { rtl_write_byte(rtlpriv, box_extreg + idx, @@ -561,6 +539,39 @@ void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) } EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd); +static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + u8 own; + unsigned long flags; + struct sk_buff *pskb = NULL; + + ring = &rtlpci->tx_ring[BEACON_QUEUE]; + + pskb = __skb_dequeue(&ring->queue); + if (pskb) + kfree_skb(pskb); + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + + pdesc = &ring->desc[0]; + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); + + rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); + + __skb_queue_tail(&ring->queue, skb); + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); + + return true; +} + #define BEACON_PG 0 /*->1*/ #define PSPOLL_PG 2 #define NULL_PG 3 @@ -678,7 +689,7 @@ static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) +void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); @@ -687,12 +698,12 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) u32 totalpacketlen; bool rtstatus; u8 u1RsvdPageLoc[3] = {0}; - bool b_dlok = false; + bool dlok = false; u8 *beacon; - u8 *p_pspoll; + u8 *pspoll; u8 *nullfunc; - u8 *p_probersp; + u8 *probersp; /*--------------------------------------------------------- (1) beacon ---------------------------------------------------------*/ @@ -703,10 +714,10 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) /*------------------------------------------------------- (2) ps-poll --------------------------------------------------------*/ - p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; - SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); - SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); - SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + pspoll = &reserved_page_packet[PSPOLL_PG * 128]; + SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000)); + SET_80211_PS_POLL_BSSID(pspoll, mac->bssid); + SET_80211_PS_POLL_TA(pspoll, mac->mac_addr); SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG); @@ -723,10 +734,10 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) /*--------------------------------------------------------- (4) probe response ----------------------------------------------------------*/ - p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; - SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); - SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); - SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + probersp = &reserved_page_packet[PROBERSP_PG * 128]; + SET_80211_HDR_ADDRESS1(probersp, mac->bssid); + SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr); + SET_80211_HDR_ADDRESS3(probersp, mac->bssid); SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG); @@ -744,12 +755,12 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) memcpy((u8 *) skb_put(skb, totalpacketlen), &reserved_page_packet, totalpacketlen); - rtstatus = rtlpriv->cfg->ops->cmd_send_packet(hw, skb); + rtstatus = _rtl92c_cmd_send_packet(hw, skb); if (rtstatus) - b_dlok = true; + dlok = true; - if (b_dlok) { + if (dlok) { RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("Set RSVD page location to Fw.\n")); RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h index 3db33bd14666..3d5823c12621 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h @@ -27,8 +27,8 @@ * *****************************************************************************/ -#ifndef __RTL92C__FW__H__ -#define __RTL92C__FW__H__ +#ifndef __RTL92C__FW__COMMON__H__ +#define __RTL92C__FW__COMMON__H__ #define FW_8192C_SIZE 0x3000 #define FW_8192C_START_ADDRESS 0x1000 diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index a70228278398..c5424cad43cb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c @@ -78,27 +78,29 @@ void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," " data(%#x)\n", regaddr, bitmask, data)); + } EXPORT_SYMBOL(rtl92c_phy_set_bb_reg); u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset) + enum radio_path rfpath, u32 offset) { RT_ASSERT(false, ("deprecated!\n")); return 0; + } EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_read); void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset, - u32 data) + enum radio_path rfpath, u32 offset, + u32 data) { RT_ASSERT(false, ("deprecated!\n")); } EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_write); u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset) + enum radio_path rfpath, u32 offset) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -149,8 +151,8 @@ u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, EXPORT_SYMBOL(_rtl92c_phy_rf_serial_read); void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset, - u32 data) + enum radio_path rfpath, u32 offset, + u32 data) { u32 data_and_addr; u32 newoffset; @@ -197,6 +199,7 @@ static void _rtl92c_phy_bb_config_1t(struct ieee80211_hw *hw) rtl_set_bbreg(hw, 0xe80, 0x0c000000, 0x2); rtl_set_bbreg(hw, 0xe88, 0x0c000000, 0x2); } + bool rtl92c_phy_rf_config(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -241,13 +244,14 @@ bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, 0x200)); + return true; } EXPORT_SYMBOL(_rtl92c_phy_bb8192c_config_parafile); void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, - u32 regaddr, u32 bitmask, - u32 data) + u32 regaddr, u32 bitmask, + u32 data) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -317,61 +321,48 @@ void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, } if (regaddr == RTXAGC_B_RATE54_24) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9])); } - if (regaddr == RTXAGC_B_CCK1_55_MCS32) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14])); } - if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15])); } - if (regaddr == RTXAGC_B_MCS03_MCS00) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10])); } - if (regaddr == RTXAGC_B_MCS07_MCS04) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11])); } - if (regaddr == RTXAGC_B_MCS11_MCS08) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12])); } - if (regaddr == RTXAGC_B_MCS15_MCS12) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][13] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n", rtlphy->pwrgroup_cnt, @@ -583,6 +574,7 @@ static void _rtl92c_ccxpower_index_check(struct ieee80211_hw *hw, rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; + } void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) @@ -611,7 +603,6 @@ bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm) struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 idx; u8 rf_path; - u8 ccktxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw, WIRELESS_MODE_B, power_indbm); @@ -639,11 +630,6 @@ bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm) } EXPORT_SYMBOL(rtl92c_phy_update_txpower_dbm); -void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval) -{ -} -EXPORT_SYMBOL(rtl92c_phy_set_beacon_hw_reg); - u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, enum wireless_mode wirelessmode, long power_indbm) @@ -741,9 +727,9 @@ void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, if (rtlphy->set_bwmode_inprogress) return; rtlphy->set_bwmode_inprogress = true; - if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) - rtlpriv->cfg->ops->phy_set_bw_mode_callback(hw); - else { + if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { + rtlphy->set_bwmode_inprogress = false; + } else { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("FALSE driver sleep or unload\n")); rtlphy->set_bwmode_inprogress = false; @@ -773,8 +759,9 @@ void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw) mdelay(delay); else continue; - } else + } else { rtlphy->sw_chnl_inprogress = false; + } break; } while (true); RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); @@ -811,9 +798,32 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw) } EXPORT_SYMBOL(rtl92c_phy_sw_chnl); -static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, - u8 channel, u8 *stage, u8 *step, - u32 *delay) +static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, + u32 cmdtableidx, u32 cmdtablesz, + enum swchnlcmd_id cmdid, + u32 para1, u32 para2, u32 msdelay) +{ + struct swchnlcmd *pcmd; + + if (cmdtable == NULL) { + RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); + return false; + } + + if (cmdtableidx >= cmdtablesz) + return false; + + pcmd = cmdtable + cmdtableidx; + pcmd->cmdid = cmdid; + pcmd->para1 = para1; + pcmd->para2 = para2; + pcmd->msdelay = msdelay; + return true; +} + +bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, + u8 channel, u8 *stage, u8 *step, + u32 *delay) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -917,29 +927,6 @@ static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, return false; } -static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, - u32 cmdtableidx, u32 cmdtablesz, - enum swchnlcmd_id cmdid, - u32 para1, u32 para2, u32 msdelay) -{ - struct swchnlcmd *pcmd; - - if (cmdtable == NULL) { - RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); - return false; - } - - if (cmdtableidx >= cmdtablesz) - return false; - - pcmd = cmdtable + cmdtableidx; - pcmd->cmdid = cmdid; - pcmd->para1 = para1; - pcmd->para2 = para2; - pcmd->msdelay = msdelay; - return true; -} - bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath) { return true; @@ -1002,13 +989,13 @@ static u8 _rtl92c_phy_path_b_iqk(struct ieee80211_hw *hw) reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD); reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD); reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD); + if (!(reg_eac & BIT(31)) && (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) && (((reg_ebc & 0x03FF0000) >> 16) != 0x42)) result |= 0x01; else return result; - if (!(reg_eac & BIT(30)) && (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) && (((reg_ecc & 0x03FF0000) >> 16) != 0x36)) @@ -1023,9 +1010,9 @@ static void _rtl92c_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, u32 oldval_0, x, tx0_a, reg; long y, tx0_c; - if (final_candidate == 0xFF) + if (final_candidate == 0xFF) { return; - else if (iqk_ok) { + } else if (iqk_ok) { oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD) >> 22) & 0x3FF; x = result[final_candidate][0]; @@ -1063,9 +1050,9 @@ static void _rtl92c_phy_path_b_fill_iqk_matrix(struct ieee80211_hw *hw, u32 oldval_1, x, tx1_a, reg; long y, tx1_c; - if (final_candidate == 0xFF) + if (final_candidate == 0xFF) { return; - else if (iqk_ok) { + } else if (iqk_ok) { oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, MASKDWORD) >> 22) & 0x3FF; x = result[final_candidate][4]; @@ -1282,6 +1269,7 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, RFPGA0_XA_HSSIPARAMETER1, BIT(8)); } + if (!rtlphy->rfpi_enable) _rtl92c_phy_pi_mode_switch(hw, true); if (t == 0) { @@ -1317,9 +1305,10 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, 0x3FF0000) >> 16; break; } else if (i == (retrycount - 1) && patha_ok == 0x01) + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & 0x3FF0000) >> - 16; + 16; result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; @@ -1375,8 +1364,7 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta, bool is2t) { - /* This routine is deliberately dummied out for later fixes */ -#if 0 +#if 0 /* This routine is deliberately dummied out for later fixes */ struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); @@ -1434,7 +1422,7 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, 0x04db25a4, 0x0b1b25a4 }; - u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c }; + const u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c }; u32 apk_normal_offset[PATH_NUM] = { 0xb28, 0xb98 }; @@ -1463,13 +1451,15 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, 0x00050006 }; - const u32 apk_result[PATH_NUM][APK_BB_REG_NUM]; + u32 apk_result[PATH_NUM][APK_BB_REG_NUM]; long bb_offset, delta_v, delta_offset; if (!is2t) pathbound = 1; + return; + for (index = 0; index < PATH_NUM; index++) { apk_offset[index] = apk_normal_offset[index]; apk_value[index] = apk_normal_value[index]; @@ -1730,8 +1720,7 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, 0x08)); } - - rtlphy->apk_done = true; + rtlphy->b_apk_done = true; #endif } @@ -1758,6 +1747,7 @@ static void _rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1); } + } #undef IQK_ADDA_REG_NUM diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h index 53ffb0981586..9a264c0d6127 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h @@ -27,8 +27,8 @@ * *****************************************************************************/ -#ifndef __RTL92C_PHY_H__ -#define __RTL92C_PHY_H__ +#ifndef __RTL92C_PHY_COMMON_H__ +#define __RTL92C_PHY_COMMON_H__ #define MAX_PRECMD_CNT 16 #define MAX_RFDEPENDCMD_CNT 16 @@ -39,6 +39,7 @@ #define RT_CANNOT_IO(hw) false #define HIGHPOWER_RADIOA_ARRAYLEN 22 +#define IQK_ADDA_REG_NUM 16 #define MAX_TOLERANCE 5 #define IQK_DELAY_TIME 1 @@ -56,6 +57,7 @@ #define IQK_ADDA_REG_NUM 16 #define IQK_MAC_REG_NUM 4 +#define IQK_DELAY_TIME 1 #define RF90_PATH_MAX 2 #define CT_OFFSET_MAC_ADDR 0X16 @@ -77,6 +79,7 @@ #define RTL92C_MAX_PATH_NUM 2 #define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255 + enum swchnlcmd_id { CMDID_END, CMDID_SET_TXPOWEROWER_LEVEL, @@ -184,45 +187,41 @@ struct tx_power_struct { u32 mcs_original_offset[4][16]; }; -extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, +u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); -extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, +void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, u32 data); -extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, +u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask); -extern void rtl92c_phy_set_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 regaddr, - u32 bitmask, u32 data); -extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); +bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); +bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, enum radio_path rfpath); -extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); -extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, +void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel); -extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); -extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, +void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm); -extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, +void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); -extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw); -extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, +void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, enum nl80211_channel_type ch_type); -extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); -extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); -extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); -extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, +void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); +u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); +void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval); void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath); -extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, +bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath); -extern bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, +bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state); void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw); void rtl92c_phy_set_io(struct ieee80211_hw *hw); @@ -235,12 +234,25 @@ u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, enum wireless_mode wirelessmode, long power_indbm); void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); -static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, - u32 cmdtableidx, u32 cmdtablesz, - enum swchnlcmd_id cmdid, u32 para1, - u32 para2, u32 msdelay); -static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, - u8 channel, u8 *stage, u8 *step, - u32 *delay); +void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw); +bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, + u8 channel, u8 *stage, u8 *step, + u32 *delay); +u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw); +u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset); +void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset); +void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw); +void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, + u32 data); +bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h index 2f577c8828fc..35ff7df41a1d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h @@ -121,19 +121,6 @@ #define CHIP_92C 0x01 #define CHIP_88C 0x00 -/* Add vendor information into chip version definition. - * Add UMC B-Cut and RTL8723 chip info definition. - * - * BIT 7 Reserved - * BIT 6 UMC BCut - * BIT 5 Manufacturer(TSMC/UMC) - * BIT 4 TEST/NORMAL - * BIT 3 8723 Version - * BIT 2 8723? - * BIT 1 1T2R? - * BIT 0 88C/92C -*/ - enum version_8192c { VERSION_A_CHIP_92C = 0x01, VERSION_A_CHIP_88C = 0x00, @@ -280,20 +267,6 @@ struct h2c_cmd_8192c { u8 *p_cmdbuffer; }; -static inline u8 _rtl92c_get_chnl_group(u8 chnl) -{ - u8 group = 0; - - if (chnl < 3) - group = 0; - else if (chnl < 9) - group = 1; - else - group = 2; - - return group; -} - /* NOTE: reference to rtl8192c_rates struct */ static inline int _rtl92c_rate_mapping(struct ieee80211_hw *hw, bool isHT, u8 desc_rate, bool first_ampdu) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c index 7d76504df4d1..2df33e53e15a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c @@ -29,10 +29,12 @@ #include "../wifi.h" #include "../base.h" +#include "../pci.h" #include "reg.h" #include "def.h" #include "phy.h" #include "dm.h" +#include "../rtl8192c/fw_common.h" void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h index 36302ebae4a3..07dd9552e82f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h @@ -192,6 +192,7 @@ void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw); void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw); void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); +void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw); void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index 05477f465a75..4a56138eb33c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -30,12 +30,14 @@ #include "../wifi.h" #include "../efuse.h" #include "../base.h" +#include "../regd.h" #include "../cam.h" #include "../ps.h" #include "../pci.h" #include "reg.h" #include "def.h" #include "phy.h" +#include "../rtl8192c/fw_common.h" #include "dm.h" #include "led.h" #include "hw.h" @@ -137,15 +139,6 @@ void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) break; } - case HW_VAR_MGT_FILTER: - *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP0); - break; - case HW_VAR_CTRL_FILTER: - *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP1); - break; - case HW_VAR_DATA_FILTER: - *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP2); - break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case not process\n")); @@ -156,6 +149,7 @@ void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -178,7 +172,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) rate_cfg |= 0x01; rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff); rtl_write_byte(rtlpriv, REG_RRSR + 1, - (rate_cfg >> 8)&0xff); + (rate_cfg >> 8) & 0xff); while (rate_cfg > 0x1) { rate_cfg = (rate_cfg >> 1); rate_index++; @@ -276,13 +270,19 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) break; } case HW_VAR_AMPDU_FACTOR:{ - u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 }; + u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9}; + u8 regtoset_bt[4] = {0x31, 0x74, 0x42, 0x97}; u8 factor_toset; u8 *p_regtoset = NULL; u8 index = 0; - p_regtoset = regtoset_normal; + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == + BT_CSR_BC4)) + p_regtoset = regtoset_bt; + else + p_regtoset = regtoset_normal; factor_toset = *((u8 *) val); if (factor_toset <= 3) { @@ -317,45 +317,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) } case HW_VAR_AC_PARAM:{ u8 e_aci = *((u8 *) val); - u32 u4b_ac_param; - u16 cw_min = le16_to_cpu(mac->ac[e_aci].cw_min); - u16 cw_max = le16_to_cpu(mac->ac[e_aci].cw_max); - u16 tx_op = le16_to_cpu(mac->ac[e_aci].tx_op); - - u4b_ac_param = (u32) mac->ac[e_aci].aifs; - u4b_ac_param |= ((u32)cw_min - & 0xF) << AC_PARAM_ECW_MIN_OFFSET; - u4b_ac_param |= ((u32)cw_max & - 0xF) << AC_PARAM_ECW_MAX_OFFSET; - u4b_ac_param |= (u32)tx_op << AC_PARAM_TXOP_OFFSET; - - RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, - ("queue:%x, ac_param:%x\n", e_aci, - u4b_ac_param)); - - switch (e_aci) { - case AC1_BK: - rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, - u4b_ac_param); - break; - case AC0_BE: - rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, - u4b_ac_param); - break; - case AC2_VI: - rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, - u4b_ac_param); - break; - case AC3_VO: - rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, - u4b_ac_param); - break; - default: - RT_ASSERT(false, - ("SetHwReg8185(): invalid aci: %d !\n", - e_aci)); - break; - } + rtl92c_dm_init_edca_turbo(hw); if (rtlpci->acm_method != eAcmWay2_SW) rtlpriv->cfg->ops->set_hw_reg(hw, @@ -526,9 +488,6 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) case HW_VAR_CORRECT_TSF:{ u8 btype_ibss = ((u8 *) (val))[0]; - /*btype_ibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? - 1 : 0;*/ - if (btype_ibss == true) _rtl92ce_stop_tx_beacon(hw); @@ -537,7 +496,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) rtl_write_dword(rtlpriv, REG_TSFTR, (u32) (mac->tsf & 0xffffffff)); rtl_write_dword(rtlpriv, REG_TSFTR + 4, - (u32) ((mac->tsf >> 32)&0xffffffff)); + (u32) ((mac->tsf >> 32) & 0xffffffff)); _rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0); @@ -547,15 +506,6 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) break; } - case HW_VAR_MGT_FILTER: - rtl_write_word(rtlpriv, REG_RXFLTMAP0, *(u16 *) val); - break; - case HW_VAR_CTRL_FILTER: - rtl_write_word(rtlpriv, REG_RXFLTMAP1, *(u16 *) val); - break; - case HW_VAR_DATA_FILTER: - rtl_write_word(rtlpriv, REG_RXFLTMAP2, *(u16 *) val); - break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case " "not process\n")); @@ -679,12 +629,12 @@ static void _rtl92ce_gen_refresh_led_state(struct ieee80211_hw *hw) rtl92ce_sw_led_on(hw, pLed0); else rtl92ce_sw_led_off(hw, pLed0); - } static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -693,9 +643,22 @@ static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) u16 retry; rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + u32 value32; + value32 = rtl_read_dword(rtlpriv, REG_APS_FSMCO); + value32 |= (SOP_ABG | SOP_AMB | XOP_BTCK); + rtl_write_dword(rtlpriv, REG_APS_FSMCO, value32); + } rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0F); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + u32 u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL); + + u4b_tmp &= (~0x00024800); + rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp); + } + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) | BIT(0); udelay(2); @@ -726,6 +689,11 @@ static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x82); udelay(2); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + bytetmp = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+2) & 0xfd; + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+2, bytetmp); + } + rtl_write_word(rtlpriv, REG_CR, 0x2ff); if (_rtl92ce_llt_table_init(hw) == false) @@ -793,6 +761,7 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); u8 reg_bw_opmode; u32 reg_ratr, reg_prsr; @@ -824,7 +793,11 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw) rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000); rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504); - rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x97427431); + else + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2); @@ -840,11 +813,20 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_PIFS, 0x1C); rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); - rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) { + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0402); + } else { + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + } - rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); - - rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) + rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666); + else + rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666); rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); @@ -948,8 +930,8 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw) } rtlhal->last_hmeboxnum = 0; - rtl92ce_phy_mac_config(hw); - rtl92ce_phy_bb_config(hw); + rtl92c_phy_mac_config(hw); + rtl92c_phy_bb_config(hw); rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; rtl92c_phy_rf_config(hw); rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, @@ -962,15 +944,20 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw) _rtl92ce_hw_configure(hw); rtl_cam_reset_all_entry(hw); rtl92ce_enable_hw_security_config(hw); + ppsc->rfpwr_state = ERFON; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); _rtl92ce_enable_aspm_back_door(hw); rtlpriv->intf_ops->enable_aspm(hw); + + rtl8192ce_bt_hw_init(hw); + if (ppsc->rfpwr_state == ERFON) { rtl92c_phy_set_rfpath_switch(hw, 1); - if (iqk_initialized) + if (iqk_initialized) { rtl92c_phy_iq_calibrate(hw, true); - else { + } else { rtl92c_phy_iq_calibrate(hw, false); iqk_initialized = true; } @@ -1128,75 +1115,62 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, return 0; } -static void _rtl92ce_set_check_bssid(struct ieee80211_hw *hw, - enum nl80211_iftype type) +void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); - u8 filterout_non_associated_bssid = false; - switch (type) { - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_STATION: - filterout_non_associated_bssid = true; - break; - case NL80211_IFTYPE_UNSPECIFIED: - case NL80211_IFTYPE_AP: - default: - break; - } + if (rtlpriv->psc.rfpwr_state != ERFON) + return; - if (filterout_non_associated_bssid == true) { + if (check_bssid == true) { reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (®_rcr)); _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4)); - } else if (filterout_non_associated_bssid == false) { + } else if (check_bssid == false) { reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); _rtl92ce_set_bcn_ctrl_reg(hw, BIT(4), 0); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (®_rcr)); } + } int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) { + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (_rtl92ce_set_media_status(hw, type)) return -EOPNOTSUPP; - _rtl92ce_set_check_bssid(hw, type); + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP) + rtl92ce_set_check_bssid(hw, true); + } else { + rtl92ce_set_check_bssid(hw, false); + } + return 0; } +/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */ void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u32 u4b_ac_param; - u16 cw_min = le16_to_cpu(mac->ac[aci].cw_min); - u16 cw_max = le16_to_cpu(mac->ac[aci].cw_max); - u16 tx_op = le16_to_cpu(mac->ac[aci].tx_op); - rtl92c_dm_init_edca_turbo(hw); - u4b_ac_param = (u32) mac->ac[aci].aifs; - u4b_ac_param |= (u32) ((cw_min & 0xF) << AC_PARAM_ECW_MIN_OFFSET); - u4b_ac_param |= (u32) ((cw_max & 0xF) << AC_PARAM_ECW_MAX_OFFSET); - u4b_ac_param |= (u32) (tx_op << AC_PARAM_TXOP_OFFSET); - RT_TRACE(rtlpriv, COMP_QOS, DBG_DMESG, - ("queue:%x, ac_param:%x aifs:%x cwmin:%x cwmax:%x txop:%x\n", - aci, u4b_ac_param, mac->ac[aci].aifs, cw_min, - cw_max, tx_op)); switch (aci) { case AC1_BK: - rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, u4b_ac_param); + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f); break; case AC0_BE: - rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); + /* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); */ break; case AC2_VI: - rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, u4b_ac_param); + rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322); break; case AC3_VO: - rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, u4b_ac_param); + rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222); break; default: RT_ASSERT(false, ("invalid aci: %d !\n", aci)); @@ -1227,8 +1201,10 @@ void rtl92ce_disable_interrupt(struct ieee80211_hw *hw) static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u8 u1b_tmp; + u32 u4b_tmp; rtlpriv->intf_ops->enable_aspm(hw); rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); @@ -1243,13 +1219,27 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00000000); u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL); - rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 | - (u1b_tmp << 8)); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) || + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8))) { + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00F30000 | + (u1b_tmp << 8)); + } else { + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 | + (u1b_tmp << 8)); + } rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790); rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080); rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80); rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23); - rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL); + u4b_tmp |= 0x03824800; + rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp); + } else { + rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e); + } + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e); rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, 0x10); } @@ -1327,6 +1317,7 @@ void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr)); + if (add_msr) rtlpci->irq_mask[0] |= add_msr; if (rm_msr) @@ -1582,7 +1573,7 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) ("RTL819X Not boot from eeprom, check it !!")); } - RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, ("MAP\n"), + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"), hwinfo, HWSET_MAX_SIZE); eeprom_id = *((u16 *)&hwinfo[0]); @@ -1610,6 +1601,10 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) rtlefuse->autoload_failflag, hwinfo); + rtl8192ce_read_bt_coexist_info_from_hwpg(hw, + rtlefuse->autoload_failflag, + hwinfo); + rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; rtlefuse->txpwr_fromeprom = true; @@ -1618,6 +1613,9 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid)); + /* set channel paln to world wide 13 */ + rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; + if (rtlhal->oem_id == RT_CID_DEFAULT) { switch (rtlefuse->eeprom_oemid) { case EEPROM_CID_DEFAULT: @@ -1701,30 +1699,36 @@ void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw) } else { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n")); } - _rtl92ce_hal_customized_behavior(hw); } -void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) +static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - - u32 ratr_value = (u32) mac->basic_rates; - u8 *mcsrate = mac->mcs; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 ratr_value; u8 ratr_index = 0; u8 nmode = mac->ht_enable; - u8 mimo_ps = 1; + u8 mimo_ps = IEEE80211_SMPS_OFF; u16 shortgi_rate; u32 tmp_ratr_value; u8 curtxbw_40mhz = mac->bw_40; - u8 curshortgi_40mhz = mac->sgi_40; - u8 curshortgi_20mhz = mac->sgi_20; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; enum wireless_mode wirelessmode = mac->mode; - ratr_value |= ((*(u16 *) (mcsrate))) << 12; - + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_value = sta->supp_rates[1] << 4; + else + ratr_value = sta->supp_rates[0]; + ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); switch (wirelessmode) { case WIRELESS_MODE_B: if (ratr_value & 0x0000000c) @@ -1738,7 +1742,7 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) case WIRELESS_MODE_N_24G: case WIRELESS_MODE_N_5G: nmode = 1; - if (mimo_ps == 0) { + if (mimo_ps == IEEE80211_SMPS_STATIC) { ratr_value &= 0x0007F005; } else { u32 ratr_mask; @@ -1761,10 +1765,19 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) break; } - ratr_value &= 0x0FFFFFFF; + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) && + (rtlpcipriv->bt_coexist.bt_cur_state) && + (rtlpcipriv->bt_coexist.bt_ant_isolation) && + ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) || + (rtlpcipriv->bt_coexist.bt_service == BT_BUSY))) + ratr_value &= 0x0fffcfc0; + else + ratr_value &= 0x0FFFFFFF; - if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) || (!curtxbw_40mhz && - curshortgi_20mhz))) { + if (nmode && ((curtxbw_40mhz && + curshortgi_40mhz) || (!curtxbw_40mhz && + curshortgi_20mhz))) { ratr_value |= 0x10000000; tmp_ratr_value = (ratr_value >> 12); @@ -1784,24 +1797,42 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) ("%x\n", rtl_read_dword(rtlpriv, REG_ARFR0))); } -void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) +static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u32 ratr_bitmap = (u32) mac->basic_rates; - u8 *p_mcsrate = mac->mcs; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u32 ratr_bitmap; u8 ratr_index; - u8 curtxbw_40mhz = mac->bw_40; - u8 curshortgi_40mhz = mac->sgi_40; - u8 curshortgi_20mhz = mac->sgi_20; - enum wireless_mode wirelessmode = mac->mode; + u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ? 1 : 0; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = 0; bool shortgi = false; u8 rate_mask[5]; u8 macid = 0; - u8 mimops = 1; + u8 mimo_ps = IEEE80211_SMPS_OFF; - ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12); + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + wirelessmode = sta_entry->wireless_mode; + if (mac->opmode == NL80211_IFTYPE_STATION) + curtxbw_40mhz = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_bitmap = sta->supp_rates[1] << 4; + else + ratr_bitmap = sta->supp_rates[0]; + ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); switch (wirelessmode) { case WIRELESS_MODE_B: ratr_index = RATR_INX_WIRELESS_B; @@ -1828,7 +1859,7 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) case WIRELESS_MODE_N_5G: ratr_index = RATR_INX_WIRELESS_NGB; - if (mimops == 0) { + if (mimo_ps == IEEE80211_SMPS_STATIC) { if (rssi_level == 1) ratr_bitmap &= 0x00070000; else if (rssi_level == 2) @@ -1892,8 +1923,8 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) } RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, ("ratr_bitmap :%x\n", ratr_bitmap)); - *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) | - (ratr_index << 28); + *(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) | + (ratr_index << 28)); rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80; RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, ("Rate_index:%x, " "ratr_val:%x, %x:%x:%x:%x:%x\n", @@ -1902,6 +1933,20 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) rate_mask[2], rate_mask[3], rate_mask[4])); rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask); + + if (macid != 0) + sta_entry->ratr_index = ratr_index; +} + +void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->dm.useramask) + rtl92ce_update_hal_rate_mask(hw, sta, rssi_level); + else + rtl92ce_update_hal_rate_table(hw, sta); } void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw) @@ -1919,7 +1964,7 @@ void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); } -bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) +bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); @@ -1929,7 +1974,7 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) bool actuallyset = false; unsigned long flag; - if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter)) + if (rtlpci->being_init_adapter) return false; if (ppsc->swrf_processing) @@ -1946,12 +1991,6 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) cur_rfstate = ppsc->rfpwr_state; - if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && - RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) { - rtlpriv->intf_ops->disable_aspm(hw); - RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); - } - rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG)&~(BIT(3))); @@ -1976,38 +2015,13 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) } if (actuallyset) { - if (e_rfpowerstate_toset == ERFON) { - if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && - RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) { - rtlpriv->intf_ops->disable_aspm(hw); - RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); - } - } - - spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); - ppsc->rfchange_inprogress = false; - spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); - - if (e_rfpowerstate_toset == ERFOFF) { - if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { - rtlpriv->intf_ops->enable_aspm(hw); - RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); - } - } - - } else if (e_rfpowerstate_toset == ERFOFF || cur_rfstate == ERFOFF) { - if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) - RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); - - if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { - rtlpriv->intf_ops->enable_aspm(hw); - RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); - } - spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); ppsc->rfchange_inprogress = false; spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); } else { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); ppsc->rfchange_inprogress = false; spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); @@ -2086,15 +2100,31 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, macaddr = cam_const_broad; entry_id = key_index; } else { + if (mac->opmode == NL80211_IFTYPE_AP) { + entry_id = rtl_cam_get_free_entry(hw, + p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + RT_TRACE(rtlpriv, COMP_SEC, + DBG_EMERG, + ("Can not find free hw" + " security cam entry\n")); + return; + } + } else { + entry_id = CAM_PAIRWISE_KEY_POSITION; + } + key_index = PAIRWISE_KEYIDX; - entry_id = CAM_PAIRWISE_KEY_POSITION; is_pairwise = true; } } if (rtlpriv->sec.key_len[key_index] == 0) { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("delete one entry\n")); + ("delete one entry, entry_id is %d\n", + entry_id)); + if (mac->opmode == NL80211_IFTYPE_AP) + rtl_cam_del_entry(hw, p_macaddr); rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); } else { RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, @@ -2146,3 +2176,132 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, } } } + +static void rtl8192ce_bt_var_init(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + rtlpcipriv->bt_coexist.bt_coexistence = + rtlpcipriv->bt_coexist.eeprom_bt_coexist; + rtlpcipriv->bt_coexist.bt_ant_num = + rtlpcipriv->bt_coexist.eeprom_bt_ant_num; + rtlpcipriv->bt_coexist.bt_coexist_type = + rtlpcipriv->bt_coexist.eeprom_bt_type; + + if (rtlpcipriv->bt_coexist.reg_bt_iso == 2) + rtlpcipriv->bt_coexist.bt_ant_isolation = + rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation; + else + rtlpcipriv->bt_coexist.bt_ant_isolation = + rtlpcipriv->bt_coexist.reg_bt_iso; + + rtlpcipriv->bt_coexist.bt_radio_shared_type = + rtlpcipriv->bt_coexist.eeprom_bt_radio_shared; + + if (rtlpcipriv->bt_coexist.bt_coexistence) { + + if (rtlpcipriv->bt_coexist.reg_bt_sco == 1) + rtlpcipriv->bt_coexist.bt_service = BT_OTHER_ACTION; + else if (rtlpcipriv->bt_coexist.reg_bt_sco == 2) + rtlpcipriv->bt_coexist.bt_service = BT_SCO; + else if (rtlpcipriv->bt_coexist.reg_bt_sco == 4) + rtlpcipriv->bt_coexist.bt_service = BT_BUSY; + else if (rtlpcipriv->bt_coexist.reg_bt_sco == 5) + rtlpcipriv->bt_coexist.bt_service = BT_OTHERBUSY; + else + rtlpcipriv->bt_coexist.bt_service = BT_IDLE; + + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + rtlpcipriv->bt_coexist.bt_rssi_state = 0xff; + } +} + +void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool auto_load_fail, u8 *hwinfo) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 value; + + if (!auto_load_fail) { + rtlpcipriv->bt_coexist.eeprom_bt_coexist = + ((hwinfo[RF_OPTION1] & 0xe0) >> 5); + value = hwinfo[RF_OPTION4]; + rtlpcipriv->bt_coexist.eeprom_bt_type = ((value & 0xe) >> 1); + rtlpcipriv->bt_coexist.eeprom_bt_ant_num = (value & 0x1); + rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = + ((value & 0x10) >> 4); + rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = + ((value & 0x20) >> 5); + } else { + rtlpcipriv->bt_coexist.eeprom_bt_coexist = 0; + rtlpcipriv->bt_coexist.eeprom_bt_type = BT_2WIRE; + rtlpcipriv->bt_coexist.eeprom_bt_ant_num = ANT_X2; + rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = 0; + rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = BT_RADIO_SHARED; + } + + rtl8192ce_bt_var_init(hw); +} + +void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + /* 0:Low, 1:High, 2:From Efuse. */ + rtlpcipriv->bt_coexist.reg_bt_iso = 2; + /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */ + rtlpcipriv->bt_coexist.reg_bt_sco = 3; + /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ + rtlpcipriv->bt_coexist.reg_bt_sco = 0; +} + + +void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + u8 u1_tmp; + + if (rtlpcipriv->bt_coexist.bt_coexistence && + ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) || + rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8)) { + + if (rtlpcipriv->bt_coexist.bt_ant_isolation) + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + + u1_tmp = rtl_read_byte(rtlpriv, 0x4fd) & + BIT_OFFSET_LEN_MASK_32(0, 1); + u1_tmp = u1_tmp | + ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? + 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | + ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) ? + 0 : BIT_OFFSET_LEN_MASK_32(2, 1)); + rtl_write_byte(rtlpriv, 0x4fd, u1_tmp); + + rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+4, 0xaaaa9aaa); + rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+8, 0xffbd0040); + rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+0xc, 0x40000010); + + /* Config to 1T1R. */ + if (rtlphy->rf_type == RF_1T1R) { + u1_tmp = rtl_read_byte(rtlpriv, ROFDM0_TRXPATHENABLE); + u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1)); + rtl_write_byte(rtlpriv, ROFDM0_TRXPATHENABLE, u1_tmp); + + u1_tmp = rtl_read_byte(rtlpriv, ROFDM1_TRXPATHENABLE); + u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1)); + rtl_write_byte(rtlpriv, ROFDM1_TRXPATHENABLE, u1_tmp); + } + } +} + +void rtl92ce_suspend(struct ieee80211_hw *hw) +{ +} + +void rtl92ce_resume(struct ieee80211_hw *hw) +{ +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h index a3dfdb635168..07dbe3e340a5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h @@ -30,7 +30,18 @@ #ifndef __RTL92CE_HW_H__ #define __RTL92CE_HW_H__ -#define H2C_RA_MASK 6 +static inline u8 _rtl92c_get_chnl_group(u8 chnl) +{ + u8 group; + + if (chnl < 3) + group = 0; + else if (chnl < 9) + group = 1; + else + group = 2; + return group; +} void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw); @@ -41,28 +52,27 @@ void rtl92ce_card_disable(struct ieee80211_hw *hw); void rtl92ce_enable_interrupt(struct ieee80211_hw *hw); void rtl92ce_disable_interrupt(struct ieee80211_hw *hw); int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci); void rtl92ce_set_beacon_related_registers(struct ieee80211_hw *hw); void rtl92ce_set_beacon_interval(struct ieee80211_hw *hw); void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw, u32 add_msr, u32 rm_msr); void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); -void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw); -void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level); +void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level); void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw); bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw); void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr, bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all); -bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); -void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); -void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); -void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); -int rtl92c_download_fw(struct ieee80211_hw *hw); -void rtl92c_firmware_selfreset(struct ieee80211_hw *hw); -void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, - u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); -bool rtl92ce_phy_mac_config(struct ieee80211_hw *hw); + +void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo); +void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw); +void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw); +void rtl92ce_suspend(struct ieee80211_hw *hw); +void rtl92ce_resume(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c index 7b1da8d7508f..9dd1ed7b6422 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c @@ -32,6 +32,14 @@ #include "reg.h" #include "led.h" +static void _rtl92ce_init_led(struct ieee80211_hw *hw, + struct rtl_led *pled, enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->ledon = false; +} + void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) { u8 ledcfg; @@ -97,13 +105,12 @@ void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) void rtl92ce_init_sw_leds(struct ieee80211_hw *hw) { + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); + _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); } -void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw) -{ -} - -void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, +static void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) { struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); @@ -138,7 +145,7 @@ void rtl92ce_led_control(struct ieee80211_hw *hw, ledaction == LED_CTL_POWER_ON)) { return; } - RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n", + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d.\n", ledaction)); _rtl92ce_sw_led_control(hw, ledaction); } diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h index 10da3018f4b7..7dfccea2095b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h @@ -31,11 +31,8 @@ #define __RTL92CE_LED_H__ void rtl92ce_init_sw_leds(struct ieee80211_hw *hw); -void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw); void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); void rtl92ce_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); -void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, - enum led_ctl_mode ledaction); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index d0541e8c6012..73ae8a431848 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -38,7 +38,9 @@ #include "dm.h" #include "table.h" -u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw, +static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); + +u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -73,9 +75,47 @@ u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw, return readback_value; } +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool is92c = IS_92C_SERIAL(rtlhal->version); + bool rtstatus = _rtl92c_phy_config_mac_with_headerfile(hw); + + if (is92c) + rtl_write_byte(rtlpriv, 0x14, 0x71); + return rtstatus; +} + +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw) +{ + bool rtstatus = true; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 regval; + u32 regvaldw; + u8 reg_hwparafile = 1; + + _rtl92c_phy_init_bb_rf_register_definition(hw); + regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, + regval | BIT(13) | BIT(0) | BIT(1)); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); + rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, + FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE | + FEN_BB_GLB_RSTn | FEN_BBRSTB); + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); + regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0); + rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23)); + if (reg_hwparafile == 1) + rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); + return rtstatus; +} + void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, - u32 regaddr, u32 bitmask, u32 data) + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -121,45 +161,7 @@ void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, bitmask, data, rfpath)); } -bool rtl92ce_phy_mac_config(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - bool is92c = IS_92C_SERIAL(rtlhal->version); - bool rtstatus = _rtl92ce_phy_config_mac_with_headerfile(hw); - - if (is92c) - rtl_write_byte(rtlpriv, 0x14, 0x71); - return rtstatus; -} - -bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw) -{ - bool rtstatus = true; - struct rtl_priv *rtlpriv = rtl_priv(hw); - u16 regval; - u32 regvaldw; - u8 reg_hwparafile = 1; - - _rtl92c_phy_init_bb_rf_register_definition(hw); - regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); - rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, - regval | BIT(13) | BIT(0) | BIT(1)); - rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83); - rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); - rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); - rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, - FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE | - FEN_BB_GLB_RSTn | FEN_BBRSTB); - rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); - regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0); - rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23)); - if (reg_hwparafile == 1) - rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); - return rtstatus; -} - -bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) +static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 i; @@ -177,7 +179,7 @@ bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) } bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, - u8 configtype) + u8 configtype) { int i; u32 *phy_regarray_table; @@ -236,7 +238,7 @@ bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, } bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, - u8 configtype) + u8 configtype) { struct rtl_priv *rtlpriv = rtl_priv(hw); int i; @@ -274,7 +276,7 @@ bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, return true; } -bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, +bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath) { @@ -364,74 +366,6 @@ bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, return true; } -void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl_phy *rtlphy = &(rtlpriv->phy); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u8 reg_bw_opmode; - u8 reg_prsr_rsc; - - RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, - ("Switch to %s bandwidth\n", - rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? - "20MHz" : "40MHz")) - - if (is_hal_stop(rtlhal)) - return; - - reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE); - reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2); - - switch (rtlphy->current_chan_bw) { - case HT_CHANNEL_WIDTH_20: - reg_bw_opmode |= BW_OPMODE_20MHZ; - rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); - break; - - case HT_CHANNEL_WIDTH_20_40: - reg_bw_opmode &= ~BW_OPMODE_20MHZ; - rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); - - reg_prsr_rsc = - (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5); - rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc); - break; - - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); - break; - } - - switch (rtlphy->current_chan_bw) { - case HT_CHANNEL_WIDTH_20: - rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0); - rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0); - rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); - break; - case HT_CHANNEL_WIDTH_20_40: - rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); - rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); - rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND, - (mac->cur_40_prime_sc >> 1)); - rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); - rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0); - rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)), - (mac->cur_40_prime_sc == - HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1); - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); - break; - } - rtl92c_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); - rtlphy->set_bwmode_inprogress = false; - RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); -} - void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) { u8 tmpreg; @@ -477,6 +411,36 @@ void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) } } +static void _rtl92ce_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ + u32 u4b_tmp; + u8 delay = 5; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); + while (u4b_tmp != 0 && delay > 0) { + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); + delay--; + } + if (delay == 0) { + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + ("Switch RF timeout !!!.\n")); + return; + } + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); +} + static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state) { @@ -523,33 +487,6 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, break; } case ERFOFF:{ - for (queue_id = 0, i = 0; - queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { - ring = &pcipriv->dev.tx_ring[queue_id]; - if (skb_queue_len(&ring->queue) == 0 || - queue_id == BEACON_QUEUE) { - queue_id++; - continue; - } else { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("eRf Off/Sleep: %d times " - "TcbBusyQueue[%d] " - "=%d before doze!\n", (i + 1), - queue_id, - skb_queue_len(&ring->queue))); - udelay(10); - i++; - } - if (i >= MAX_DOZE_WAITING_TIMES_9x) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("\nERFOFF: %d times " - "TcbBusyQueue[%d] = %d !\n", - MAX_DOZE_WAITING_TIMES_9x, - queue_id, - skb_queue_len(&ring->queue))); - break; - } - } if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, ("IPS Set eRf nic disable\n")); @@ -581,6 +518,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, "TcbBusyQueue[%d] =%d before " "doze!\n", (i + 1), queue_id, skb_queue_len(&ring->queue))); + udelay(10); i++; } @@ -599,7 +537,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, jiffies_to_msecs(jiffies - ppsc->last_awake_jiffies))); ppsc->last_sleep_jiffies = jiffies; - _rtl92c_phy_set_rf_sleep(hw); + _rtl92ce_phy_set_rf_sleep(hw); break; } default: @@ -614,10 +552,11 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, return bresult; } -bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, +bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state) { struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool bresult = false; if (rfpwr_state == ppsc->rfpwr_state) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h index a37267e3fc22..ad580852cc76 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h @@ -39,6 +39,7 @@ #define RT_CANNOT_IO(hw) false #define HIGHPOWER_RADIOA_ARRAYLEN 22 +#define IQK_ADDA_REG_NUM 16 #define MAX_TOLERANCE 5 #define IQK_DELAY_TIME 1 @@ -56,6 +57,8 @@ #define IQK_ADDA_REG_NUM 16 #define IQK_MAC_REG_NUM 4 +#define IQK_DELAY_TIME 1 + #define RF90_PATH_MAX 2 #define CT_OFFSET_MAC_ADDR 0X16 @@ -76,7 +79,7 @@ #define CT_OFFSET_CUSTOMER_ID 0x7F #define RTL92C_MAX_PATH_NUM 2 -#define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255 + enum swchnlcmd_id { CMDID_END, CMDID_SET_TXPOWEROWER_LEVEL, @@ -184,43 +187,44 @@ struct tx_power_struct { u32 mcs_original_offset[4][16]; }; -extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); +u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); -extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, +void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, u32 data); -extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, +u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask); extern void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 regaddr, - u32 bitmask, u32 data); -extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); + enum radio_path rfpath, u32 regaddr, + u32 bitmask, u32 data); +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, +bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); +bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, enum radio_path rfpath); -extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); -extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, +void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel); -extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); -extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, +void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm); -extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, +void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); -extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw); -extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, +void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, enum nl80211_channel_type ch_type); -extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); -extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); -extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); -extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, +void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); +u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); +void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval); void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); +void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath); -extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, +bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath); bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, @@ -237,9 +241,6 @@ u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask); void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data); -void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, - u32 regaddr, u32 bitmask, - u32 data); void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data); @@ -250,5 +251,11 @@ bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw); void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw); +bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); +bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype); +bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h index b0868a613841..598cecc63f41 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h @@ -72,6 +72,7 @@ #define REG_GPIO_IO_SEL_2 0x0062 /* RTL8723 WIFI/BT/GPS Multi-Function control source. */ #define REG_MULTI_FUNC_CTRL 0x0068 + #define REG_MCUFWDL 0x0080 #define REG_HMEBOX_EXT_0 0x0088 @@ -542,7 +543,7 @@ #define IMR_OCPINT BIT(1) #define IMR_WLANOFF BIT(0) -#define HWSET_MAX_SIZE 128 +#define EFUSE_REAL_CONTENT_LEN 512 #define EEPROM_DEFAULT_TSSI 0x0 #define EEPROM_DEFAULT_TXPOWERDIFF 0x0 @@ -656,6 +657,7 @@ #define STOPBE BIT(1) #define STOPBK BIT(0) +#define RCR_APPFCS BIT(31) #define RCR_APP_FCS BIT(31) #define RCR_APP_MIC BIT(30) #define RCR_APP_ICV BIT(29) @@ -688,6 +690,7 @@ #define REG_USB_INFO 0xFE17 #define REG_USB_SPECIAL_OPTION 0xFE55 + #define REG_USB_DMA_AGG_TO 0xFE5B #define REG_USB_AGG_TO 0xFE5C #define REG_USB_AGG_TH 0xFE5D @@ -775,7 +778,6 @@ #define BOOT_FROM_EEPROM BIT(4) #define EEPROM_EN BIT(5) -#define EEPROMSEL BOOT_FROM_EEPROM #define AFE_BGEN BIT(0) #define AFE_MBEN BIT(1) @@ -901,28 +903,7 @@ #define BD_PKG_SEL BIT(25) #define BD_HCI_SEL BIT(26) #define TYPE_ID BIT(27) - -/* REG_GPIO_OUTSTS (For RTL8723 only) */ -#define EFS_HCI_SEL (BIT(0)|BIT(1)) -#define PAD_HCI_SEL (BIT(2)|BIT(3)) -#define HCI_SEL (BIT(4)|BIT(5)) -#define PKG_SEL_HCI BIT(6) -#define FEN_GPS BIT(7) -#define FEN_BT BIT(8) -#define FEN_WL BIT(9) -#define FEN_PCI BIT(10) -#define FEN_USB BIT(11) -#define BTRF_HWPDN_N BIT(12) -#define WLRF_HWPDN_N BIT(13) -#define PDN_BT_N BIT(14) -#define PDN_GPS_N BIT(15) -#define BT_CTL_HWPDN BIT(16) -#define GPS_CTL_HWPDN BIT(17) -#define PPHY_SUSB BIT(20) -#define UPHY_SUSB BIT(21) -#define PCI_SUSEN BIT(22) -#define USB_SUSEN BIT(23) -#define RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28)) +#define RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28)) #define CHIP_VER_RTL_MASK 0xF000 #define CHIP_VER_RTL_SHIFT 12 @@ -1077,6 +1058,7 @@ #define _RARF_RC8(x) (((x) & 0x1F) << 24) #define AC_PARAM_TXOP_OFFSET 16 +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 #define AC_PARAM_ECW_MAX_OFFSET 12 #define AC_PARAM_ECW_MIN_OFFSET 8 #define AC_PARAM_AIFS_OFFSET 0 @@ -1221,34 +1203,12 @@ #define EPROM_CMD_CONFIG 0x3 #define EPROM_CMD_LOAD 1 -#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE +#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE + +#define WL_HWPDN_EN BIT(0) #define HAL_8192C_HW_GPIO_WPS_BIT BIT(2) -/* REG_MULTI_FUNC_CTRL(For RTL8723 Only) */ -/* Enable GPIO[9] as WiFi HW PDn source */ -#define WL_HWPDN_EN BIT(0) -/* WiFi HW PDn polarity control */ -#define WL_HWPDN_SL BIT(1) -/* WiFi function enable */ -#define WL_FUNC_EN BIT(2) -/* Enable GPIO[9] as WiFi RF HW PDn source */ -#define WL_HWROF_EN BIT(3) -/* Enable GPIO[11] as BT HW PDn source */ -#define BT_HWPDN_EN BIT(16) -/* BT HW PDn polarity control */ -#define BT_HWPDN_SL BIT(17) -/* BT function enable */ -#define BT_FUNC_EN BIT(18) -/* Enable GPIO[11] as BT/GPS RF HW PDn source */ -#define BT_HWROF_EN BIT(19) -/* Enable GPIO[10] as GPS HW PDn source */ -#define GPS_HWPDN_EN BIT(20) -/* GPS HW PDn polarity control */ -#define GPS_HWPDN_SL BIT(21) -/* GPS function enable */ -#define GPS_FUNC_EN BIT(22) - #define RPMAC_RESET 0x100 #define RPMAC_TXSTART 0x104 #define RPMAC_TXLEGACYSIG 0x108 diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c index 669b1168dbec..90d0f2cf3b27 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c @@ -34,9 +34,9 @@ #include "rf.h" #include "dm.h" -static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw); +static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw); -void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) +void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -62,7 +62,7 @@ void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) } void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel) + u8 *ppowerlevel) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -128,8 +128,7 @@ void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, tmpval = tx_agc[RF90_PATH_A] >> 8; - if (mac->mode == WIRELESS_MODE_B) - tmpval = tmpval & 0xff00ffff; + tmpval = tmpval & 0xff00ffff; rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); @@ -202,7 +201,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - u8 i, chnlgroup, pwr_diff_limit[4]; + u8 i, chnlgroup = 0, pwr_diff_limit[4]; u32 writeVal, customer_limit, rf; for (rf = 0; rf < 2; rf++) { @@ -440,16 +439,17 @@ bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw) else rtlphy->num_total_rfpath = 2; - return _rtl92c_phy_rf6052_config_parafile(hw); + return _rtl92ce_phy_rf6052_config_parafile(hw); + } -static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) +static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); - u32 u4_regvalue; + u32 u4_regvalue = 0; u8 rfpath; - bool rtstatus; + bool rtstatus = true; struct bb_reg_def *pphyreg; for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { @@ -484,12 +484,12 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) switch (rfpath) { case RF90_PATH_A: - rtstatus = rtl92ce_phy_config_rf_with_headerfile(hw, - (enum radio_path) rfpath); + rtstatus = rtl92c_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); break; case RF90_PATH_B: - rtstatus = rtl92ce_phy_config_rf_with_headerfile(hw, - (enum radio_path) rfpath); + rtstatus = rtl92c_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); break; case RF90_PATH_C: break; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h index 3aa520c1c171..39ff03685986 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h @@ -34,14 +34,11 @@ #define RF6052_MAX_REG 0x3F #define RF6052_MAX_PATH 2 -extern void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, - u8 bandwidth); -extern void rtl92c_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel); -extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel, u8 channel); -bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw); -bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, - enum radio_path rfpath); - +extern void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, + u8 bandwidth); +extern void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +extern void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); +extern bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index b1cc4d44f534..390bbb5ee11d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -42,10 +42,58 @@ #include "trx.h" #include "led.h" +static void rtl92c_init_aspm_vars(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + /*close ASPM for AMD defaultly */ + rtlpci->const_amdpci_aspm = 0; + + /* + * ASPM PS mode. + * 0 - Disable ASPM, + * 1 - Enable ASPM without Clock Req, + * 2 - Enable ASPM with Clock Req, + * 3 - Alwyas Enable ASPM with Clock Req, + * 4 - Always Enable ASPM without Clock Req. + * set defult to RTL8192CE:3 RTL8192E:2 + * */ + rtlpci->const_pci_aspm = 3; + + /*Setting for PCI-E device */ + rtlpci->const_devicepci_aspm_setting = 0x03; + + /*Setting for PCI-E bridge */ + rtlpci->const_hostpci_aspm_setting = 0x02; + + /* + * In Hw/Sw Radio Off situation. + * 0 - Default, + * 1 - From ASPM setting without low Mac Pwr, + * 2 - From ASPM setting with low Mac Pwr, + * 3 - Bus D3 + * set default to RTL8192CE:0 RTL8192SE:2 + */ + rtlpci->const_hwsw_rfoff_d3 = 0; + + /* + * This setting works for those device with + * backdoor ASPM setting such as EPHY setting. + * 0 - Not support ASPM, + * 1 - Support ASPM, + * 2 - According to chipset. + */ + rtlpci->const_support_pciaspm = 1; +} + int rtl92c_init_sw_vars(struct ieee80211_hw *hw) { + int err; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + const struct firmware *firmware; + + rtl8192ce_bt_reg_init(hw); rtlpriv->dm.dm_initialgain_enable = 1; rtlpriv->dm.dm_flag = 0; @@ -53,7 +101,12 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->dm.thermalvalue = 0; rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13); - rtlpci->receive_config = (RCR_APP_FCS | + /* compatible 5G band 88ce just 2.4G band & smsp */ + rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; + rtlpriv->rtlhal.bandset = BAND_ON_2_4G; + rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; + + rtlpci->receive_config = (RCR_APPFCS | RCR_AMF | RCR_ADF | RCR_APP_MIC | @@ -76,13 +129,49 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD | 0); - rtlpriv->rtlhal.pfirmware = (u8 *) vmalloc(0x4000); + /* for LPS & IPS */ + rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; + rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; + rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpriv->psc.reg_fwctrl_lps = 3; + rtlpriv->psc.reg_max_lps_awakeintvl = 5; + /* for ASPM, you can close aspm through + * set const_support_pciaspm = 0 */ + rtl92c_init_aspm_vars(hw); + + if (rtlpriv->psc.reg_fwctrl_lps == 1) + rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 2) + rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 3) + rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = vzalloc(0x4000); if (!rtlpriv->rtlhal.pfirmware) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Can't alloc buffer for fw.\n")); return 1; } + /* request fw */ + err = request_firmware(&firmware, rtlpriv->cfg->fw_name, + rtlpriv->io.dev); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Failed to request firmware!\n")); + return 1; + } + if (firmware->size > 0x4000) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Firmware is too big!\n")); + release_firmware(firmware); + return 1; + } + memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); + rtlpriv->rtlhal.fwsize = firmware->size; + release_firmware(firmware); + return 0; } @@ -103,17 +192,19 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = { .interrupt_recognized = rtl92ce_interrupt_recognized, .hw_init = rtl92ce_hw_init, .hw_disable = rtl92ce_card_disable, + .hw_suspend = rtl92ce_suspend, + .hw_resume = rtl92ce_resume, .enable_interrupt = rtl92ce_enable_interrupt, .disable_interrupt = rtl92ce_disable_interrupt, .set_network_type = rtl92ce_set_network_type, + .set_chk_bssid = rtl92ce_set_check_bssid, .set_qos = rtl92ce_set_qos, .set_bcn_reg = rtl92ce_set_beacon_related_registers, .set_bcn_intv = rtl92ce_set_beacon_interval, .update_interrupt_mask = rtl92ce_update_interrupt_mask, .get_hw_reg = rtl92ce_get_hw_reg, .set_hw_reg = rtl92ce_set_hw_reg, - .update_rate_table = rtl92ce_update_hal_rate_table, - .update_rate_mask = rtl92ce_update_hal_rate_mask, + .update_rate_tbl = rtl92ce_update_hal_rate_tbl, .fill_tx_desc = rtl92ce_tx_fill_desc, .fill_tx_cmddesc = rtl92ce_tx_fill_cmddesc, .query_rx_desc = rtl92ce_rx_query_desc, @@ -123,7 +214,7 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = { .switch_channel = rtl92c_phy_sw_chnl, .dm_watchdog = rtl92c_dm_watchdog, .scan_operation_backup = rtl92c_phy_scan_operation_backup, - .set_rf_power_state = rtl92ce_phy_set_rf_power_state, + .set_rf_power_state = rtl92c_phy_set_rf_power_state, .led_control = rtl92ce_led_control, .set_desc = rtl92ce_set_desc, .get_desc = rtl92ce_get_desc, @@ -131,27 +222,29 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = { .enable_hw_sec = rtl92ce_enable_hw_security_config, .set_key = rtl92ce_set_key, .init_sw_leds = rtl92ce_init_sw_leds, - .deinit_sw_leds = rtl92ce_deinit_sw_leds, .get_bbreg = rtl92c_phy_query_bb_reg, .set_bbreg = rtl92c_phy_set_bb_reg, - .get_rfreg = rtl92ce_phy_query_rf_reg, .set_rfreg = rtl92ce_phy_set_rf_reg, - .cmd_send_packet = _rtl92c_cmd_send_packet, + .get_rfreg = rtl92c_phy_query_rf_reg, .phy_rf6052_config = rtl92ce_phy_rf6052_config, .phy_rf6052_set_cck_txpower = rtl92ce_phy_rf6052_set_cck_txpower, .phy_rf6052_set_ofdm_txpower = rtl92ce_phy_rf6052_set_ofdm_txpower, .config_bb_with_headerfile = _rtl92ce_phy_config_bb_with_headerfile, .config_bb_with_pgheaderfile = _rtl92ce_phy_config_bb_with_pgheaderfile, .phy_lc_calibrate = _rtl92ce_phy_lc_calibrate, - .phy_set_bw_mode_callback = rtl92ce_phy_set_bw_mode_callback, .dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower, }; static struct rtl_mod_params rtl92ce_mod_params = { - .sw_crypto = 0, + .sw_crypto = false, + .inactiveps = true, + .swctrl_lps = false, + .fwctrl_lps = true, }; static struct rtl_hal_cfg rtl92ce_hal_cfg = { + .bar_id = 2, + .write_readback = true, .name = "rtl92c_pci", .fw_name = "rtlwifi/rtl8192cfw.bin", .ops = &rtl8192ce_hal_ops, @@ -175,6 +268,8 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = { .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN, .maps[EFUSE_ANA8M] = EFUSE_ANA8M, .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE, + .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, + .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, .maps[RWCAM] = REG_CAMCMD, .maps[WCAMI] = REG_CAMWRITE, @@ -239,7 +334,7 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = { .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, }; -static struct pci_device_id rtl92ce_pci_ids[] __devinitdata = { +DEFINE_PCI_DEVICE_TABLE(rtl92ce_pci_ids) = { {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8191, rtl92ce_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8178, rtl92ce_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8177, rtl92ce_hal_cfg)}, @@ -257,7 +352,13 @@ MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n PCI wireless"); MODULE_FIRMWARE("rtlwifi/rtl8192cfw.bin"); module_param_named(swenc, rtl92ce_mod_params.sw_crypto, bool, 0444); +module_param_named(ips, rtl92ce_mod_params.inactiveps, bool, 0444); +module_param_named(swlps, rtl92ce_mod_params.swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl92ce_mod_params.fwctrl_lps, bool, 0444); MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); +MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); +MODULE_PARM_DESC(fwlps, "using linked fw control power save " + "(default 1 is open)\n"); static struct pci_driver rtl92ce_driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h index 36e657668c1e..b7dc3263e433 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h @@ -33,19 +33,9 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw); void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw); void rtl92c_init_var_map(struct ieee80211_hw *hw); -bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, - struct sk_buff *skb); -void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel); -void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel, u8 channel); bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, - u8 configtype); + u8 configtype); bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, - u8 configtype); -void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); -u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 regaddr, u32 bitmask); -void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw); + u8 configtype); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index aa2b5815600f..54b2bd53d36a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -36,42 +36,16 @@ #include "trx.h" #include "led.h" -static enum rtl_desc_qsel _rtl92ce_map_hwqueue_to_fwqueue(__le16 fc, - unsigned int - skb_queue) +static u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) { - enum rtl_desc_qsel qsel; + __le16 fc = rtl_get_fc(skb); - if (unlikely(ieee80211_is_beacon(fc))) { - qsel = QSLT_BEACON; - return qsel; - } + if (unlikely(ieee80211_is_beacon(fc))) + return QSLT_BEACON; + if (ieee80211_is_mgmt(fc)) + return QSLT_MGNT; - if (ieee80211_is_mgmt(fc)) { - qsel = QSLT_MGNT; - return qsel; - } - - switch (skb_queue) { - case VO_QUEUE: - qsel = QSLT_VO; - break; - case VI_QUEUE: - qsel = QSLT_VI; - break; - case BE_QUEUE: - qsel = QSLT_BE; - break; - case BK_QUEUE: - qsel = QSLT_BK; - break; - default: - qsel = QSLT_BE; - RT_ASSERT(false, ("BE queue, skb_queue:%d," - " set qsel = 0x%X\n", skb_queue, QSLT_BE)); - break; - } - return qsel; + return skb->priority; } static int _rtl92ce_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu) @@ -255,6 +229,7 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw, u8 evm, pwdb_all, rf_rx_num = 0; u8 i, max_spatial_stream; u32 rssi, total_rssi = 0; + bool in_powersavemode = false; bool is_cck_rate; is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); @@ -270,9 +245,13 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw, u8 report, cck_highpwr; cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; - cck_highpwr = (u8) rtl_get_bbreg(hw, - RFPGA0_XA_HSSIPARAMETER2, - BIT(9)); + if (!in_powersavemode) + cck_highpwr = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + BIT(9)); + else + cck_highpwr = false; + if (!cck_highpwr) { u8 cck_agc_rpt = cck_buf->cck_agc_rpt; report = cck_buf->cck_agc_rpt & 0xc0; @@ -398,6 +377,7 @@ static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw, if (rtlpriv->stats.ui_rssi.total_num++ >= PHY_RSSI_SLID_WIN_MAX) { + rtlpriv->stats.ui_rssi.total_num = PHY_RSSI_SLID_WIN_MAX; last_rssi = @@ -424,10 +404,6 @@ static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw, if (!pstats->is_cck && pstats->packet_toself) { for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; rfpath++) { - - if (!rtl8192_phy_check_is_legal_rfpath(hw, rfpath)) - continue; - if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { rtlpriv->stats.rx_rssi_percentage[rfpath] = pstats->rx_mimo_signalstrength[rfpath]; @@ -723,7 +699,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, struct sk_buff *skb, - unsigned int queue_index) + u8 hw_queue, struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); @@ -732,16 +708,9 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, bool defaultadapter = true; struct ieee80211_sta *sta; u8 *pdesc = (u8 *) pdesc_tx; - struct rtl_tcb_desc tcb_desc; - u8 *qc = ieee80211_get_qos_ctl(hdr); - u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u16 seq_number; __le16 fc = hdr->frame_control; - u8 rate_flag = info->control.rates[0].flags; - - enum rtl_desc_qsel fw_qsel = - _rtl92ce_map_hwqueue_to_fwqueue(fc, queue_index); - + u8 fw_qsel = _rtl92ce_map_hwqueue_to_fwqueue(skb, hw_queue); bool firstseg = ((hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); @@ -751,56 +720,68 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + u8 bw_40 = 0; + + rcu_read_lock(); + sta = get_sta(hw, mac->vif, mac->bssid); + if (mac->opmode == NL80211_IFTYPE_STATION) { + bw_40 = mac->bw_40; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) + bw_40 = sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; - rtl_get_tcb_desc(hw, info, skb, &tcb_desc); + rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92c)); + if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { + firstseg = true; + lastseg = true; + } if (firstseg) { SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); - SET_TX_DESC_TX_RATE(pdesc, tcb_desc.hw_rate); + SET_TX_DESC_TX_RATE(pdesc, tcb_desc->hw_rate); - if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble) + if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble) SET_TX_DESC_DATA_SHORTGI(pdesc, 1); - if (mac->tids[tid].agg.agg_state == RTL_AGG_ON && - info->flags & IEEE80211_TX_CTL_AMPDU) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) { SET_TX_DESC_AGG_BREAK(pdesc, 1); SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14); } SET_TX_DESC_SEQ(pdesc, seq_number); - SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc.rts_enable && - !tcb_desc. + SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc->rts_enable && + !tcb_desc-> cts_enable) ? 1 : 0)); SET_TX_DESC_HW_RTS_ENABLE(pdesc, - ((tcb_desc.rts_enable - || tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc.rts_stbc) ? 1 : 0)); + ((tcb_desc->rts_enable + || tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc->rts_stbc) ? 1 : 0)); - SET_TX_DESC_RTS_RATE(pdesc, tcb_desc.rts_rate); + SET_TX_DESC_RTS_RATE(pdesc, tcb_desc->rts_rate); SET_TX_DESC_RTS_BW(pdesc, 0); - SET_TX_DESC_RTS_SC(pdesc, tcb_desc.rts_sc); + SET_TX_DESC_RTS_SC(pdesc, tcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, - ((tcb_desc.rts_rate <= DESC92C_RATE54M) ? - (tcb_desc.rts_use_shortpreamble ? 1 : 0) - : (tcb_desc.rts_use_shortgi ? 1 : 0))); + ((tcb_desc->rts_rate <= DESC92C_RATE54M) ? + (tcb_desc->rts_use_shortpreamble ? 1 : 0) + : (tcb_desc->rts_use_shortgi ? 1 : 0))); - if (mac->bw_40) { - if (tcb_desc.packet_bw) { + if (bw_40) { + if (tcb_desc->packet_bw) { SET_TX_DESC_DATA_BW(pdesc, 1); SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3); } else { SET_TX_DESC_DATA_BW(pdesc, 0); - - if (rate_flag & IEEE80211_TX_RC_DUP_DATA) { - SET_TX_DESC_TX_SUB_CARRIER(pdesc, - mac->cur_40_prime_sc); - } + SET_TX_DESC_TX_SUB_CARRIER(pdesc, + mac->cur_40_prime_sc); } } else { SET_TX_DESC_DATA_BW(pdesc, 0); @@ -810,13 +791,10 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_LINIP(pdesc, 0); SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); - rcu_read_lock(); - sta = ieee80211_find_sta(mac->vif, mac->bssid); if (sta) { u8 ampdu_density = sta->ht_cap.ampdu_density; SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density); } - rcu_read_unlock(); if (info->control.hw_key) { struct ieee80211_key_conf *keyconf = @@ -844,7 +822,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF); SET_TX_DESC_DISABLE_FB(pdesc, 0); - SET_TX_DESC_USE_RATE(pdesc, tcb_desc.use_driver_rate ? 1 : 0); + SET_TX_DESC_USE_RATE(pdesc, tcb_desc->use_driver_rate ? 1 : 0); if (ieee80211_is_data_qos(fc)) { if (mac->rdg_en) { @@ -855,24 +833,24 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, } } } + rcu_read_unlock(); SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); - SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); if (rtlpriv->dm.useramask) { - SET_TX_DESC_RATE_ID(pdesc, tcb_desc.ratr_index); - SET_TX_DESC_MACID(pdesc, tcb_desc.mac_id); + SET_TX_DESC_RATE_ID(pdesc, tcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, tcb_desc->mac_id); } else { - SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc.ratr_index); - SET_TX_DESC_MACID(pdesc, tcb_desc.ratr_index); + SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, tcb_desc->ratr_index); } - if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps && - ppsc->fwctrl_lps) { + if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) { SET_TX_DESC_HWSEQ_EN(pdesc, 1); SET_TX_DESC_PKT_ID(pdesc, 8); @@ -923,7 +901,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len)); - SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); SET_TX_DESC_RATE_ID(pdesc, 7); SET_TX_DESC_MACID(pdesc, 0); @@ -1021,7 +999,7 @@ u32 rtl92ce_get_desc(u8 *p_desc, bool istx, u8 desc_name) return ret; } -void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue) +void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) { struct rtl_priv *rtlpriv = rtl_priv(hw); if (hw_queue == BEACON_QUEUE) { @@ -1032,35 +1010,3 @@ void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue) } } -bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, - struct sk_buff *skb) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - struct rtl8192_tx_ring *ring; - struct rtl_tx_desc *pdesc; - u8 own; - unsigned long flags; - struct sk_buff *pskb = NULL; - - ring = &rtlpci->tx_ring[BEACON_QUEUE]; - - spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); - - pskb = __skb_dequeue(&ring->queue); - if (pskb) - kfree_skb(pskb); - - pdesc = &ring->desc[0]; - own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); - - rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); - - __skb_queue_tail(&ring->queue, skb); - - spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); - - rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); - - return true; -} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h index 803adcc80c96..0f1177137501 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h @@ -532,9 +532,9 @@ #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); \ + memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ else \ - memset((void *)__pdesc, 0, _size); \ + memset(__pdesc, 0, _size); \ } while (0); #define RX_HAL_IS_CCK_RATE(_pdesc)\ @@ -724,17 +724,16 @@ struct rx_desc_92c { void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc, struct ieee80211_tx_info *info, - struct sk_buff *skb, unsigned int qsel); + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name); -void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue); +void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool b_firstseg, bool b_lastseg, struct sk_buff *skb); -bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb); - #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 9444e76838cf..52e2af58c1ed 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -39,6 +39,7 @@ #include "mac.h" #include "dm.h" #include "hw.h" +#include "../rtl8192ce/hw.h" #include "trx.h" #include "led.h" #include "table.h" @@ -605,10 +606,10 @@ void rtl92cu_read_eeprom_info(struct ieee80211_hw *hw) if (!IS_NORMAL_CHIP(rtlhal->version)) return; tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); - rtlefuse->epromtype = (tmp_u1b & EEPROMSEL) ? + rtlefuse->epromtype = (tmp_u1b & BOOT_FROM_EEPROM) ? EEPROM_93C46 : EEPROM_BOOT_EFUSE; RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from %s\n", - (tmp_u1b & EEPROMSEL) ? "EERROM" : "EFUSE")); + (tmp_u1b & BOOT_FROM_EEPROM) ? "EERROM" : "EFUSE")); rtlefuse->autoload_failflag = (tmp_u1b & EEPROM_EN) ? false : true; RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload %s\n", (tmp_u1b & EEPROM_EN) ? "OK!!" : "ERR!!")); @@ -921,7 +922,7 @@ static void _rtl92cu_init_chipT_queue_priority(struct ieee80211_hw *hw, u8 out_ep_num, u8 queue_sel) { - u8 hq_sele; + u8 hq_sele = 0; struct rtl_priv *rtlpriv = rtl_priv(hw); switch (out_ep_num) { @@ -977,7 +978,7 @@ static void _rtl92cu_init_wmac_setting(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APP_FCS | + mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APPFCS | RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | RCR_APP_MIC | RCR_APP_PHYSTS | RCR_ACRC32); rtl_write_dword(rtlpriv, REG_RCR, mac->rx_conf); @@ -2182,7 +2183,9 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) } } -void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw) +void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h index 62af555bb61c..32f85cba106a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h @@ -98,13 +98,14 @@ void rtl92cu_update_interrupt_mask(struct ieee80211_hw *hw, u32 add_msr, u32 rm_msr); void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); -void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw); +void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level); void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level); void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw); bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid); void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); -u8 _rtl92c_get_chnl_group(u8 chnl); int rtl92c_download_fw(struct ieee80211_hw *hw); void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c index 4e020e654e6b..9a3d0239e27e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c @@ -38,7 +38,7 @@ #include "table.h" u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 regaddr, u32 bitmask) + enum radio_path rfpath, u32 regaddr, u32 bitmask) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, readback_value, bitshift; @@ -64,8 +64,8 @@ u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, } void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, - u32 regaddr, u32 bitmask, u32 data) + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -163,7 +163,7 @@ bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) } bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, - u8 configtype) + u8 configtype) { int i; u32 *phy_regarray_table; @@ -223,7 +223,7 @@ bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, } bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, - u8 configtype) + u8 configtype) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -459,7 +459,7 @@ void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) } } -bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, +static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -595,7 +595,7 @@ bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, } bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, - enum rf_pwrstate rfpwr_state) + enum rf_pwrstate rfpwr_state) { struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); bool bresult = false; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h index 06299559ab68..ff81a61729d7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h @@ -34,3 +34,17 @@ bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath); void rtl92c_phy_set_io(struct ieee80211_hw *hw); bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw); +u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, u32 bitmask); +void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); +bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw); +bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); +void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); +bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype); +void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c index 1c79c226f145..c7576ec4744e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c @@ -62,7 +62,7 @@ void rtl92cu_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) } void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel) + u8 *ppowerlevel) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -389,7 +389,7 @@ static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw, } void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel, u8 channel) + u8 *ppowerlevel, u8 channel) { u32 writeVal[2], powerBase0[2], powerBase1[2]; u8 index = 0; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h index 86c2728cfa00..500a2094b6bb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h @@ -43,5 +43,9 @@ extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, bool rtl92cu_phy_rf6052_config(struct ieee80211_hw *hw); bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath); +void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 71244a38d49e..bee7c1480f63 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -94,7 +94,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = { .update_interrupt_mask = rtl92cu_update_interrupt_mask, .get_hw_reg = rtl92cu_get_hw_reg, .set_hw_reg = rtl92cu_set_hw_reg, - .update_rate_table = rtl92cu_update_hal_rate_table, + .update_rate_tbl = rtl92cu_update_hal_rate_table, .update_rate_mask = rtl92cu_update_hal_rate_mask, .fill_tx_desc = rtl92cu_tx_fill_desc, .fill_fake_txdesc = rtl92cu_fill_fake_txdesc, diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index d0b0d43b9a6d..3a92ba3c4a1e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -372,7 +372,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) __le16 fc; struct ieee80211_hdr *hdr; - memset(rx_status, 0, sizeof(rx_status)); + memset(rx_status, 0, sizeof(*rx_status)); rxdesc = skb->data; skb_len = skb->len; drvinfo_len = (GET_RX_DESC_DRVINFO_SIZE(rxdesc) * RTL_RX_DRV_INFO_UNIT); @@ -434,7 +434,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) "0x%02X\n", fc, (u32)hdr->addr1[0], (u32)hdr->addr1[1], (u32)hdr->addr1[2], (u32)hdr->addr1[3], (u32)hdr->addr1[4], (u32)hdr->addr1[5])); - memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); ieee80211_rx_irqsafe(hw, skb); } @@ -498,14 +498,14 @@ static void _rtl_tx_desc_checksum(u8 *txdesc) void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, struct sk_buff *skb, - unsigned int queue_index) + u8 queue_index, + struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); bool defaultadapter = true; - struct ieee80211_sta *sta; - struct rtl_tcb_desc tcb_desc; + struct ieee80211_sta *sta = info->control.sta = info->control.sta; u8 *qc = ieee80211_get_qos_ctl(hdr); u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u16 seq_number; @@ -517,15 +517,15 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, u8 *txdesc; seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; - rtl_get_tcb_desc(hw, info, skb, &tcb_desc); + rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); txdesc = (u8 *)skb_push(skb, RTL_TX_HEADER_SIZE); memset(txdesc, 0, RTL_TX_HEADER_SIZE); SET_TX_DESC_PKT_SIZE(txdesc, pktlen); SET_TX_DESC_LINIP(txdesc, 0); SET_TX_DESC_PKT_OFFSET(txdesc, RTL_DUMMY_OFFSET); SET_TX_DESC_OFFSET(txdesc, RTL_TX_HEADER_SIZE); - SET_TX_DESC_TX_RATE(txdesc, tcb_desc.hw_rate); - if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble) + SET_TX_DESC_TX_RATE(txdesc, tcb_desc->hw_rate); + if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble) SET_TX_DESC_DATA_SHORTGI(txdesc, 1); if (mac->tids[tid].agg.agg_state == RTL_AGG_ON && info->flags & IEEE80211_TX_CTL_AMPDU) { @@ -535,21 +535,21 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_AGG_BREAK(txdesc, 1); } SET_TX_DESC_SEQ(txdesc, seq_number); - SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc.rts_enable && - !tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc.rts_enable || - tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc.rts_stbc) ? 1 : 0)); - SET_TX_DESC_RTS_RATE(txdesc, tcb_desc.rts_rate); + SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable && + !tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable || + tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc->rts_stbc) ? 1 : 0)); + SET_TX_DESC_RTS_RATE(txdesc, tcb_desc->rts_rate); SET_TX_DESC_RTS_BW(txdesc, 0); - SET_TX_DESC_RTS_SC(txdesc, tcb_desc.rts_sc); + SET_TX_DESC_RTS_SC(txdesc, tcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(txdesc, - ((tcb_desc.rts_rate <= DESC92C_RATE54M) ? - (tcb_desc.rts_use_shortpreamble ? 1 : 0) - : (tcb_desc.rts_use_shortgi ? 1 : 0))); + ((tcb_desc->rts_rate <= DESC92C_RATE54M) ? + (tcb_desc->rts_use_shortpreamble ? 1 : 0) + : (tcb_desc->rts_use_shortgi ? 1 : 0))); if (mac->bw_40) { - if (tcb_desc.packet_bw) { + if (tcb_desc->packet_bw) { SET_TX_DESC_DATA_BW(txdesc, 1); SET_TX_DESC_DATA_SC(txdesc, 3); } else { @@ -590,7 +590,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_DATA_RATE_FB_LIMIT(txdesc, 0x1F); SET_TX_DESC_RTS_RATE_FB_LIMIT(txdesc, 0xF); SET_TX_DESC_DISABLE_FB(txdesc, 0); - SET_TX_DESC_USE_RATE(txdesc, tcb_desc.use_driver_rate ? 1 : 0); + SET_TX_DESC_USE_RATE(txdesc, tcb_desc->use_driver_rate ? 1 : 0); if (ieee80211_is_data_qos(fc)) { if (mac->rdg_en) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, @@ -600,11 +600,11 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, } } if (rtlpriv->dm.useramask) { - SET_TX_DESC_RATE_ID(txdesc, tcb_desc.ratr_index); - SET_TX_DESC_MACID(txdesc, tcb_desc.mac_id); + SET_TX_DESC_RATE_ID(txdesc, tcb_desc->ratr_index); + SET_TX_DESC_MACID(txdesc, tcb_desc->mac_id); } else { - SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc.ratr_index); - SET_TX_DESC_MACID(txdesc, tcb_desc.ratr_index); + SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc->ratr_index); + SET_TX_DESC_MACID(txdesc, tcb_desc->ratr_index); } if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps && ppsc->fwctrl_lps) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h index b396d46edbb7..53de5f66e242 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h @@ -37,6 +37,8 @@ #define RTL92C_SIZE_MAX_RX_BUFFER 15360 /* 8192 */ #define RX_DRV_INFO_SIZE_UNIT 8 +#define RTL_AGG_ON 1 + enum usb_rx_agg_mode { USB_RX_AGG_DISABLE, USB_RX_AGG_DMA, @@ -419,7 +421,8 @@ struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *, void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, struct sk_buff *skb, - unsigned int queue_index); + u8 queue_index, + struct rtl_tcb_desc *tcb_desc); void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc, u32 buffer_len, bool bIsPsPoll); void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/Makefile b/drivers/net/wireless/rtlwifi/rtl8192se/Makefile new file mode 100644 index 000000000000..b7eb13819cbc --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/Makefile @@ -0,0 +1,15 @@ +rtl8192se-objs := \ + dm.o \ + fw.o \ + hw.o \ + led.o \ + phy.o \ + rf.o \ + sw.o \ + table.o \ + trx.o + +obj-$(CONFIG_RTL8192SE) += rtl8192se.o + +ccflags-y += -D__CHECK_ENDIAN__ + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h new file mode 100644 index 000000000000..69828f2b3fab --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h @@ -0,0 +1,598 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __REALTEK_92S_DEF_H__ +#define __REALTEK_92S_DEF_H__ + +#define RX_MPDU_QUEUE 0 +#define RX_CMD_QUEUE 1 +#define RX_MAX_QUEUE 2 + +#define DESC92S_RATE1M 0x00 +#define DESC92S_RATE2M 0x01 +#define DESC92S_RATE5_5M 0x02 +#define DESC92S_RATE11M 0x03 +#define DESC92S_RATE6M 0x04 +#define DESC92S_RATE9M 0x05 +#define DESC92S_RATE12M 0x06 +#define DESC92S_RATE18M 0x07 +#define DESC92S_RATE24M 0x08 +#define DESC92S_RATE36M 0x09 +#define DESC92S_RATE48M 0x0a +#define DESC92S_RATE54M 0x0b +#define DESC92S_RATEMCS0 0x0c +#define DESC92S_RATEMCS1 0x0d +#define DESC92S_RATEMCS2 0x0e +#define DESC92S_RATEMCS3 0x0f +#define DESC92S_RATEMCS4 0x10 +#define DESC92S_RATEMCS5 0x11 +#define DESC92S_RATEMCS6 0x12 +#define DESC92S_RATEMCS7 0x13 +#define DESC92S_RATEMCS8 0x14 +#define DESC92S_RATEMCS9 0x15 +#define DESC92S_RATEMCS10 0x16 +#define DESC92S_RATEMCS11 0x17 +#define DESC92S_RATEMCS12 0x18 +#define DESC92S_RATEMCS13 0x19 +#define DESC92S_RATEMCS14 0x1a +#define DESC92S_RATEMCS15 0x1b +#define DESC92S_RATEMCS15_SG 0x1c +#define DESC92S_RATEMCS32 0x20 + +#define SHORT_SLOT_TIME 9 +#define NON_SHORT_SLOT_TIME 20 + +/* Rx smooth factor */ +#define RX_SMOOTH_FACTOR 20 + +/* Queue Select Value in TxDesc */ +#define QSLT_BK 0x2 +#define QSLT_BE 0x0 +#define QSLT_VI 0x5 +#define QSLT_VO 0x6 +#define QSLT_BEACON 0x10 +#define QSLT_HIGH 0x11 +#define QSLT_MGNT 0x12 +#define QSLT_CMD 0x13 + +#define PHY_RSSI_SLID_WIN_MAX 100 +#define PHY_LINKQUALITY_SLID_WIN_MAX 20 +#define PHY_BEACON_RSSI_SLID_WIN_MAX 10 + +/* Tx Desc */ +#define TX_DESC_SIZE_RTL8192S (16 * 4) +#define TX_CMDDESC_SIZE_RTL8192S (16 * 4) + +/* Define a macro that takes a le32 word, converts it to host ordering, + * right shifts by a specified count, creates a mask of the specified + * bit count, and extracts that number of bits. + */ + +#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \ + ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \ + BIT_LEN_MASK_32(__mask)) + +/* Define a macro that clears a bit field in an le32 word and + * sets the specified value into that bit field. The resulting + * value remains in le32 ordering; however, it is properly converted + * to host ordering for the clear and set operations before conversion + * back to le32. + */ + +#define SET_BITS_OFFSET_LE(__pdesc, __shift, __len, __val) \ + (*(__le32 *)(__pdesc) = \ + (cpu_to_le32((le32_to_cpu(*((__le32 *)(__pdesc))) & \ + (~(BIT_OFFSET_LEN_MASK_32((__shift), __len)))) | \ + (((u32)(__val) & BIT_LEN_MASK_32(__len)) << (__shift))))); + +/* macros to read/write various fields in RX or TX descriptors */ + +/* Dword 0 */ +#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 0, 16, __val) +#define SET_TX_DESC_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 16, 8, __val) +#define SET_TX_DESC_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val) +#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) +#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) +#define SET_TX_DESC_LINIP(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) +#define SET_TX_DESC_AMSDU(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) +#define SET_TX_DESC_GREEN_FIELD(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) +#define SET_TX_DESC_OWN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + +#define GET_TX_DESC_OWN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 31, 1) + +/* Dword 1 */ +#define SET_TX_DESC_MACID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) +#define SET_TX_DESC_MORE_DATA(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 5, 1, __val) +#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 6, 1, __val) +#define SET_TX_DESC_PIFS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 7, 1, __val) +#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 8, 5, __val) +#define SET_TX_DESC_ACK_POLICY(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 13, 2, __val) +#define SET_TX_DESC_NO_ACM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val) +#define SET_TX_DESC_NON_QOS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 16, 1, __val) +#define SET_TX_DESC_KEY_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 17, 2, __val) +#define SET_TX_DESC_OUI(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 19, 1, __val) +#define SET_TX_DESC_PKT_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 20, 1, __val) +#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 21, 1, __val) +#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 22, 2, __val) +#define SET_TX_DESC_WDS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val) +#define SET_TX_DESC_HTC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val) +#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 26, 5, __val) +#define SET_TX_DESC_HWPC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val) + +/* Dword 2 */ +#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 0, 6, __val) +#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 6, 1, __val) +#define SET_TX_DESC_TSFL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 7, 5, __val) +#define SET_TX_DESC_RTS_RETRY_COUNT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 12, 6, __val) +#define SET_TX_DESC_DATA_RETRY_COUNT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 18, 6, __val) +#define SET_TX_DESC_RSVD_MACID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(((__pdesc) + 8), 24, 5, __val) +#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 29, 1, __val) +#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val) +#define SET_TX_DESC_OWN_MAC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 31, 1, __val) + +/* Dword 3 */ +#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 0, 8, __val) +#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 8, 8, __val) +#define SET_TX_DESC_SEQ(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 16, 12, __val) +#define SET_TX_DESC_FRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 28, 4, __val) + +/* Dword 4 */ +#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 0, 6, __val) +#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 6, 1, __val) +#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 7, 4, __val) +#define SET_TX_DESC_CTS_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 11, 1, __val) +#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 12, 1, __val) +#define SET_TX_DESC_RA_BRSR_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 13, 3, __val) +#define SET_TX_DESC_TXHT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 16, 1, __val) +#define SET_TX_DESC_TX_SHORT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 17, 1, __val) +#define SET_TX_DESC_TX_BANDWIDTH(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 18, 1, __val) +#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 19, 2, __val) +#define SET_TX_DESC_TX_STBC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 21, 2, __val) +#define SET_TX_DESC_TX_REVERSE_DIRECTION(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 23, 1, __val) +#define SET_TX_DESC_RTS_HT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 24, 1, __val) +#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 25, 1, __val) +#define SET_TX_DESC_RTS_BANDWIDTH(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 26, 1, __val) +#define SET_TX_DESC_RTS_SUB_CARRIER(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 27, 2, __val) +#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 29, 2, __val) +#define SET_TX_DESC_USER_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 31, 1, __val) + +/* Dword 5 */ +#define SET_TX_DESC_PACKET_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 0, 9, __val) +#define SET_TX_DESC_TX_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 9, 6, __val) +#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 15, 1, __val) +#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 16, 5, __val) +#define SET_TX_DESC_TX_AGC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 21, 11, __val) + +/* Dword 6 */ +#define SET_TX_DESC_IP_CHECK_SUM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 24, 0, 16, __val) +#define SET_TX_DESC_TCP_CHECK_SUM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 24, 16, 16, __val) + +/* Dword 7 */ +#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 28, 0, 16, __val) +#define SET_TX_DESC_IP_HEADER_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 28, 16, 8, __val) +#define SET_TX_DESC_TCP_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 28, 31, 1, __val) + +/* Dword 8 */ +#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 32, 0, 32, __val) +#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 32, 0, 32) + +/* Dword 9 */ +#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 36, 0, 32, __val) + +/* Because the PCI Tx descriptors are chaied at the + * initialization and all the NextDescAddresses in + * these descriptors cannot not be cleared (,or + * driver/HW cannot find the next descriptor), the + * offset 36 (NextDescAddresses) is reserved when + * 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); + +/* Rx Desc */ +#define RX_STATUS_DESC_SIZE 24 +#define RX_DRV_INFO_SIZE_UNIT 8 + +/* DWORD 0 */ +#define SET_RX_STATUS_DESC_PKT_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 0, 14, __val) +#define SET_RX_STATUS_DESC_CRC32(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 14, 1, __val) +#define SET_RX_STATUS_DESC_ICV(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 15, 1, __val) +#define SET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 16, 4, __val) +#define SET_RX_STATUS_DESC_SECURITY(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 20, 3, __val) +#define SET_RX_STATUS_DESC_QOS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 23, 1, __val) +#define SET_RX_STATUS_DESC_SHIFT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val) +#define SET_RX_STATUS_DESC_PHY_STATUS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) +#define SET_RX_STATUS_DESC_SWDEC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) +#define SET_RX_STATUS_DESC_LAST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) +#define SET_RX_STATUS_DESC_FIRST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) +#define SET_RX_STATUS_DESC_EOR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) +#define SET_RX_STATUS_DESC_OWN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + +#define GET_RX_STATUS_DESC_PKT_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 0, 14) +#define GET_RX_STATUS_DESC_CRC32(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 14, 1) +#define GET_RX_STATUS_DESC_ICV(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 15, 1) +#define GET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 16, 4) +#define GET_RX_STATUS_DESC_SECURITY(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 20, 3) +#define GET_RX_STATUS_DESC_QOS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 23, 1) +#define GET_RX_STATUS_DESC_SHIFT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 24, 2) +#define GET_RX_STATUS_DESC_PHY_STATUS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 26, 1) +#define GET_RX_STATUS_DESC_SWDEC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 27, 1) +#define GET_RX_STATUS_DESC_LAST_SEG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 28, 1) +#define GET_RX_STATUS_DESC_FIRST_SEG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 29, 1) +#define GET_RX_STATUS_DESC_EOR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 30, 1) +#define GET_RX_STATUS_DESC_OWN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 31, 1) + +/* DWORD 1 */ +#define SET_RX_STATUS_DESC_MACID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) +#define SET_RX_STATUS_DESC_TID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 5, 4, __val) +#define SET_RX_STATUS_DESC_PAGGR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 14, 1, __val) +#define SET_RX_STATUS_DESC_FAGGR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val) +#define SET_RX_STATUS_DESC_A1_FIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 16, 4, __val) +#define SET_RX_STATUS_DESC_A2_FIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 20, 4, __val) +#define SET_RX_STATUS_DESC_PAM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val) +#define SET_RX_STATUS_DESC_PWR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val) +#define SET_RX_STATUS_DESC_MOREDATA(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 26, 1, __val) +#define SET_RX_STATUS_DESC_MOREFRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val) +#define SET_RX_STATUS_DESC_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 28, 2, __val) +#define SET_RX_STATUS_DESC_MC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 30, 1, __val) +#define SET_RX_STATUS_DESC_BC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 31, 1, __val) + +#define GET_RX_STATUS_DEC_MACID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 0, 5) +#define GET_RX_STATUS_DESC_TID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 5, 4) +#define GET_RX_STATUS_DESC_PAGGR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 14, 1) +#define GET_RX_STATUS_DESC_FAGGR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 15, 1) +#define GET_RX_STATUS_DESC_A1_FIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 16, 4) +#define GET_RX_STATUS_DESC_A2_FIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 20, 4) +#define GET_RX_STATUS_DESC_PAM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 24, 1) +#define GET_RX_STATUS_DESC_PWR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 25, 1) +#define GET_RX_STATUS_DESC_MORE_DATA(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 26, 1) +#define GET_RX_STATUS_DESC_MORE_FRAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 27, 1) +#define GET_RX_STATUS_DESC_TYPE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 28, 2) +#define GET_RX_STATUS_DESC_MC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 30, 1) +#define GET_RX_STATUS_DESC_BC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 31, 1) + +/* DWORD 2 */ +#define SET_RX_STATUS_DESC_SEQ(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 0, 12, __val) +#define SET_RX_STATUS_DESC_FRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 12, 4, __val) +#define SET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 16, 8, __val) +#define SET_RX_STATUS_DESC_NEXT_IND(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val) + +#define GET_RX_STATUS_DESC_SEQ(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 8, 0, 12) +#define GET_RX_STATUS_DESC_FRAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 8, 12, 4) +#define GET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 8, 16, 8) +#define GET_RX_STATUS_DESC_NEXT_IND(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 8, 30, 1) + +/* DWORD 3 */ +#define SET_RX_STATUS_DESC_RX_MCS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 0, 6, __val) +#define SET_RX_STATUS_DESC_RX_HT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 6, 1, __val) +#define SET_RX_STATUS_DESC_AMSDU(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 7, 1, __val) +#define SET_RX_STATUS_DESC_SPLCP(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 8, 1, __val) +#define SET_RX_STATUS_DESC_BW(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 9, 1, __val) +#define SET_RX_STATUS_DESC_HTC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 10, 1, __val) +#define SET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 11, 1, __val) +#define SET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 12, 1, __val) +#define SET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 13, 1, __val) +#define SET_RX_STATUS_DESC_HWPC_ERR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 14, 1, __val) +#define SET_RX_STATUS_DESC_HWPC_IND(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 15, 1, __val) +#define SET_RX_STATUS_DESC_IV0(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 16, 16, __val) + +#define GET_RX_STATUS_DESC_RX_MCS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 0, 6) +#define GET_RX_STATUS_DESC_RX_HT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 6, 1) +#define GET_RX_STATUS_DESC_AMSDU(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 7, 1) +#define GET_RX_STATUS_DESC_SPLCP(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 8, 1) +#define GET_RX_STATUS_DESC_BW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 9, 1) +#define GET_RX_STATUS_DESC_HTC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 10, 1) +#define GET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 11, 1) +#define GET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 12, 1) +#define GET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 13, 1) +#define GET_RX_STATUS_DESC_HWPC_ERR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 14, 1) +#define GET_RX_STATUS_DESC_HWPC_IND(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 15, 1) +#define GET_RX_STATUS_DESC_IV0(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 16, 16) + +/* DWORD 4 */ +#define SET_RX_STATUS_DESC_IV1(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 0, 32, __val) +#define GET_RX_STATUS_DESC_IV1(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 16, 0, 32) + +/* DWORD 5 */ +#define SET_RX_STATUS_DESC_TSFL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 0, 32, __val) +#define GET_RX_STATUS_DESC_TSFL(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 20, 0, 32) + +/* DWORD 6 */ +#define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val) + +#define RX_HAL_IS_CCK_RATE(_pdesc)\ + (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE1M || \ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE2M || \ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE5_5M ||\ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE11M) + +enum rf_optype { + RF_OP_BY_SW_3WIRE = 0, + RF_OP_BY_FW, + RF_OP_MAX +}; + +enum ic_inferiority { + IC_INFERIORITY_A = 0, + IC_INFERIORITY_B = 1, +}; + +enum fwcmd_iotype { + /* For DIG DM */ + FW_CMD_DIG_ENABLE = 0, + FW_CMD_DIG_DISABLE = 1, + FW_CMD_DIG_HALT = 2, + FW_CMD_DIG_RESUME = 3, + /* For High Power DM */ + FW_CMD_HIGH_PWR_ENABLE = 4, + FW_CMD_HIGH_PWR_DISABLE = 5, + /* For Rate adaptive DM */ + FW_CMD_RA_RESET = 6, + FW_CMD_RA_ACTIVE = 7, + FW_CMD_RA_REFRESH_N = 8, + FW_CMD_RA_REFRESH_BG = 9, + FW_CMD_RA_INIT = 10, + /* For FW supported IQK */ + FW_CMD_IQK_INIT = 11, + /* Tx power tracking switch, + * MP driver only */ + FW_CMD_TXPWR_TRACK_ENABLE = 12, + /* Tx power tracking switch, + * MP driver only */ + FW_CMD_TXPWR_TRACK_DISABLE = 13, + /* Tx power tracking with thermal + * indication, for Normal driver */ + FW_CMD_TXPWR_TRACK_THERMAL = 14, + FW_CMD_PAUSE_DM_BY_SCAN = 15, + FW_CMD_RESUME_DM_BY_SCAN = 16, + FW_CMD_RA_REFRESH_N_COMB = 17, + FW_CMD_RA_REFRESH_BG_COMB = 18, + FW_CMD_ANTENNA_SW_ENABLE = 19, + FW_CMD_ANTENNA_SW_DISABLE = 20, + /* Tx Status report for CCX from FW */ + FW_CMD_TX_FEEDBACK_CCX_ENABLE = 21, + /* Indifate firmware that driver + * enters LPS, For PS-Poll issue */ + FW_CMD_LPS_ENTER = 22, + /* Indicate firmware that driver + * leave LPS*/ + FW_CMD_LPS_LEAVE = 23, + /* Set DIG mode to signal strength */ + FW_CMD_DIG_MODE_SS = 24, + /* Set DIG mode to false alarm. */ + FW_CMD_DIG_MODE_FA = 25, + FW_CMD_ADD_A2_ENTRY = 26, + FW_CMD_CTRL_DM_BY_DRIVER = 27, + FW_CMD_CTRL_DM_BY_DRIVER_NEW = 28, + FW_CMD_PAPE_CONTROL = 29, + FW_CMD_IQK_ENABLE = 30, +}; + +/* + * Driver info contain PHY status + * and other variabel size info + * PHY Status content as below + */ +struct rx_fwinfo { + /* DWORD 0 */ + u8 gain_trsw[4]; + /* DWORD 1 */ + u8 pwdb_all; + u8 cfosho[4]; + /* DWORD 2 */ + u8 cfotail[4]; + /* DWORD 3 */ + s8 rxevm[2]; + s8 rxsnr[4]; + /* DWORD 4 */ + u8 pdsnr[2]; + /* DWORD 5 */ + u8 csi_current[2]; + u8 csi_target[2]; + /* DWORD 6 */ + u8 sigevm; + u8 max_ex_pwr; + u8 ex_intf_flag:1; + u8 sgi_en:1; + u8 rxsc:2; + u8 reserve:4; +}; + +struct phy_sts_cck_8192s_t { + u8 adc_pwdb_x[4]; + u8 sq_rpt; + u8 cck_agc_rpt; +}; + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c new file mode 100644 index 000000000000..da86db86fa4a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c @@ -0,0 +1,733 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#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 */ + 0x5ea44f, /* 2 REALTEK_92SE */ + 0xa630, /* 3 BROAD */ + 0xa44f, /* 4 RAL */ + 0xa630, /* 5 ATH */ + 0xa630, /* 6 CISCO */ + 0xa42b, /* 7 MARV */ +}; + +static const u32 edca_setting_dl_gmode[PEER_MAX] = { + 0x4322, /* 0 UNKNOWN */ + 0xa44f, /* 1 REALTEK_90 */ + 0x5ea44f, /* 2 REALTEK_92SE */ + 0xa42b, /* 3 BROAD */ + 0x5e4322, /* 4 RAL */ + 0x4322, /* 5 ATH */ + 0xa430, /* 6 CISCO */ + 0x5ea44f, /* 7 MARV */ +}; + +static const u32 edca_setting_ul[PEER_MAX] = { + 0x5e4322, /* 0 UNKNOWN */ + 0xa44f, /* 1 REALTEK_90 */ + 0x5ea44f, /* 2 REALTEK_92SE */ + 0x5ea322, /* 3 BROAD */ + 0x5ea422, /* 4 RAL */ + 0x5ea322, /* 5 ATH */ + 0x3ea44f, /* 6 CISCO */ + 0x5ea44f, /* 7 MARV */ +}; + +static void _rtl92s_dm_check_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + static u64 last_txok_cnt; + static u64 last_rxok_cnt; + u64 cur_txok_cnt = 0; + u64 cur_rxok_cnt = 0; + + u32 edca_be_ul = edca_setting_ul[mac->vendor]; + u32 edca_be_dl = edca_setting_dl[mac->vendor]; + u32 edca_gmode = edca_setting_dl_gmode[mac->vendor]; + + if (mac->link_state != MAC80211_LINKED) { + rtlpriv->dm.current_turbo_edca = false; + goto dm_checkedcaturbo_exit; + } + + if ((!rtlpriv->dm.is_any_nonbepkts) && + (!rtlpriv->dm.disable_framebursting)) { + cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; + cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; + + if (rtlpriv->phy.rf_type == RF_1T2R) { + if (cur_txok_cnt > 4 * cur_rxok_cnt) { + /* Uplink TP is present. */ + if (rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + rtl_write_dword(rtlpriv, EDCAPARA_BE, + edca_be_ul); + rtlpriv->dm.is_cur_rdlstate = false; + } + } else {/* Balance TP is present. */ + if (!rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + if (mac->mode == WIRELESS_MODE_G || + mac->mode == WIRELESS_MODE_B) + rtl_write_dword(rtlpriv, + EDCAPARA_BE, + edca_gmode); + else + rtl_write_dword(rtlpriv, + EDCAPARA_BE, + edca_be_dl); + rtlpriv->dm.is_cur_rdlstate = true; + } + } + rtlpriv->dm.current_turbo_edca = true; + } else { + if (cur_rxok_cnt > 4 * cur_txok_cnt) { + if (!rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + if (mac->mode == WIRELESS_MODE_G || + mac->mode == WIRELESS_MODE_B) + rtl_write_dword(rtlpriv, + EDCAPARA_BE, + edca_gmode); + else + rtl_write_dword(rtlpriv, + EDCAPARA_BE, + edca_be_dl); + rtlpriv->dm.is_cur_rdlstate = true; + } + } else { + if (rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + rtl_write_dword(rtlpriv, EDCAPARA_BE, + edca_be_ul); + rtlpriv->dm.is_cur_rdlstate = false; + } + } + rtlpriv->dm.current_turbo_edca = true; + } + } else { + if (rtlpriv->dm.current_turbo_edca) { + u8 tmp = AC0_BE; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, + (u8 *)(&tmp)); + rtlpriv->dm.current_turbo_edca = false; + } + } + +dm_checkedcaturbo_exit: + rtlpriv->dm.is_any_nonbepkts = false; + last_txok_cnt = rtlpriv->stats.txbytesunicast; + last_rxok_cnt = rtlpriv->stats.rxbytesunicast; +} + +static void _rtl92s_dm_txpowertracking_callback_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 thermalvalue = 0; + + rtlpriv->dm.txpower_trackinginit = true; + + thermalvalue = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0x1f); + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x " + "eeprom_thermalmeter 0x%x\n", thermalvalue, + rtlpriv->dm.thermalvalue, rtlefuse->eeprom_thermalmeter)); + + if (thermalvalue) { + rtlpriv->dm.thermalvalue = thermalvalue; + rtl92s_phy_set_fw_cmd(hw, FW_CMD_TXPWR_TRACK_THERMAL); + } + + rtlpriv->dm.txpowercount = 0; +} + +static void _rtl92s_dm_check_txpowertracking_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + static u8 tm_trigger; + u8 tx_power_checkcnt = 5; + + /* 2T2R TP issue */ + if (rtlphy->rf_type == RF_2T2R) + return; + + if (!rtlpriv->dm.txpower_tracking) + return; + + if (rtlpriv->dm.txpowercount <= tx_power_checkcnt) { + rtlpriv->dm.txpowercount++; + return; + } + + if (!tm_trigger) { + rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, + RFREG_OFFSET_MASK, 0x60); + tm_trigger = 1; + } else { + _rtl92s_dm_txpowertracking_callback_thermalmeter(hw); + tm_trigger = 0; + } +} + +static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rate_adaptive *ra = &(rtlpriv->ra); + + u32 low_rssi_thresh = 0; + u32 middle_rssi_thresh = 0; + u32 high_rssi_thresh = 0; + u8 rssi_level; + struct ieee80211_sta *sta = NULL; + + if (is_hal_stop(rtlhal)) + return; + + if (!rtlpriv->dm.useramask) + return; + + if (!rtlpriv->dm.inform_fw_driverctrldm) { + rtl92s_phy_set_fw_cmd(hw, FW_CMD_CTRL_DM_BY_DRIVER); + rtlpriv->dm.inform_fw_driverctrldm = true; + } + + rcu_read_lock(); + if (mac->opmode == NL80211_IFTYPE_STATION) + sta = get_sta(hw, mac->vif, mac->bssid); + if ((mac->link_state == MAC80211_LINKED) && + (mac->opmode == NL80211_IFTYPE_STATION)) { + switch (ra->pre_ratr_state) { + case DM_RATR_STA_HIGH: + high_rssi_thresh = 40; + middle_rssi_thresh = 30; + low_rssi_thresh = 20; + break; + case DM_RATR_STA_MIDDLE: + high_rssi_thresh = 44; + middle_rssi_thresh = 30; + low_rssi_thresh = 20; + break; + case DM_RATR_STA_LOW: + high_rssi_thresh = 44; + middle_rssi_thresh = 34; + low_rssi_thresh = 20; + break; + case DM_RATR_STA_ULTRALOW: + high_rssi_thresh = 44; + middle_rssi_thresh = 34; + low_rssi_thresh = 24; + break; + default: + high_rssi_thresh = 44; + middle_rssi_thresh = 34; + low_rssi_thresh = 24; + break; + } + + if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)high_rssi_thresh) { + ra->ratr_state = DM_RATR_STA_HIGH; + rssi_level = 1; + } else if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)middle_rssi_thresh) { + ra->ratr_state = DM_RATR_STA_LOW; + rssi_level = 3; + } else if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)low_rssi_thresh) { + ra->ratr_state = DM_RATR_STA_LOW; + rssi_level = 5; + } else { + ra->ratr_state = DM_RATR_STA_ULTRALOW; + rssi_level = 6; + } + + if (ra->pre_ratr_state != ra->ratr_state) { + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, ("RSSI = %ld " + "RSSI_LEVEL = %d PreState = %d, CurState = %d\n", + rtlpriv->dm.undecorated_smoothed_pwdb, + ra->ratr_state, + ra->pre_ratr_state, ra->ratr_state)); + + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, + ra->ratr_state); + ra->pre_ratr_state = ra->ratr_state; + } + } + rcu_read_unlock(); +} + +static void _rtl92s_dm_switch_baseband_mrc(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + bool current_mrc; + bool enable_mrc = true; + long tmpentry_maxpwdb = 0; + u8 rssi_a = 0; + u8 rssi_b = 0; + + if (is_hal_stop(rtlhal)) + return; + + if ((rtlphy->rf_type == RF_1T1R) || (rtlphy->rf_type == RF_2T2R)) + return; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MRC, (u8 *)(¤t_mrc)); + + if (mac->link_state >= MAC80211_LINKED) { + if (rtlpriv->dm.undecorated_smoothed_pwdb > tmpentry_maxpwdb) { + rssi_a = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_A]; + rssi_b = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_B]; + } + } + + /* MRC settings would NOT affect TP on Wireless B mode. */ + if (mac->mode != WIRELESS_MODE_B) { + if ((rssi_a == 0) && (rssi_b == 0)) { + enable_mrc = true; + } else if (rssi_b > 30) { + /* Turn on B-Path */ + enable_mrc = true; + } else if (rssi_b < 5) { + /* Turn off B-path */ + enable_mrc = false; + /* Take care of RSSI differentiation. */ + } else if (rssi_a > 15 && (rssi_a >= rssi_b)) { + if ((rssi_a - rssi_b) > 15) + /* Turn off B-path */ + enable_mrc = false; + else if ((rssi_a - rssi_b) < 10) + /* Turn on B-Path */ + enable_mrc = true; + else + enable_mrc = current_mrc; + } else { + /* Turn on B-Path */ + enable_mrc = true; + } + } + + /* Update MRC settings if needed. */ + if (enable_mrc != current_mrc) + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC, + (u8 *)&enable_mrc); + +} + +void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.current_turbo_edca = false; + rtlpriv->dm.is_any_nonbepkts = false; + rtlpriv->dm.is_cur_rdlstate = false; +} + +static void _rtl92s_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rate_adaptive *ra = &(rtlpriv->ra); + + ra->ratr_state = DM_RATR_STA_MAX; + ra->pre_ratr_state = DM_RATR_STA_MAX; + + if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) + rtlpriv->dm.useramask = true; + else + rtlpriv->dm.useramask = false; + + rtlpriv->dm.useramask = false; + rtlpriv->dm.inform_fw_driverctrldm = false; +} + +static void _rtl92s_dm_init_txpowertracking_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.txpower_tracking = true; + rtlpriv->dm.txpowercount = 0; + rtlpriv->dm.txpower_trackinginit = false; +} + +static void _rtl92s_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + u32 ret_value; + + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD); + falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16); + + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD); + falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff); + falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD); + falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff); + + falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail + + falsealm_cnt->cnt_rate_illegal + falsealm_cnt->cnt_crc8_fail + + falsealm_cnt->cnt_mcs_fail; + + /* read CCK false alarm */ + ret_value = rtl_get_bbreg(hw, 0xc64, MASKDWORD); + falsealm_cnt->cnt_cck_fail = (ret_value & 0xffff); + falsealm_cnt->cnt_all = falsealm_cnt->cnt_ofdm_fail + + falsealm_cnt->cnt_cck_fail; +} + +static void rtl92s_backoff_enable_flag(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + 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; + 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; + else + digtable.backoff_val += 6; + } +} + +static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + 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 (rtlpriv->psc.rfpwr_state != ERFON) + return; + + if (digtable.backoff_enable_flag == true) + 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; + else + 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; + + if (falsealm_cnt->cnt_all > 16000) + digtable.cur_igvalue = + digtable.rx_gain_range_max; + /* connected -> connected or disconnected -> disconnected */ + } else { + /* Firmware control DIG, do nothing in driver dm */ + return; + } + /* disconnected -> connected or connected -> + * disconnected or beforeconnect->(dis)connected */ + } else { + /* Enable FW DIG */ + 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; + return; + } + + /* Forced writing to prevent from fw-dig overwriting. */ + if (digtable.pre_igvalue != rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, + MASKBYTE0)) + force_write = 1; + + 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; + + /* 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; + initialized = 1; + force_write = 0; + } +} + +static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->mac80211.act_scanning) + return; + + /* 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; + else + digtable.cur_sta_connectstate = DIG_STA_DISCONNECT; + + 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 == + DIG_TWO_PORT_ALGO_FALSE_ALARM) { + digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; + rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_MODE_SS); + } + } + + _rtl92s_dm_false_alarm_counter_statistics(hw); + _rtl92s_dm_initial_gain_sta_beforeconnect(hw); + + 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); + + /* 2T2R TP issue */ + if (rtlphy->rf_type == RF_2T2R) + return; + + if (!rtlpriv->dm.dm_initialgain_enable) + return; + + if (digtable.dig_enable_flag == false) + return; + + _rtl92s_dm_ctrl_initgain_bytwoport(hw); +} + +static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + long txpwr_threshold_lv1, txpwr_threshold_lv2; + + /* 2T2R TP issue */ + if (rtlphy->rf_type == RF_2T2R) + return; + + if (!rtlpriv->dm.dynamic_txpower_enable || + rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; + return; + } + + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + ("Not connected to any\n")); + + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; + + rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL; + return; + } + + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("AP Client PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("STA Default Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("AP Ext Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } + + txpwr_threshold_lv2 = TX_POWER_NEAR_FIELD_THRESH_LVL2; + txpwr_threshold_lv1 = TX_POWER_NEAR_FIELD_THRESH_LVL1; + + if (rtl_get_bbreg(hw, 0xc90, MASKBYTE0) == 1) + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; + else if (undecorated_smoothed_pwdb >= txpwr_threshold_lv2) + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL2; + else if ((undecorated_smoothed_pwdb < (txpwr_threshold_lv2 - 3)) && + (undecorated_smoothed_pwdb >= txpwr_threshold_lv1)) + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL1; + else if (undecorated_smoothed_pwdb < (txpwr_threshold_lv1 - 3)) + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; + + if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) + rtl92s_phy_set_txpower(hw, rtlphy->current_channel); + + rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} + +static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* Disable DIG scheme now.*/ + 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; + else + 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; + + /* 2007/10/04 MH Define init gain threshol. */ + 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.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.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.rx_gain_range_min = DM_DIG_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) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if ((hal_get_firmwareversion(rtlpriv) >= 60) && + (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)) + rtlpriv->dm.dynamic_txpower_enable = true; + else + rtlpriv->dm.dynamic_txpower_enable = false; + + rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL; + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; +} + +void rtl92s_dm_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; + rtlpriv->dm.undecorated_smoothed_pwdb = -1; + + _rtl92s_dm_init_dynamic_txpower(hw); + rtl92s_dm_init_edca_turbo(hw); + _rtl92s_dm_init_rate_adaptive_mask(hw); + _rtl92s_dm_init_txpowertracking_thermalmeter(hw); + _rtl92s_dm_init_dig(hw); + + rtl_write_dword(rtlpriv, WFM5, FW_CCA_CHK_ENABLE); +} + +void rtl92s_dm_watchdog(struct ieee80211_hw *hw) +{ + _rtl92s_dm_check_edca_turbo(hw); + _rtl92s_dm_check_txpowertracking_thermalmeter(hw); + _rtl92s_dm_ctrl_initgain_byrssi(hw); + _rtl92s_dm_dynamic_txpower(hw); + _rtl92s_dm_refresh_rateadaptive_mask(hw); + _rtl92s_dm_switch_baseband_mrc(hw); +} + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h new file mode 100644 index 000000000000..9051a556acc4 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h @@ -0,0 +1,164 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#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, + DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM = 2, + DIG_ALGO_BY_TOW_PORT = 3, + DIG_ALGO_MAX +}; + +enum dm_dig_two_port_alg { + DIG_TWO_PORT_ALGO_RSSI = 0, + DIG_TWO_PORT_ALGO_FALSE_ALARM = 1, +}; + +enum dm_dig_dbg { + DM_DBG_OFF = 0, + DM_DBG_ON = 1, + DM_DBG_MAX +}; + +enum dm_dig_sta { + DM_STA_DIG_OFF = 0, + DM_STA_DIG_ON, + DM_STA_DIG_MAX +}; + +enum dm_dig_connect { + DIG_STA_DISCONNECT = 0, + DIG_STA_CONNECT = 1, + DIG_STA_BEFORE_CONNECT = 2, + DIG_AP_DISCONNECT = 3, + DIG_AP_CONNECT = 4, + DIG_AP_ADD_STATION = 5, + DIG_CONNECT_MAX +}; + +enum dm_dig_ext_port_alg { + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_ratr_sta { + DM_RATR_STA_HIGH = 0, + DM_RATR_STA_MIDDLEHIGH = 1, + DM_RATR_STA_MIDDLE = 2, + DM_RATR_STA_MIDDLELOW = 3, + DM_RATR_STA_LOW = 4, + DM_RATR_STA_ULTRALOW = 5, + DM_RATR_STA_MAX +}; + +#define DM_TYPE_BYFW 0 +#define DM_TYPE_BYDRIVER 1 + +#define TX_HIGH_PWR_LEVEL_NORMAL 0 +#define TX_HIGH_PWR_LEVEL_LEVEL1 1 +#define TX_HIGH_PWR_LEVEL_LEVEL2 2 + +#define HAL_DM_DIG_DISABLE BIT(0) /* Disable Dig */ +#define HAL_DM_HIPWR_DISABLE BIT(1) /* Disable High Power */ + +#define TX_HIGHPWR_LEVEL_NORMAL 0 +#define TX_HIGHPWR_LEVEL_NORMAL1 1 +#define TX_HIGHPWR_LEVEL_NORMAL2 2 + +#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 + +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 +#define DM_FALSEALARM_THRESH_LOW 40 +#define DM_FALSEALARM_THRESH_HIGH 1000 +#define DM_DIG_HIGH_PWR_THRESH_HIGH 75 +#define DM_DIG_HIGH_PWR_THRESH_LOW 70 +#define DM_DIG_BACKOFF 12 +#define DM_DIG_MAX 0x3e +#define DM_DIG_MIN 0x1c +#define DM_DIG_MIN_Netcore 0x12 +#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); + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c new file mode 100644 index 000000000000..3b5af0113d7f --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c @@ -0,0 +1,654 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "fw.h" + +static void _rtl92s_fw_set_rqpn(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_dword(rtlpriv, RQPN, 0xffffffff); + rtl_write_dword(rtlpriv, RQPN + 4, 0xffffffff); + rtl_write_byte(rtlpriv, RQPN + 8, 0xff); + rtl_write_byte(rtlpriv, RQPN + 0xB, 0x80); +} + +static bool _rtl92s_firmware_enable_cpu(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 ichecktime = 200; + u16 tmpu2b; + u8 tmpu1b, cpustatus = 0; + + _rtl92s_fw_set_rqpn(hw); + + /* Enable CPU. */ + tmpu1b = rtl_read_byte(rtlpriv, SYS_CLKR); + /* AFE source */ + rtl_write_byte(rtlpriv, SYS_CLKR, (tmpu1b | SYS_CPU_CLKSEL)); + + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | FEN_CPUEN)); + + /* Polling IMEM Ready after CPU has refilled. */ + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & IMEM_RDY) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("IMEM Ready after CPU has refilled.\n")); + break; + } + + udelay(100); + } while (ichecktime--); + + if (!(cpustatus & IMEM_RDY)) + return false; + + return true; +} + +static enum fw_status _rtl92s_firmware_get_nextstatus( + enum fw_status fw_currentstatus) +{ + enum fw_status next_fwstatus = 0; + + switch (fw_currentstatus) { + case FW_STATUS_INIT: + next_fwstatus = FW_STATUS_LOAD_IMEM; + break; + case FW_STATUS_LOAD_IMEM: + next_fwstatus = FW_STATUS_LOAD_EMEM; + break; + case FW_STATUS_LOAD_EMEM: + next_fwstatus = FW_STATUS_LOAD_DMEM; + break; + case FW_STATUS_LOAD_DMEM: + next_fwstatus = FW_STATUS_READY; + break; + default: + break; + } + + return next_fwstatus; +} + +static u8 _rtl92s_firmware_header_map_rftype(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + switch (rtlphy->rf_type) { + case RF_1T1R: + return 0x11; + break; + case RF_1T2R: + return 0x12; + break; + case RF_2T2R: + return 0x22; + break; + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("Unknown RF type(%x)\n", + rtlphy->rf_type)); + break; + } + return 0x22; +} + +static void _rtl92s_firmwareheader_priveupdate(struct ieee80211_hw *hw, + struct fw_priv *pfw_priv) +{ + /* Update RF types for RATR settings. */ + pfw_priv->rf_config = _rtl92s_firmware_header_map_rftype(hw); +} + + + +static bool _rtl92s_cmd_send_packet(struct ieee80211_hw *hw, + struct sk_buff *skb, u8 last) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + unsigned long flags; + u8 idx = 0; + + ring = &rtlpci->tx_ring[TXCMD_QUEUE]; + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + + idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; + pdesc = &ring->desc[idx]; + rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb); + __skb_queue_tail(&ring->queue, skb); + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + return true; +} + +static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw, + u8 *code_virtual_address, u32 buffer_len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct sk_buff *skb; + struct rtl_tcb_desc *tcb_desc; + unsigned char *seg_ptr; + u16 frag_threshold = MAX_FIRMWARE_CODE_SIZE; + u16 frag_length, frag_offset = 0; + u16 extra_descoffset = 0; + u8 last_inipkt = 0; + + _rtl92s_fw_set_rqpn(hw); + + if (buffer_len >= MAX_FIRMWARE_CODE_SIZE) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Size over FIRMWARE_CODE_SIZE!\n")); + + return false; + } + + extra_descoffset = 0; + + do { + if ((buffer_len - frag_offset) > frag_threshold) { + frag_length = frag_threshold + extra_descoffset; + } else { + frag_length = (u16)(buffer_len - frag_offset + + extra_descoffset); + last_inipkt = 1; + } + + /* Allocate skb buffer to contain firmware */ + /* info and tx descriptor info. */ + skb = dev_alloc_skb(frag_length); + skb_reserve(skb, extra_descoffset); + seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length - + extra_descoffset)); + memcpy(seg_ptr, code_virtual_address + frag_offset, + (u32)(frag_length - extra_descoffset)); + + tcb_desc = (struct rtl_tcb_desc *)(skb->cb); + tcb_desc->queue_index = TXCMD_QUEUE; + tcb_desc->cmd_or_init = DESC_PACKET_TYPE_INIT; + tcb_desc->last_inipkt = last_inipkt; + + _rtl92s_cmd_send_packet(hw, skb, last_inipkt); + + frag_offset += (frag_length - extra_descoffset); + + } while (frag_offset < buffer_len); + + rtl_write_byte(rtlpriv, TP_POLL, TPPOLL_CQ); + + return true ; +} + +static bool _rtl92s_firmware_checkready(struct ieee80211_hw *hw, + u8 loadfw_status) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rt_firmware *firmware = (struct rt_firmware *)rtlhal->pfirmware; + u32 tmpu4b; + u8 cpustatus = 0; + short pollingcnt = 1000; + bool rtstatus = true; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("LoadStaus(%d)\n", + loadfw_status)); + + firmware->fwstatus = (enum fw_status)loadfw_status; + + switch (loadfw_status) { + case FW_STATUS_LOAD_IMEM: + /* Polling IMEM code done. */ + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & IMEM_CODE_DONE) + break; + udelay(5); + } while (pollingcnt--); + + if (!(cpustatus & IMEM_CHK_RPT) || (pollingcnt <= 0)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("FW_STATUS_LOAD_IMEM" + " FAIL CPU, Status=%x\r\n", cpustatus)); + goto status_check_fail; + } + break; + + case FW_STATUS_LOAD_EMEM: + /* Check Put Code OK and Turn On CPU */ + /* Polling EMEM code done. */ + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & EMEM_CODE_DONE) + break; + udelay(5); + } while (pollingcnt--); + + if (!(cpustatus & EMEM_CHK_RPT) || (pollingcnt <= 0)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("FW_STATUS_LOAD_EMEM" + " FAIL CPU, Status=%x\r\n", cpustatus)); + goto status_check_fail; + } + + /* Turn On CPU */ + rtstatus = _rtl92s_firmware_enable_cpu(hw); + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Enable CPU fail!\n")); + goto status_check_fail; + } + break; + + case FW_STATUS_LOAD_DMEM: + /* Polling DMEM code done */ + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & DMEM_CODE_DONE) + break; + udelay(5); + } while (pollingcnt--); + + if (!(cpustatus & DMEM_CODE_DONE) || (pollingcnt <= 0)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Polling DMEM code done" + " fail ! cpustatus(%#x)\n", cpustatus)); + goto status_check_fail; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("DMEM code download success," + " cpustatus(%#x)\n", cpustatus)); + + /* Prevent Delay too much and being scheduled out */ + /* Polling Load Firmware ready */ + pollingcnt = 2000; + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & FWRDY) + break; + udelay(40); + } while (pollingcnt--); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Polling Load Firmware ready," + " cpustatus(%x)\n", cpustatus)); + + if (((cpustatus & LOAD_FW_READY) != LOAD_FW_READY) || + (pollingcnt <= 0)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Polling Load Firmware" + " ready fail ! cpustatus(%x)\n", cpustatus)); + goto status_check_fail; + } + + /* If right here, we can set TCR/RCR to desired value */ + /* and config MAC lookback mode to normal mode */ + tmpu4b = rtl_read_dword(rtlpriv, TCR); + rtl_write_dword(rtlpriv, TCR, (tmpu4b & (~TCR_ICV))); + + tmpu4b = rtl_read_dword(rtlpriv, RCR); + rtl_write_dword(rtlpriv, RCR, (tmpu4b | RCR_APPFCS | + RCR_APP_ICV | RCR_APP_MIC)); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Current RCR settings(%#x)\n", tmpu4b)); + + /* Set to normal mode. */ + rtl_write_byte(rtlpriv, LBKMD_SEL, LBK_NORMAL); + break; + + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("Unknown status check!\n")); + rtstatus = false; + break; + } + +status_check_fail: + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("loadfw_status(%d), " + "rtstatus(%x)\n", loadfw_status, rtstatus)); + return rtstatus; +} + +int rtl92s_download_fw(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rt_firmware *firmware = NULL; + struct fw_hdr *pfwheader; + struct fw_priv *pfw_priv = NULL; + u8 *puc_mappedfile = NULL; + u32 ul_filelength = 0; + u32 file_length = 0; + u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE; + u8 fwstatus = FW_STATUS_INIT; + bool rtstatus = true; + + if (!rtlhal->pfirmware) + return 1; + + firmware = (struct rt_firmware *)rtlhal->pfirmware; + firmware->fwstatus = FW_STATUS_INIT; + + puc_mappedfile = firmware->sz_fw_tmpbuffer; + file_length = firmware->sz_fw_tmpbufferlen; + + /* 1. Retrieve FW header. */ + firmware->pfwheader = (struct fw_hdr *) puc_mappedfile; + pfwheader = firmware->pfwheader; + firmware->firmwareversion = byte(pfwheader->version, 0); + firmware->pfwheader->fwpriv.hci_sel = 1;/* pcie */ + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("signature:%x, version:" + "%x, size:%x," + "imemsize:%x, sram size:%x\n", pfwheader->signature, + pfwheader->version, pfwheader->dmem_size, + pfwheader->img_imem_size, pfwheader->img_sram_size)); + + /* 2. Retrieve IMEM image. */ + if ((pfwheader->img_imem_size == 0) || (pfwheader->img_imem_size > + sizeof(firmware->fw_imem))) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("memory for data image is less than IMEM required\n")); + goto fail; + } else { + puc_mappedfile += fwhdr_size; + + memcpy(firmware->fw_imem, puc_mappedfile, + pfwheader->img_imem_size); + firmware->fw_imem_len = pfwheader->img_imem_size; + } + + /* 3. Retriecve EMEM image. */ + if (pfwheader->img_sram_size > sizeof(firmware->fw_emem)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("memory for data image is less than EMEM required\n")); + goto fail; + } else { + puc_mappedfile += firmware->fw_imem_len; + + memcpy(firmware->fw_emem, puc_mappedfile, + pfwheader->img_sram_size); + firmware->fw_emem_len = pfwheader->img_sram_size; + } + + /* 4. download fw now */ + fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus); + while (fwstatus != FW_STATUS_READY) { + /* Image buffer redirection. */ + switch (fwstatus) { + case FW_STATUS_LOAD_IMEM: + puc_mappedfile = firmware->fw_imem; + ul_filelength = firmware->fw_imem_len; + break; + case FW_STATUS_LOAD_EMEM: + puc_mappedfile = firmware->fw_emem; + ul_filelength = firmware->fw_emem_len; + break; + case FW_STATUS_LOAD_DMEM: + /* Partial update the content of header private. */ + pfwheader = firmware->pfwheader; + pfw_priv = &pfwheader->fwpriv; + _rtl92s_firmwareheader_priveupdate(hw, pfw_priv); + puc_mappedfile = (u8 *)(firmware->pfwheader) + + RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; + ul_filelength = fwhdr_size - + RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Unexpected Download step!!\n")); + goto fail; + break; + } + + /* <2> Download image file */ + rtstatus = _rtl92s_firmware_downloadcode(hw, puc_mappedfile, + ul_filelength); + + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("fail!\n")); + goto fail; + } + + /* <3> Check whether load FW process is ready */ + rtstatus = _rtl92s_firmware_checkready(hw, fwstatus); + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("fail!\n")); + goto fail; + } + + fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus); + } + + return rtstatus; +fail: + return 0; +} + +static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen, + u32 cmd_num, u32 *pelement_id, u32 *pcmd_len, + u8 **pcmb_buffer, u8 *cmd_start_seq) +{ + u32 totallen = 0, len = 0, tx_desclen = 0; + u32 pre_continueoffset = 0; + u8 *ph2c_buffer; + u8 i = 0; + + do { + /* 8 - Byte aligment */ + len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8); + + /* Buffer length is not enough */ + if (h2cbufferlen < totallen + len + tx_desclen) + break; + + /* Clear content */ + ph2c_buffer = (u8 *)skb_put(skb, (u32)len); + memset((ph2c_buffer + totallen + tx_desclen), 0, len); + + /* CMD len */ + SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), + 0, 16, pcmd_len[i]); + + /* CMD ID */ + SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), + 16, 8, pelement_id[i]); + + /* CMD Sequence */ + *cmd_start_seq = *cmd_start_seq % 0x80; + SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), + 24, 7, *cmd_start_seq); + ++*cmd_start_seq; + + /* Copy memory */ + memcpy((ph2c_buffer + totallen + tx_desclen + + H2C_TX_CMD_HDR_LEN), pcmb_buffer[i], pcmd_len[i]); + + /* CMD continue */ + /* set the continue in prevoius cmd. */ + if (i < cmd_num - 1) + SET_BITS_TO_LE_4BYTE((ph2c_buffer + pre_continueoffset), + 31, 1, 1); + + pre_continueoffset = totallen; + + totallen += len; + } while (++i < cmd_num); + + return totallen; +} + +static u32 _rtl92s_get_h2c_cmdlen(u32 h2cbufferlen, u32 cmd_num, u32 *pcmd_len) +{ + u32 totallen = 0, len = 0, tx_desclen = 0; + u8 i = 0; + + do { + /* 8 - Byte aligment */ + len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8); + + /* Buffer length is not enough */ + if (h2cbufferlen < totallen + len + tx_desclen) + break; + + totallen += len; + } while (++i < cmd_num); + + return totallen + tx_desclen; +} + +static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd, + u8 *pcmd_buffer) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_tcb_desc *cb_desc; + struct sk_buff *skb; + u32 element_id = 0; + u32 cmd_len = 0; + u32 len; + + switch (h2c_cmd) { + case FW_H2C_SETPWRMODE: + element_id = H2C_SETPWRMODE_CMD ; + cmd_len = sizeof(struct h2c_set_pwrmode_parm); + break; + case FW_H2C_JOINBSSRPT: + element_id = H2C_JOINBSSRPT_CMD; + cmd_len = sizeof(struct h2c_joinbss_rpt_parm); + break; + case FW_H2C_WOWLAN_UPDATE_GTK: + element_id = H2C_WOWLAN_UPDATE_GTK_CMD; + cmd_len = sizeof(struct h2c_wpa_two_way_parm); + break; + case FW_H2C_WOWLAN_UPDATE_IV: + element_id = H2C_WOWLAN_UPDATE_IV_CMD; + cmd_len = sizeof(unsigned long long); + break; + case FW_H2C_WOWLAN_OFFLOAD: + element_id = H2C_WOWLAN_FW_OFFLOAD; + cmd_len = sizeof(u8); + break; + default: + break; + } + + len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len); + skb = dev_alloc_skb(len); + cb_desc = (struct rtl_tcb_desc *)(skb->cb); + cb_desc->queue_index = TXCMD_QUEUE; + cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL; + cb_desc->last_inipkt = false; + + _rtl92s_fill_h2c_cmd(skb, MAX_TRANSMIT_BUFFER_SIZE, 1, &element_id, + &cmd_len, &pcmd_buffer, &rtlhal->h2c_txcmd_seq); + _rtl92s_cmd_send_packet(hw, skb, false); + rtlpriv->cfg->ops->tx_polling(hw, TXCMD_QUEUE); + + return true; +} + +void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 Mode) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct h2c_set_pwrmode_parm pwrmode; + u16 max_wakeup_period = 0; + + pwrmode.mode = Mode; + pwrmode.flag_low_traffic_en = 0; + pwrmode.flag_lpnav_en = 0; + pwrmode.flag_rf_low_snr_en = 0; + pwrmode.flag_dps_en = 0; + pwrmode.bcn_rx_en = 0; + pwrmode.bcn_to = 0; + SET_BITS_TO_LE_2BYTE((u8 *)(&pwrmode) + 8, 0, 16, + mac->vif->bss_conf.beacon_int); + pwrmode.app_itv = 0; + pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl; + pwrmode.smart_ps = 1; + pwrmode.bcn_pass_period = 10; + + /* Set beacon pass count */ + if (pwrmode.mode == FW_PS_MIN_MODE) + max_wakeup_period = mac->vif->bss_conf.beacon_int; + else if (pwrmode.mode == FW_PS_MAX_MODE) + max_wakeup_period = mac->vif->bss_conf.beacon_int * + mac->vif->bss_conf.dtim_period; + + if (max_wakeup_period >= 500) + pwrmode.bcn_pass_cnt = 1; + else if ((max_wakeup_period >= 300) && (max_wakeup_period < 500)) + pwrmode.bcn_pass_cnt = 2; + else if ((max_wakeup_period >= 200) && (max_wakeup_period < 300)) + pwrmode.bcn_pass_cnt = 3; + else if ((max_wakeup_period >= 20) && (max_wakeup_period < 200)) + pwrmode.bcn_pass_cnt = 5; + else + pwrmode.bcn_pass_cnt = 1; + + _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_SETPWRMODE, (u8 *)&pwrmode); + +} + +void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, + u8 mstatus, u8 ps_qosinfo) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct h2c_joinbss_rpt_parm joinbss_rpt; + + joinbss_rpt.opmode = mstatus; + joinbss_rpt.ps_qos_info = ps_qosinfo; + joinbss_rpt.bssid[0] = mac->bssid[0]; + joinbss_rpt.bssid[1] = mac->bssid[1]; + joinbss_rpt.bssid[2] = mac->bssid[2]; + joinbss_rpt.bssid[3] = mac->bssid[3]; + joinbss_rpt.bssid[4] = mac->bssid[4]; + joinbss_rpt.bssid[5] = mac->bssid[5]; + SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 8, 0, 16, + mac->vif->bss_conf.beacon_int); + SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 10, 0, 16, mac->assoc_id); + + _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt); +} + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.h b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h new file mode 100644 index 000000000000..74cc503efe8a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h @@ -0,0 +1,375 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __REALTEK_FIRMWARE92S_H__ +#define __REALTEK_FIRMWARE92S_H__ + +#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 +#define RTL8190_CPU_START_OFFSET 0x80 +/* Firmware Local buffer size. 64k */ +#define MAX_FIRMWARE_CODE_SIZE 0xFF00 + +#define RT_8192S_FIRMWARE_HDR_SIZE 80 +#define RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE 32 + +/* support till 64 bit bus width OS */ +#define MAX_DEV_ADDR_SIZE 8 +#define MAX_FIRMWARE_INFORMATION_SIZE 32 +#define MAX_802_11_HEADER_LENGTH (40 + \ + MAX_FIRMWARE_INFORMATION_SIZE) +#define ENCRYPTION_MAX_OVERHEAD 128 +#define MAX_FRAGMENT_COUNT 8 +#define MAX_TRANSMIT_BUFFER_SIZE (1600 + \ + (MAX_802_11_HEADER_LENGTH + \ + ENCRYPTION_MAX_OVERHEAD) *\ + MAX_FRAGMENT_COUNT) + +#define H2C_TX_CMD_HDR_LEN 8 + +/* The following DM control code are for Reg0x364, */ +#define FW_DIG_ENABLE_CTL BIT(0) +#define FW_HIGH_PWR_ENABLE_CTL BIT(1) +#define FW_SS_CTL BIT(2) +#define FW_RA_INIT_CTL BIT(3) +#define FW_RA_BG_CTL BIT(4) +#define FW_RA_N_CTL BIT(5) +#define FW_PWR_TRK_CTL BIT(6) +#define FW_IQK_CTL BIT(7) +#define FW_FA_CTL BIT(8) +#define FW_DRIVER_CTRL_DM_CTL BIT(9) +#define FW_PAPE_CTL_BY_SW_HW BIT(10) +#define FW_DISABLE_ALL_DM 0 +#define FW_PWR_TRK_PARAM_CLR 0x0000ffff +#define FW_RA_PARAM_CLR 0xffff0000 + +enum desc_packet_type { + DESC_PACKET_TYPE_INIT = 0, + DESC_PACKET_TYPE_NORMAL = 1, +}; + +/* 8-bytes alignment required */ +struct fw_priv { + /* --- long word 0 ---- */ + /* 0x12: CE product, 0x92: IT product */ + u8 signature_0; + /* 0x87: CE product, 0x81: IT product */ + u8 signature_1; + /* 0x81: PCI-AP, 01:PCIe, 02: 92S-U, + * 0x82: USB-AP, 0x12: 72S-U, 03:SDIO */ + u8 hci_sel; + /* the same value as reigster value */ + u8 chip_version; + /* customer ID low byte */ + u8 customer_id_0; + /* customer ID high byte */ + u8 customer_id_1; + /* 0x11: 1T1R, 0x12: 1T2R, + * 0x92: 1T2R turbo, 0x22: 2T2R */ + u8 rf_config; + /* 4: 4EP, 6: 6EP, 11: 11EP */ + u8 usb_ep_num; + + /* --- long word 1 ---- */ + /* regulatory class bit map 0 */ + u8 regulatory_class_0; + /* regulatory class bit map 1 */ + u8 regulatory_class_1; + /* regulatory class bit map 2 */ + u8 regulatory_class_2; + /* regulatory class bit map 3 */ + u8 regulatory_class_3; + /* 0:SWSI, 1:HWSI, 2:HWPI */ + u8 rfintfs; + u8 def_nettype; + u8 rsvd010; + u8 rsvd011; + + /* --- long word 2 ---- */ + /* 0x00: normal, 0x03: MACLBK, 0x01: PHYLBK */ + u8 lbk_mode; + /* 1: for MP use, 0: for normal + * driver (to be discussed) */ + u8 mp_mode; + u8 rsvd020; + u8 rsvd021; + u8 rsvd022; + u8 rsvd023; + u8 rsvd024; + u8 rsvd025; + + /* --- long word 3 ---- */ + /* QoS enable */ + u8 qos_en; + /* 40MHz BW enable */ + /* 4181 convert AMSDU to AMPDU, 0: disable */ + u8 bw_40mhz_en; + u8 amsdu2ampdu_en; + /* 11n AMPDU enable */ + u8 ampdu_en; + /* FW offloads, 0: driver handles */ + u8 rate_control_offload; + /* FW offloads, 0: driver handles */ + u8 aggregation_offload; + u8 rsvd030; + u8 rsvd031; + + /* --- long word 4 ---- */ + /* 1. FW offloads, 0: driver handles */ + u8 beacon_offload; + /* 2. FW offloads, 0: driver handles */ + u8 mlme_offload; + /* 3. FW offloads, 0: driver handles */ + u8 hwpc_offload; + /* 4. FW offloads, 0: driver handles */ + u8 tcp_checksum_offload; + /* 5. FW offloads, 0: driver handles */ + u8 tcp_offload; + /* 6. FW offloads, 0: driver handles */ + u8 ps_control_offload; + /* 7. FW offloads, 0: driver handles */ + u8 wwlan_offload; + u8 rsvd040; + + /* --- long word 5 ---- */ + /* tcp tx packet length low byte */ + u8 tcp_tx_frame_len_L; + /* tcp tx packet length high byte */ + u8 tcp_tx_frame_len_H; + /* tcp rx packet length low byte */ + u8 tcp_rx_frame_len_L; + /* tcp rx packet length high byte */ + u8 tcp_rx_frame_len_H; + u8 rsvd050; + u8 rsvd051; + u8 rsvd052; + u8 rsvd053; +}; + +/* 8-byte alinment required */ +struct fw_hdr { + + /* --- LONG WORD 0 ---- */ + u16 signature; + /* 0x8000 ~ 0x8FFF for FPGA version, + * 0x0000 ~ 0x7FFF for ASIC version, */ + u16 version; + /* define the size of boot loader */ + u32 dmem_size; + + + /* --- LONG WORD 1 ---- */ + /* define the size of FW in IMEM */ + u32 img_imem_size; + /* define the size of FW in SRAM */ + u32 img_sram_size; + + /* --- LONG WORD 2 ---- */ + /* define the size of DMEM variable */ + u32 fw_priv_size; + u32 rsvd0; + + /* --- LONG WORD 3 ---- */ + u32 rsvd1; + u32 rsvd2; + + struct fw_priv fwpriv; + +} ; + +enum fw_status { + FW_STATUS_INIT = 0, + FW_STATUS_LOAD_IMEM = 1, + FW_STATUS_LOAD_EMEM = 2, + FW_STATUS_LOAD_DMEM = 3, + FW_STATUS_READY = 4, +}; + +struct rt_firmware { + struct fw_hdr *pfwheader; + enum fw_status fwstatus; + u16 firmwareversion; + u8 fw_imem[RTL8190_MAX_FIRMWARE_CODE_SIZE]; + u8 fw_emem[RTL8190_MAX_FIRMWARE_CODE_SIZE]; + u32 fw_imem_len; + u32 fw_emem_len; + u8 sz_fw_tmpbuffer[164000]; + u32 sz_fw_tmpbufferlen; + u16 cmdpacket_fragthresold; +}; + +struct h2c_set_pwrmode_parm { + u8 mode; + u8 flag_low_traffic_en; + u8 flag_lpnav_en; + u8 flag_rf_low_snr_en; + /* 1: dps, 0: 32k */ + u8 flag_dps_en; + u8 bcn_rx_en; + u8 bcn_pass_cnt; + /* beacon TO (ms). ¡§=0¡¨ no limit. */ + u8 bcn_to; + u16 bcn_itv; + /* only for VOIP mode. */ + u8 app_itv; + u8 awake_bcn_itvl; + u8 smart_ps; + /* unit: 100 ms */ + u8 bcn_pass_period; +}; + +struct h2c_joinbss_rpt_parm { + u8 opmode; + u8 ps_qos_info; + u8 bssid[6]; + u16 bcnitv; + u16 aid; +} ; + +struct h2c_wpa_ptk { + /* EAPOL-Key Key Confirmation Key (KCK) */ + u8 kck[16]; + /* EAPOL-Key Key Encryption Key (KEK) */ + u8 kek[16]; + /* Temporal Key 1 (TK1) */ + u8 tk1[16]; + union { + /* Temporal Key 2 (TK2) */ + u8 tk2[16]; + struct { + u8 tx_mic_key[8]; + u8 rx_mic_key[8]; + } athu; + } u; +}; + +struct h2c_wpa_two_way_parm { + /* algorithm TKIP or AES */ + u8 pairwise_en_alg; + u8 group_en_alg; + struct h2c_wpa_ptk wpa_ptk_value; +} ; + +enum h2c_cmd { + FW_H2C_SETPWRMODE = 0, + FW_H2C_JOINBSSRPT = 1, + FW_H2C_WOWLAN_UPDATE_GTK = 2, + FW_H2C_WOWLAN_UPDATE_IV = 3, + FW_H2C_WOWLAN_OFFLOAD = 4, +}; + +enum fw_h2c_cmd { + H2C_READ_MACREG_CMD, /*0*/ + H2C_WRITE_MACREG_CMD, + H2C_READBB_CMD, + H2C_WRITEBB_CMD, + H2C_READRF_CMD, + H2C_WRITERF_CMD, /*5*/ + H2C_READ_EEPROM_CMD, + H2C_WRITE_EEPROM_CMD, + H2C_READ_EFUSE_CMD, + H2C_WRITE_EFUSE_CMD, + H2C_READ_CAM_CMD, /*10*/ + H2C_WRITE_CAM_CMD, + H2C_SETBCNITV_CMD, + H2C_SETMBIDCFG_CMD, + H2C_JOINBSS_CMD, + H2C_DISCONNECT_CMD, /*15*/ + H2C_CREATEBSS_CMD, + H2C_SETOPMode_CMD, + H2C_SITESURVEY_CMD, + H2C_SETAUTH_CMD, + H2C_SETKEY_CMD, /*20*/ + H2C_SETSTAKEY_CMD, + H2C_SETASSOCSTA_CMD, + H2C_DELASSOCSTA_CMD, + H2C_SETSTAPWRSTATE_CMD, + H2C_SETBASICRATE_CMD, /*25*/ + H2C_GETBASICRATE_CMD, + H2C_SETDATARATE_CMD, + H2C_GETDATARATE_CMD, + H2C_SETPHYINFO_CMD, + H2C_GETPHYINFO_CMD, /*30*/ + H2C_SETPHY_CMD, + H2C_GETPHY_CMD, + H2C_READRSSI_CMD, + H2C_READGAIN_CMD, + H2C_SETATIM_CMD, /*35*/ + H2C_SETPWRMODE_CMD, + H2C_JOINBSSRPT_CMD, + H2C_SETRATABLE_CMD, + H2C_GETRATABLE_CMD, + H2C_GETCCXREPORT_CMD, /*40*/ + H2C_GETDTMREPORT_CMD, + H2C_GETTXRATESTATICS_CMD, + H2C_SETUSBSUSPEND_CMD, + H2C_SETH2CLBK_CMD, + H2C_TMP1, /*45*/ + H2C_WOWLAN_UPDATE_GTK_CMD, + H2C_WOWLAN_FW_OFFLOAD, + H2C_TMP2, + H2C_TMP3, + H2C_WOWLAN_UPDATE_IV_CMD, /*50*/ + H2C_TMP4, + MAX_H2CCMD /*52*/ +}; + +/* The following macros are used for FW + * CMD map and parameter updated. */ +#define FW_CMD_IO_CLR(rtlpriv, _Bit) \ + do { \ + udelay(1000); \ + rtlpriv->rtlhal.fwcmd_iomap &= (~_Bit); \ + } while (0); + +#define FW_CMD_IO_UPDATE(rtlpriv, _val) \ + rtlpriv->rtlhal.fwcmd_iomap = _val; + +#define FW_CMD_IO_SET(rtlpriv, _val) \ + do { \ + rtl_write_word(rtlpriv, LBUS_MON_ADDR, (u16)_val); \ + FW_CMD_IO_UPDATE(rtlpriv, _val); \ + } 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); + +#define FW_CMD_IO_QUERY(rtlpriv) \ + (u16)(rtlpriv->rtlhal.fwcmd_iomap) +#define FW_CMD_IO_PARA_QUERY(rtlpriv) \ + ((u32)(rtlpriv->rtlhal.fwcmd_ioparam)) + +int rtl92s_download_fw(struct ieee80211_hw *hw); +void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, + u8 mstatus, u8 ps_qosinfo); + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c new file mode 100644 index 000000000000..2e9005d0454b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -0,0 +1,2512 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../regd.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" +#include "led.h" +#include "hw.h" + +void rtl92se_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + switch (variable) { + case HW_VAR_RCR: { + *((u32 *) (val)) = rtlpci->receive_config; + break; + } + case HW_VAR_RF_STATE: { + *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state; + break; + } + case HW_VAR_FW_PSMODE_STATUS: { + *((bool *) (val)) = ppsc->fw_current_inpsmode; + break; + } + case HW_VAR_CORRECT_TSF: { + u64 tsf; + u32 *ptsf_low = (u32 *)&tsf; + u32 *ptsf_high = ((u32 *)&tsf) + 1; + + *ptsf_high = rtl_read_dword(rtlpriv, (TSFR + 4)); + *ptsf_low = rtl_read_dword(rtlpriv, TSFR); + + *((u64 *) (val)) = tsf; + + break; + } + case HW_VAR_MRC: { + *((bool *)(val)) = rtlpriv->dm.current_mrc_switch; + break; + } + default: { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + } +} + +void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + switch (variable) { + case HW_VAR_ETHER_ADDR:{ + rtl_write_dword(rtlpriv, IDR0, ((u32 *)(val))[0]); + rtl_write_word(rtlpriv, IDR4, ((u16 *)(val + 4))[0]); + break; + } + case HW_VAR_BASIC_RATE:{ + u16 rate_cfg = ((u16 *) val)[0]; + u8 rate_index = 0; + + if (rtlhal->version == VERSION_8192S_ACUT) + rate_cfg = rate_cfg & 0x150; + else + rate_cfg = rate_cfg & 0x15f; + + rate_cfg |= 0x01; + + rtl_write_byte(rtlpriv, RRSR, rate_cfg & 0xff); + rtl_write_byte(rtlpriv, RRSR + 1, + (rate_cfg >> 8) & 0xff); + + while (rate_cfg > 0x1) { + rate_cfg = (rate_cfg >> 1); + rate_index++; + } + rtl_write_byte(rtlpriv, INIRTSMCS_SEL, rate_index); + + break; + } + case HW_VAR_BSSID:{ + rtl_write_dword(rtlpriv, BSSIDR, ((u32 *)(val))[0]); + rtl_write_word(rtlpriv, BSSIDR + 4, + ((u16 *)(val + 4))[0]); + break; + } + case HW_VAR_SIFS:{ + rtl_write_byte(rtlpriv, SIFS_OFDM, val[0]); + rtl_write_byte(rtlpriv, SIFS_OFDM + 1, val[1]); + break; + } + case HW_VAR_SLOT_TIME:{ + u8 e_aci; + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + ("HW_VAR_SLOT_TIME %x\n", val[0])); + + rtl_write_byte(rtlpriv, SLOT_TIME, val[0]); + + for (e_aci = 0; e_aci < AC_MAX; e_aci++) { + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_AC_PARAM, + (u8 *)(&e_aci)); + } + break; + } + case HW_VAR_ACK_PREAMBLE:{ + u8 reg_tmp; + u8 short_preamble = (bool) (*(u8 *) val); + reg_tmp = (mac->cur_40_prime_sc) << 5; + if (short_preamble) + reg_tmp |= 0x80; + + rtl_write_byte(rtlpriv, RRSR + 2, reg_tmp); + break; + } + case HW_VAR_AMPDU_MIN_SPACE:{ + u8 min_spacing_to_set; + u8 sec_min_space; + + min_spacing_to_set = *((u8 *)val); + if (min_spacing_to_set <= 7) { + if (rtlpriv->sec.pairwise_enc_algorithm == + NO_ENCRYPTION) + sec_min_space = 0; + else + sec_min_space = 1; + + if (min_spacing_to_set < sec_min_space) + min_spacing_to_set = sec_min_space; + if (min_spacing_to_set > 5) + min_spacing_to_set = 5; + + mac->min_space_cfg = + ((mac->min_space_cfg & 0xf8) | + min_spacing_to_set); + + *val = min_spacing_to_set; + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", + mac->min_space_cfg)); + + rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, + mac->min_space_cfg); + } + break; + } + case HW_VAR_SHORTGI_DENSITY:{ + u8 density_to_set; + + density_to_set = *((u8 *) val); + mac->min_space_cfg = rtlpriv->rtlhal.minspace_cfg; + mac->min_space_cfg |= (density_to_set << 3); + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + ("Set HW_VAR_SHORTGI_DENSITY: %#x\n", + mac->min_space_cfg)); + + rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, + mac->min_space_cfg); + + break; + } + case HW_VAR_AMPDU_FACTOR:{ + u8 factor_toset; + u8 regtoset; + u8 factorlevel[18] = { + 2, 4, 4, 7, 7, 13, 13, + 13, 2, 7, 7, 13, 13, + 15, 15, 15, 15, 0}; + u8 index = 0; + + factor_toset = *((u8 *) val); + if (factor_toset <= 3) { + factor_toset = (1 << (factor_toset + 2)); + if (factor_toset > 0xf) + factor_toset = 0xf; + + for (index = 0; index < 17; index++) { + if (factorlevel[index] > factor_toset) + factorlevel[index] = + factor_toset; + } + + for (index = 0; index < 8; index++) { + regtoset = ((factorlevel[index * 2]) | + (factorlevel[index * + 2 + 1] << 4)); + rtl_write_byte(rtlpriv, + AGGLEN_LMT_L + index, + regtoset); + } + + regtoset = ((factorlevel[16]) | + (factorlevel[17] << 4)); + rtl_write_byte(rtlpriv, AGGLEN_LMT_H, regtoset); + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + ("Set HW_VAR_AMPDU_FACTOR: %#x\n", + factor_toset)); + } + break; + } + case HW_VAR_AC_PARAM:{ + u8 e_aci = *((u8 *) val); + rtl92s_dm_init_edca_turbo(hw); + + if (rtlpci->acm_method != eAcmWay2_SW) + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_ACM_CTRL, + (u8 *)(&e_aci)); + break; + } + case HW_VAR_ACM_CTRL:{ + u8 e_aci = *((u8 *) val); + union aci_aifsn *p_aci_aifsn = (union aci_aifsn *)(&( + mac->ac[0].aifs)); + u8 acm = p_aci_aifsn->f.acm; + u8 acm_ctrl = rtl_read_byte(rtlpriv, AcmHwCtrl); + + acm_ctrl = acm_ctrl | ((rtlpci->acm_method == 2) ? + 0x0 : 0x1); + + if (acm) { + switch (e_aci) { + case AC0_BE: + acm_ctrl |= AcmHw_BeqEn; + break; + case AC2_VI: + acm_ctrl |= AcmHw_ViqEn; + break; + case AC3_VO: + acm_ctrl |= AcmHw_VoqEn; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("HW_VAR_ACM_CTRL acm set " + "failed: eACI is %d\n", acm)); + break; + } + } else { + switch (e_aci) { + case AC0_BE: + acm_ctrl &= (~AcmHw_BeqEn); + break; + case AC2_VI: + acm_ctrl &= (~AcmHw_ViqEn); + break; + case AC3_VO: + acm_ctrl &= (~AcmHw_BeqEn); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + } + + RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE, + ("HW_VAR_ACM_CTRL Write 0x%X\n", acm_ctrl)); + rtl_write_byte(rtlpriv, AcmHwCtrl, acm_ctrl); + break; + } + case HW_VAR_RCR:{ + rtl_write_dword(rtlpriv, RCR, ((u32 *) (val))[0]); + rtlpci->receive_config = ((u32 *) (val))[0]; + break; + } + case HW_VAR_RETRY_LIMIT:{ + u8 retry_limit = ((u8 *) (val))[0]; + + rtl_write_word(rtlpriv, RETRY_LIMIT, + retry_limit << RETRY_LIMIT_SHORT_SHIFT | + retry_limit << RETRY_LIMIT_LONG_SHIFT); + break; + } + case HW_VAR_DUAL_TSF_RST: { + break; + } + case HW_VAR_EFUSE_BYTES: { + rtlefuse->efuse_usedbytes = *((u16 *) val); + break; + } + case HW_VAR_EFUSE_USAGE: { + rtlefuse->efuse_usedpercentage = *((u8 *) val); + break; + } + case HW_VAR_IO_CMD: { + break; + } + case HW_VAR_WPA_CONFIG: { + rtl_write_byte(rtlpriv, REG_SECR, *((u8 *) val)); + break; + } + case HW_VAR_SET_RPWM:{ + break; + } + case HW_VAR_H2C_FW_PWRMODE:{ + break; + } + case HW_VAR_FW_PSMODE_STATUS: { + ppsc->fw_current_inpsmode = *((bool *) val); + break; + } + case HW_VAR_H2C_FW_JOINBSSRPT:{ + break; + } + case HW_VAR_AID:{ + break; + } + case HW_VAR_CORRECT_TSF:{ + break; + } + case HW_VAR_MRC: { + bool bmrc_toset = *((bool *)val); + u8 u1bdata = 0; + + if (bmrc_toset) { + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, + MASKBYTE0, 0x33); + u1bdata = (u8)rtl_get_bbreg(hw, + ROFDM1_TRXPATHENABLE, + MASKBYTE0); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, + MASKBYTE0, + ((u1bdata & 0xf0) | 0x03)); + u1bdata = (u8)rtl_get_bbreg(hw, + ROFDM0_TRXPATHENABLE, + MASKBYTE1); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, + MASKBYTE1, + (u1bdata | 0x04)); + + /* Update current settings. */ + rtlpriv->dm.current_mrc_switch = bmrc_toset; + } else { + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, + MASKBYTE0, 0x13); + u1bdata = (u8)rtl_get_bbreg(hw, + ROFDM1_TRXPATHENABLE, + MASKBYTE0); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, + MASKBYTE0, + ((u1bdata & 0xf0) | 0x01)); + u1bdata = (u8)rtl_get_bbreg(hw, + ROFDM0_TRXPATHENABLE, + MASKBYTE1); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, + MASKBYTE1, (u1bdata & 0xfb)); + + /* Update current settings. */ + rtlpriv->dm.current_mrc_switch = bmrc_toset; + } + + break; + } + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + +} + +void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 sec_reg_value = 0x0; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("PairwiseEncAlgorithm = %d " + "GroupEncAlgorithm = %d\n", + rtlpriv->sec.pairwise_enc_algorithm, + rtlpriv->sec.group_enc_algorithm)); + + if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("not open hw encryption\n")); + return; + } + + sec_reg_value = SCR_TXENCENABLE | SCR_RXENCENABLE; + + if (rtlpriv->sec.use_defaultkey) { + sec_reg_value |= SCR_TXUSEDK; + sec_reg_value |= SCR_RXUSEDK; + } + + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("The SECR-value %x\n", + sec_reg_value)); + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); + +} + +static u8 _rtl92ce_halset_sysclk(struct ieee80211_hw *hw, u8 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 waitcount = 100; + bool bresult = false; + u8 tmpvalue; + + rtl_write_byte(rtlpriv, SYS_CLKR + 1, data); + + /* Wait the MAC synchronized. */ + udelay(400); + + /* Check if it is set ready. */ + tmpvalue = rtl_read_byte(rtlpriv, SYS_CLKR + 1); + bresult = ((tmpvalue & BIT(7)) == (data & BIT(7))); + + if ((data & (BIT(6) | BIT(7))) == false) { + waitcount = 100; + tmpvalue = 0; + + while (1) { + waitcount--; + + tmpvalue = rtl_read_byte(rtlpriv, SYS_CLKR + 1); + if ((tmpvalue & BIT(6))) + break; + + printk(KERN_ERR "wait for BIT(6) return value %x\n", + tmpvalue); + if (waitcount == 0) + break; + + udelay(10); + } + + if (waitcount == 0) + bresult = false; + else + bresult = true; + } + + return bresult; +} + +void rtl8192se_gpiobit3_cfg_inputmode(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1tmp; + + /* The following config GPIO function */ + rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO)); + u1tmp = rtl_read_byte(rtlpriv, GPIO_IO_SEL); + + /* config GPIO3 to input */ + u1tmp &= HAL_8192S_HW_GPIO_OFF_MASK; + rtl_write_byte(rtlpriv, GPIO_IO_SEL, u1tmp); + +} + +static u8 _rtl92se_rf_onoff_detect(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1tmp; + u8 retval = ERFON; + + /* The following config GPIO function */ + rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO)); + u1tmp = rtl_read_byte(rtlpriv, GPIO_IO_SEL); + + /* config GPIO3 to input */ + u1tmp &= HAL_8192S_HW_GPIO_OFF_MASK; + rtl_write_byte(rtlpriv, GPIO_IO_SEL, u1tmp); + + /* On some of the platform, driver cannot read correct + * value without delay between Write_GPIO_SEL and Read_GPIO_IN */ + mdelay(10); + + /* check GPIO3 */ + u1tmp = rtl_read_byte(rtlpriv, GPIO_IN); + retval = (u1tmp & HAL_8192S_HW_GPIO_OFF_BIT) ? ERFON : ERFOFF; + + return retval; +} + +static void _rtl92se_macconfig_before_fwdownload(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + u8 i; + u8 tmpu1b; + u16 tmpu2b; + u8 pollingcnt = 20; + + if (rtlpci->first_init) { + /* Reset PCIE Digital */ + tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + tmpu1b &= 0xFE; + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b); + udelay(1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b | BIT(0)); + } + + /* Switch to SW IO control */ + tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + if (tmpu1b & BIT(7)) { + tmpu1b &= ~(BIT(6) | BIT(7)); + + /* Set failed, return to prevent hang. */ + if (!_rtl92ce_halset_sysclk(hw, tmpu1b)) + return; + } + + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x0); + udelay(50); + rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); + udelay(50); + + /* Clear FW RPWM for FW control LPS.*/ + rtl_write_byte(rtlpriv, RPWM, 0x0); + + /* Reset MAC-IO and CPU and Core Digital BIT(10)/11/15 */ + tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + tmpu1b &= 0x73; + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b); + /* wait for BIT 10/11/15 to pull high automatically!! */ + mdelay(1); + + rtl_write_byte(rtlpriv, CMDR, 0); + rtl_write_byte(rtlpriv, TCR, 0); + + /* Data sheet not define 0x562!!! Copy from WMAC!!!!! */ + tmpu1b = rtl_read_byte(rtlpriv, 0x562); + tmpu1b |= 0x08; + rtl_write_byte(rtlpriv, 0x562, tmpu1b); + tmpu1b &= ~(BIT(3)); + rtl_write_byte(rtlpriv, 0x562, tmpu1b); + + /* Enable AFE clock source */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, (tmpu1b | 0x01)); + /* Delay 1.5ms */ + mdelay(2); + tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL + 1); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, (tmpu1b & 0xfb)); + + /* Enable AFE Macro Block's Bandgap */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); + rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | BIT(0))); + mdelay(1); + + /* Enable AFE Mbias */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); + rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | 0x02)); + mdelay(1); + + /* Enable LDOA15 block */ + tmpu1b = rtl_read_byte(rtlpriv, LDOA15_CTRL); + rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0))); + + /* Set Digital Vdd to Retention isolation Path. */ + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_ISO_CTRL); + rtl_write_word(rtlpriv, REG_SYS_ISO_CTRL, (tmpu2b | BIT(11))); + + /* For warm reboot NIC disappera bug. */ + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(13))); + + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x68); + + /* Enable AFE PLL Macro Block */ + /* We need to delay 100u before enabling PLL. */ + udelay(200); + tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4))); + + /* for divider reset */ + udelay(100); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | + BIT(4) | BIT(6))); + udelay(10); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4))); + udelay(10); + + /* Enable MAC 80MHZ clock */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL + 1); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, (tmpu1b | BIT(0))); + mdelay(1); + + /* Release isolation AFE PLL & MD */ + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, 0xA6); + + /* Enable MAC clock */ + tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); + rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11))); + + /* Enable Core digital and enable IOREG R/W */ + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11))); + + tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b & ~(BIT(7))); + + /* enable REG_EN */ + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15))); + + /* Switch the control path. */ + tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); + rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b & (~BIT(2)))); + + tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6))); + if (!_rtl92ce_halset_sysclk(hw, tmpu1b)) + return; /* Set failed, return to prevent hang. */ + + rtl_write_word(rtlpriv, CMDR, 0x07FC); + + /* MH We must enable the section of code to prevent load IMEM fail. */ + /* Load MAC register from WMAc temporarily We simulate macreg. */ + /* txt HW will provide MAC txt later */ + rtl_write_byte(rtlpriv, 0x6, 0x30); + rtl_write_byte(rtlpriv, 0x49, 0xf0); + + rtl_write_byte(rtlpriv, 0x4b, 0x81); + + rtl_write_byte(rtlpriv, 0xb5, 0x21); + + rtl_write_byte(rtlpriv, 0xdc, 0xff); + rtl_write_byte(rtlpriv, 0xdd, 0xff); + rtl_write_byte(rtlpriv, 0xde, 0xff); + rtl_write_byte(rtlpriv, 0xdf, 0xff); + + rtl_write_byte(rtlpriv, 0x11a, 0x00); + rtl_write_byte(rtlpriv, 0x11b, 0x00); + + for (i = 0; i < 32; i++) + rtl_write_byte(rtlpriv, INIMCS_SEL + i, 0x1b); + + rtl_write_byte(rtlpriv, 0x236, 0xff); + + rtl_write_byte(rtlpriv, 0x503, 0x22); + + if (ppsc->support_aspm && !ppsc->support_backdoor) + rtl_write_byte(rtlpriv, 0x560, 0x40); + else + rtl_write_byte(rtlpriv, 0x560, 0x00); + + rtl_write_byte(rtlpriv, DBG_PORT, 0x91); + + /* Set RX Desc Address */ + rtl_write_dword(rtlpriv, RDQDA, rtlpci->rx_ring[RX_MPDU_QUEUE].dma); + rtl_write_dword(rtlpriv, RCDA, rtlpci->rx_ring[RX_CMD_QUEUE].dma); + + /* Set TX Desc Address */ + rtl_write_dword(rtlpriv, TBKDA, rtlpci->tx_ring[BK_QUEUE].dma); + rtl_write_dword(rtlpriv, TBEDA, rtlpci->tx_ring[BE_QUEUE].dma); + rtl_write_dword(rtlpriv, TVIDA, rtlpci->tx_ring[VI_QUEUE].dma); + rtl_write_dword(rtlpriv, TVODA, rtlpci->tx_ring[VO_QUEUE].dma); + rtl_write_dword(rtlpriv, TBDA, rtlpci->tx_ring[BEACON_QUEUE].dma); + rtl_write_dword(rtlpriv, TCDA, rtlpci->tx_ring[TXCMD_QUEUE].dma); + rtl_write_dword(rtlpriv, TMDA, rtlpci->tx_ring[MGNT_QUEUE].dma); + rtl_write_dword(rtlpriv, THPDA, rtlpci->tx_ring[HIGH_QUEUE].dma); + rtl_write_dword(rtlpriv, HDA, rtlpci->tx_ring[HCCA_QUEUE].dma); + + rtl_write_word(rtlpriv, CMDR, 0x37FC); + + /* To make sure that TxDMA can ready to download FW. */ + /* We should reset TxDMA if IMEM RPT was not ready. */ + do { + tmpu1b = rtl_read_byte(rtlpriv, TCR); + if ((tmpu1b & TXDMA_INIT_VALUE) == TXDMA_INIT_VALUE) + break; + + udelay(5); + } while (pollingcnt--); + + if (pollingcnt <= 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Polling TXDMA_INIT_VALUE " + "timeout!! Current TCR(%#x)\n", tmpu1b)); + tmpu1b = rtl_read_byte(rtlpriv, CMDR); + rtl_write_byte(rtlpriv, CMDR, tmpu1b & (~TXDMA_EN)); + udelay(2); + /* Reset TxDMA */ + rtl_write_byte(rtlpriv, CMDR, tmpu1b | TXDMA_EN); + } + + /* After MACIO reset,we must refresh LED state. */ + if ((ppsc->rfoff_reason == RF_CHANGE_BY_IPS) || + (ppsc->rfoff_reason == 0)) { + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + enum rf_pwrstate rfpwr_state_toset; + rfpwr_state_toset = _rtl92se_rf_onoff_detect(hw); + + if (rfpwr_state_toset == ERFON) + rtl92se_sw_led_on(hw, pLed0); + } +} + +static void _rtl92se_macconfig_after_fwdownload(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 i; + u16 tmpu2b; + + /* 1. System Configure Register (Offset: 0x0000 - 0x003F) */ + + /* 2. Command Control Register (Offset: 0x0040 - 0x004F) */ + /* Turn on 0x40 Command register */ + rtl_write_word(rtlpriv, CMDR, (BBRSTN | BB_GLB_RSTN | + SCHEDULE_EN | MACRXEN | MACTXEN | DDMA_EN | FW2HW_EN | + RXDMA_EN | TXDMA_EN | HCI_RXDMA_EN | HCI_TXDMA_EN)); + + /* Set TCR TX DMA pre 2 FULL enable bit */ + rtl_write_dword(rtlpriv, TCR, rtl_read_dword(rtlpriv, TCR) | + TXDMAPRE2FULL); + + /* Set RCR */ + rtl_write_dword(rtlpriv, RCR, rtlpci->receive_config); + + /* 3. MACID Setting Register (Offset: 0x0050 - 0x007F) */ + + /* 4. Timing Control Register (Offset: 0x0080 - 0x009F) */ + /* Set CCK/OFDM SIFS */ + /* CCK SIFS shall always be 10us. */ + rtl_write_word(rtlpriv, SIFS_CCK, 0x0a0a); + rtl_write_word(rtlpriv, SIFS_OFDM, 0x1010); + + /* Set AckTimeout */ + rtl_write_byte(rtlpriv, ACK_TIMEOUT, 0x40); + + /* Beacon related */ + rtl_write_word(rtlpriv, BCN_INTERVAL, 100); + rtl_write_word(rtlpriv, ATIMWND, 2); + + /* 5. FIFO Control Register (Offset: 0x00A0 - 0x015F) */ + /* 5.1 Initialize Number of Reserved Pages in Firmware Queue */ + /* Firmware allocate now, associate with FW internal setting.!!! */ + + /* 5.2 Setting TX/RX page size 0/1/2/3/4=64/128/256/512/1024 */ + /* 5.3 Set driver info, we only accept PHY status now. */ + /* 5.4 Set RXDMA arbitration to control RXDMA/MAC/FW R/W for RXFIFO */ + rtl_write_byte(rtlpriv, RXDMA, rtl_read_byte(rtlpriv, RXDMA) | BIT(6)); + + /* 6. Adaptive Control Register (Offset: 0x0160 - 0x01CF) */ + /* Set RRSR to all legacy rate and HT rate + * CCK rate is supported by default. + * CCK rate will be filtered out only when associated + * AP does not support it. + * Only enable ACK rate to OFDM 24M + * Disable RRSR for CCK rate in A-Cut */ + + if (rtlhal->version == VERSION_8192S_ACUT) + rtl_write_byte(rtlpriv, RRSR, 0xf0); + else if (rtlhal->version == VERSION_8192S_BCUT) + rtl_write_byte(rtlpriv, RRSR, 0xff); + rtl_write_byte(rtlpriv, RRSR + 1, 0x01); + rtl_write_byte(rtlpriv, RRSR + 2, 0x00); + + /* A-Cut IC do not support CCK rate. We forbid ARFR to */ + /* fallback to CCK rate */ + for (i = 0; i < 8; i++) { + /*Disable RRSR for CCK rate in A-Cut */ + if (rtlhal->version == VERSION_8192S_ACUT) + rtl_write_dword(rtlpriv, ARFR0 + i * 4, 0x1f0ff0f0); + } + + /* Different rate use different AMPDU size */ + /* MCS32/ MCS15_SG use max AMPDU size 15*2=30K */ + rtl_write_byte(rtlpriv, AGGLEN_LMT_H, 0x0f); + /* MCS0/1/2/3 use max AMPDU size 4*2=8K */ + rtl_write_word(rtlpriv, AGGLEN_LMT_L, 0x7442); + /* MCS4/5 use max AMPDU size 8*2=16K 6/7 use 10*2=20K */ + rtl_write_word(rtlpriv, AGGLEN_LMT_L + 2, 0xddd7); + /* MCS8/9 use max AMPDU size 8*2=16K 10/11 use 10*2=20K */ + rtl_write_word(rtlpriv, AGGLEN_LMT_L + 4, 0xd772); + /* MCS12/13/14/15 use max AMPDU size 15*2=30K */ + rtl_write_word(rtlpriv, AGGLEN_LMT_L + 6, 0xfffd); + + /* Set Data / Response auto rate fallack retry count */ + rtl_write_dword(rtlpriv, DARFRC, 0x04010000); + rtl_write_dword(rtlpriv, DARFRC + 4, 0x09070605); + rtl_write_dword(rtlpriv, RARFRC, 0x04010000); + rtl_write_dword(rtlpriv, RARFRC + 4, 0x09070605); + + /* 7. EDCA Setting Register (Offset: 0x01D0 - 0x01FF) */ + /* Set all rate to support SG */ + rtl_write_word(rtlpriv, SG_RATE, 0xFFFF); + + /* 8. WMAC, BA, and CCX related Register (Offset: 0x0200 - 0x023F) */ + /* Set NAV protection length */ + rtl_write_word(rtlpriv, NAV_PROT_LEN, 0x0080); + /* CF-END Threshold */ + rtl_write_byte(rtlpriv, CFEND_TH, 0xFF); + /* Set AMPDU minimum space */ + rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, 0x07); + /* Set TXOP stall control for several queue/HI/BCN/MGT/ */ + rtl_write_byte(rtlpriv, TXOP_STALL_CTRL, 0x00); + + /* 9. Security Control Register (Offset: 0x0240 - 0x025F) */ + /* 10. Power Save Control Register (Offset: 0x0260 - 0x02DF) */ + /* 11. General Purpose Register (Offset: 0x02E0 - 0x02FF) */ + /* 12. Host Interrupt Status Register (Offset: 0x0300 - 0x030F) */ + /* 13. Test Mode and Debug Control Register (Offset: 0x0310 - 0x034F) */ + + /* 14. Set driver info, we only accept PHY status now. */ + rtl_write_byte(rtlpriv, RXDRVINFO_SZ, 4); + + /* 15. For EEPROM R/W Workaround */ + /* 16. For EFUSE to share REG_SYS_FUNC_EN with EEPROM!!! */ + tmpu2b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, tmpu2b | BIT(13)); + tmpu2b = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL); + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, tmpu2b & (~BIT(8))); + + /* 17. For EFUSE */ + /* We may R/W EFUSE in EEPROM mode */ + if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { + u8 tempval; + + tempval = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL + 1); + tempval &= 0xFE; + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, tempval); + + /* Change Program timing */ + rtl_write_byte(rtlpriv, REG_EFUSE_CTRL + 3, 0x72); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("EFUSE CONFIG OK\n")); + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("OK\n")); + +} + +static void _rtl92se_hw_configure(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + u8 reg_bw_opmode = 0; + u32 reg_ratr = 0, reg_rrsr = 0; + u8 regtmp = 0; + + reg_bw_opmode = BW_OPMODE_20MHZ; + reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | + RATE_ALL_OFDM_2SS; + reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + + regtmp = rtl_read_byte(rtlpriv, INIRTSMCS_SEL); + reg_rrsr = ((reg_rrsr & 0x000fffff) << 8) | regtmp; + rtl_write_dword(rtlpriv, INIRTSMCS_SEL, reg_rrsr); + rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode); + + /* Set Retry Limit here */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, + (u8 *)(&rtlpci->shortretry_limit)); + + rtl_write_byte(rtlpriv, MLT, 0x8f); + + /* For Min Spacing configuration. */ + switch (rtlphy->rf_type) { + case RF_1T2R: + case RF_1T1R: + rtlhal->minspace_cfg = (MAX_MSS_DENSITY_1T << 3); + break; + case RF_2T2R: + case RF_2T2R_GREEN: + rtlhal->minspace_cfg = (MAX_MSS_DENSITY_2T << 3); + break; + } + rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, rtlhal->minspace_cfg); +} + +int rtl92se_hw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 tmp_byte = 0; + + bool rtstatus = true; + u8 tmp_u1b; + int err = false; + u8 i; + int wdcapra_add[] = { + EDCAPARA_BE, EDCAPARA_BK, + EDCAPARA_VI, EDCAPARA_VO}; + u8 secr_value = 0x0; + + rtlpci->being_init_adapter = true; + + rtlpriv->intf_ops->disable_aspm(hw); + + /* 1. MAC Initialize */ + /* Before FW download, we have to set some MAC register */ + _rtl92se_macconfig_before_fwdownload(hw); + + rtlhal->version = (enum version_8192s)((rtl_read_dword(rtlpriv, + PMC_FSM) >> 16) & 0xF); + + rtl8192se_gpiobit3_cfg_inputmode(hw); + + /* 2. download firmware */ + rtstatus = rtl92s_download_fw(hw); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("Failed to download FW. " + "Init HW without FW now.., Please copy FW into" + "/lib/firmware/rtlwifi\n")); + rtlhal->fw_ready = false; + } else { + rtlhal->fw_ready = true; + } + + /* After FW download, we have to reset MAC register */ + _rtl92se_macconfig_after_fwdownload(hw); + + /*Retrieve default FW Cmd IO map. */ + rtlhal->fwcmd_iomap = rtl_read_word(rtlpriv, LBUS_MON_ADDR); + rtlhal->fwcmd_ioparam = rtl_read_dword(rtlpriv, LBUS_ADDR_MASK); + + /* 3. Initialize MAC/PHY Config by MACPHY_reg.txt */ + if (rtl92s_phy_mac_config(hw) != true) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("MAC Config failed\n")); + return rtstatus; + } + + /* Make sure BB/RF write OK. We should prevent enter IPS. radio off. */ + /* We must set flag avoid BB/RF config period later!! */ + rtl_write_dword(rtlpriv, CMDR, 0x37FC); + + /* 4. Initialize BB After MAC Config PHY_reg.txt, AGC_Tab.txt */ + if (rtl92s_phy_bb_config(hw) != true) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ("BB Config failed\n")); + return rtstatus; + } + + /* 5. Initiailze RF RAIO_A.txt RF RAIO_B.txt */ + /* Before initalizing RF. We can not use FW to do RF-R/W. */ + + rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; + + /* RF Power Save */ +#if 0 + /* H/W or S/W RF OFF before sleep. */ + if (rtlpriv->psc.rfoff_reason > RF_CHANGE_BY_PS) { + u32 rfoffreason = rtlpriv->psc.rfoff_reason; + + rtlpriv->psc.rfoff_reason = RF_CHANGE_BY_INIT; + rtlpriv->psc.rfpwr_state = ERFON; + rtl_ps_set_rf_state(hw, ERFOFF, rfoffreason, true); + } else { + /* gpio radio on/off is out of adapter start */ + if (rtlpriv->psc.hwradiooff == false) { + rtlpriv->psc.rfpwr_state = ERFON; + rtlpriv->psc.rfoff_reason = 0; + } + } +#endif + + /* Before RF-R/W we must execute the IO from Scott's suggestion. */ + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, 0xDB); + if (rtlhal->version == VERSION_8192S_ACUT) + rtl_write_byte(rtlpriv, SPS1_CTRL + 3, 0x07); + else + rtl_write_byte(rtlpriv, RF_CTRL, 0x07); + + if (rtl92s_phy_rf_config(hw) != true) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("RF Config failed\n")); + return rtstatus; + } + + /* After read predefined TXT, we must set BB/MAC/RF + * register as our requirement */ + + rtlphy->rfreg_chnlval[0] = rtl92s_phy_query_rf_reg(hw, + (enum radio_path)0, + RF_CHNLBW, + RFREG_OFFSET_MASK); + rtlphy->rfreg_chnlval[1] = rtl92s_phy_query_rf_reg(hw, + (enum radio_path)1, + RF_CHNLBW, + RFREG_OFFSET_MASK); + + /*---- Set CCK and OFDM Block "ON"----*/ + rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); + + /*3 Set Hardware(Do nothing now) */ + _rtl92se_hw_configure(hw); + + /* Read EEPROM TX power index and PHY_REG_PG.txt to capture correct */ + /* TX power index for different rate set. */ + /* Get original hw reg values */ + rtl92s_phy_get_hw_reg_originalvalue(hw); + /* Write correct tx power index */ + rtl92s_phy_set_txpower(hw, rtlphy->current_channel); + + /* We must set MAC address after firmware download. */ + for (i = 0; i < 6; i++) + rtl_write_byte(rtlpriv, MACIDR0 + i, rtlefuse->dev_addr[i]); + + /* EEPROM R/W workaround */ + tmp_u1b = rtl_read_byte(rtlpriv, MAC_PINMUX_CFG); + rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, tmp_u1b & (~BIT(3))); + + rtl_write_byte(rtlpriv, 0x4d, 0x0); + + if (hal_get_firmwareversion(rtlpriv) >= 0x49) { + tmp_byte = rtl_read_byte(rtlpriv, FW_RSVD_PG_CRTL) & (~BIT(4)); + tmp_byte = tmp_byte | BIT(5); + rtl_write_byte(rtlpriv, FW_RSVD_PG_CRTL, tmp_byte); + rtl_write_dword(rtlpriv, TXDESC_MSK, 0xFFFFCFFF); + } + + /* We enable high power and RA related mechanism after NIC + * initialized. */ + rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_INIT); + + /* Add to prevent ASPM bug. */ + /* Always enable hst and NIC clock request. */ + rtl92s_phy_switch_ephy_parameter(hw); + + /* Security related + * 1. Clear all H/W keys. + * 2. Enable H/W encryption/decryption. */ + rtl_cam_reset_all_entry(hw); + secr_value |= SCR_TXENCENABLE; + secr_value |= SCR_RXENCENABLE; + secr_value |= SCR_NOSKMC; + rtl_write_byte(rtlpriv, REG_SECR, secr_value); + + for (i = 0; i < 4; i++) + rtl_write_dword(rtlpriv, wdcapra_add[i], 0x5e4322); + + if (rtlphy->rf_type == RF_1T2R) { + bool mrc2set = true; + /* Turn on B-Path */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC, (u8 *)&mrc2set); + } + + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON); + rtl92s_dm_init(hw); + rtlpci->being_init_adapter = false; + + return err; +} + +void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr) +{ +} + +void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 reg_rcr = rtlpci->receive_config; + + if (rtlpriv->psc.rfpwr_state != ERFON) + return; + + if (check_bssid == true) { + reg_rcr |= (RCR_CBSSID); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + } else if (check_bssid == false) { + reg_rcr &= (~RCR_CBSSID); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + } + +} + +static int _rtl92se_set_media_status(struct ieee80211_hw *hw, + enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 bt_msr = rtl_read_byte(rtlpriv, MSR); + enum led_ctl_mode ledaction = LED_CTL_NO_LINK; + u32 temp; + bt_msr &= ~MSR_LINK_MASK; + + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + bt_msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT); + ledaction = LED_CTL_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Set Network type to NO LINK!\n")); + break; + case NL80211_IFTYPE_ADHOC: + bt_msr |= (MSR_LINK_ADHOC << MSR_LINK_SHIFT); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Set Network type to Ad Hoc!\n")); + break; + case NL80211_IFTYPE_STATION: + bt_msr |= (MSR_LINK_MANAGED << MSR_LINK_SHIFT); + ledaction = LED_CTL_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Set Network type to STA!\n")); + break; + case NL80211_IFTYPE_AP: + bt_msr |= (MSR_LINK_MASTER << MSR_LINK_SHIFT); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Set Network type to AP!\n")); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Network type %d not support!\n", type)); + return 1; + break; + + } + + rtl_write_byte(rtlpriv, (MSR), bt_msr); + + temp = rtl_read_dword(rtlpriv, TCR); + rtl_write_dword(rtlpriv, TCR, temp & (~BIT(8))); + rtl_write_dword(rtlpriv, TCR, temp | BIT(8)); + + + return 0; +} + +/* HW_VAR_MEDIA_STATUS & HW_VAR_CECHK_BSSID */ +int rtl92se_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (_rtl92se_set_media_status(hw, type)) + return -EOPNOTSUPP; + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP) + rtl92se_set_check_bssid(hw, true); + } else { + rtl92se_set_check_bssid(hw, false); + } + + return 0; +} + +/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */ +void rtl92se_set_qos(struct ieee80211_hw *hw, int aci) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl92s_dm_init_edca_turbo(hw); + + switch (aci) { + case AC1_BK: + rtl_write_dword(rtlpriv, EDCAPARA_BK, 0xa44f); + break; + case AC0_BE: + /* rtl_write_dword(rtlpriv, EDCAPARA_BE, u4b_ac_param); */ + break; + case AC2_VI: + rtl_write_dword(rtlpriv, EDCAPARA_VI, 0x5e4322); + break; + case AC3_VO: + rtl_write_dword(rtlpriv, EDCAPARA_VO, 0x2f3222); + break; + default: + RT_ASSERT(false, ("invalid aci: %d !\n", aci)); + break; + } +} + +void rtl92se_enable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_dword(rtlpriv, INTA_MASK, rtlpci->irq_mask[0]); + /* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */ + rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F); + + rtlpci->irq_enabled = true; +} + +void rtl92se_disable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_dword(rtlpriv, INTA_MASK, 0); + rtl_write_dword(rtlpriv, INTA_MASK + 4, 0); + + rtlpci->irq_enabled = false; +} + + +static u8 _rtl92s_set_sysclk(struct ieee80211_hw *hw, u8 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 waitcnt = 100; + bool result = false; + u8 tmp; + + rtl_write_byte(rtlpriv, SYS_CLKR + 1, data); + + /* Wait the MAC synchronized. */ + udelay(400); + + /* Check if it is set ready. */ + tmp = rtl_read_byte(rtlpriv, SYS_CLKR + 1); + result = ((tmp & BIT(7)) == (data & BIT(7))); + + if ((data & (BIT(6) | BIT(7))) == false) { + waitcnt = 100; + tmp = 0; + + while (1) { + waitcnt--; + tmp = rtl_read_byte(rtlpriv, SYS_CLKR + 1); + + if ((tmp & BIT(6))) + break; + + printk(KERN_ERR "wait for BIT(6) return value %x\n", + tmp); + + if (waitcnt == 0) + break; + udelay(10); + } + + if (waitcnt == 0) + result = false; + else + result = true; + } + + return result; +} + +static void _rtl92s_phy_set_rfhalt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + u8 u1btmp; + + if (rtlhal->driver_going2unload) + rtl_write_byte(rtlpriv, 0x560, 0x0); + + /* Power save for BB/RF */ + u1btmp = rtl_read_byte(rtlpriv, LDOV12D_CTRL); + u1btmp |= BIT(0); + rtl_write_byte(rtlpriv, LDOV12D_CTRL, u1btmp); + rtl_write_byte(rtlpriv, SPS1_CTRL, 0x0); + rtl_write_byte(rtlpriv, TXPAUSE, 0xFF); + rtl_write_word(rtlpriv, CMDR, 0x57FC); + udelay(100); + rtl_write_word(rtlpriv, CMDR, 0x77FC); + rtl_write_byte(rtlpriv, PHY_CCA, 0x0); + udelay(10); + rtl_write_word(rtlpriv, CMDR, 0x37FC); + udelay(10); + rtl_write_word(rtlpriv, CMDR, 0x77FC); + udelay(10); + rtl_write_word(rtlpriv, CMDR, 0x57FC); + rtl_write_word(rtlpriv, CMDR, 0x0000); + + if (rtlhal->driver_going2unload) { + u1btmp = rtl_read_byte(rtlpriv, (REG_SYS_FUNC_EN + 1)); + u1btmp &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1btmp); + } + + u1btmp = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + + /* Add description. After switch control path. register + * after page1 will be invisible. We can not do any IO + * for register>0x40. After resume&MACIO reset, we need + * to remember previous reg content. */ + if (u1btmp & BIT(7)) { + u1btmp &= ~(BIT(6) | BIT(7)); + if (!_rtl92s_set_sysclk(hw, u1btmp)) { + printk(KERN_ERR "Switch ctrl path fail\n"); + return; + } + } + + /* Power save for MAC */ + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS && + !rtlhal->driver_going2unload) { + /* enable LED function */ + rtl_write_byte(rtlpriv, 0x03, 0xF9); + /* SW/HW radio off or halt adapter!! For example S3/S4 */ + } else { + /* LED function disable. Power range is about 8mA now. */ + /* if write 0xF1 disconnet_pci power + * ifconfig wlan0 down power are both high 35:70 */ + /* if write oxF9 disconnet_pci power + * ifconfig wlan0 down power are both low 12:45*/ + rtl_write_byte(rtlpriv, 0x03, 0xF9); + } + + rtl_write_byte(rtlpriv, SYS_CLKR + 1, 0x70); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, 0x68); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x00); + rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, 0x0E); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + +} + +static void _rtl92se_gen_refreshledstate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + + if (rtlpci->up_first_time == 1) + return; + + if (rtlpriv->psc.rfoff_reason == RF_CHANGE_BY_IPS) + rtl92se_sw_led_on(hw, pLed0); + else + rtl92se_sw_led_off(hw, pLed0); +} + + +static void _rtl92se_power_domain_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 tmpu2b; + u8 tmpu1b; + + rtlpriv->psc.pwrdomain_protect = true; + + tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + if (tmpu1b & BIT(7)) { + tmpu1b &= ~(BIT(6) | BIT(7)); + if (!_rtl92s_set_sysclk(hw, tmpu1b)) { + rtlpriv->psc.pwrdomain_protect = false; + return; + } + } + + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x0); + rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); + + /* Reset MAC-IO and CPU and Core Digital BIT10/11/15 */ + tmpu1b = rtl_read_byte(rtlpriv, SYS_FUNC_EN + 1); + + /* If IPS we need to turn LED on. So we not + * not disable BIT 3/7 of reg3. */ + if (rtlpriv->psc.rfoff_reason & (RF_CHANGE_BY_IPS | RF_CHANGE_BY_HW)) + tmpu1b &= 0xFB; + else + tmpu1b &= 0x73; + + rtl_write_byte(rtlpriv, SYS_FUNC_EN + 1, tmpu1b); + /* wait for BIT 10/11/15 to pull high automatically!! */ + mdelay(1); + + rtl_write_byte(rtlpriv, CMDR, 0); + rtl_write_byte(rtlpriv, TCR, 0); + + /* Data sheet not define 0x562!!! Copy from WMAC!!!!! */ + tmpu1b = rtl_read_byte(rtlpriv, 0x562); + tmpu1b |= 0x08; + rtl_write_byte(rtlpriv, 0x562, tmpu1b); + tmpu1b &= ~(BIT(3)); + rtl_write_byte(rtlpriv, 0x562, tmpu1b); + + /* Enable AFE clock source */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, (tmpu1b | 0x01)); + /* Delay 1.5ms */ + udelay(1500); + tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL + 1); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, (tmpu1b & 0xfb)); + + /* Enable AFE Macro Block's Bandgap */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); + rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | BIT(0))); + mdelay(1); + + /* Enable AFE Mbias */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); + rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | 0x02)); + mdelay(1); + + /* Enable LDOA15 block */ + tmpu1b = rtl_read_byte(rtlpriv, LDOA15_CTRL); + rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0))); + + /* Set Digital Vdd to Retention isolation Path. */ + tmpu2b = rtl_read_word(rtlpriv, SYS_ISO_CTRL); + rtl_write_word(rtlpriv, SYS_ISO_CTRL, (tmpu2b | BIT(11))); + + + /* For warm reboot NIC disappera bug. */ + tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN); + rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(13))); + + rtl_write_byte(rtlpriv, SYS_ISO_CTRL + 1, 0x68); + + /* Enable AFE PLL Macro Block */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4))); + /* Enable MAC 80MHZ clock */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL + 1); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, (tmpu1b | BIT(0))); + mdelay(1); + + /* Release isolation AFE PLL & MD */ + rtl_write_byte(rtlpriv, SYS_ISO_CTRL, 0xA6); + + /* Enable MAC clock */ + tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); + rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11))); + + /* Enable Core digital and enable IOREG R/W */ + tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN); + rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11))); + /* enable REG_EN */ + rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15))); + + /* Switch the control path. */ + tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); + rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b & (~BIT(2)))); + + tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6))); + if (!_rtl92s_set_sysclk(hw, tmpu1b)) { + rtlpriv->psc.pwrdomain_protect = false; + return; + } + + rtl_write_word(rtlpriv, CMDR, 0x37FC); + + /* After MACIO reset,we must refresh LED state. */ + _rtl92se_gen_refreshledstate(hw); + + rtlpriv->psc.pwrdomain_protect = false; +} + +void rtl92se_card_disable(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + enum nl80211_iftype opmode; + u8 wait = 30; + + rtlpriv->intf_ops->enable_aspm(hw); + + if (rtlpci->driver_is_goingto_unload || + ppsc->rfoff_reason > RF_CHANGE_BY_PS) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + + /* we should chnge GPIO to input mode + * this will drop away current about 25mA*/ + rtl8192se_gpiobit3_cfg_inputmode(hw); + + /* this is very important for ips power save */ + while (wait-- >= 10 && rtlpriv->psc.pwrdomain_protect) { + if (rtlpriv->psc.pwrdomain_protect) + mdelay(20); + else + break; + } + + mac->link_state = MAC80211_NOLINK; + opmode = NL80211_IFTYPE_UNSPECIFIED; + _rtl92se_set_media_status(hw, opmode); + + _rtl92s_phy_set_rfhalt(hw); + udelay(100); +} + +void rtl92se_interrupt_recognized(struct ieee80211_hw *hw, u32 *p_inta, + u32 *p_intb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0]; + rtl_write_dword(rtlpriv, ISR, *p_inta); + + *p_intb = rtl_read_dword(rtlpriv, ISR + 4) & rtlpci->irq_mask[1]; + rtl_write_dword(rtlpriv, ISR + 4, *p_intb); +} + +void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcntime_cfg = 0; + u16 bcn_cw = 6, bcn_ifs = 0xf; + u16 atim_window = 2; + + /* ATIM Window (in unit of TU). */ + rtl_write_word(rtlpriv, ATIMWND, atim_window); + + /* Beacon interval (in unit of TU). */ + rtl_write_word(rtlpriv, BCN_INTERVAL, mac->beacon_interval); + + /* DrvErlyInt (in unit of TU). (Time to send + * interrupt to notify driver to change + * beacon content) */ + rtl_write_word(rtlpriv, BCN_DRV_EARLY_INT, 10 << 4); + + /* BcnDMATIM(in unit of us). Indicates the + * time before TBTT to perform beacon queue DMA */ + rtl_write_word(rtlpriv, BCN_DMATIME, 256); + + /* Force beacon frame transmission even + * after receiving beacon frame from + * other ad hoc STA */ + rtl_write_byte(rtlpriv, BCN_ERR_THRESH, 100); + + /* Beacon Time Configuration */ + if (mac->opmode == NL80211_IFTYPE_ADHOC) + bcntime_cfg |= (bcn_cw << BCN_TCFG_CW_SHIFT); + + /* TODO: bcn_ifs may required to be changed on ASIC */ + bcntime_cfg |= bcn_ifs << BCN_TCFG_IFS; + + /*for beacon changed */ + rtl92s_phy_set_beacon_hwreg(hw, mac->beacon_interval); +} + +void rtl92se_set_beacon_interval(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcn_interval = mac->beacon_interval; + + /* Beacon interval (in unit of TU). */ + rtl_write_word(rtlpriv, BCN_INTERVAL, bcn_interval); + /* 2008.10.24 added by tynli for beacon changed. */ + rtl92s_phy_set_beacon_hwreg(hw, bcn_interval); +} + +void rtl92se_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr)); + + if (add_msr) + rtlpci->irq_mask[0] |= add_msr; + + if (rm_msr) + rtlpci->irq_mask[0] &= (~rm_msr); + + rtl92se_disable_interrupt(hw); + rtl92se_enable_interrupt(hw); +} + +static void _rtl8192se_get_IC_Inferiority(struct ieee80211_hw *hw) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 efuse_id; + + rtlhal->ic_class = IC_INFERIORITY_A; + + /* Only retrieving while using EFUSE. */ + if ((rtlefuse->epromtype == EEPROM_BOOT_EFUSE) && + !rtlefuse->autoload_failflag) { + efuse_id = efuse_read_1byte(hw, EFUSE_IC_ID_OFFSET); + + if (efuse_id == 0xfe) + rtlhal->ic_class = IC_INFERIORITY_B; + } +} + +static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u16 i, usvalue; + u16 eeprom_id; + u8 tempval; + u8 hwinfo[HWSET_MAX_SIZE_92S]; + u8 rf_path, index; + + if (rtlefuse->epromtype == EEPROM_93C46) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("RTL819X Not boot from eeprom, check it !!")); + } else if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { + rtl_efuse_shadow_map_update(hw); + + memcpy((void *)hwinfo, (void *) + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + HWSET_MAX_SIZE_92S); + } + + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"), + hwinfo, HWSET_MAX_SIZE_92S); + + eeprom_id = *((u16 *)&hwinfo[0]); + if (eeprom_id != RTL8190_EEPROM_ID) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("EEPROM ID(%#x) is invalid!!\n", eeprom_id)); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n")); + rtlefuse->autoload_failflag = false; + } + + if (rtlefuse->autoload_failflag == true) + return; + + _rtl8192se_get_IC_Inferiority(hw); + + /* Read IC Version && Channel Plan */ + /* VID, DID SE 0xA-D */ + rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; + rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; + rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; + rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; + rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROMId = 0x%4x\n", eeprom_id)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid)); + + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; + *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; + } + + for (i = 0; i < 6; i++) + rtl_write_byte(rtlpriv, MACIDR0 + i, rtlefuse->dev_addr[i]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + (MAC_FMT "\n", MAC_ARG(rtlefuse->dev_addr))); + + /* Get Tx Power Level by Channel */ + /* Read Tx power of Channel 1 ~ 14 from EEPROM. */ + /* 92S suupport RF A & B */ + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 3; i++) { + /* Read CCK RF A & B Tx power */ + rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][i] = + hwinfo[EEPROM_TXPOWERBASE + rf_path * 3 + i]; + + /* Read OFDM RF A & B Tx power for 1T */ + rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] = + hwinfo[EEPROM_TXPOWERBASE + 6 + rf_path * 3 + i]; + + /* Read OFDM RF A & B Tx power for 2T */ + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i] + = hwinfo[EEPROM_TXPOWERBASE + 12 + + rf_path * 3 + i]; + } + } + + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + ("RF(%d) EEPROM CCK Area(%d) = 0x%x\n", rf_path, + i, rtlefuse->eeprom_chnlarea_txpwr_cck + [rf_path][i])); + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + ("RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse->eeprom_chnlarea_txpwr_ht40_1s + [rf_path][i])); + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + ("RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif + [rf_path][i])); + + for (rf_path = 0; rf_path < 2; rf_path++) { + + /* Assign dedicated channel tx power */ + for (i = 0; i < 14; i++) { + /* channel 1~3 use the same Tx Power Level. */ + if (i < 3) + index = 0; + /* Channel 4-8 */ + else if (i < 8) + index = 1; + /* Channel 9-14 */ + else + index = 2; + + /* Record A & B CCK /OFDM - 1T/2T Channel area + * tx power */ + rtlefuse->txpwrlevel_cck[rf_path][i] = + rtlefuse->eeprom_chnlarea_txpwr_cck + [rf_path][index]; + rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = + rtlefuse->eeprom_chnlarea_txpwr_ht40_1s + [rf_path][index]; + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif + [rf_path][index]; + } + + for (i = 0; i < 14; i++) { + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = " + "[0x%x / 0x%x / 0x%x]\n", rf_path, i, + rtlefuse->txpwrlevel_cck[rf_path][i], + rtlefuse->txpwrlevel_ht40_1s[rf_path][i], + rtlefuse->txpwrlevel_ht40_2s[rf_path][i])); + } + } + + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 3; i++) { + /* Read Power diff limit. */ + rtlefuse->eeprom_pwrgroup[rf_path][i] = + hwinfo[EEPROM_TXPWRGROUP + rf_path * 3 + i]; + } + } + + for (rf_path = 0; rf_path < 2; rf_path++) { + /* Fill Pwr group */ + for (i = 0; i < 14; i++) { + /* Chanel 1-3 */ + if (i < 3) + index = 0; + /* Channel 4-8 */ + else if (i < 8) + index = 1; + /* Channel 9-13 */ + else + index = 2; + + rtlefuse->pwrgroup_ht20[rf_path][i] = + (rtlefuse->eeprom_pwrgroup[rf_path][index] & + 0xf); + rtlefuse->pwrgroup_ht40[rf_path][i] = + ((rtlefuse->eeprom_pwrgroup[rf_path][index] & + 0xf0) >> 4); + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF-%d pwrgroup_ht20[%d] = 0x%x\n", + rf_path, i, + rtlefuse->pwrgroup_ht20[rf_path][i])); + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF-%d pwrgroup_ht40[%d] = 0x%x\n", + rf_path, i, + rtlefuse->pwrgroup_ht40[rf_path][i])); + } + } + + for (i = 0; i < 14; i++) { + /* Read tx power difference between HT OFDM 20/40 MHZ */ + /* channel 1-3 */ + if (i < 3) + index = 0; + /* Channel 4-8 */ + else if (i < 8) + index = 1; + /* Channel 9-14 */ + else + index = 2; + + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_HT20_DIFF + + index]) & 0xff; + rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF); + rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] = + ((tempval >> 4) & 0xF); + + /* Read OFDM<->HT tx power diff */ + /* Channel 1-3 */ + if (i < 3) + index = 0; + /* Channel 4-8 */ + else if (i < 8) + index = 0x11; + /* Channel 9-14 */ + else + index = 1; + + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_OFDM_DIFF + index]) + & 0xff; + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] = + (tempval & 0xF); + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] = + ((tempval >> 4) & 0xF); + + tempval = (*(u8 *)&hwinfo[TX_PWR_SAFETY_CHK]); + rtlefuse->txpwr_safetyflag = (tempval & 0x01); + } + + rtlefuse->eeprom_regulatory = 0; + if (rtlefuse->eeprom_version >= 2) { + /* BIT(0)~2 */ + if (rtlefuse->eeprom_version >= 4) + rtlefuse->eeprom_regulatory = + (hwinfo[EEPROM_REGULATORY] & 0x7); + else /* BIT(0) */ + rtlefuse->eeprom_regulatory = + (hwinfo[EEPROM_REGULATORY] & 0x1); + } + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory)); + + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i, + rtlefuse->txpwr_ht20diff[RF90_PATH_A][i])); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i, + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i])); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i, + rtlefuse->txpwr_ht20diff[RF90_PATH_B][i])); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i, + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i])); + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TxPwrSafetyFlag = %d\n", + rtlefuse->txpwr_safetyflag)); + + /* Read RF-indication and Tx Power gain + * index diff of legacy to HT OFDM rate. */ + tempval = (*(u8 *)&hwinfo[EEPROM_RFIND_POWERDIFF]) & 0xff; + rtlefuse->eeprom_txpowerdiff = tempval; + rtlefuse->legacy_httxpowerdiff = + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][0]; + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TxPowerDiff = %#x\n", + rtlefuse->eeprom_txpowerdiff)); + + /* Get TSSI value for each path. */ + usvalue = *(u16 *)&hwinfo[EEPROM_TSSI_A]; + rtlefuse->eeprom_tssi[RF90_PATH_A] = (u8)((usvalue & 0xff00) >> 8); + usvalue = *(u8 *)&hwinfo[EEPROM_TSSI_B]; + rtlefuse->eeprom_tssi[RF90_PATH_B] = (u8)(usvalue & 0xff); + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TSSI_A = 0x%x, TSSI_B = 0x%x\n", + rtlefuse->eeprom_tssi[RF90_PATH_A], + rtlefuse->eeprom_tssi[RF90_PATH_B])); + + /* Read antenna tx power offset of B/C/D to A from EEPROM */ + /* and read ThermalMeter from EEPROM */ + tempval = *(u8 *)&hwinfo[EEPROM_THERMALMETER]; + rtlefuse->eeprom_thermalmeter = tempval; + RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("thermalmeter = 0x%x\n", + rtlefuse->eeprom_thermalmeter)); + + /* ThermalMeter, BIT(0)~3 for RFIC1, BIT(4)~7 for RFIC2 */ + rtlefuse->thermalmeter[0] = (rtlefuse->eeprom_thermalmeter & 0x1f); + rtlefuse->tssi_13dbm = rtlefuse->eeprom_thermalmeter * 100; + + /* Read CrystalCap from EEPROM */ + tempval = (*(u8 *)&hwinfo[EEPROM_CRYSTALCAP]) >> 4; + rtlefuse->eeprom_crystalcap = tempval; + /* CrystalCap, BIT(12)~15 */ + rtlefuse->crystalcap = rtlefuse->eeprom_crystalcap; + + /* Read IC Version && Channel Plan */ + /* Version ID, Channel plan */ + rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; + rtlefuse->txpwr_fromeprom = true; + RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("EEPROM ChannelPlan = 0x%4x\n", + rtlefuse->eeprom_channelplan)); + + /* Read Customer ID or Board Type!!! */ + tempval = *(u8 *)&hwinfo[EEPROM_BOARDTYPE]; + /* Change RF type definition */ + if (tempval == 0) + rtlphy->rf_type = RF_2T2R; + else if (tempval == 1) + rtlphy->rf_type = RF_1T2R; + else if (tempval == 2) + rtlphy->rf_type = RF_1T2R; + else if (tempval == 3) + rtlphy->rf_type = RF_1T1R; + + /* 1T2R but 1SS (1x1 receive combining) */ + rtlefuse->b1x1_recvcombine = false; + if (rtlphy->rf_type == RF_1T2R) { + tempval = rtl_read_byte(rtlpriv, 0x07); + if (!(tempval & BIT(0))) { + rtlefuse->b1x1_recvcombine = true; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("RF_TYPE=1T2R but only 1SS\n")); + } + } + rtlefuse->b1ss_support = rtlefuse->b1x1_recvcombine; + rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMID]; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("EEPROM Customer ID: 0x%2x", + rtlefuse->eeprom_oemid)); + + /* set channel paln to world wide 13 */ + rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; +} + +void rtl92se_read_eeprom_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 tmp_u1b = 0; + + tmp_u1b = rtl_read_byte(rtlpriv, EPROM_CMD); + + if (tmp_u1b & BIT(4)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EEPROM\n")); + rtlefuse->epromtype = EEPROM_93C46; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EFUSE\n")); + rtlefuse->epromtype = EEPROM_BOOT_EFUSE; + } + + if (tmp_u1b & BIT(5)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n")); + rtlefuse->autoload_failflag = false; + _rtl92se_read_adapter_info(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n")); + rtlefuse->autoload_failflag = true; + } +} + +static void rtl92se_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 ratr_value; + u8 ratr_index = 0; + u8 nmode = mac->ht_enable; + u8 mimo_ps = IEEE80211_SMPS_OFF; + u16 shortgi_rate = 0; + u32 tmp_ratr_value = 0; + u8 curtxbw_40mhz = mac->bw_40; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = mac->mode; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_value = sta->supp_rates[1] << 4; + else + ratr_value = sta->supp_rates[0]; + ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + ratr_value &= 0x0000000D; + break; + case WIRELESS_MODE_G: + ratr_value &= 0x00000FF5; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + nmode = 1; + if (mimo_ps == IEEE80211_SMPS_STATIC) { + ratr_value &= 0x0007F005; + } else { + u32 ratr_mask; + + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_1T1R) { + if (curtxbw_40mhz) + ratr_mask = 0x000ff015; + else + ratr_mask = 0x000ff005; + } else { + if (curtxbw_40mhz) + ratr_mask = 0x0f0ff015; + else + ratr_mask = 0x0f0ff005; + } + + ratr_value &= ratr_mask; + } + break; + default: + if (rtlphy->rf_type == RF_1T2R) + ratr_value &= 0x000ff0ff; + else + ratr_value &= 0x0f0ff0ff; + + break; + } + + if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT) + ratr_value &= 0x0FFFFFFF; + else if (rtlpriv->rtlhal.version == VERSION_8192S_ACUT) + ratr_value &= 0x0FFFFFF0; + + if (nmode && ((curtxbw_40mhz && + curshortgi_40mhz) || (!curtxbw_40mhz && + curshortgi_20mhz))) { + + ratr_value |= 0x10000000; + tmp_ratr_value = (ratr_value >> 12); + + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { + if ((1 << shortgi_rate) & tmp_ratr_value) + break; + } + + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | + (shortgi_rate << 4) | (shortgi_rate); + + rtl_write_byte(rtlpriv, SG_RATE, shortgi_rate); + } + + rtl_write_dword(rtlpriv, ARFR0 + ratr_index * 4, ratr_value); + if (ratr_value & 0xfffff000) + rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_REFRESH_N); + else + rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_REFRESH_BG); + + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + ("%x\n", rtl_read_dword(rtlpriv, ARFR0))); +} + +static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u32 ratr_bitmap; + u8 ratr_index = 0; + u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ? 1 : 0; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = 0; + bool shortgi = false; + u32 ratr_value = 0; + u8 shortgi_rate = 0; + u32 mask = 0; + u32 band = 0; + bool bmulticast = false; + u8 macid = 0; + u8 mimo_ps = IEEE80211_SMPS_OFF; + + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + wirelessmode = sta_entry->wireless_mode; + if (mac->opmode == NL80211_IFTYPE_STATION) + curtxbw_40mhz = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_bitmap = sta->supp_rates[1] << 4; + else + ratr_bitmap = sta->supp_rates[0]; + ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + band |= WIRELESS_11B; + ratr_index = RATR_INX_WIRELESS_B; + if (ratr_bitmap & 0x0000000c) + ratr_bitmap &= 0x0000000d; + else + ratr_bitmap &= 0x0000000f; + break; + case WIRELESS_MODE_G: + band |= (WIRELESS_11G | WIRELESS_11B); + ratr_index = RATR_INX_WIRELESS_GB; + + if (rssi_level == 1) + ratr_bitmap &= 0x00000f00; + else if (rssi_level == 2) + ratr_bitmap &= 0x00000ff0; + else + ratr_bitmap &= 0x00000ff5; + break; + case WIRELESS_MODE_A: + band |= WIRELESS_11A; + ratr_index = RATR_INX_WIRELESS_A; + ratr_bitmap &= 0x00000ff0; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + band |= (WIRELESS_11N | WIRELESS_11G | WIRELESS_11B); + ratr_index = RATR_INX_WIRELESS_NGB; + + if (mimo_ps == IEEE80211_SMPS_STATIC) { + if (rssi_level == 1) + ratr_bitmap &= 0x00070000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0007f000; + else + ratr_bitmap &= 0x0007f005; + } else { + if (rtlphy->rf_type == RF_1T2R || + rtlphy->rf_type == RF_1T1R) { + if (rssi_level == 1) { + ratr_bitmap &= 0x000f0000; + } else if (rssi_level == 3) { + ratr_bitmap &= 0x000fc000; + } else if (rssi_level == 5) { + ratr_bitmap &= 0x000ff000; + } else { + if (curtxbw_40mhz) + ratr_bitmap &= 0x000ff015; + else + ratr_bitmap &= 0x000ff005; + } + } else { + if (rssi_level == 1) { + ratr_bitmap &= 0x0f8f0000; + } else if (rssi_level == 3) { + ratr_bitmap &= 0x0f8fc000; + } else if (rssi_level == 5) { + ratr_bitmap &= 0x0f8ff000; + } else { + if (curtxbw_40mhz) + ratr_bitmap &= 0x0f8ff015; + else + ratr_bitmap &= 0x0f8ff005; + } + } + } + + if ((curtxbw_40mhz && curshortgi_40mhz) || + (!curtxbw_40mhz && curshortgi_20mhz)) { + if (macid == 0) + shortgi = true; + else if (macid == 1) + shortgi = false; + } + break; + default: + band |= (WIRELESS_11N | WIRELESS_11G | WIRELESS_11B); + ratr_index = RATR_INX_WIRELESS_NGB; + + if (rtlphy->rf_type == RF_1T2R) + ratr_bitmap &= 0x000ff0ff; + else + ratr_bitmap &= 0x0f8ff0ff; + break; + } + + if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT) + ratr_bitmap &= 0x0FFFFFFF; + else if (rtlpriv->rtlhal.version == VERSION_8192S_ACUT) + ratr_bitmap &= 0x0FFFFFF0; + + if (shortgi) { + ratr_bitmap |= 0x10000000; + /* Get MAX MCS available. */ + ratr_value = (ratr_bitmap >> 12); + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { + if ((1 << shortgi_rate) & ratr_value) + break; + } + + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | + (shortgi_rate << 4) | (shortgi_rate); + rtl_write_byte(rtlpriv, SG_RATE, shortgi_rate); + } + + mask |= (bmulticast ? 1 : 0) << 9 | (macid & 0x1f) << 4 | (band & 0xf); + + RT_TRACE(rtlpriv, COMP_RATR, DBG_TRACE, ("mask = %x, bitmap = %x\n", + mask, ratr_bitmap)); + rtl_write_dword(rtlpriv, 0x2c4, ratr_bitmap); + rtl_write_dword(rtlpriv, WFM5, (FW_RA_UPDATE_MASK | (mask << 8))); + + if (macid != 0) + sta_entry->ratr_index = ratr_index; +} + +void rtl92se_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->dm.useramask) + rtl92se_update_hal_rate_mask(hw, sta, rssi_level); + else + rtl92se_update_hal_rate_table(hw, sta); +} + +void rtl92se_update_channel_access_setting(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 sifs_timer; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, + (u8 *)&mac->slot_time); + sifs_timer = 0x0e0e; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); + +} + +/* this ifunction is for RFKILL, it's different with windows, + * because UI will disable wireless when GPIO Radio Off. + * And here we not check or Disable/Enable ASPM like windows*/ +bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + enum rf_pwrstate rfpwr_toset, cur_rfstate; + unsigned long flag = 0; + bool actuallyset = false; + bool turnonbypowerdomain = false; + + /* just 8191se can check gpio before firstup, 92c/92d have fixed it */ + if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter)) + return false; + + if (ppsc->swrf_processing) + return false; + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + if (ppsc->rfchange_inprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + return false; + } else { + ppsc->rfchange_inprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + + cur_rfstate = ppsc->rfpwr_state; + + /* because after _rtl92s_phy_set_rfhalt, all power + * closed, so we must open some power for GPIO check, + * or we will always check GPIO RFOFF here, + * And we should close power after GPIO check */ + if (RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { + _rtl92se_power_domain_init(hw); + turnonbypowerdomain = true; + } + + rfpwr_toset = _rtl92se_rf_onoff_detect(hw); + + if ((ppsc->hwradiooff == true) && (rfpwr_toset == ERFON)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("RFKILL-HW Radio ON, RF ON\n")); + + rfpwr_toset = ERFON; + ppsc->hwradiooff = false; + actuallyset = true; + } else if ((ppsc->hwradiooff == false) && (rfpwr_toset == ERFOFF)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("RFKILL-HW Radio OFF, RF OFF\n")); + + rfpwr_toset = ERFOFF; + ppsc->hwradiooff = true; + actuallyset = true; + } + + if (actuallyset) { + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + + /* this not include ifconfig wlan0 down case */ + /* } else if (rfpwr_toset == ERFOFF || cur_rfstate == ERFOFF) { */ + } else { + /* because power_domain_init may be happen when + * _rtl92s_phy_set_rfhalt, this will open some powers + * and cause current increasing about 40 mA for ips, + * rfoff and ifconfig down, so we set + * _rtl92s_phy_set_rfhalt again here */ + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC && + turnonbypowerdomain) { + _rtl92s_phy_set_rfhalt(hw); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + } + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + + *valid = 1; + return !ppsc->hwradiooff; + +} + +/* Is_wepkey just used for WEP used as group & pairwise key + * if pairwise is AES ang group is WEP Is_wepkey == false.*/ +void rtl92se_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr, + bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 *macaddr = p_macaddr; + + u32 entry_id = 0; + bool is_pairwise = false; + + static u8 cam_const_addr[4][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x03} + }; + static u8 cam_const_broad[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + if (clear_all) { + u8 idx = 0; + u8 cam_offset = 0; + u8 clear_number = 5; + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("clear_all\n")); + + for (idx = 0; idx < clear_number; idx++) { + rtl_cam_mark_invalid(hw, cam_offset + idx); + rtl_cam_empty_entry(hw, cam_offset + idx); + + if (idx < 5) { + memset(rtlpriv->sec.key_buf[idx], 0, + MAX_KEY_LEN); + rtlpriv->sec.key_len[idx] = 0; + } + } + + } else { + switch (enc_algo) { + case WEP40_ENCRYPTION: + enc_algo = CAM_WEP40; + break; + case WEP104_ENCRYPTION: + enc_algo = CAM_WEP104; + break; + case TKIP_ENCRYPTION: + enc_algo = CAM_TKIP; + break; + case AESCCMP_ENCRYPTION: + enc_algo = CAM_AES; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + enc_algo = CAM_TKIP; + break; + } + + if (is_wepkey || rtlpriv->sec.use_defaultkey) { + macaddr = cam_const_addr[key_index]; + entry_id = key_index; + } else { + if (is_group) { + macaddr = cam_const_broad; + entry_id = key_index; + } else { + if (mac->opmode == NL80211_IFTYPE_AP) { + entry_id = rtl_cam_get_free_entry(hw, + p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + RT_TRACE(rtlpriv, + COMP_SEC, DBG_EMERG, + ("Can not find free hw" + " security cam entry\n")); + return; + } + } else { + entry_id = CAM_PAIRWISE_KEY_POSITION; + } + + key_index = PAIRWISE_KEYIDX; + is_pairwise = true; + } + } + + if (rtlpriv->sec.key_len[key_index] == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("delete one entry, entry_id is %d\n", + entry_id)); + if (mac->opmode == NL80211_IFTYPE_AP) + rtl_cam_del_entry(hw, p_macaddr); + rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("The insert KEY length is %d\n", + rtlpriv->sec.key_len[PAIRWISE_KEYIDX])); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("The insert KEY is %x %x\n", + rtlpriv->sec.key_buf[0][0], + rtlpriv->sec.key_buf[0][1])); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("add one entry\n")); + if (is_pairwise) { + RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD, + "Pairwiase Key content :", + rtlpriv->sec.pairwise_key, + rtlpriv->sec.key_len[PAIRWISE_KEYIDX]); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("set Pairwiase key\n")); + + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[key_index]); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("set group key\n")); + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + rtl_cam_add_one_entry(hw, + rtlefuse->dev_addr, + PAIRWISE_KEYIDX, + CAM_PAIRWISE_KEY_POSITION, + enc_algo, CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + + } + } +} + +void rtl92se_suspend(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtlpci->up_first_time = true; +} + +void rtl92se_resume(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 val; + + pci_read_config_dword(rtlpci->pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(rtlpci->pdev, 0x40, + val & 0xffff00ff); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h new file mode 100644 index 000000000000..6160a9bfe98a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h @@ -0,0 +1,79 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __REALTEK_PCI92SE_HW_H__ +#define __REALTEK_PCI92SE_HW_H__ + +#define MSR_LINK_MANAGED 2 +#define MSR_LINK_NONE 0 +#define MSR_LINK_SHIFT 0 +#define MSR_LINK_ADHOC 1 +#define MSR_LINK_MASTER 3 + +enum WIRELESS_NETWORK_TYPE { + WIRELESS_11B = 1, + WIRELESS_11G = 2, + WIRELESS_11A = 4, + WIRELESS_11N = 8 +}; + +void rtl92se_get_hw_reg(struct ieee80211_hw *hw, + u8 variable, u8 *val); +void rtl92se_read_eeprom_info(struct ieee80211_hw *hw); +void rtl92se_interrupt_recognized(struct ieee80211_hw *hw, + u32 *inta, u32 *intb); +int rtl92se_hw_init(struct ieee80211_hw *hw); +void rtl92se_card_disable(struct ieee80211_hw *hw); +void rtl92se_enable_interrupt(struct ieee80211_hw *hw); +void rtl92se_disable_interrupt(struct ieee80211_hw *hw); +int rtl92se_set_network_type(struct ieee80211_hw *hw, + enum nl80211_iftype type); +void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr); +void rtl92se_set_qos(struct ieee80211_hw *hw, int aci); +void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl92se_set_beacon_interval(struct ieee80211_hw *hw); +void rtl92se_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr); +void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, + u8 *val); +void rtl92se_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level); +void rtl92se_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, + u8 *valid); +void rtl8192se_gpiobit3_cfg_inputmode(struct ieee80211_hw *hw); +void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw); +void rtl92se_set_key(struct ieee80211_hw *hw, + u32 key_index, u8 *macaddr, bool is_group, + u8 enc_algo, bool is_wepkey, bool clear_all); +void rtl92se_suspend(struct ieee80211_hw *hw); +void rtl92se_resume(struct ieee80211_hw *hw); + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/led.c b/drivers/net/wireless/rtlwifi/rtl8192se/led.c new file mode 100644 index 000000000000..6d4f66616680 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/led.c @@ -0,0 +1,149 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "reg.h" +#include "led.h" + +static void _rtl92se_init_led(struct ieee80211_hw *hw, + struct rtl_led *pled, enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->ledon = false; +} + +void rtl92se_init_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + _rtl92se_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); + _rtl92se_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); +} + +void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + u8 ledcfg; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, + ("LedAddr:%X ledpin=%d\n", LEDCFG, pled->ledpin)); + + ledcfg = rtl_read_byte(rtlpriv, LEDCFG); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0xf0); + break; + case LED_PIN_LED1: + rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0x0f); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + pled->ledon = true; +} + +void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u8 ledcfg; + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, + ("LedAddr:%X ledpin=%d\n", LEDCFG, pled->ledpin)); + + ledcfg = rtl_read_byte(rtlpriv, LEDCFG); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg &= 0xf0; + if (pcipriv->ledctl.led_opendrain == true) + rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(1))); + else + rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3))); + break; + case LED_PIN_LED1: + ledcfg &= 0x0f; + rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3))); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + pled->ledon = false; +} + +static void _rtl92se_sw_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + switch (ledaction) { + case LED_CTL_POWER_ON: + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + rtl92se_sw_led_on(hw, pLed0); + break; + case LED_CTL_POWER_OFF: + rtl92se_sw_led_off(hw, pLed0); + break; + default: + break; + } +} + +void rtl92se_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) && + (ledaction == LED_CTL_TX || + ledaction == LED_CTL_RX || + ledaction == LED_CTL_SITE_SURVEY || + ledaction == LED_CTL_LINK || + ledaction == LED_CTL_NO_LINK || + ledaction == LED_CTL_START_TO_LINK || + ledaction == LED_CTL_POWER_ON)) { + return; + } + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n", + ledaction)); + + _rtl92se_sw_led_control(hw, ledaction); +} + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/led.h b/drivers/net/wireless/rtlwifi/rtl8192se/led.h new file mode 100644 index 000000000000..8cce3870af3c --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/led.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __REALTEK_PCI92SE_LED_H__ +#define __REALTEK_PCI92SE_LED_H__ + +void rtl92se_init_sw_leds(struct ieee80211_hw *hw); +void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92se_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c new file mode 100644 index 000000000000..63b45e60a95e --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c @@ -0,0 +1,1740 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../ps.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" +#include "fw.h" +#include "hw.h" +#include "table.h" + +static u32 _rtl92s_phy_calculate_bit_shift(u32 bitmask) +{ + u32 i; + + for (i = 0; i <= 31; i++) { + if (((bitmask >> i) & 0x1) == 1) + break; + } + + return i; +} + +u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 returnvalue = 0, originalvalue, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)\n", + regaddr, bitmask)); + + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); + returnvalue = (originalvalue & bitmask) >> bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + ("BBR MASK=0x%x Addr[0x%x]=0x%x\n", + bitmask, regaddr, originalvalue)); + + return returnvalue; + +} + +void rtl92s_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, + u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 originalvalue, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," + " data(%#x)\n", regaddr, bitmask, data)); + + if (bitmask != MASKDWORD) { + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); + data = ((originalvalue & (~bitmask)) | (data << bitshift)); + } + + rtl_write_dword(rtlpriv, regaddr, data); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," + " data(%#x)\n", regaddr, bitmask, data)); + +} + +static u32 _rtl92s_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset) +{ + + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + u32 newoffset; + u32 tmplong, tmplong2; + u8 rfpi_enable = 0; + u32 retvalue = 0; + + offset &= 0x3f; + newoffset = offset; + + tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD); + + if (rfpath == RF90_PATH_A) + tmplong2 = tmplong; + else + tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD); + + tmplong2 = (tmplong2 & (~BLSSI_READADDRESS)) | (newoffset << 23) | + BLSSI_READEDGE; + + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, + tmplong & (~BLSSI_READEDGE)); + + mdelay(1); + + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); + mdelay(1); + + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong | + BLSSI_READEDGE); + mdelay(1); + + if (rfpath == RF90_PATH_A) + rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, + BIT(8)); + else if (rfpath == RF90_PATH_B) + rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1, + BIT(8)); + + if (rfpi_enable) + retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi, + BLSSI_READBACK_DATA); + else + retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, + BLSSI_READBACK_DATA); + + retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, + BLSSI_READBACK_DATA); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFR-%d Addr[0x%x]=0x%x\n", + rfpath, pphyreg->rflssi_readback, retvalue)); + + return retvalue; + +} + +static void _rtl92s_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + u32 data_and_addr = 0; + u32 newoffset; + + offset &= 0x3f; + newoffset = offset; + + data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; + rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFW-%d Addr[0x%x]=0x%x\n", + rfpath, pphyreg->rf3wire_offset, data_and_addr)); +} + + +u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 original_value, readback_value, bitshift; + unsigned long flags; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), " + "bitmask(%#x)\n", regaddr, rfpath, bitmask)); + + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + + original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, regaddr); + + bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); + readback_value = (original_value & bitmask) >> bitshift; + + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), " + "bitmask(%#x), original_value(%#x)\n", regaddr, rfpath, + bitmask, original_value)); + + return readback_value; +} + +void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 original_value, bitshift; + unsigned long flags; + + if (!((rtlphy->rf_pathmap >> rfpath) & 0x1)) + return; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," + " data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath)); + + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + + if (bitmask != RFREG_OFFSET_MASK) { + original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, + regaddr); + bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); + data = ((original_value & (~bitmask)) | (data << bitshift)); + } + + _rtl92s_phy_rf_serial_write(hw, rfpath, regaddr, data); + + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x), " + "data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath)); + +} + +void rtl92s_phy_scan_operation_backup(struct ieee80211_hw *hw, + u8 operation) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (!is_hal_stop(rtlhal)) { + switch (operation) { + case SCAN_OPT_BACKUP: + rtl92s_phy_set_fw_cmd(hw, FW_CMD_PAUSE_DM_BY_SCAN); + break; + case SCAN_OPT_RESTORE: + rtl92s_phy_set_fw_cmd(hw, FW_CMD_RESUME_DM_BY_SCAN); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Unknown operation.\n")); + break; + } + } +} + +void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u8 reg_bw_opmode; + u8 reg_prsr_rsc; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("Switch to %s bandwidth\n", + rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? + "20MHz" : "40MHz")); + + if (rtlphy->set_bwmode_inprogress) + return; + if (is_hal_stop(rtlhal)) + return; + + rtlphy->set_bwmode_inprogress = true; + + reg_bw_opmode = rtl_read_byte(rtlpriv, BW_OPMODE); + reg_prsr_rsc = rtl_read_byte(rtlpriv, RRSR + 2); + + switch (rtlphy->current_chan_bw) { + case HT_CHANNEL_WIDTH_20: + reg_bw_opmode |= BW_OPMODE_20MHZ; + rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode); + break; + case HT_CHANNEL_WIDTH_20_40: + reg_bw_opmode &= ~BW_OPMODE_20MHZ; + rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("unknown bandwidth: %#X\n", + rtlphy->current_chan_bw)); + break; + } + + switch (rtlphy->current_chan_bw) { + case HT_CHANNEL_WIDTH_20: + rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0); + rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0); + + if (rtlhal->version >= VERSION_8192S_BCUT) + rtl_write_byte(rtlpriv, RFPGA0_ANALOGPARAMETER2, 0x58); + break; + case HT_CHANNEL_WIDTH_20_40: + rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); + rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); + + rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND, + (mac->cur_40_prime_sc >> 1)); + rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); + + if (rtlhal->version >= VERSION_8192S_BCUT) + rtl_write_byte(rtlpriv, RFPGA0_ANALOGPARAMETER2, 0x18); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); + break; + } + + rtl92s_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); + rtlphy->set_bwmode_inprogress = false; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); +} + +static bool _rtl92s_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, + u32 cmdtableidx, u32 cmdtablesz, enum swchnlcmd_id cmdid, + u32 para1, u32 para2, u32 msdelay) +{ + struct swchnlcmd *pcmd; + + if (cmdtable == NULL) { + RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); + return false; + } + + if (cmdtableidx >= cmdtablesz) + return false; + + pcmd = cmdtable + cmdtableidx; + pcmd->cmdid = cmdid; + pcmd->para1 = para1; + pcmd->para2 = para2; + pcmd->msdelay = msdelay; + + return true; +} + +static bool _rtl92s_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, + u8 channel, u8 *stage, u8 *step, u32 *delay) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct swchnlcmd precommoncmd[MAX_PRECMD_CNT]; + u32 precommoncmdcnt; + struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT]; + u32 postcommoncmdcnt; + struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT]; + u32 rfdependcmdcnt; + struct swchnlcmd *currentcmd = NULL; + u8 rfpath; + u8 num_total_rfpath = rtlphy->num_total_rfpath; + + precommoncmdcnt = 0; + _rtl92s_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0); + _rtl92s_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); + + postcommoncmdcnt = 0; + + _rtl92s_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, + MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0); + + rfdependcmdcnt = 0; + + RT_ASSERT((channel >= 1 && channel <= 14), + ("illegal channel for Zebra: %d\n", channel)); + + _rtl92s_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG, + RF_CHNLBW, channel, 10); + + _rtl92s_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0); + + do { + switch (*stage) { + case 0: + currentcmd = &precommoncmd[*step]; + break; + case 1: + currentcmd = &rfdependcmd[*step]; + break; + case 2: + currentcmd = &postcommoncmd[*step]; + break; + } + + if (currentcmd->cmdid == CMDID_END) { + if ((*stage) == 2) { + return true; + } else { + (*stage)++; + (*step) = 0; + continue; + } + } + + switch (currentcmd->cmdid) { + case CMDID_SET_TXPOWEROWER_LEVEL: + rtl92s_phy_set_txpower(hw, channel); + break; + case CMDID_WRITEPORT_ULONG: + rtl_write_dword(rtlpriv, currentcmd->para1, + currentcmd->para2); + break; + case CMDID_WRITEPORT_USHORT: + rtl_write_word(rtlpriv, currentcmd->para1, + (u16)currentcmd->para2); + break; + case CMDID_WRITEPORT_UCHAR: + rtl_write_byte(rtlpriv, currentcmd->para1, + (u8)currentcmd->para2); + break; + case CMDID_RF_WRITEREG: + for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) { + rtlphy->rfreg_chnlval[rfpath] = + ((rtlphy->rfreg_chnlval[rfpath] & + 0xfffffc00) | currentcmd->para2); + rtl_set_rfreg(hw, (enum radio_path)rfpath, + currentcmd->para1, + RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[rfpath]); + } + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + + break; + } while (true); + + (*delay) = currentcmd->msdelay; + (*step)++; + return false; +} + +u8 rtl92s_phy_sw_chnl(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 delay; + bool ret; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, + ("switch to channel%d\n", + rtlphy->current_channel)); + + if (rtlphy->sw_chnl_inprogress) + return 0; + + if (rtlphy->set_bwmode_inprogress) + return 0; + + if (is_hal_stop(rtlhal)) + return 0; + + rtlphy->sw_chnl_inprogress = true; + rtlphy->sw_chnl_stage = 0; + rtlphy->sw_chnl_step = 0; + + do { + if (!rtlphy->sw_chnl_inprogress) + break; + + ret = _rtl92s_phy_sw_chnl_step_by_step(hw, + rtlphy->current_channel, + &rtlphy->sw_chnl_stage, + &rtlphy->sw_chnl_step, &delay); + if (!ret) { + if (delay > 0) + mdelay(delay); + else + continue; + } else { + rtlphy->sw_chnl_inprogress = false; + } + break; + } while (true); + + rtlphy->sw_chnl_inprogress = false; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); + + return 1; +} + +static void _rtl92se_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1btmp; + + u1btmp = rtl_read_byte(rtlpriv, LDOV12D_CTRL); + u1btmp |= BIT(0); + + rtl_write_byte(rtlpriv, LDOV12D_CTRL, u1btmp); + rtl_write_byte(rtlpriv, SPS1_CTRL, 0x0); + rtl_write_byte(rtlpriv, TXPAUSE, 0xFF); + rtl_write_word(rtlpriv, CMDR, 0x57FC); + udelay(100); + + rtl_write_word(rtlpriv, CMDR, 0x77FC); + rtl_write_byte(rtlpriv, PHY_CCA, 0x0); + udelay(10); + + rtl_write_word(rtlpriv, CMDR, 0x37FC); + udelay(10); + + rtl_write_word(rtlpriv, CMDR, 0x77FC); + udelay(10); + + rtl_write_word(rtlpriv, CMDR, 0x57FC); + + /* we should chnge GPIO to input mode + * this will drop away current about 25mA*/ + rtl8192se_gpiobit3_cfg_inputmode(hw); +} + +bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool bresult = true; + u8 i, queue_id; + struct rtl8192_tx_ring *ring = NULL; + + if (rfpwr_state == ppsc->rfpwr_state) + return false; + + ppsc->set_rfpowerstate_inprogress = true; + + switch (rfpwr_state) { + case ERFON:{ + if ((ppsc->rfpwr_state == ERFOFF) && + RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { + + bool rtstatus; + u32 InitializeCount = 0; + do { + InitializeCount++; + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("IPS Set eRf nic enable\n")); + rtstatus = rtl_ps_enable_nic(hw); + } while ((rtstatus != true) && + (InitializeCount < 10)); + + RT_CLEAR_PS_LEVEL(ppsc, + RT_RF_OFF_LEVL_HALT_NIC); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + ("awake, sleeped:%d ms " + "state_inap:%x\n", + jiffies_to_msecs(jiffies - + ppsc->last_sleep_jiffies), + rtlpriv->psc.state_inap)); + ppsc->last_awake_jiffies = jiffies; + rtl_write_word(rtlpriv, CMDR, 0x37FC); + rtl_write_byte(rtlpriv, TXPAUSE, 0x00); + rtl_write_byte(rtlpriv, PHY_CCA, 0x3); + } + + if (mac->link_state == MAC80211_LINKED) + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_LINK); + else + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_NO_LINK); + break; + } + case ERFOFF:{ + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("IPS Set eRf nic disable\n")); + rtl_ps_disable_nic(hw); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + } else { + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_NO_LINK); + else + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_POWER_OFF); + } + break; + } + case ERFSLEEP: + if (ppsc->rfpwr_state == ERFOFF) + break; + + for (queue_id = 0, i = 0; + queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { + ring = &pcipriv->dev.tx_ring[queue_id]; + if (skb_queue_len(&ring->queue) == 0 || + queue_id == BEACON_QUEUE) { + queue_id++; + continue; + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("eRf Off/Sleep: " + "%d times TcbBusyQueue[%d] = " + "%d before doze!\n", + (i + 1), queue_id, + skb_queue_len(&ring->queue))); + + udelay(10); + i++; + } + + if (i >= MAX_DOZE_WAITING_TIMES_9x) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("\nERFOFF: %d times" + "TcbBusyQueue[%d] = %d !\n", + MAX_DOZE_WAITING_TIMES_9x, + queue_id, + skb_queue_len(&ring->queue))); + break; + } + } + + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + ("Set ERFSLEEP awaked:%d ms\n", + jiffies_to_msecs(jiffies - + ppsc->last_awake_jiffies))); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + ("sleep awaked:%d ms " + "state_inap:%x\n", jiffies_to_msecs(jiffies - + ppsc->last_awake_jiffies), + rtlpriv->psc.state_inap)); + ppsc->last_sleep_jiffies = jiffies; + _rtl92se_phy_set_rf_sleep(hw); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + bresult = false; + break; + } + + if (bresult) + ppsc->rfpwr_state = rfpwr_state; + + ppsc->set_rfpowerstate_inprogress = false; + + return bresult; +} + +static bool _rtl92s_phy_config_rfpa_bias_current(struct ieee80211_hw *hw, + enum radio_path rfpath) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool rtstatus = true; + u32 tmpval = 0; + + /* If inferiority IC, we have to increase the PA bias current */ + if (rtlhal->ic_class != IC_INFERIORITY_A) { + tmpval = rtl92s_phy_query_rf_reg(hw, rfpath, RF_IPA, 0xf); + rtl92s_phy_set_rf_reg(hw, rfpath, RF_IPA, 0xf, tmpval + 1); + } + + return rtstatus; +} + +static void _rtl92s_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw, + u32 reg_addr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (reg_addr == RTXAGC_RATE18_06) + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] = + data; + if (reg_addr == RTXAGC_RATE54_24) + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] = + data; + if (reg_addr == RTXAGC_CCK_MCS32) + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] = + data; + if (reg_addr == RTXAGC_MCS03_MCS00) + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] = + data; + if (reg_addr == RTXAGC_MCS07_MCS04) + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] = + data; + if (reg_addr == RTXAGC_MCS11_MCS08) + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] = + data; + if (reg_addr == RTXAGC_MCS15_MCS12) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] = + data; + rtlphy->pwrgroup_cnt++; + } +} + +static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /*RF Interface Sowrtware Control */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW; + + /* RF Interface Readback Value */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB; + + /* RF Interface Output (and Enable) */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_C].rfintfo = RFPGA0_XC_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_D].rfintfo = RFPGA0_XD_RFINTERFACEOE; + + /* RF Interface (Output and) Enable */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_C].rfintfe = RFPGA0_XC_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_D].rfintfe = RFPGA0_XD_RFINTERFACEOE; + + /* Addr of LSSI. Wirte RF register by driver */ + rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = + RFPGA0_XA_LSSIPARAMETER; + rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = + RFPGA0_XB_LSSIPARAMETER; + rtlphy->phyreg_def[RF90_PATH_C].rf3wire_offset = + RFPGA0_XC_LSSIPARAMETER; + rtlphy->phyreg_def[RF90_PATH_D].rf3wire_offset = + RFPGA0_XD_LSSIPARAMETER; + + /* RF parameter */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = RFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = RFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = RFPGA0_XCD_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = RFPGA0_XCD_RFPARAMETER; + + /* Tx AGC Gain Stage (same for all path. Should we remove this?) */ + rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE; + + /* Tranceiver A~D HSSI Parameter-1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1; + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1; + rtlphy->phyreg_def[RF90_PATH_C].rfhssi_para1 = RFPGA0_XC_HSSIPARAMETER1; + rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para1 = RFPGA0_XD_HSSIPARAMETER1; + + /* Tranceiver A~D HSSI Parameter-2 */ + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2; + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2; + rtlphy->phyreg_def[RF90_PATH_C].rfhssi_para2 = RFPGA0_XC_HSSIPARAMETER2; + rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para2 = RFPGA0_XD_HSSIPARAMETER2; + + /* RF switch Control */ + rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control = + RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control = + RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control = + RFPGA0_XCD_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control = + RFPGA0_XCD_SWITCHCONTROL; + + /* AGC control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1; + + /* AGC control 2 */ + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2; + + /* RX AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance = + ROFDM0_XARXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance = + ROFDM0_XBRXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance = + ROFDM0_XCRXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance = + ROFDM0_XDRXIQIMBALANCE; + + /* RX AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; + rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE; + rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE; + rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE; + + /* Tx AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance = + ROFDM0_XATXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance = + ROFDM0_XBTXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance = + ROFDM0_XCTXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance = + ROFDM0_XDTXIQIMBALANCE; + + /* Tx AFE control 2 */ + rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE; + rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE; + rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE; + rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE; + + /* Tranceiver LSSI Readback */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback = + RFPGA0_XA_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback = + RFPGA0_XB_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback = + RFPGA0_XC_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback = + RFPGA0_XD_LSSIREADBACK; + + /* Tranceiver LSSI Readback PI mode */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = + TRANSCEIVERA_HSPI_READBACK; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = + TRANSCEIVERB_HSPI_READBACK; +} + + +static bool _rtl92s_phy_config_bb(struct ieee80211_hw *hw, u8 configtype) +{ + int i; + u32 *phy_reg_table; + u32 *agc_table; + u16 phy_reg_len, agc_len; + + agc_len = AGCTAB_ARRAYLENGTH; + agc_table = rtl8192seagctab_array; + /* Default RF_type: 2T2R */ + phy_reg_len = PHY_REG_2T2RARRAYLENGTH; + phy_reg_table = rtl8192sephy_reg_2t2rarray; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_reg_len; i = i + 2) { + if (phy_reg_table[i] == 0xfe) + mdelay(50); + else if (phy_reg_table[i] == 0xfd) + mdelay(5); + else if (phy_reg_table[i] == 0xfc) + mdelay(1); + else if (phy_reg_table[i] == 0xfb) + udelay(50); + else if (phy_reg_table[i] == 0xfa) + udelay(5); + else if (phy_reg_table[i] == 0xf9) + udelay(1); + + /* Add delay for ECS T20 & LG malow platform, */ + udelay(1); + + rtl92s_phy_set_bb_reg(hw, phy_reg_table[i], MASKDWORD, + phy_reg_table[i + 1]); + } + } else if (configtype == BASEBAND_CONFIG_AGC_TAB) { + for (i = 0; i < agc_len; i = i + 2) { + rtl92s_phy_set_bb_reg(hw, agc_table[i], MASKDWORD, + agc_table[i + 1]); + + /* Add delay for ECS T20 & LG malow platform */ + udelay(1); + } + } + + return true; +} + +static bool _rtl92s_phy_set_bb_to_diff_rf(struct ieee80211_hw *hw, + u8 configtype) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 *phy_regarray2xtxr_table; + u16 phy_regarray2xtxr_len; + int i; + + if (rtlphy->rf_type == RF_1T1R) { + phy_regarray2xtxr_table = rtl8192sephy_changeto_1t1rarray; + phy_regarray2xtxr_len = PHY_CHANGETO_1T1RARRAYLENGTH; + } else if (rtlphy->rf_type == RF_1T2R) { + phy_regarray2xtxr_table = rtl8192sephy_changeto_1t2rarray; + phy_regarray2xtxr_len = PHY_CHANGETO_1T2RARRAYLENGTH; + } else { + return false; + } + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_regarray2xtxr_len; i = i + 3) { + if (phy_regarray2xtxr_table[i] == 0xfe) + mdelay(50); + else if (phy_regarray2xtxr_table[i] == 0xfd) + mdelay(5); + else if (phy_regarray2xtxr_table[i] == 0xfc) + mdelay(1); + else if (phy_regarray2xtxr_table[i] == 0xfb) + udelay(50); + else if (phy_regarray2xtxr_table[i] == 0xfa) + udelay(5); + else if (phy_regarray2xtxr_table[i] == 0xf9) + udelay(1); + + rtl92s_phy_set_bb_reg(hw, phy_regarray2xtxr_table[i], + phy_regarray2xtxr_table[i + 1], + phy_regarray2xtxr_table[i + 2]); + } + } + + return true; +} + +static bool _rtl92s_phy_config_bb_with_pg(struct ieee80211_hw *hw, + u8 configtype) +{ + int i; + u32 *phy_table_pg; + u16 phy_pg_len; + + phy_pg_len = PHY_REG_ARRAY_PGLENGTH; + phy_table_pg = rtl8192sephy_reg_array_pg; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_pg_len; i = i + 3) { + if (phy_table_pg[i] == 0xfe) + mdelay(50); + else if (phy_table_pg[i] == 0xfd) + mdelay(5); + else if (phy_table_pg[i] == 0xfc) + mdelay(1); + else if (phy_table_pg[i] == 0xfb) + udelay(50); + else if (phy_table_pg[i] == 0xfa) + udelay(5); + else if (phy_table_pg[i] == 0xf9) + udelay(1); + + _rtl92s_store_pwrindex_diffrate_offset(hw, + phy_table_pg[i], + phy_table_pg[i + 1], + phy_table_pg[i + 2]); + rtl92s_phy_set_bb_reg(hw, phy_table_pg[i], + phy_table_pg[i + 1], + phy_table_pg[i + 2]); + } + } + + return true; +} + +static bool _rtl92s_phy_bb_config_parafile(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + bool rtstatus = true; + + /* 1. Read PHY_REG.TXT BB INIT!! */ + /* We will separate as 1T1R/1T2R/1T2R_GREEN/2T2R */ + if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_2T2R || + rtlphy->rf_type == RF_1T1R || rtlphy->rf_type == RF_2T2R_GREEN) { + rtstatus = _rtl92s_phy_config_bb(hw, BASEBAND_CONFIG_PHY_REG); + + if (rtlphy->rf_type != RF_2T2R && + rtlphy->rf_type != RF_2T2R_GREEN) + /* so we should reconfig BB reg with the right + * PHY parameters. */ + rtstatus = _rtl92s_phy_set_bb_to_diff_rf(hw, + BASEBAND_CONFIG_PHY_REG); + } else { + rtstatus = false; + } + + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("Write BB Reg Fail!!")); + goto phy_BB8190_Config_ParaFile_Fail; + } + + /* 2. If EEPROM or EFUSE autoload OK, We must config by + * PHY_REG_PG.txt */ + if (rtlefuse->autoload_failflag == false) { + rtlphy->pwrgroup_cnt = 0; + + rtstatus = _rtl92s_phy_config_bb_with_pg(hw, + BASEBAND_CONFIG_PHY_REG); + } + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("_rtl92s_phy_bb_config_parafile(): " + "BB_PG Reg Fail!!")); + goto phy_BB8190_Config_ParaFile_Fail; + } + + /* 3. BB AGC table Initialization */ + rtstatus = _rtl92s_phy_config_bb(hw, BASEBAND_CONFIG_AGC_TAB); + + if (rtstatus != true) { + printk(KERN_ERR "_rtl92s_phy_bb_config_parafile(): " + "AGC Table Fail\n"); + goto phy_BB8190_Config_ParaFile_Fail; + } + + /* Check if the CCK HighPower is turned ON. */ + /* This is used to calculate PWDB. */ + rtlphy->cck_high_power = (bool)(rtl92s_phy_query_bb_reg(hw, + RFPGA0_XA_HSSIPARAMETER2, 0x200)); + +phy_BB8190_Config_ParaFile_Fail: + return rtstatus; +} + +u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + int i; + bool rtstatus = true; + u32 *radio_a_table; + u32 *radio_b_table; + u16 radio_a_tblen, radio_b_tblen; + + radio_a_tblen = RADIOA_1T_ARRAYLENGTH; + radio_a_table = rtl8192seradioa_1t_array; + + /* Using Green mode array table for RF_2T2R_GREEN */ + if (rtlphy->rf_type == RF_2T2R_GREEN) { + radio_b_table = rtl8192seradiob_gm_array; + radio_b_tblen = RADIOB_GM_ARRAYLENGTH; + } else { + radio_b_table = rtl8192seradiob_array; + radio_b_tblen = RADIOB_ARRAYLENGTH; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Radio No %x\n", rfpath)); + rtstatus = true; + + switch (rfpath) { + case RF90_PATH_A: + for (i = 0; i < radio_a_tblen; i = i + 2) { + if (radio_a_table[i] == 0xfe) + /* Delay specific ms. Only RF configuration + * requires delay. */ + mdelay(50); + else if (radio_a_table[i] == 0xfd) + mdelay(5); + else if (radio_a_table[i] == 0xfc) + mdelay(1); + else if (radio_a_table[i] == 0xfb) + udelay(50); + else if (radio_a_table[i] == 0xfa) + udelay(5); + else if (radio_a_table[i] == 0xf9) + udelay(1); + else + rtl92s_phy_set_rf_reg(hw, rfpath, + radio_a_table[i], + MASK20BITS, + radio_a_table[i + 1]); + + /* Add delay for ECS T20 & LG malow platform */ + udelay(1); + } + + /* PA Bias current for inferiority IC */ + _rtl92s_phy_config_rfpa_bias_current(hw, rfpath); + break; + case RF90_PATH_B: + for (i = 0; i < radio_b_tblen; i = i + 2) { + if (radio_b_table[i] == 0xfe) + /* Delay specific ms. Only RF configuration + * requires delay.*/ + mdelay(50); + else if (radio_b_table[i] == 0xfd) + mdelay(5); + else if (radio_b_table[i] == 0xfc) + mdelay(1); + else if (radio_b_table[i] == 0xfb) + udelay(50); + else if (radio_b_table[i] == 0xfa) + udelay(5); + else if (radio_b_table[i] == 0xf9) + udelay(1); + else + rtl92s_phy_set_rf_reg(hw, rfpath, + radio_b_table[i], + MASK20BITS, + radio_b_table[i + 1]); + + /* Add delay for ECS T20 & LG malow platform */ + udelay(1); + } + break; + case RF90_PATH_C: + ; + break; + case RF90_PATH_D: + ; + break; + default: + break; + } + + return rtstatus; +} + + +bool rtl92s_phy_mac_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + u32 arraylength; + u32 *ptraArray; + + arraylength = MAC_2T_ARRAYLENGTH; + ptraArray = rtl8192semac_2t_array; + + for (i = 0; i < arraylength; i = i + 2) + rtl_write_byte(rtlpriv, ptraArray[i], (u8)ptraArray[i + 1]); + + return true; +} + + +bool rtl92s_phy_bb_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + bool rtstatus = true; + u8 pathmap, index, rf_num = 0; + u8 path1, path2; + + _rtl92s_phy_init_register_definition(hw); + + /* Config BB and AGC */ + rtstatus = _rtl92s_phy_bb_config_parafile(hw); + + + /* Check BB/RF confiuration setting. */ + /* We only need to configure RF which is turned on. */ + path1 = (u8)(rtl92s_phy_query_bb_reg(hw, RFPGA0_TXINFO, 0xf)); + mdelay(10); + path2 = (u8)(rtl92s_phy_query_bb_reg(hw, ROFDM0_TRXPATHENABLE, 0xf)); + pathmap = path1 | path2; + + rtlphy->rf_pathmap = pathmap; + for (index = 0; index < 4; index++) { + if ((pathmap >> index) & 0x1) + rf_num++; + } + + if ((rtlphy->rf_type == RF_1T1R && rf_num != 1) || + (rtlphy->rf_type == RF_1T2R && rf_num != 2) || + (rtlphy->rf_type == RF_2T2R && rf_num != 2) || + (rtlphy->rf_type == RF_2T2R_GREEN && rf_num != 2)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("RF_Type(%x) does not match " + "RF_Num(%x)!!\n", rtlphy->rf_type, rf_num)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("path1 0x%x, path2 0x%x, pathmap " + "0x%x\n", path1, path2, pathmap)); + } + + return rtstatus; +} + +bool rtl92s_phy_rf_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /* Initialize general global value */ + if (rtlphy->rf_type == RF_1T1R) + rtlphy->num_total_rfpath = 1; + else + rtlphy->num_total_rfpath = 2; + + /* Config BB and RF */ + return rtl92s_phy_rf6052_config(hw); +} + +void rtl92s_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /* read rx initial gain */ + rtlphy->default_initialgain[0] = rtl_get_bbreg(hw, + ROFDM0_XAAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[1] = rtl_get_bbreg(hw, + ROFDM0_XBAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[2] = rtl_get_bbreg(hw, + ROFDM0_XCAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[3] = rtl_get_bbreg(hw, + ROFDM0_XDAGCCORE1, MASKBYTE0); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Default initial gain " + "(c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x)\n", + rtlphy->default_initialgain[0], + rtlphy->default_initialgain[1], + rtlphy->default_initialgain[2], + rtlphy->default_initialgain[3])); + + /* read framesync */ + rtlphy->framesync = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3, MASKBYTE0); + rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2, + MASKDWORD); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Default framesync (0x%x) = 0x%x\n", + ROFDM0_RXDETECTOR3, rtlphy->framesync)); + +} + +static void _rtl92s_phy_get_txpower_index(struct ieee80211_hw *hw, u8 channel, + u8 *cckpowerlevel, u8 *ofdmpowerLevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 index = (channel - 1); + + /* 1. CCK */ + /* RF-A */ + cckpowerlevel[0] = rtlefuse->txpwrlevel_cck[0][index]; + /* RF-B */ + cckpowerlevel[1] = rtlefuse->txpwrlevel_cck[1][index]; + + /* 2. OFDM for 1T or 2T */ + if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_1T1R) { + /* Read HT 40 OFDM TX power */ + ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_1s[0][index]; + ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_1s[1][index]; + } else if (rtlphy->rf_type == RF_2T2R) { + /* Read HT 40 OFDM TX power */ + ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_2s[0][index]; + ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_2s[1][index]; + } +} + +static void _rtl92s_phy_ccxpower_indexcheck(struct ieee80211_hw *hw, + u8 channel, u8 *cckpowerlevel, u8 *ofdmpowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; + rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; +} + +void rtl92s_phy_set_txpower(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + /* [0]:RF-A, [1]:RF-B */ + u8 cckpowerlevel[2], ofdmpowerLevel[2]; + + if (rtlefuse->txpwr_fromeprom == false) + return; + + /* Mainly we use RF-A Tx Power to write the Tx Power registers, + * but the RF-B Tx Power must be calculated by the antenna diff. + * So we have to rewrite Antenna gain offset register here. + * Please refer to BB register 0x80c + * 1. For CCK. + * 2. For OFDM 1T or 2T */ + _rtl92s_phy_get_txpower_index(hw, channel, &cckpowerlevel[0], + &ofdmpowerLevel[0]); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Channel-%d, cckPowerLevel (A / B) = " + "0x%x / 0x%x, ofdmPowerLevel (A / B) = 0x%x / 0x%x\n", + channel, cckpowerlevel[0], cckpowerlevel[1], + ofdmpowerLevel[0], ofdmpowerLevel[1])); + + _rtl92s_phy_ccxpower_indexcheck(hw, channel, &cckpowerlevel[0], + &ofdmpowerLevel[0]); + + rtl92s_phy_rf6052_set_ccktxpower(hw, cckpowerlevel[0]); + rtl92s_phy_rf6052_set_ofdmtxpower(hw, &ofdmpowerLevel[0], channel); + +} + +void rtl92s_phy_chk_fwcmd_iodone(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 pollingcnt = 10000; + u32 tmpvalue; + + /* Make sure that CMD IO has be accepted by FW. */ + do { + udelay(10); + + tmpvalue = rtl_read_dword(rtlpriv, WFM5); + if (tmpvalue == 0) + break; + } while (--pollingcnt); + + if (pollingcnt == 0) + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Set FW Cmd fail!!\n")); +} + + +static void _rtl92s_phy_set_fwcmd_io(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 input, current_aid = 0; + + if (is_hal_stop(rtlhal)) + return; + + /* We re-map RA related CMD IO to combinational ones */ + /* if FW version is v.52 or later. */ + switch (rtlhal->current_fwcmd_io) { + case FW_CMD_RA_REFRESH_N: + rtlhal->current_fwcmd_io = FW_CMD_RA_REFRESH_N_COMB; + break; + case FW_CMD_RA_REFRESH_BG: + rtlhal->current_fwcmd_io = FW_CMD_RA_REFRESH_BG_COMB; + break; + default: + break; + } + + switch (rtlhal->current_fwcmd_io) { + case FW_CMD_RA_RESET: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_RA_RESET\n")); + rtl_write_dword(rtlpriv, WFM5, FW_RA_RESET); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_ACTIVE: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_RA_ACTIVE\n")); + rtl_write_dword(rtlpriv, WFM5, FW_RA_ACTIVE); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_REFRESH_N: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_RA_REFRESH_N\n")); + input = FW_RA_REFRESH; + rtl_write_dword(rtlpriv, WFM5, input); + rtl92s_phy_chk_fwcmd_iodone(hw); + rtl_write_dword(rtlpriv, WFM5, FW_RA_ENABLE_RSSI_MASK); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_REFRESH_BG: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_RA_REFRESH_BG\n")); + rtl_write_dword(rtlpriv, WFM5, FW_RA_REFRESH); + rtl92s_phy_chk_fwcmd_iodone(hw); + rtl_write_dword(rtlpriv, WFM5, FW_RA_DISABLE_RSSI_MASK); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_REFRESH_N_COMB: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_RA_REFRESH_N_COMB\n")); + input = FW_RA_IOT_N_COMB; + rtl_write_dword(rtlpriv, WFM5, input); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_REFRESH_BG_COMB: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_RA_REFRESH_BG_COMB\n")); + input = FW_RA_IOT_BG_COMB; + rtl_write_dword(rtlpriv, WFM5, input); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_IQK_ENABLE: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_IQK_ENABLE\n")); + rtl_write_dword(rtlpriv, WFM5, FW_IQK_ENABLE); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_PAUSE_DM_BY_SCAN: + /* Lower initial gain */ + rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, 0x17); + rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, 0x17); + /* CCA threshold */ + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x40); + break; + case FW_CMD_RESUME_DM_BY_SCAN: + /* CCA threshold */ + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); + rtl92s_phy_set_txpower(hw, rtlphy->current_channel); + break; + case FW_CMD_HIGH_PWR_DISABLE: + if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) + break; + + /* Lower initial gain */ + rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, 0x17); + rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, 0x17); + /* CCA threshold */ + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x40); + break; + case FW_CMD_HIGH_PWR_ENABLE: + if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) || + (rtlpriv->dm.dynamic_txpower_enable == true)) + break; + + /* CCA threshold */ + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); + break; + case FW_CMD_LPS_ENTER: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_LPS_ENTER\n")); + current_aid = rtlpriv->mac80211.assoc_id; + rtl_write_dword(rtlpriv, WFM5, (FW_LPS_ENTER | + ((current_aid | 0xc000) << 8))); + rtl92s_phy_chk_fwcmd_iodone(hw); + /* FW set TXOP disable here, so disable EDCA + * turbo mode until driver leave LPS */ + break; + case FW_CMD_LPS_LEAVE: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_LPS_LEAVE\n")); + rtl_write_dword(rtlpriv, WFM5, FW_LPS_LEAVE); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_ADD_A2_ENTRY: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_ADD_A2_ENTRY\n")); + rtl_write_dword(rtlpriv, WFM5, FW_ADD_A2_ENTRY); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_CTRL_DM_BY_DRIVER: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("FW_CMD_CTRL_DM_BY_DRIVER\n")); + rtl_write_dword(rtlpriv, WFM5, FW_CTRL_DM_BY_DRIVER); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + + default: + break; + } + + rtl92s_phy_chk_fwcmd_iodone(hw); + + /* Clear FW CMD operation flag. */ + rtlhal->set_fwcmd_inprogress = false; +} + +bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + 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); + u16 fw_cmdmap = FW_CMD_IO_QUERY(rtlpriv); + bool bPostProcessing = false; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Set FW Cmd(%#x), set_fwcmd_inprogress(%d)\n", + fw_cmdio, rtlhal->set_fwcmd_inprogress)); + + do { + /* We re-map to combined FW CMD ones if firmware version */ + /* is v.53 or later. */ + switch (fw_cmdio) { + case FW_CMD_RA_REFRESH_N: + fw_cmdio = FW_CMD_RA_REFRESH_N_COMB; + break; + case FW_CMD_RA_REFRESH_BG: + fw_cmdio = FW_CMD_RA_REFRESH_BG_COMB; + break; + default: + break; + } + + /* If firmware version is v.62 or later, + * use FW_CMD_IO_SET for FW_CMD_CTRL_DM_BY_DRIVER */ + if (hal_get_firmwareversion(rtlpriv) >= 0x3E) { + if (fw_cmdio == FW_CMD_CTRL_DM_BY_DRIVER) + fw_cmdio = FW_CMD_CTRL_DM_BY_DRIVER_NEW; + } + + + /* We shall revise all FW Cmd IO into Reg0x364 + * DM map table in the future. */ + switch (fw_cmdio) { + case FW_CMD_RA_INIT: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("RA init!!\n")); + fw_cmdmap |= FW_RA_INIT_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_RA_INIT_CTL); + break; + case FW_CMD_DIG_DISABLE: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Set DIG disable!!\n")); + fw_cmdmap &= ~FW_DIG_ENABLE_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + case FW_CMD_DIG_ENABLE: + case FW_CMD_DIG_RESUME: + if (!(rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE)) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Set DIG enable or resume!!\n")); + fw_cmdmap |= (FW_DIG_ENABLE_CTL | FW_SS_CTL); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + } + break; + case FW_CMD_DIG_HALT: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Set DIG halt!!\n")); + fw_cmdmap &= ~(FW_DIG_ENABLE_CTL | FW_SS_CTL); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + case FW_CMD_TXPWR_TRACK_THERMAL: { + u8 thermalval = 0; + fw_cmdmap |= FW_PWR_TRK_CTL; + + /* Clear FW parameter in terms of thermal parts. */ + fw_param &= FW_PWR_TRK_PARAM_CLR; + + thermalval = rtlpriv->dm.thermalvalue; + fw_param |= ((thermalval << 24) | + (rtlefuse->thermalmeter[0] << 16)); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Set TxPwr tracking!! " + "FwCmdMap(%#x), FwParam(%#x)\n", + fw_cmdmap, fw_param)); + + FW_CMD_PARA_SET(rtlpriv, fw_param); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_PWR_TRK_CTL); + } + break; + /* The following FW CMDs are only compatible to + * v.53 or later. */ + case FW_CMD_RA_REFRESH_N_COMB: + fw_cmdmap |= FW_RA_N_CTL; + + /* Clear RA BG mode control. */ + fw_cmdmap &= ~(FW_RA_BG_CTL | FW_RA_INIT_CTL); + + /* Clear FW parameter in terms of RA parts. */ + fw_param &= FW_RA_PARAM_CLR; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("[FW CMD] [New Version] " + "Set RA/IOT Comb in n mode!! FwCmdMap(%#x), " + "FwParam(%#x)\n", fw_cmdmap, fw_param)); + + FW_CMD_PARA_SET(rtlpriv, fw_param); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_RA_N_CTL); + break; + case FW_CMD_RA_REFRESH_BG_COMB: + fw_cmdmap |= FW_RA_BG_CTL; + + /* Clear RA n-mode control. */ + fw_cmdmap &= ~(FW_RA_N_CTL | FW_RA_INIT_CTL); + /* Clear FW parameter in terms of RA parts. */ + fw_param &= FW_RA_PARAM_CLR; + + FW_CMD_PARA_SET(rtlpriv, fw_param); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_RA_BG_CTL); + break; + case FW_CMD_IQK_ENABLE: + fw_cmdmap |= FW_IQK_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_IQK_CTL); + break; + /* The following FW CMD is compatible to v.62 or later. */ + case FW_CMD_CTRL_DM_BY_DRIVER_NEW: + fw_cmdmap |= FW_DRIVER_CTRL_DM_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + /* The followed FW Cmds needs post-processing later. */ + case FW_CMD_RESUME_DM_BY_SCAN: + fw_cmdmap |= (FW_DIG_ENABLE_CTL | + FW_HIGH_PWR_ENABLE_CTL | + FW_SS_CTL); + + if (rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE || + !digtable.dig_enable_flag) + fw_cmdmap &= ~FW_DIG_ENABLE_CTL; + + if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) || + (rtlpriv->dm.dynamic_txpower_enable == true)) + fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL; + + if ((digtable.dig_ext_port_stage == + DIG_EXT_PORT_STAGE_0) || + (digtable.dig_ext_port_stage == + DIG_EXT_PORT_STAGE_1)) + fw_cmdmap &= ~FW_DIG_ENABLE_CTL; + + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + bPostProcessing = true; + break; + case FW_CMD_PAUSE_DM_BY_SCAN: + fw_cmdmap &= ~(FW_DIG_ENABLE_CTL | + FW_HIGH_PWR_ENABLE_CTL | + FW_SS_CTL); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + bPostProcessing = true; + break; + case FW_CMD_HIGH_PWR_DISABLE: + fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + bPostProcessing = true; + break; + case FW_CMD_HIGH_PWR_ENABLE: + if (!(rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) && + (rtlpriv->dm.dynamic_txpower_enable != true)) { + fw_cmdmap |= (FW_HIGH_PWR_ENABLE_CTL | + FW_SS_CTL); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + bPostProcessing = true; + } + break; + case FW_CMD_DIG_MODE_FA: + fw_cmdmap |= FW_FA_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + case FW_CMD_DIG_MODE_SS: + fw_cmdmap &= ~FW_FA_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + case FW_CMD_PAPE_CONTROL: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("[FW CMD] Set PAPE Control\n")); + fw_cmdmap &= ~FW_PAPE_CTL_BY_SW_HW; + + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + default: + /* Pass to original FW CMD processing callback + * routine. */ + bPostProcessing = true; + break; + } + } while (false); + + /* We shall post processing these FW CMD if + * variable bPostProcessing is set. */ + if (bPostProcessing && !rtlhal->set_fwcmd_inprogress) { + rtlhal->set_fwcmd_inprogress = true; + /* Update current FW Cmd for callback use. */ + rtlhal->current_fwcmd_io = fw_cmdio; + } else { + return false; + } + + _rtl92s_phy_set_fwcmd_io(hw); + return true; +} + +static void _rtl92s_phy_check_ephy_switchready(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 delay = 100; + u8 regu1; + + regu1 = rtl_read_byte(rtlpriv, 0x554); + while ((regu1 & BIT(5)) && (delay > 0)) { + regu1 = rtl_read_byte(rtlpriv, 0x554); + delay--; + /* We delay only 50us to prevent + * being scheduled out. */ + udelay(50); + } +} + +void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + /* The way to be capable to switch clock request + * when the PG setting does not support clock request. + * This is the backdoor solution to switch clock + * request before ASPM or D3. */ + rtl_write_dword(rtlpriv, 0x540, 0x73c11); + rtl_write_dword(rtlpriv, 0x548, 0x2407c); + + /* Switch EPHY parameter!!!! */ + rtl_write_word(rtlpriv, 0x550, 0x1000); + rtl_write_byte(rtlpriv, 0x554, 0x20); + _rtl92s_phy_check_ephy_switchready(hw); + + rtl_write_word(rtlpriv, 0x550, 0xa0eb); + rtl_write_byte(rtlpriv, 0x554, 0x3e); + _rtl92s_phy_check_ephy_switchready(hw); + + rtl_write_word(rtlpriv, 0x550, 0xff80); + rtl_write_byte(rtlpriv, 0x554, 0x39); + _rtl92s_phy_check_ephy_switchready(hw); + + /* Delay L1 enter time */ + if (ppsc->support_aspm && !ppsc->support_backdoor) + rtl_write_byte(rtlpriv, 0x560, 0x40); + else + rtl_write_byte(rtlpriv, 0x560, 0x00); + +} + +void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 BeaconInterval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl_write_dword(rtlpriv, WFM5, 0xF1000000 | (BeaconInterval << 8)); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.h b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h new file mode 100644 index 000000000000..37e504af6446 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __RTL92S_PHY_H__ +#define __RTL92S_PHY_H__ + +#define MAX_TXPWR_IDX_NMODE_92S 63 +#define MAX_DOZE_WAITING_TIMES_9x 64 + +/* Channel switch:The size of + * command tables for switch channel */ +#define MAX_PRECMD_CNT 16 +#define MAX_RFDEPENDCMD_CNT 16 +#define MAX_POSTCMD_CNT 16 + +#define RF90_PATH_MAX 4 + +enum version_8192s { + VERSION_8192S_ACUT, + VERSION_8192S_BCUT, + VERSION_8192S_CCUT +}; + +enum swchnlcmd_id { + CMDID_END, + CMDID_SET_TXPOWEROWER_LEVEL, + CMDID_BBREGWRITE10, + CMDID_WRITEPORT_ULONG, + CMDID_WRITEPORT_USHORT, + CMDID_WRITEPORT_UCHAR, + CMDID_RF_WRITEREG, +}; + +struct swchnlcmd { + enum swchnlcmd_id cmdid; + u32 para1; + u32 para2; + u32 msdelay; +}; + +enum baseband_config_type { + /* Radio Path A */ + BASEBAND_CONFIG_PHY_REG = 0, + /* Radio Path B */ + BASEBAND_CONFIG_AGC_TAB = 1, +}; + +#define hal_get_firmwareversion(rtlpriv) \ + (((struct rt_firmware *)(rtlpriv->rtlhal.pfirmware))->firmwareversion) + +u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); +void rtl92s_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, + u32 data); +void rtl92s_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); +u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask); +void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); +void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); +u8 rtl92s_phy_sw_chnl(struct ieee80211_hw *hw); +bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpower_state); +bool rtl92s_phy_mac_config(struct ieee80211_hw *hw); +void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw); +bool rtl92s_phy_bb_config(struct ieee80211_hw *hw); +bool rtl92s_phy_rf_config(struct ieee80211_hw *hw); +void rtl92s_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +void rtl92s_phy_set_txpower(struct ieee80211_hw *hw, u8 channel); +bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fwcmd_io); +void rtl92s_phy_chk_fwcmd_iodone(struct ieee80211_hw *hw); +void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 beaconinterval); +u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) ; + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h new file mode 100644 index 000000000000..0116eaddbfac --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h @@ -0,0 +1,1188 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __REALTEK_92S_REG_H__ +#define __REALTEK_92S_REG_H__ + +/* 1. System Configuration Registers */ +#define REG_SYS_ISO_CTRL 0x0000 +#define REG_SYS_FUNC_EN 0x0002 +#define PMC_FSM 0x0004 +#define SYS_CLKR 0x0008 +#define EPROM_CMD 0x000A +#define EE_VPD 0x000C +#define AFE_MISC 0x0010 +#define SPS0_CTRL 0x0011 +#define SPS1_CTRL 0x0018 +#define RF_CTRL 0x001F +#define LDOA15_CTRL 0x0020 +#define LDOV12D_CTRL 0x0021 +#define LDOHCI12_CTRL 0x0022 +#define LDO_USB_SDIO 0x0023 +#define LPLDO_CTRL 0x0024 +#define AFE_XTAL_CTRL 0x0026 +#define AFE_PLL_CTRL 0x0028 +#define REG_EFUSE_CTRL 0x0030 +#define REG_EFUSE_TEST 0x0034 +#define PWR_DATA 0x0038 +#define DBG_PORT 0x003A +#define DPS_TIMER 0x003C +#define RCLK_MON 0x003E + +/* 2. Command Control Registers */ +#define CMDR 0x0040 +#define TXPAUSE 0x0042 +#define LBKMD_SEL 0x0043 +#define TCR 0x0044 +#define RCR 0x0048 +#define MSR 0x004C +#define SYSF_CFG 0x004D +#define RX_PKY_LIMIT 0x004E +#define MBIDCTRL 0x004F + +/* 3. MACID Setting Registers */ +#define MACIDR 0x0050 +#define MACIDR0 0x0050 +#define MACIDR4 0x0054 +#define BSSIDR 0x0058 +#define HWVID 0x005E +#define MAR 0x0060 +#define MBIDCAMCONTENT 0x0068 +#define MBIDCAMCFG 0x0070 +#define BUILDTIME 0x0074 +#define BUILDUSER 0x0078 + +#define IDR0 MACIDR0 +#define IDR4 MACIDR4 + +/* 4. Timing Control Registers */ +#define TSFR 0x0080 +#define SLOT_TIME 0x0089 +#define USTIME 0x008A +#define SIFS_CCK 0x008C +#define SIFS_OFDM 0x008E +#define PIFS_TIME 0x0090 +#define ACK_TIMEOUT 0x0091 +#define EIFSTR 0x0092 +#define BCN_INTERVAL 0x0094 +#define ATIMWND 0x0096 +#define BCN_DRV_EARLY_INT 0x0098 +#define BCN_DMATIME 0x009A +#define BCN_ERR_THRESH 0x009C +#define MLT 0x009D +#define RSVD_MAC_TUNE_US 0x009E + +/* 5. FIFO Control Registers */ +#define RQPN 0x00A0 +#define RQPN1 0x00A0 +#define RQPN2 0x00A1 +#define RQPN3 0x00A2 +#define RQPN4 0x00A3 +#define RQPN5 0x00A4 +#define RQPN6 0x00A5 +#define RQPN7 0x00A6 +#define RQPN8 0x00A7 +#define RQPN9 0x00A8 +#define RQPN10 0x00A9 +#define LD_RQPN 0x00AB +#define RXFF_BNDY 0x00AC +#define RXRPT_BNDY 0x00B0 +#define TXPKTBUF_PGBNDY 0x00B4 +#define PBP 0x00B5 +#define RXDRVINFO_SZ 0x00B6 +#define TXFF_STATUS 0x00B7 +#define RXFF_STATUS 0x00B8 +#define TXFF_EMPTY_TH 0x00B9 +#define SDIO_RX_BLKSZ 0x00BC +#define RXDMA 0x00BD +#define RXPKT_NUM 0x00BE +#define C2HCMD_UDT_SIZE 0x00C0 +#define C2HCMD_UDT_ADDR 0x00C2 +#define FIFOPAGE1 0x00C4 +#define FIFOPAGE2 0x00C8 +#define FIFOPAGE3 0x00CC +#define FIFOPAGE4 0x00D0 +#define FIFOPAGE5 0x00D4 +#define FW_RSVD_PG_CRTL 0x00D8 +#define RXDMA_AGG_PG_TH 0x00D9 +#define TXDESC_MSK 0x00DC +#define TXRPTFF_RDPTR 0x00E0 +#define TXRPTFF_WTPTR 0x00E4 +#define C2HFF_RDPTR 0x00E8 +#define C2HFF_WTPTR 0x00EC +#define RXFF0_RDPTR 0x00F0 +#define RXFF0_WTPTR 0x00F4 +#define RXFF1_RDPTR 0x00F8 +#define RXFF1_WTPTR 0x00FC +#define RXRPT0_RDPTR 0x0100 +#define RXRPT0_WTPTR 0x0104 +#define RXRPT1_RDPTR 0x0108 +#define RXRPT1_WTPTR 0x010C +#define RX0_UDT_SIZE 0x0110 +#define RX1PKTNUM 0x0114 +#define RXFILTERMAP 0x0116 +#define RXFILTERMAP_GP1 0x0118 +#define RXFILTERMAP_GP2 0x011A +#define RXFILTERMAP_GP3 0x011C +#define BCNQ_CTRL 0x0120 +#define MGTQ_CTRL 0x0124 +#define HIQ_CTRL 0x0128 +#define VOTID7_CTRL 0x012c +#define VOTID6_CTRL 0x0130 +#define VITID5_CTRL 0x0134 +#define VITID4_CTRL 0x0138 +#define BETID3_CTRL 0x013c +#define BETID0_CTRL 0x0140 +#define BKTID2_CTRL 0x0144 +#define BKTID1_CTRL 0x0148 +#define CMDQ_CTRL 0x014c +#define TXPKT_NUM_CTRL 0x0150 +#define TXQ_PGADD 0x0152 +#define TXFF_PG_NUM 0x0154 +#define TRXDMA_STATUS 0x0156 + +/* 6. Adaptive Control Registers */ +#define INIMCS_SEL 0x0160 +#define TX_RATE_REG INIMCS_SEL +#define INIRTSMCS_SEL 0x0180 +#define RRSR 0x0181 +#define ARFR0 0x0184 +#define ARFR1 0x0188 +#define ARFR2 0x018C +#define ARFR3 0x0190 +#define ARFR4 0x0194 +#define ARFR5 0x0198 +#define ARFR6 0x019C +#define ARFR7 0x01A0 +#define AGGLEN_LMT_H 0x01A7 +#define AGGLEN_LMT_L 0x01A8 +#define DARFRC 0x01B0 +#define RARFRC 0x01B8 +#define MCS_TXAGC 0x01C0 +#define CCK_TXAGC 0x01C8 + +/* 7. EDCA Setting Registers */ +#define EDCAPARA_VO 0x01D0 +#define EDCAPARA_VI 0x01D4 +#define EDCAPARA_BE 0x01D8 +#define EDCAPARA_BK 0x01DC +#define BCNTCFG 0x01E0 +#define CWRR 0x01E2 +#define ACMAVG 0x01E4 +#define AcmHwCtrl 0x01E7 +#define VO_ADMTM 0x01E8 +#define VI_ADMTM 0x01EC +#define BE_ADMTM 0x01F0 +#define RETRY_LIMIT 0x01F4 +#define SG_RATE 0x01F6 + +/* 8. WMAC, BA and CCX related Register. */ +#define NAV_CTRL 0x0200 +#define BW_OPMODE 0x0203 +#define BACAMCMD 0x0204 +#define BACAMCONTENT 0x0208 + +/* the 0x2xx register WMAC definition */ +#define LBDLY 0x0210 +#define FWDLY 0x0211 +#define HWPC_RX_CTRL 0x0218 +#define MQIR 0x0220 +#define MAIR 0x0222 +#define MSIR 0x0224 +#define CLM_RESULT 0x0227 +#define NHM_RPI_CNT 0x0228 +#define RXERR_RPT 0x0230 +#define NAV_PROT_LEN 0x0234 +#define CFEND_TH 0x0236 +#define AMPDU_MIN_SPACE 0x0237 +#define TXOP_STALL_CTRL 0x0238 + +/* 9. Security Control Registers */ +#define REG_RWCAM 0x0240 +#define REG_WCAMI 0x0244 +#define REG_RCAMO 0x0248 +#define REG_CAMDBG 0x024C +#define REG_SECR 0x0250 + +/* 10. Power Save Control Registers */ +#define WOW_CTRL 0x0260 +#define PSSTATUS 0x0261 +#define PSSWITCH 0x0262 +#define MIMOPS_WAIT_PERIOD 0x0263 +#define LPNAV_CTRL 0x0264 +#define WFM0 0x0270 +#define WFM1 0x0280 +#define WFM2 0x0290 +#define WFM3 0x02A0 +#define WFM4 0x02B0 +#define WFM5 0x02C0 +#define WFCRC 0x02D0 +#define FW_RPT_REG 0x02c4 + +/* 11. General Purpose Registers */ +#define PSTIME 0x02E0 +#define TIMER0 0x02E4 +#define TIMER1 0x02E8 +#define GPIO_CTRL 0x02EC +#define GPIO_IN 0x02EC +#define GPIO_OUT 0x02ED +#define GPIO_IO_SEL 0x02EE +#define GPIO_MOD 0x02EF +#define GPIO_INTCTRL 0x02F0 +#define MAC_PINMUX_CFG 0x02F1 +#define LEDCFG 0x02F2 +#define PHY_REG 0x02F3 +#define PHY_REG_DATA 0x02F4 +#define REG_EFUSE_CLK 0x02F8 + +/* 12. Host Interrupt Status Registers */ +#define INTA_MASK 0x0300 +#define ISR 0x0308 + +/* 13. Test Mode and Debug Control Registers */ +#define DBG_PORT_SWITCH 0x003A +#define BIST 0x0310 +#define DBS 0x0314 +#define CPUINST 0x0318 +#define CPUCAUSE 0x031C +#define LBUS_ERR_ADDR 0x0320 +#define LBUS_ERR_CMD 0x0324 +#define LBUS_ERR_DATA_L 0x0328 +#define LBUS_ERR_DATA_H 0x032C +#define LX_EXCEPTION_ADDR 0x0330 +#define WDG_CTRL 0x0334 +#define INTMTU 0x0338 +#define INTM 0x033A +#define FDLOCKTURN0 0x033C +#define FDLOCKTURN1 0x033D +#define TRXPKTBUF_DBG_DATA 0x0340 +#define TRXPKTBUF_DBG_CTRL 0x0348 +#define DPLL 0x034A +#define CBUS_ERR_ADDR 0x0350 +#define CBUS_ERR_CMD 0x0354 +#define CBUS_ERR_DATA_L 0x0358 +#define CBUS_ERR_DATA_H 0x035C +#define USB_SIE_INTF_ADDR 0x0360 +#define USB_SIE_INTF_WD 0x0361 +#define USB_SIE_INTF_RD 0x0362 +#define USB_SIE_INTF_CTRL 0x0363 +#define LBUS_MON_ADDR 0x0364 +#define LBUS_ADDR_MASK 0x0368 + +/* Boundary is 0x37F */ + +/* 14. PCIE config register */ +#define TP_POLL 0x0500 +#define PM_CTRL 0x0502 +#define PCIF 0x0503 + +#define THPDA 0x0514 +#define TMDA 0x0518 +#define TCDA 0x051C +#define HDA 0x0520 +#define TVODA 0x0524 +#define TVIDA 0x0528 +#define TBEDA 0x052C +#define TBKDA 0x0530 +#define TBDA 0x0534 +#define RCDA 0x0538 +#define RDQDA 0x053C +#define DBI_WDATA 0x0540 +#define DBI_RDATA 0x0544 +#define DBI_CTRL 0x0548 +#define MDIO_DATA 0x0550 +#define MDIO_CTRL 0x0554 +#define PCI_RPWM 0x0561 +#define PCI_CPWM 0x0563 + +/* Config register (Offset 0x800-) */ +#define PHY_CCA 0x803 + +/* Min Spacing related settings. */ +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +/* Rx DMA Control related settings */ +#define RXDMA_AGG_EN BIT(7) + +#define RPWM PCI_RPWM + +/* Regsiter Bit and Content definition */ + +#define ISO_MD2PP BIT(0) +#define ISO_PA2PCIE BIT(3) +#define ISO_PLL2MD BIT(4) +#define ISO_PWC_DV2RP BIT(11) +#define ISO_PWC_RV2RP BIT(12) + + +#define FEN_MREGEN BIT(15) +#define FEN_DCORE BIT(11) +#define FEN_CPUEN BIT(10) + +#define PAD_HWPD_IDN BIT(22) + +#define SYS_CLKSEL_80M BIT(0) +#define SYS_PS_CLKSEL BIT(1) +#define SYS_CPU_CLKSEL BIT(2) +#define SYS_MAC_CLK_EN BIT(11) +#define SYS_SWHW_SEL BIT(14) +#define SYS_FWHW_SEL BIT(15) + +#define CmdEEPROM_En BIT(5) +#define CmdEERPOMSEL BIT(4) +#define Cmd9346CR_9356SEL BIT(4) + +#define AFE_MBEN BIT(1) +#define AFE_BGEN BIT(0) + +#define SPS1_SWEN BIT(1) +#define SPS1_LDEN BIT(0) + +#define RF_EN BIT(0) +#define RF_RSTB BIT(1) +#define RF_SDMRSTB BIT(2) + +#define LDA15_EN BIT(0) + +#define LDV12_EN BIT(0) +#define LDV12_SDBY BIT(1) + +#define XTAL_GATE_AFE BIT(10) + +#define APLL_EN BIT(0) + +#define AFR_CardBEn BIT(0) +#define AFR_CLKRUN_SEL BIT(1) +#define AFR_FuncRegEn BIT(2) + +#define APSDOFF_STATUS BIT(15) +#define APSDOFF BIT(14) +#define BBRSTN BIT(13) +#define BB_GLB_RSTN BIT(12) +#define SCHEDULE_EN BIT(10) +#define MACRXEN BIT(9) +#define MACTXEN BIT(8) +#define DDMA_EN BIT(7) +#define FW2HW_EN BIT(6) +#define RXDMA_EN BIT(5) +#define TXDMA_EN BIT(4) +#define HCI_RXDMA_EN BIT(3) +#define HCI_TXDMA_EN BIT(2) + +#define StopHCCA BIT(6) +#define StopHigh BIT(5) +#define StopMgt BIT(4) +#define StopVO BIT(3) +#define StopVI BIT(2) +#define StopBE BIT(1) +#define StopBK BIT(0) + +#define LBK_NORMAL 0x00 +#define LBK_MAC_LB (BIT(0) | BIT(1) | BIT(3)) +#define LBK_MAC_DLB (BIT(0) | BIT(1)) +#define LBK_DMA_LB (BIT(0) | BIT(1) | BIT(2)) + +#define TCP_OFDL_EN BIT(25) +#define HWPC_TX_EN BIT(24) +#define TXDMAPRE2FULL BIT(23) +#define DISCW BIT(20) +#define TCRICV BIT(19) +#define CfendForm BIT(17) +#define TCRCRC BIT(16) +#define FAKE_IMEM_EN BIT(15) +#define TSFRST BIT(9) +#define TSFEN BIT(8) +#define FWALLRDY (BIT(0) | BIT(1) | BIT(2) | \ + BIT(3) | BIT(4) | BIT(5) | \ + BIT(6) | BIT(7)) +#define FWRDY BIT(7) +#define BASECHG BIT(6) +#define IMEM BIT(5) +#define DMEM_CODE_DONE BIT(4) +#define EXT_IMEM_CHK_RPT BIT(3) +#define EXT_IMEM_CODE_DONE BIT(2) +#define IMEM_CHK_RPT BIT(1) +#define IMEM_CODE_DONE BIT(0) +#define IMEM_CODE_DONE BIT(0) +#define IMEM_CHK_RPT BIT(1) +#define EMEM_CODE_DONE BIT(2) +#define EMEM_CHK_RPT BIT(3) +#define DMEM_CODE_DONE BIT(4) +#define IMEM_RDY BIT(5) +#define BASECHG BIT(6) +#define FWRDY BIT(7) +#define LOAD_FW_READY (IMEM_CODE_DONE | \ + IMEM_CHK_RPT | \ + EMEM_CODE_DONE | \ + EMEM_CHK_RPT | \ + DMEM_CODE_DONE | \ + IMEM_RDY | \ + BASECHG | \ + FWRDY) +#define TCR_TSFEN BIT(8) +#define TCR_TSFRST BIT(9) +#define TCR_FAKE_IMEM_EN BIT(15) +#define TCR_CRC BIT(16) +#define TCR_ICV BIT(19) +#define TCR_DISCW BIT(20) +#define TCR_HWPC_TX_EN BIT(24) +#define TCR_TCP_OFDL_EN BIT(25) +#define TXDMA_INIT_VALUE (IMEM_CHK_RPT | \ + EXT_IMEM_CHK_RPT) + +#define RCR_APPFCS BIT(31) +#define RCR_DIS_ENC_2BYTE BIT(30) +#define RCR_DIS_AES_2BYTE BIT(29) +#define RCR_HTC_LOC_CTRL BIT(28) +#define RCR_ENMBID BIT(27) +#define RCR_RX_TCPOFDL_EN BIT(26) +#define RCR_APP_PHYST_RXFF BIT(25) +#define RCR_APP_PHYST_STAFF BIT(24) +#define RCR_CBSSID BIT(23) +#define RCR_APWRMGT BIT(22) +#define RCR_ADD3 BIT(21) +#define RCR_AMF BIT(20) +#define RCR_ACF BIT(19) +#define RCR_ADF BIT(18) +#define RCR_APP_MIC BIT(17) +#define RCR_APP_ICV BIT(16) +#define RCR_RXFTH BIT(13) +#define RCR_AICV BIT(12) +#define RCR_RXDESC_LK_EN BIT(11) +#define RCR_APP_BA_SSN BIT(6) +#define RCR_ACRC32 BIT(5) +#define RCR_RXSHFT_EN BIT(4) +#define RCR_AB BIT(3) +#define RCR_AM BIT(2) +#define RCR_APM BIT(1) +#define RCR_AAP BIT(0) +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 + + +#define MSR_LINK_MASK ((1 << 0) | (1 << 1)) +#define MSR_LINK_MANAGED 2 +#define MSR_LINK_NONE 0 +#define MSR_LINK_SHIFT 0 +#define MSR_LINK_ADHOC 1 +#define MSR_LINK_MASTER 3 +#define MSR_NOLINK 0x00 +#define MSR_ADHOC 0x01 +#define MSR_INFRA 0x02 +#define MSR_AP 0x03 + +#define ENUART BIT(7) +#define ENJTAG BIT(3) +#define BTMODE (BIT(2) | BIT(1)) +#define ENBT BIT(0) + +#define ENMBID BIT(7) +#define BCNUM (BIT(6) | BIT(5) | BIT(4)) + +#define USTIME_EDCA 0xFF00 +#define USTIME_TSF 0x00FF + +#define SIFS_TRX 0xFF00 +#define SIFS_CTX 0x00FF + +#define ENSWBCN BIT(15) +#define DRVERLY_TU 0x0FF0 +#define DRVERLY_US 0x000F +#define BCN_TCFG_CW_SHIFT 8 +#define BCN_TCFG_IFS 0 + +#define RRSR_RSC_OFFSET 21 +#define RRSR_SHORT_OFFSET 23 +#define RRSR_RSC_BW_40M 0x600000 +#define RRSR_RSC_UPSUBCHNL 0x400000 +#define RRSR_RSC_LOWSUBCHNL 0x200000 +#define RRSR_SHORT 0x800000 +#define RRSR_1M BIT(0) +#define RRSR_2M BIT(1) +#define RRSR_5_5M BIT(2) +#define RRSR_11M BIT(3) +#define RRSR_6M BIT(4) +#define RRSR_9M BIT(5) +#define RRSR_12M BIT(6) +#define RRSR_18M BIT(7) +#define RRSR_24M BIT(8) +#define RRSR_36M BIT(9) +#define RRSR_48M BIT(10) +#define RRSR_54M BIT(11) +#define RRSR_MCS0 BIT(12) +#define RRSR_MCS1 BIT(13) +#define RRSR_MCS2 BIT(14) +#define RRSR_MCS3 BIT(15) +#define RRSR_MCS4 BIT(16) +#define RRSR_MCS5 BIT(17) +#define RRSR_MCS6 BIT(18) +#define RRSR_MCS7 BIT(19) +#define BRSR_AckShortPmb BIT(23) + +#define RATR_1M 0x00000001 +#define RATR_2M 0x00000002 +#define RATR_55M 0x00000004 +#define RATR_11M 0x00000008 +#define RATR_6M 0x00000010 +#define RATR_9M 0x00000020 +#define RATR_12M 0x00000040 +#define RATR_18M 0x00000080 +#define RATR_24M 0x00000100 +#define RATR_36M 0x00000200 +#define RATR_48M 0x00000400 +#define RATR_54M 0x00000800 +#define RATR_MCS0 0x00001000 +#define RATR_MCS1 0x00002000 +#define RATR_MCS2 0x00004000 +#define RATR_MCS3 0x00008000 +#define RATR_MCS4 0x00010000 +#define RATR_MCS5 0x00020000 +#define RATR_MCS6 0x00040000 +#define RATR_MCS7 0x00080000 +#define RATR_MCS8 0x00100000 +#define RATR_MCS9 0x00200000 +#define RATR_MCS10 0x00400000 +#define RATR_MCS11 0x00800000 +#define RATR_MCS12 0x01000000 +#define RATR_MCS13 0x02000000 +#define RATR_MCS14 0x04000000 +#define RATR_MCS15 0x08000000 + +#define RATE_ALL_CCK (RATR_1M | RATR_2M | \ + RATR_55M | RATR_11M) +#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | \ + RATR_12M | RATR_18M | \ + RATR_24M | RATR_36M | \ + RATR_48M | RATR_54M) +#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | \ + RATR_MCS2 | RATR_MCS3 | \ + RATR_MCS4 | RATR_MCS5 | \ + RATR_MCS6 | RATR_MCS7) +#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | \ + RATR_MCS10 | RATR_MCS11 | \ + RATR_MCS12 | RATR_MCS13 | \ + RATR_MCS14 | RATR_MCS15) + +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 +#define AC_PARAM_ECW_MAX_OFFSET 12 +#define AC_PARAM_ECW_MIN_OFFSET 8 +#define AC_PARAM_AIFS_OFFSET 0 + +#define AcmHw_HwEn BIT(0) +#define AcmHw_BeqEn BIT(1) +#define AcmHw_ViqEn BIT(2) +#define AcmHw_VoqEn BIT(3) +#define AcmHw_BeqStatus BIT(4) +#define AcmHw_ViqStatus BIT(5) +#define AcmHw_VoqStatus BIT(6) + +#define RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_LONG_SHIFT 0 + +#define NAV_UPPER_EN BIT(16) +#define NAV_UPPER 0xFF00 +#define NAV_RTSRST 0xFF + +#define BW_OPMODE_20MHZ BIT(2) +#define BW_OPMODE_5G BIT(1) +#define BW_OPMODE_11J BIT(0) + +#define RXERR_RPT_RST BIT(27) +#define RXERR_OFDM_PPDU 0 +#define RXERR_OFDM_FALSE_ALARM 1 +#define RXERR_OFDM_MPDU_OK 2 +#define RXERR_OFDM_MPDU_FAIL 3 +#define RXERR_CCK_PPDU 4 +#define RXERR_CCK_FALSE_ALARM 5 +#define RXERR_CCK_MPDU_OK 6 +#define RXERR_CCK_MPDU_FAIL 7 +#define RXERR_HT_PPDU 8 +#define RXERR_HT_FALSE_ALARM 9 +#define RXERR_HT_MPDU_TOTAL 10 +#define RXERR_HT_MPDU_OK 11 +#define RXERR_HT_MPDU_FAIL 12 +#define RXERR_RX_FULL_DROP 15 + +#define SCR_TXUSEDK BIT(0) +#define SCR_RXUSEDK BIT(1) +#define SCR_TXENCENABLE BIT(2) +#define SCR_RXENCENABLE BIT(3) +#define SCR_SKBYA2 BIT(4) +#define SCR_NOSKMC BIT(5) + +#define CAM_VALID BIT(15) +#define CAM_NOTVALID 0x0000 +#define CAM_USEDK BIT(5) + +#define CAM_NONE 0x0 +#define CAM_WEP40 0x01 +#define CAM_TKIP 0x02 +#define CAM_AES 0x04 +#define CAM_WEP104 0x05 + +#define TOTAL_CAM_ENTRY 32 +#define HALF_CAM_ENTRY 16 + +#define CAM_WRITE BIT(16) +#define CAM_READ 0x00000000 +#define CAM_POLLINIG BIT(31) + +#define WOW_PMEN BIT(0) +#define WOW_WOMEN BIT(1) +#define WOW_MAGIC BIT(2) +#define WOW_UWF BIT(3) + +#define GPIOMUX_EN BIT(3) +#define GPIOSEL_GPIO 0 +#define GPIOSEL_PHYDBG 1 +#define GPIOSEL_BT 2 +#define GPIOSEL_WLANDBG 3 +#define GPIOSEL_GPIO_MASK (~(BIT(0)|BIT(1))) + +#define HST_RDBUSY BIT(0) +#define CPU_WTBUSY BIT(1) + +#define IMR8190_DISABLED 0x0 +#define IMR_CPUERR BIT(5) +#define IMR_ATIMEND BIT(4) +#define IMR_TBDOK BIT(3) +#define IMR_TBDER BIT(2) +#define IMR_BCNDMAINT8 BIT(1) +#define IMR_BCNDMAINT7 BIT(0) +#define IMR_BCNDMAINT6 BIT(31) +#define IMR_BCNDMAINT5 BIT(30) +#define IMR_BCNDMAINT4 BIT(29) +#define IMR_BCNDMAINT3 BIT(28) +#define IMR_BCNDMAINT2 BIT(27) +#define IMR_BCNDMAINT1 BIT(26) +#define IMR_BCNDOK8 BIT(25) +#define IMR_BCNDOK7 BIT(24) +#define IMR_BCNDOK6 BIT(23) +#define IMR_BCNDOK5 BIT(22) +#define IMR_BCNDOK4 BIT(21) +#define IMR_BCNDOK3 BIT(20) +#define IMR_BCNDOK2 BIT(19) +#define IMR_BCNDOK1 BIT(18) +#define IMR_TIMEOUT2 BIT(17) +#define IMR_TIMEOUT1 BIT(16) +#define IMR_TXFOVW BIT(15) +#define IMR_PSTIMEOUT BIT(14) +#define IMR_BCNINT BIT(13) +#define IMR_RXFOVW BIT(12) +#define IMR_RDU BIT(11) +#define IMR_RXCMDOK BIT(10) +#define IMR_BDOK BIT(9) +#define IMR_HIGHDOK BIT(8) +#define IMR_COMDOK BIT(7) +#define IMR_MGNTDOK BIT(6) +#define IMR_HCCADOK BIT(5) +#define IMR_BKDOK BIT(4) +#define IMR_BEDOK BIT(3) +#define IMR_VIDOK BIT(2) +#define IMR_VODOK BIT(1) +#define IMR_ROK BIT(0) + +#define TPPOLL_BKQ BIT(0) +#define TPPOLL_BEQ BIT(1) +#define TPPOLL_VIQ BIT(2) +#define TPPOLL_VOQ BIT(3) +#define TPPOLL_BQ BIT(4) +#define TPPOLL_CQ BIT(5) +#define TPPOLL_MQ BIT(6) +#define TPPOLL_HQ BIT(7) +#define TPPOLL_HCCAQ BIT(8) +#define TPPOLL_STOPBK BIT(9) +#define TPPOLL_STOPBE BIT(10) +#define TPPOLL_STOPVI BIT(11) +#define TPPOLL_STOPVO BIT(12) +#define TPPOLL_STOPMGT BIT(13) +#define TPPOLL_STOPHIGH BIT(14) +#define TPPOLL_STOPHCCA BIT(15) +#define TPPOLL_SHIFT 8 + +#define CCX_CMD_CLM_ENABLE BIT(0) +#define CCX_CMD_NHM_ENABLE BIT(1) +#define CCX_CMD_FUNCTION_ENABLE BIT(8) +#define CCX_CMD_IGNORE_CCA BIT(9) +#define CCX_CMD_IGNORE_TXON BIT(10) +#define CCX_CLM_RESULT_READY BIT(16) +#define CCX_NHM_RESULT_READY BIT(16) +#define CCX_CMD_RESET 0x0 + + +#define HWSET_MAX_SIZE_92S 128 +#define EFUSE_MAX_SECTION 16 +#define EFUSE_REAL_CONTENT_LEN 512 + +#define RTL8190_EEPROM_ID 0x8129 +#define EEPROM_HPON 0x02 +#define EEPROM_CLK 0x06 +#define EEPROM_TESTR 0x08 + +#define EEPROM_VID 0x0A +#define EEPROM_DID 0x0C +#define EEPROM_SVID 0x0E +#define EEPROM_SMID 0x10 + +#define EEPROM_MAC_ADDR 0x12 +#define EEPROM_NODE_ADDRESS_BYTE_0 0x12 + +#define EEPROM_PWDIFF 0x54 + +#define EEPROM_TXPOWERBASE 0x50 +#define EEPROM_TX_PWR_INDEX_RANGE 28 + +#define EEPROM_TX_PWR_HT20_DIFF 0x62 +#define DEFAULT_HT20_TXPWR_DIFF 2 +#define EEPROM_TX_PWR_OFDM_DIFF 0x65 + +#define EEPROM_TXPWRGROUP 0x67 +#define EEPROM_REGULATORY 0x6D + +#define TX_PWR_SAFETY_CHK 0x6D +#define EEPROM_TXPWINDEX_CCK_24G 0x5D +#define EEPROM_TXPWINDEX_OFDM_24G 0x6B +#define EEPROM_HT2T_CH1_A 0x6c +#define EEPROM_HT2T_CH7_A 0x6d +#define EEPROM_HT2T_CH13_A 0x6e +#define EEPROM_HT2T_CH1_B 0x6f +#define EEPROM_HT2T_CH7_B 0x70 +#define EEPROM_HT2T_CH13_B 0x71 + +#define EEPROM_TSSI_A 0x74 +#define EEPROM_TSSI_B 0x75 + +#define EEPROM_RFIND_POWERDIFF 0x76 +#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3 + +#define EEPROM_THERMALMETER 0x77 +#define EEPROM_BLUETOOTH_COEXIST 0x78 +#define EEPROM_BLUETOOTH_TYPE 0x4f + +#define EEPROM_OPTIONAL 0x78 +#define EEPROM_WOWLAN 0x78 + +#define EEPROM_CRYSTALCAP 0x79 +#define EEPROM_CHANNELPLAN 0x7B +#define EEPROM_VERSION 0x7C +#define EEPROM_CUSTOMID 0x7A +#define EEPROM_BOARDTYPE 0x7E + +#define EEPROM_CHANNEL_PLAN_FCC 0x0 +#define EEPROM_CHANNEL_PLAN_IC 0x1 +#define EEPROM_CHANNEL_PLAN_ETSI 0x2 +#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 +#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 +#define EEPROM_CHANNEL_PLAN_MKK 0x5 +#define EEPROM_CHANNEL_PLAN_MKK1 0x6 +#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 +#define EEPROM_CHANNEL_PLAN_TELEC 0x8 +#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 +#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA +#define EEPROM_CHANNEL_PLAN_NCC 0xB +#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 + +#define FW_DIG_DISABLE 0xfd00cc00 +#define FW_DIG_ENABLE 0xfd000000 +#define FW_DIG_HALT 0xfd000001 +#define FW_DIG_RESUME 0xfd000002 +#define FW_HIGH_PWR_DISABLE 0xfd000008 +#define FW_HIGH_PWR_ENABLE 0xfd000009 +#define FW_ADD_A2_ENTRY 0xfd000016 +#define FW_TXPWR_TRACK_ENABLE 0xfd000017 +#define FW_TXPWR_TRACK_DISABLE 0xfd000018 +#define FW_TXPWR_TRACK_THERMAL 0xfd000019 +#define FW_TXANT_SWITCH_ENABLE 0xfd000023 +#define FW_TXANT_SWITCH_DISABLE 0xfd000024 +#define FW_RA_INIT 0xfd000026 +#define FW_CTRL_DM_BY_DRIVER 0Xfd00002a +#define FW_RA_IOT_BG_COMB 0xfd000030 +#define FW_RA_IOT_N_COMB 0xfd000031 +#define FW_RA_REFRESH 0xfd0000a0 +#define FW_RA_UPDATE_MASK 0xfd0000a2 +#define FW_RA_DISABLE 0xfd0000a4 +#define FW_RA_ACTIVE 0xfd0000a6 +#define FW_RA_DISABLE_RSSI_MASK 0xfd0000ac +#define FW_RA_ENABLE_RSSI_MASK 0xfd0000ad +#define FW_RA_RESET 0xfd0000af +#define FW_DM_DISABLE 0xfd00aa00 +#define FW_IQK_ENABLE 0xf0000020 +#define FW_IQK_SUCCESS 0x0000dddd +#define FW_IQK_FAIL 0x0000ffff +#define FW_OP_FAILURE 0xffffffff +#define FW_TX_FEEDBACK_NONE 0xfb000000 +#define FW_TX_FEEDBACK_DTM_ENABLE (FW_TX_FEEDBACK_NONE | 0x1) +#define FW_TX_FEEDBACK_CCX_ENABL (FW_TX_FEEDBACK_NONE | 0x2) +#define FW_BB_RESET_ENABLE 0xff00000d +#define FW_BB_RESET_DISABLE 0xff00000e +#define FW_CCA_CHK_ENABLE 0xff000011 +#define FW_CCK_RESET_CNT 0xff000013 +#define FW_LPS_ENTER 0xfe000010 +#define FW_LPS_LEAVE 0xfe000011 +#define FW_INDIRECT_READ 0xf2000000 +#define FW_INDIRECT_WRITE 0xf2000001 +#define FW_CHAN_SET 0xf3000001 + +#define RFPC 0x5F +#define RCR_9356SEL BIT(6) +#define TCR_LRL_OFFSET 0 +#define TCR_SRL_OFFSET 8 +#define TCR_MXDMA_OFFSET 21 +#define TCR_SAT BIT(24) +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 +#define RCR_OnlyErlPkt BIT(31) +#define CWR 0xDC +#define RETRYCTR 0xDE + +#define CPU_GEN_SYSTEM_RESET 0x00000001 + +#define CCX_COMMAND_REG 0x890 +#define CLM_PERIOD_REG 0x894 +#define NHM_PERIOD_REG 0x896 + +#define NHM_THRESHOLD0 0x898 +#define NHM_THRESHOLD1 0x899 +#define NHM_THRESHOLD2 0x89A +#define NHM_THRESHOLD3 0x89B +#define NHM_THRESHOLD4 0x89C +#define NHM_THRESHOLD5 0x89D +#define NHM_THRESHOLD6 0x89E +#define CLM_RESULT_REG 0x8D0 +#define NHM_RESULT_REG 0x8D4 +#define NHM_RPI_COUNTER0 0x8D8 +#define NHM_RPI_COUNTER1 0x8D9 +#define NHM_RPI_COUNTER2 0x8DA +#define NHM_RPI_COUNTER3 0x8DB +#define NHM_RPI_COUNTER4 0x8DC +#define NHM_RPI_COUNTER5 0x8DD +#define NHM_RPI_COUNTER6 0x8DE +#define NHM_RPI_COUNTER7 0x8DF + +#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) + +#define RPMAC_RESET 0x100 +#define RPMAC_TXSTART 0x104 +#define RPMAC_TXLEGACYSIG 0x108 +#define RPMAC_TXHTSIG1 0x10c +#define RPMAC_TXHTSIG2 0x110 +#define RPMAC_PHYDEBUG 0x114 +#define RPMAC_TXPACKETNNM 0x118 +#define RPMAC_TXIDLE 0x11c +#define RPMAC_TXMACHEADER0 0x120 +#define RPMAC_TXMACHEADER1 0x124 +#define RPMAC_TXMACHEADER2 0x128 +#define RPMAC_TXMACHEADER3 0x12c +#define RPMAC_TXMACHEADER4 0x130 +#define RPMAC_TXMACHEADER5 0x134 +#define RPMAC_TXDATATYPE 0x138 +#define RPMAC_TXRANDOMSEED 0x13c +#define RPMAC_CCKPLCPPREAMBLE 0x140 +#define RPMAC_CCKPLCPHEADER 0x144 +#define RPMAC_CCKCRC16 0x148 +#define RPMAC_OFDMRXCRC32OK 0x170 +#define RPMAC_OFDMRXCRC32ER 0x174 +#define RPMAC_OFDMRXPARITYER 0x178 +#define RPMAC_OFDMRXCRC8ER 0x17c +#define RPMAC_CCKCRXRC16ER 0x180 +#define RPMAC_CCKCRXRC32ER 0x184 +#define RPMAC_CCKCRXRC32OK 0x188 +#define RPMAC_TXSTATUS 0x18c + +#define RF_BB_CMD_ADDR 0x02c0 +#define RF_BB_CMD_DATA 0x02c4 + +#define RFPGA0_RFMOD 0x800 + +#define RFPGA0_TXINFO 0x804 +#define RFPGA0_PSDFUNCTION 0x808 + +#define RFPGA0_TXGAINSTAGE 0x80c + +#define RFPGA0_RFTIMING1 0x810 +#define RFPGA0_RFTIMING2 0x814 +#define RFPGA0_XA_HSSIPARAMETER1 0x820 +#define RFPGA0_XA_HSSIPARAMETER2 0x824 +#define RFPGA0_XB_HSSIPARAMETER1 0x828 +#define RFPGA0_XB_HSSIPARAMETER2 0x82c +#define RFPGA0_XC_HSSIPARAMETER1 0x830 +#define RFPGA0_XC_HSSIPARAMETER2 0x834 +#define RFPGA0_XD_HSSIPARAMETER1 0x838 +#define RFPGA0_XD_HSSIPARAMETER2 0x83c +#define RFPGA0_XA_LSSIPARAMETER 0x840 +#define RFPGA0_XB_LSSIPARAMETER 0x844 +#define RFPGA0_XC_LSSIPARAMETER 0x848 +#define RFPGA0_XD_LSSIPARAMETER 0x84c + +#define RFPGA0_RFWAKEUP_PARAMETER 0x850 +#define RFPGA0_RFSLEEPUP_PARAMETER 0x854 + +#define RFPGA0_XAB_SWITCHCONTROL 0x858 +#define RFPGA0_XCD_SWITCHCONTROL 0x85c + +#define RFPGA0_XA_RFINTERFACEOE 0x860 +#define RFPGA0_XB_RFINTERFACEOE 0x864 +#define RFPGA0_XC_RFINTERFACEOE 0x868 +#define RFPGA0_XD_RFINTERFACEOE 0x86c + +#define RFPGA0_XAB_RFINTERFACESW 0x870 +#define RFPGA0_XCD_RFINTERFACESW 0x874 + +#define RFPGA0_XAB_RFPARAMETER 0x878 +#define RFPGA0_XCD_RFPARAMETER 0x87c + +#define RFPGA0_ANALOGPARAMETER1 0x880 +#define RFPGA0_ANALOGPARAMETER2 0x884 +#define RFPGA0_ANALOGPARAMETER3 0x888 +#define RFPGA0_ANALOGPARAMETER4 0x88c + +#define RFPGA0_XA_LSSIREADBACK 0x8a0 +#define RFPGA0_XB_LSSIREADBACK 0x8a4 +#define RFPGA0_XC_LSSIREADBACK 0x8a8 +#define RFPGA0_XD_LSSIREADBACK 0x8ac + +#define RFPGA0_PSDREPORT 0x8b4 +#define TRANSCEIVERA_HSPI_READBACK 0x8b8 +#define TRANSCEIVERB_HSPI_READBACK 0x8bc +#define RFPGA0_XAB_RFINTERFACERB 0x8e0 +#define RFPGA0_XCD_RFINTERFACERB 0x8e4 +#define RFPGA1_RFMOD 0x900 + +#define RFPGA1_TXBLOCK 0x904 +#define RFPGA1_DEBUGSELECT 0x908 +#define RFPGA1_TXINFO 0x90c + +#define RCCK0_SYSTEM 0xa00 + +#define RCCK0_AFESETTING 0xa04 +#define RCCK0_CCA 0xa08 + +#define RCCK0_RXAGC1 0xa0c +#define RCCK0_RXAGC2 0xa10 + +#define RCCK0_RXHP 0xa14 + +#define RCCK0_DSPPARAMETER1 0xa18 +#define RCCK0_DSPPARAMETER2 0xa1c + +#define RCCK0_TXFILTER1 0xa20 +#define RCCK0_TXFILTER2 0xa24 +#define RCCK0_DEBUGPORT 0xa28 +#define RCCK0_FALSEALARMREPORT 0xa2c +#define RCCK0_TRSSIREPORT 0xa50 +#define RCCK0_RXREPORT 0xa54 +#define RCCK0_FACOUNTERLOWER 0xa5c +#define RCCK0_FACOUNTERUPPER 0xa58 + +#define ROFDM0_LSTF 0xc00 + +#define ROFDM0_TRXPATHENABLE 0xc04 +#define ROFDM0_TRMUXPAR 0xc08 +#define ROFDM0_TRSWISOLATION 0xc0c + +#define ROFDM0_XARXAFE 0xc10 +#define ROFDM0_XARXIQIMBALANCE 0xc14 +#define ROFDM0_XBRXAFE 0xc18 +#define ROFDM0_XBRXIQIMBALANCE 0xc1c +#define ROFDM0_XCRXAFE 0xc20 +#define ROFDM0_XCRXIQIMBALANCE 0xc24 +#define ROFDM0_XDRXAFE 0xc28 +#define ROFDM0_XDRXIQIMBALANCE 0xc2c + +#define ROFDM0_RXDETECTOR1 0xc30 +#define ROFDM0_RXDETECTOR2 0xc34 +#define ROFDM0_RXDETECTOR3 0xc38 +#define ROFDM0_RXDETECTOR4 0xc3c + +#define ROFDM0_RXDSP 0xc40 +#define ROFDM0_CFO_AND_DAGC 0xc44 +#define ROFDM0_CCADROP_THRESHOLD 0xc48 +#define ROFDM0_ECCA_THRESHOLD 0xc4c + +#define ROFDM0_XAAGCCORE1 0xc50 +#define ROFDM0_XAAGCCORE2 0xc54 +#define ROFDM0_XBAGCCORE1 0xc58 +#define ROFDM0_XBAGCCORE2 0xc5c +#define ROFDM0_XCAGCCORE1 0xc60 +#define ROFDM0_XCAGCCORE2 0xc64 +#define ROFDM0_XDAGCCORE1 0xc68 +#define ROFDM0_XDAGCCORE2 0xc6c + +#define ROFDM0_AGCPARAMETER1 0xc70 +#define ROFDM0_AGCPARAMETER2 0xc74 +#define ROFDM0_AGCRSSITABLE 0xc78 +#define ROFDM0_HTSTFAGC 0xc7c + +#define ROFDM0_XATXIQIMBALANCE 0xc80 +#define ROFDM0_XATXAFE 0xc84 +#define ROFDM0_XBTXIQIMBALANCE 0xc88 +#define ROFDM0_XBTXAFE 0xc8c +#define ROFDM0_XCTXIQIMBALANCE 0xc90 +#define ROFDM0_XCTXAFE 0xc94 +#define ROFDM0_XDTXIQIMBALANCE 0xc98 +#define ROFDM0_XDTXAFE 0xc9c + +#define ROFDM0_RXHP_PARAMETER 0xce0 +#define ROFDM0_TXPSEUDO_NOISE_WGT 0xce4 +#define ROFDM0_FRAME_SYNC 0xcf0 +#define ROFDM0_DFSREPORT 0xcf4 +#define ROFDM0_TXCOEFF1 0xca4 +#define ROFDM0_TXCOEFF2 0xca8 +#define ROFDM0_TXCOEFF3 0xcac +#define ROFDM0_TXCOEFF4 0xcb0 +#define ROFDM0_TXCOEFF5 0xcb4 +#define ROFDM0_TXCOEFF6 0xcb8 + + +#define ROFDM1_LSTF 0xd00 +#define ROFDM1_TRXPATHENABLE 0xd04 + +#define ROFDM1_CFO 0xd08 +#define ROFDM1_CSI1 0xd10 +#define ROFDM1_SBD 0xd14 +#define ROFDM1_CSI2 0xd18 +#define ROFDM1_CFOTRACKING 0xd2c +#define ROFDM1_TRXMESAURE1 0xd34 +#define ROFDM1_INTF_DET 0xd3c +#define ROFDM1_PSEUDO_NOISESTATEAB 0xd50 +#define ROFDM1_PSEUDO_NOISESTATECD 0xd54 +#define ROFDM1_RX_PSEUDO_NOISE_WGT 0xd58 + +#define ROFDM_PHYCOUNTER1 0xda0 +#define ROFDM_PHYCOUNTER2 0xda4 +#define ROFDM_PHYCOUNTER3 0xda8 + +#define ROFDM_SHORT_CFOAB 0xdac +#define ROFDM_SHORT_CFOCD 0xdb0 +#define ROFDM_LONG_CFOAB 0xdb4 +#define ROFDM_LONG_CFOCD 0xdb8 +#define ROFDM_TAIL_CFOAB 0xdbc +#define ROFDM_TAIL_CFOCD 0xdc0 +#define ROFDM_PW_MEASURE1 0xdc4 +#define ROFDM_PW_MEASURE2 0xdc8 +#define ROFDM_BW_REPORT 0xdcc +#define ROFDM_AGC_REPORT 0xdd0 +#define ROFDM_RXSNR 0xdd4 +#define ROFDM_RXEVMCSI 0xdd8 +#define ROFDM_SIG_REPORT 0xddc + + +#define RTXAGC_RATE18_06 0xe00 +#define RTXAGC_RATE54_24 0xe04 +#define RTXAGC_CCK_MCS32 0xe08 +#define RTXAGC_MCS03_MCS00 0xe10 +#define RTXAGC_MCS07_MCS04 0xe14 +#define RTXAGC_MCS11_MCS08 0xe18 +#define RTXAGC_MCS15_MCS12 0xe1c + + +#define RF_AC 0x00 +#define RF_IQADJ_G1 0x01 +#define RF_IQADJ_G2 0x02 +#define RF_POW_TRSW 0x05 +#define RF_GAIN_RX 0x06 +#define RF_GAIN_TX 0x07 +#define RF_TXM_IDAC 0x08 +#define RF_BS_IQGEN 0x0F + +#define RF_MODE1 0x10 +#define RF_MODE2 0x11 +#define RF_RX_AGC_HP 0x12 +#define RF_TX_AGC 0x13 +#define RF_BIAS 0x14 +#define RF_IPA 0x15 +#define RF_POW_ABILITY 0x17 +#define RF_MODE_AG 0x18 +#define RF_CHANNEL 0x18 +#define RF_CHNLBW 0x18 +#define RF_TOP 0x19 +#define RF_RX_G1 0x1A +#define RF_RX_G2 0x1B +#define RF_RX_BB2 0x1C +#define RF_RX_BB1 0x1D +#define RF_RCK1 0x1E +#define RF_RCK2 0x1F + +#define RF_TX_G1 0x20 +#define RF_TX_G2 0x21 +#define RF_TX_G3 0x22 +#define RF_TX_BB1 0x23 +#define RF_T_METER 0x24 +#define RF_SYN_G1 0x25 +#define RF_SYN_G2 0x26 +#define RF_SYN_G3 0x27 +#define RF_SYN_G4 0x28 +#define RF_SYN_G5 0x29 +#define RF_SYN_G6 0x2A +#define RF_SYN_G7 0x2B +#define RF_SYN_G8 0x2C + +#define RF_RCK_OS 0x30 +#define RF_TXPA_G1 0x31 +#define RF_TXPA_G2 0x32 +#define RF_TXPA_G3 0x33 + +#define BRFMOD 0x1 +#define BCCKEN 0x1000000 +#define BOFDMEN 0x2000000 + +#define BXBTXAGC 0xf00 +#define BXCTXAGC 0xf000 +#define BXDTXAGC 0xf0000 + +#define B3WIRE_DATALENGTH 0x800 +#define B3WIRE_ADDRESSLENGTH 0x400 + +#define BRFSI_RFENV 0x10 + +#define BLSSI_READADDRESS 0x7f800000 +#define BLSSI_READEDGE 0x80000000 +#define BLSSI_READBACK_DATA 0xfffff + +#define BADCLKPHASE 0x4000000 + +#define BCCK_SIDEBAND 0x10 + +#define BTX_AGCRATECCK 0x7f00 + +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff + +#define MAKS12BITS 0xfffff +#define MASK20BITS 0xfffff +#define RFREG_OFFSET_MASK 0xfffff + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c new file mode 100644 index 000000000000..1d3a48330399 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c @@ -0,0 +1,546 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" + + +static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel, + u8 chnl, u32 *ofdmbase, u32 *mcsbase, + u8 *p_final_pwridx) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 pwrbase0, pwrbase1; + u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0; + u8 i, pwrlevel[4]; + + for (i = 0; i < 2; i++) + pwrlevel[i] = p_pwrlevel[i]; + + /* We only care about the path A for legacy. */ + if (rtlefuse->eeprom_version < 2) { + pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_httxpowerdiff & 0xf); + } else if (rtlefuse->eeprom_version >= 2) { + legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff + [RF90_PATH_A][chnl - 1]; + + /* For legacy OFDM, tx pwr always > HT OFDM pwr. + * We do not care Path B + * legacy OFDM pwr diff. NO BB register + * to notify HW. */ + pwrbase0 = pwrlevel[0] + legacy_pwrdiff; + } + + pwrbase0 = (pwrbase0 << 24) | (pwrbase0 << 16) | (pwrbase0 << 8) | + pwrbase0; + *ofdmbase = pwrbase0; + + /* MCS rates */ + if (rtlefuse->eeprom_version >= 2) { + /* Check HT20 to HT40 diff */ + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { + for (i = 0; i < 2; i++) { + /* rf-A, rf-B */ + /* HT 20<->40 pwr diff */ + ht20_pwrdiff = rtlefuse->txpwr_ht20diff + [i][chnl - 1]; + + if (ht20_pwrdiff < 8) /* 0~+7 */ + pwrlevel[i] += ht20_pwrdiff; + else /* index8-15=-8~-1 */ + pwrlevel[i] -= (16 - ht20_pwrdiff); + } + } + } + + /* use index of rf-A */ + pwrbase1 = pwrlevel[0]; + pwrbase1 = (pwrbase1 << 24) | (pwrbase1 << 16) | (pwrbase1 << 8) | + pwrbase1; + *mcsbase = pwrbase1; + + /* The following is for Antenna + * diff from Ant-B to Ant-A */ + p_final_pwridx[0] = pwrlevel[0]; + p_final_pwridx[1] = pwrlevel[1]; + + switch (rtlefuse->eeprom_regulatory) { + case 3: + /* The following is for calculation + * of the power diff for Ant-B to Ant-A. */ + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + p_final_pwridx[0] += rtlefuse->pwrgroup_ht40 + [RF90_PATH_A][ + chnl - 1]; + p_final_pwridx[1] += rtlefuse->pwrgroup_ht40 + [RF90_PATH_B][ + chnl - 1]; + } else { + p_final_pwridx[0] += rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][ + chnl - 1]; + p_final_pwridx[1] += rtlefuse->pwrgroup_ht20 + [RF90_PATH_B][ + chnl - 1]; + } + break; + default: + break; + } + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("40MHz finalpwr_idx " + "(A / B) = 0x%x / 0x%x\n", p_final_pwridx[0], + p_final_pwridx[1])); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("20MHz finalpwr_idx " + "(A / B) = 0x%x / 0x%x\n", p_final_pwridx[0], + p_final_pwridx[1])); + } +} + +static void _rtl92s_set_antennadiff(struct ieee80211_hw *hw, + u8 *p_final_pwridx) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + char ant_pwr_diff = 0; + u32 u4reg_val = 0; + + if (rtlphy->rf_type == RF_2T2R) { + ant_pwr_diff = p_final_pwridx[1] - p_final_pwridx[0]; + + /* range is from 7~-8, + * index = 0x0~0xf */ + if (ant_pwr_diff > 7) + ant_pwr_diff = 7; + if (ant_pwr_diff < -8) + ant_pwr_diff = -8; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Antenna Diff from RF-B " + "to RF-A = %d (0x%x)\n", ant_pwr_diff, + ant_pwr_diff & 0xf)); + + ant_pwr_diff &= 0xf; + } + + /* Antenna TX power difference */ + rtlefuse->antenna_txpwdiff[2] = 0;/* RF-D, don't care */ + rtlefuse->antenna_txpwdiff[1] = 0;/* RF-C, don't care */ + rtlefuse->antenna_txpwdiff[0] = (u8)(ant_pwr_diff); /* RF-B */ + + u4reg_val = rtlefuse->antenna_txpwdiff[2] << 8 | + rtlefuse->antenna_txpwdiff[1] << 4 | + rtlefuse->antenna_txpwdiff[0]; + + rtl_set_bbreg(hw, RFPGA0_TXGAINSTAGE, (BXBTXAGC | BXCTXAGC | BXDTXAGC), + u4reg_val); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Write BCD-Diff(0x%x) = 0x%x\n", + RFPGA0_TXGAINSTAGE, u4reg_val)); +} + +static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw, + u8 chnl, u8 index, + u32 pwrbase0, + u32 pwrbase1, + u32 *p_outwrite_val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 i, chnlgroup, pwrdiff_limit[4]; + u32 writeval, customer_limit; + + /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */ + switch (rtlefuse->eeprom_regulatory) { + case 0: + /* Realtek better performance increase power diff + * defined by Realtek for large power */ + chnlgroup = 0; + + writeval = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index] + + ((index < 2) ? pwrbase0 : pwrbase1); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("RTK better performance, " + "writeval = 0x%x\n", writeval)); + break; + case 1: + /* Realtek regulatory increase power diff defined + * by Realtek for regulatory */ + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + writeval = ((index < 2) ? pwrbase0 : pwrbase1); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Realtek regulatory, " + "40MHz, writeval = 0x%x\n", writeval)); + } else { + if (rtlphy->pwrgroup_cnt == 1) + chnlgroup = 0; + + if (rtlphy->pwrgroup_cnt >= 3) { + if (chnl <= 3) + chnlgroup = 0; + else if (chnl >= 4 && chnl <= 8) + chnlgroup = 1; + else if (chnl > 8) + chnlgroup = 2; + if (rtlphy->pwrgroup_cnt == 4) + chnlgroup++; + } + + writeval = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index] + + ((index < 2) ? + pwrbase0 : pwrbase1); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Realtek regulatory, " + "20MHz, writeval = 0x%x\n", writeval)); + } + break; + case 2: + /* Better regulatory don't increase any power diff */ + writeval = ((index < 2) ? pwrbase0 : pwrbase1); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Better regulatory, " + "writeval = 0x%x\n", writeval)); + break; + case 3: + /* Customer defined power diff. increase power diff + defined by customer. */ + chnlgroup = 0; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("customer's limit, 40MHz = 0x%x\n", + rtlefuse->pwrgroup_ht40 + [RF90_PATH_A][chnl - 1])); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("customer's limit, 20MHz = 0x%x\n", + rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][chnl - 1])); + } + + for (i = 0; i < 4; i++) { + pwrdiff_limit[i] = + (u8)((rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index] & (0x7f << (i * 8))) + >> (i * 8)); + + if (rtlphy->current_chan_bw == + HT_CHANNEL_WIDTH_20_40) { + if (pwrdiff_limit[i] > + rtlefuse->pwrgroup_ht40 + [RF90_PATH_A][chnl - 1]) { + pwrdiff_limit[i] = + rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][chnl - 1]; + } + } else { + if (pwrdiff_limit[i] > + rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][chnl - 1]) { + pwrdiff_limit[i] = + rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][chnl - 1]; + } + } + } + + customer_limit = (pwrdiff_limit[3] << 24) | + (pwrdiff_limit[2] << 16) | + (pwrdiff_limit[1] << 8) | + (pwrdiff_limit[0]); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Customer's limit = 0x%x\n", + customer_limit)); + + writeval = customer_limit + ((index < 2) ? + pwrbase0 : pwrbase1); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Customer, writeval = " + "0x%x\n", writeval)); + break; + default: + chnlgroup = 0; + writeval = rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index] + + ((index < 2) ? pwrbase0 : pwrbase1); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("RTK better performance, " + "writeval = 0x%x\n", writeval)); + break; + } + + if (rtlpriv->dm.dynamic_txhighpower_lvl == TX_HIGH_PWR_LEVEL_LEVEL1) + writeval = 0x10101010; + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TX_HIGH_PWR_LEVEL_LEVEL2) + writeval = 0x0; + + *p_outwrite_val = writeval; + +} + +static void _rtl92s_write_ofdm_powerreg(struct ieee80211_hw *hw, + u8 index, u32 val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u16 regoffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c}; + u8 i, rfa_pwr[4]; + u8 rfa_lower_bound = 0, rfa_upper_bound = 0, rf_pwr_diff = 0; + u32 writeval = val; + + /* If path A and Path B coexist, we must limit Path A tx power. + * Protect Path B pwr over or under flow. We need to calculate + * upper and lower bound of path A tx power. */ + if (rtlphy->rf_type == RF_2T2R) { + rf_pwr_diff = rtlefuse->antenna_txpwdiff[0]; + + /* Diff=-8~-1 */ + if (rf_pwr_diff >= 8) { + /* Prevent underflow!! */ + rfa_lower_bound = 0x10 - rf_pwr_diff; + /* if (rf_pwr_diff >= 0) Diff = 0-7 */ + } else { + rfa_upper_bound = RF6052_MAX_TX_PWR - rf_pwr_diff; + } + } + + for (i = 0; i < 4; i++) { + rfa_pwr[i] = (u8)((writeval & (0x7f << (i * 8))) >> (i * 8)); + if (rfa_pwr[i] > RF6052_MAX_TX_PWR) + rfa_pwr[i] = RF6052_MAX_TX_PWR; + + /* If path A and Path B coexist, we must limit Path A tx power. + * Protect Path B pwr over or under flow. We need to calculate + * upper and lower bound of path A tx power. */ + if (rtlphy->rf_type == RF_2T2R) { + /* Diff=-8~-1 */ + if (rf_pwr_diff >= 8) { + /* Prevent underflow!! */ + if (rfa_pwr[i] < rfa_lower_bound) + rfa_pwr[i] = rfa_lower_bound; + /* Diff = 0-7 */ + } else if (rf_pwr_diff >= 1) { + /* Prevent overflow */ + if (rfa_pwr[i] > rfa_upper_bound) + rfa_pwr[i] = rfa_upper_bound; + } + } + + } + + writeval = (rfa_pwr[3] << 24) | (rfa_pwr[2] << 16) | (rfa_pwr[1] << 8) | + rfa_pwr[0]; + + rtl_set_bbreg(hw, regoffset[index], 0x7f7f7f7f, writeval); +} + +void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw, + u8 *p_pwrlevel, u8 chnl) +{ + u32 writeval, pwrbase0, pwrbase1; + u8 index = 0; + u8 finalpwr_idx[4]; + + _rtl92s_get_powerbase(hw, p_pwrlevel, chnl, &pwrbase0, &pwrbase1, + &finalpwr_idx[0]); + _rtl92s_set_antennadiff(hw, &finalpwr_idx[0]); + + for (index = 0; index < 6; index++) { + _rtl92s_get_txpower_writeval_byregulatory(hw, chnl, index, + pwrbase0, pwrbase1, &writeval); + + _rtl92s_write_ofdm_powerreg(hw, index, writeval); + } +} + +void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, u8 pwrlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 txagc = 0; + bool dont_inc_cck_or_turboscanoff = false; + + if (((rtlefuse->eeprom_version >= 2) && + (rtlefuse->txpwr_safetyflag == 1)) || + ((rtlefuse->eeprom_version >= 2) && + (rtlefuse->eeprom_regulatory != 0))) + dont_inc_cck_or_turboscanoff = true; + + if (mac->act_scanning == true) { + txagc = 0x3f; + if (dont_inc_cck_or_turboscanoff) + txagc = pwrlevel; + } else { + txagc = pwrlevel; + + if (rtlpriv->dm.dynamic_txhighpower_lvl == + TX_HIGH_PWR_LEVEL_LEVEL1) + txagc = 0x10; + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TX_HIGH_PWR_LEVEL_LEVEL2) + txagc = 0x0; + } + + if (txagc > RF6052_MAX_TX_PWR) + txagc = RF6052_MAX_TX_PWR; + + rtl_set_bbreg(hw, RTXAGC_CCK_MCS32, BTX_AGCRATECCK, txagc); + +} + +bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 u4reg_val = 0; + u8 rfpath; + bool rtstatus = true; + struct bb_reg_def *pphyreg; + + /* Initialize RF */ + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + + pphyreg = &rtlphy->phyreg_def[rfpath]; + + /* Store original RFENV control type */ + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + u4reg_val = rtl92s_phy_query_bb_reg(hw, + pphyreg->rfintfs, + BRFSI_RFENV); + break; + case RF90_PATH_B: + case RF90_PATH_D: + u4reg_val = rtl92s_phy_query_bb_reg(hw, + pphyreg->rfintfs, + BRFSI_RFENV << 16); + break; + } + + /* Set RF_ENV enable */ + rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfe, + BRFSI_RFENV << 16, 0x1); + + /* Set RF_ENV output high */ + rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); + + /* Set bit number of Address and Data for RF register */ + rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2, + B3WIRE_ADDRESSLENGTH, 0x0); + rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2, + B3WIRE_DATALENGTH, 0x0); + + /* Initialize RF fom connfiguration file */ + switch (rfpath) { + case RF90_PATH_A: + rtstatus = rtl92s_phy_config_rf(hw, + (enum radio_path)rfpath); + break; + case RF90_PATH_B: + rtstatus = rtl92s_phy_config_rf(hw, + (enum radio_path)rfpath); + break; + case RF90_PATH_C: + break; + case RF90_PATH_D: + break; + } + + /* Restore RFENV control type */ + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, BRFSI_RFENV, + u4reg_val); + break; + case RF90_PATH_B: + case RF90_PATH_D: + rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, + BRFSI_RFENV << 16, + u4reg_val); + break; + } + + if (rtstatus != true) { + printk(KERN_ERR "Radio[%d] Fail!!", rfpath); + goto fail; + } + + } + + return rtstatus; + +fail: + return rtstatus; +} + +void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + switch (bandwidth) { + case HT_CHANNEL_WIDTH_20: + rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & + 0xfffff3ff) | 0x0400); + rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[0]); + break; + case HT_CHANNEL_WIDTH_20_40: + rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & + 0xfffff3ff)); + rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[0]); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("unknown bandwidth: %#X\n", + bandwidth)); + break; + } +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.h b/drivers/net/wireless/rtlwifi/rtl8192se/rf.h new file mode 100644 index 000000000000..3843baa1a874 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __INC_RTL92S_RF_H +#define __INC_RTL92S_RF_H + +#define RF6052_MAX_TX_PWR 0x3F + +void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, + u8 bandwidth); +bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) ; +void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, + u8 powerlevel); +void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw, + u8 *p_pwrlevel, u8 chnl); + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c new file mode 100644 index 000000000000..1c6cb1d7d660 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -0,0 +1,423 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include + +#include "../wifi.h" +#include "../core.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" +#include "hw.h" +#include "sw.h" +#include "trx.h" +#include "led.h" + +static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + /*close ASPM for AMD defaultly */ + rtlpci->const_amdpci_aspm = 0; + + /* + * ASPM PS mode. + * 0 - Disable ASPM, + * 1 - Enable ASPM without Clock Req, + * 2 - Enable ASPM with Clock Req, + * 3 - Alwyas Enable ASPM with Clock Req, + * 4 - Always Enable ASPM without Clock Req. + * set defult to RTL8192CE:3 RTL8192E:2 + * */ + rtlpci->const_pci_aspm = 2; + + /*Setting for PCI-E device */ + rtlpci->const_devicepci_aspm_setting = 0x03; + + /*Setting for PCI-E bridge */ + rtlpci->const_hostpci_aspm_setting = 0x02; + + /* + * In Hw/Sw Radio Off situation. + * 0 - Default, + * 1 - From ASPM setting without low Mac Pwr, + * 2 - From ASPM setting with low Mac Pwr, + * 3 - Bus D3 + * set default to RTL8192CE:0 RTL8192SE:2 + */ + rtlpci->const_hwsw_rfoff_d3 = 2; + + /* + * This setting works for those device with + * backdoor ASPM setting such as EPHY setting. + * 0 - Not support ASPM, + * 1 - Support ASPM, + * 2 - According to chipset. + */ + rtlpci->const_support_pciaspm = 2; +} + +static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + const struct firmware *firmware; + struct rt_firmware *pfirmware = NULL; + int err = 0; + u16 earlyrxthreshold = 7; + + rtlpriv->dm.dm_initialgain_enable = 1; + rtlpriv->dm.dm_flag = 0; + rtlpriv->dm.disable_framebursting = 0; + rtlpriv->dm.thermalvalue = 0; + rtlpriv->dm.useramask = true; + + /* compatible 5G band 91se just 2.4G band & smsp */ + rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; + rtlpriv->rtlhal.bandset = BAND_ON_2_4G; + rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; + + rtlpci->transmit_config = 0; + + rtlpci->receive_config = + RCR_APPFCS | + RCR_APWRMGT | + /*RCR_ADD3 |*/ + RCR_AMF | + RCR_ADF | + RCR_APP_MIC | + RCR_APP_ICV | + RCR_AICV | + /* Accept ICV error, CRC32 Error */ + RCR_ACRC32 | + RCR_AB | + /* Accept Broadcast, Multicast */ + RCR_AM | + /* Accept Physical match */ + RCR_APM | + /* Accept Destination Address packets */ + /*RCR_AAP |*/ + RCR_APP_PHYST_STAFF | + /* Accept PHY status */ + RCR_APP_PHYST_RXFF | + (earlyrxthreshold << RCR_FIFO_OFFSET); + + rtlpci->irq_mask[0] = (u32) + (IMR_ROK | + IMR_VODOK | + IMR_VIDOK | + IMR_BEDOK | + IMR_BKDOK | + IMR_HCCADOK | + IMR_MGNTDOK | + IMR_COMDOK | + IMR_HIGHDOK | + IMR_BDOK | + IMR_RXCMDOK | + /*IMR_TIMEOUT0 |*/ + IMR_RDU | + IMR_RXFOVW | + IMR_BCNINT + /*| IMR_TXFOVW*/ + /*| IMR_TBDOK | + IMR_TBDER*/); + + rtlpci->irq_mask[1] = (u32) 0; + + rtlpci->shortretry_limit = 0x30; + rtlpci->longretry_limit = 0x30; + + rtlpci->first_init = true; + + /* for LPS & IPS */ + rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; + rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; + rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpriv->psc.reg_fwctrl_lps = 3; + rtlpriv->psc.reg_max_lps_awakeintvl = 5; + /* for ASPM, you can close aspm through + * set const_support_pciaspm = 0 */ + rtl92s_init_aspm_vars(hw); + + if (rtlpriv->psc.reg_fwctrl_lps == 1) + rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 2) + rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 3) + rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = vzalloc(sizeof(struct rt_firmware)); + if (!rtlpriv->rtlhal.pfirmware) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Can't alloc buffer for fw.\n")); + return 1; + } + + printk(KERN_INFO "rtl8192se: Driver for Realtek RTL8192SE/RTL8191SE\n" + " Loading firmware %s\n", rtlpriv->cfg->fw_name); + /* request fw */ + err = request_firmware(&firmware, rtlpriv->cfg->fw_name, + rtlpriv->io.dev); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Failed to request firmware!\n")); + return 1; + } + if (firmware->size > sizeof(struct rt_firmware)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Firmware is too big!\n")); + release_firmware(firmware); + return 1; + } + + pfirmware = (struct rt_firmware *)rtlpriv->rtlhal.pfirmware; + memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size); + pfirmware->sz_fw_tmpbufferlen = firmware->size; + release_firmware(firmware); + + return err; +} + +static void rtl92s_deinit_sw_vars(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->rtlhal.pfirmware) { + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; + } +} + +static struct rtl_hal_ops rtl8192se_hal_ops = { + .init_sw_vars = rtl92s_init_sw_vars, + .deinit_sw_vars = rtl92s_deinit_sw_vars, + .read_eeprom_info = rtl92se_read_eeprom_info, + .interrupt_recognized = rtl92se_interrupt_recognized, + .hw_init = rtl92se_hw_init, + .hw_disable = rtl92se_card_disable, + .hw_suspend = rtl92se_suspend, + .hw_resume = rtl92se_resume, + .enable_interrupt = rtl92se_enable_interrupt, + .disable_interrupt = rtl92se_disable_interrupt, + .set_network_type = rtl92se_set_network_type, + .set_chk_bssid = rtl92se_set_check_bssid, + .set_qos = rtl92se_set_qos, + .set_bcn_reg = rtl92se_set_beacon_related_registers, + .set_bcn_intv = rtl92se_set_beacon_interval, + .update_interrupt_mask = rtl92se_update_interrupt_mask, + .get_hw_reg = rtl92se_get_hw_reg, + .set_hw_reg = rtl92se_set_hw_reg, + .update_rate_tbl = rtl92se_update_hal_rate_tbl, + .fill_tx_desc = rtl92se_tx_fill_desc, + .fill_tx_cmddesc = rtl92se_tx_fill_cmddesc, + .query_rx_desc = rtl92se_rx_query_desc, + .set_channel_access = rtl92se_update_channel_access_setting, + .radio_onoff_checking = rtl92se_gpio_radio_on_off_checking, + .set_bw_mode = rtl92s_phy_set_bw_mode, + .switch_channel = rtl92s_phy_sw_chnl, + .dm_watchdog = rtl92s_dm_watchdog, + .scan_operation_backup = rtl92s_phy_scan_operation_backup, + .set_rf_power_state = rtl92s_phy_set_rf_power_state, + .led_control = rtl92se_led_control, + .set_desc = rtl92se_set_desc, + .get_desc = rtl92se_get_desc, + .tx_polling = rtl92se_tx_polling, + .enable_hw_sec = rtl92se_enable_hw_security_config, + .set_key = rtl92se_set_key, + .init_sw_leds = rtl92se_init_sw_leds, + .get_bbreg = rtl92s_phy_query_bb_reg, + .set_bbreg = rtl92s_phy_set_bb_reg, + .get_rfreg = rtl92s_phy_query_rf_reg, + .set_rfreg = rtl92s_phy_set_rf_reg, +}; + +static struct rtl_mod_params rtl92se_mod_params = { + .sw_crypto = false, + .inactiveps = true, + .swctrl_lps = true, + .fwctrl_lps = false, +}; + +/* Because memory R/W bursting will cause system hang/crash + * for 92se, so we don't read back after every write action */ +static struct rtl_hal_cfg rtl92se_hal_cfg = { + .bar_id = 1, + .write_readback = false, + .name = "rtl92s_pci", + .fw_name = "rtlwifi/rtl8192sefw.bin", + .ops = &rtl8192se_hal_ops, + .mod_params = &rtl92se_mod_params, + + .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, + .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN, + .maps[SYS_CLK] = SYS_CLKR, + .maps[MAC_RCR_AM] = RCR_AM, + .maps[MAC_RCR_AB] = RCR_AB, + .maps[MAC_RCR_ACRC32] = RCR_ACRC32, + .maps[MAC_RCR_ACF] = RCR_ACF, + .maps[MAC_RCR_AAP] = RCR_AAP, + + .maps[EFUSE_TEST] = REG_EFUSE_TEST, + .maps[EFUSE_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_CLK] = REG_EFUSE_CLK, + .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_PWC_EV12V] = 0, /* nouse for 8192se */ + .maps[EFUSE_FEN_ELDR] = 0, /* nouse for 8192se */ + .maps[EFUSE_LOADER_CLK_EN] = 0,/* nouse for 8192se */ + .maps[EFUSE_ANA8M] = EFUSE_ANA8M, + .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE_92S, + .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, + .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, + + .maps[RWCAM] = REG_RWCAM, + .maps[WCAMI] = REG_WCAMI, + .maps[RCAMO] = REG_RCAMO, + .maps[CAMDBG] = REG_CAMDBG, + .maps[SECR] = REG_SECR, + .maps[SEC_CAM_NONE] = CAM_NONE, + .maps[SEC_CAM_WEP40] = CAM_WEP40, + .maps[SEC_CAM_TKIP] = CAM_TKIP, + .maps[SEC_CAM_AES] = CAM_AES, + .maps[SEC_CAM_WEP104] = CAM_WEP104, + + .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6, + .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5, + .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4, + .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3, + .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2, + .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1, + .maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8, + .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7, + .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6, + .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5, + .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4, + .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3, + .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2, + .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1, + .maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2, + .maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1, + + .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW, + .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT, + .maps[RTL_IMR_BcnInt] = IMR_BCNINT, + .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, + .maps[RTL_IMR_RDU] = IMR_RDU, + .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, + .maps[RTL_IMR_BDOK] = IMR_BDOK, + .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK, + .maps[RTL_IMR_TBDER] = IMR_TBDER, + .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK, + .maps[RTL_IMR_COMDOK] = IMR_COMDOK, + .maps[RTL_IMR_TBDOK] = IMR_TBDOK, + .maps[RTL_IMR_BKDOK] = IMR_BKDOK, + .maps[RTL_IMR_BEDOK] = IMR_BEDOK, + .maps[RTL_IMR_VIDOK] = IMR_VIDOK, + .maps[RTL_IMR_VODOK] = IMR_VODOK, + .maps[RTL_IMR_ROK] = IMR_ROK, + .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), + + .maps[RTL_RC_CCK_RATE1M] = DESC92S_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC92S_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC92S_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC92S_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC92S_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC92S_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC92S_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC92S_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC92S_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC92S_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC92S_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC92S_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC92S_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC92S_RATEMCS15, +}; + +static struct pci_device_id rtl92se_pci_ids[] __devinitdata = { + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8192, rtl92se_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8171, rtl92se_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8172, rtl92se_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8173, rtl92se_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8174, rtl92se_hal_cfg)}, + {}, +}; + +MODULE_DEVICE_TABLE(pci, rtl92se_pci_ids); + +MODULE_AUTHOR("lizhaoming "); +MODULE_AUTHOR("Realtek WlanFAE "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8192S/8191S 802.11n PCI wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8192sefw.bin"); + +module_param_named(swenc, rtl92se_mod_params.sw_crypto, bool, 0444); +module_param_named(ips, rtl92se_mod_params.inactiveps, bool, 0444); +module_param_named(swlps, rtl92se_mod_params.swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl92se_mod_params.fwctrl_lps, bool, 0444); +MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); +MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); +MODULE_PARM_DESC(swlps, "using linked sw control power save (default 1 is " + "open)\n"); + + +static struct pci_driver rtl92se_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl92se_pci_ids, + .probe = rtl_pci_probe, + .remove = rtl_pci_disconnect, + +#ifdef CONFIG_PM + .suspend = rtl_pci_suspend, + .resume = rtl_pci_resume, +#endif + +}; + +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); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/rtlwifi/rtl8192se/sw.h similarity index 69% rename from drivers/net/wireless/iwlwifi/iwl-agn-led.h rename to drivers/net/wireless/rtlwifi/rtl8192se/sw.h index 96f323dc5dd6..fc4eb285a0ac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2009-2010 Realtek Corporation. * * 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 @@ -19,15 +19,18 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. * *****************************************************************************/ +#ifndef __REALTEK_PCI92SE_SW_H__ +#define __REALTEK_PCI92SE_SW_H__ -#ifndef __iwl_agn_led_h__ -#define __iwl_agn_led_h__ +#define EFUSE_MAX_SECTION 16 -extern const struct iwl_led_ops iwlagn_led_ops; -void iwlagn_led_enable(struct iwl_priv *priv); +int rtl92se_init_sw(struct ieee80211_hw *hw); +void rtl92se_deinit_sw(struct ieee80211_hw *hw); +void rtl92se_init_var_map(struct ieee80211_hw *hw); -#endif /* __iwl_agn_led_h__ */ +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/table.c b/drivers/net/wireless/rtlwifi/rtl8192se/table.c new file mode 100644 index 000000000000..154185b3969d --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/table.c @@ -0,0 +1,634 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + * Created on 2010/ 5/18, 1:41 + *****************************************************************************/ + +#include "table.h" + +u32 rtl8192sephy_reg_2t2rarray[PHY_REG_2T2RARRAYLENGTH] = { + 0x01c, 0x07000000, + 0x800, 0x00040000, + 0x804, 0x00008003, + 0x808, 0x0000fc00, + 0x80c, 0x0000000a, + 0x810, 0x10005088, + 0x814, 0x020c3d10, + 0x818, 0x00200185, + 0x81c, 0x00000000, + 0x820, 0x01000000, + 0x824, 0x00390004, + 0x828, 0x01000000, + 0x82c, 0x00390004, + 0x830, 0x00000004, + 0x834, 0x00690200, + 0x838, 0x00000004, + 0x83c, 0x00690200, + 0x840, 0x00010000, + 0x844, 0x00010000, + 0x848, 0x00000000, + 0x84c, 0x00000000, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x48484848, + 0x85c, 0x65a965a9, + 0x860, 0x0f7f0130, + 0x864, 0x0f7f0130, + 0x868, 0x0f7f0130, + 0x86c, 0x0f7f0130, + 0x870, 0x03000700, + 0x874, 0x03000300, + 0x878, 0x00020002, + 0x87c, 0x004f0201, + 0x880, 0xa8300ac1, + 0x884, 0x00000058, + 0x888, 0x00000008, + 0x88c, 0x00000004, + 0x890, 0x00000000, + 0x894, 0xfffffffe, + 0x898, 0x40302010, + 0x89c, 0x00706050, + 0x8b0, 0x00000000, + 0x8e0, 0x00000000, + 0x8e4, 0x00000000, + 0xe00, 0x30333333, + 0xe04, 0x2a2d2e2f, + 0xe08, 0x00003232, + 0xe10, 0x30333333, + 0xe14, 0x2a2d2e2f, + 0xe18, 0x30333333, + 0xe1c, 0x2a2d2e2f, + 0xe30, 0x01007c00, + 0xe34, 0x01004800, + 0xe38, 0x1000dc1f, + 0xe3c, 0x10008c1f, + 0xe40, 0x021400a0, + 0xe44, 0x281600a0, + 0xe48, 0xf8000001, + 0xe4c, 0x00002910, + 0xe50, 0x01007c00, + 0xe54, 0x01004800, + 0xe58, 0x1000dc1f, + 0xe5c, 0x10008c1f, + 0xe60, 0x021400a0, + 0xe64, 0x281600a0, + 0xe6c, 0x00002910, + 0xe70, 0x31ed92fb, + 0xe74, 0x361536fb, + 0xe78, 0x361536fb, + 0xe7c, 0x361536fb, + 0xe80, 0x361536fb, + 0xe84, 0x000d92fb, + 0xe88, 0x000d92fb, + 0xe8c, 0x31ed92fb, + 0xed0, 0x31ed92fb, + 0xed4, 0x31ed92fb, + 0xed8, 0x000d92fb, + 0xedc, 0x000d92fb, + 0xee0, 0x000d92fb, + 0xee4, 0x015e5448, + 0xee8, 0x21555448, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90c, 0x01121313, + 0xa00, 0x00d047c8, + 0xa04, 0x80ff0008, + 0xa08, 0x8ccd8300, + 0xa0c, 0x2e62120f, + 0xa10, 0x9500bb78, + 0xa14, 0x11144028, + 0xa18, 0x00881117, + 0xa1c, 0x89140f00, + 0xa20, 0x1a1b0000, + 0xa24, 0x090e1317, + 0xa28, 0x00000204, + 0xa2c, 0x10d30000, + 0xc00, 0x40071d40, + 0xc04, 0x00a05633, + 0xc08, 0x000000e4, + 0xc0c, 0x6c6c6c6c, + 0xc10, 0x08800000, + 0xc14, 0x40000100, + 0xc18, 0x08000000, + 0xc1c, 0x40000100, + 0xc20, 0x08000000, + 0xc24, 0x40000100, + 0xc28, 0x08000000, + 0xc2c, 0x40000100, + 0xc30, 0x6de9ac44, + 0xc34, 0x469652cf, + 0xc38, 0x49795994, + 0xc3c, 0x0a979764, + 0xc40, 0x1f7c403f, + 0xc44, 0x000100b7, + 0xc48, 0xec020000, + 0xc4c, 0x007f037f, + 0xc50, 0x69543420, + 0xc54, 0x433c0094, + 0xc58, 0x69543420, + 0xc5c, 0x433c0094, + 0xc60, 0x69543420, + 0xc64, 0x433c0094, + 0xc68, 0x69543420, + 0xc6c, 0x433c0094, + 0xc70, 0x2c7f000d, + 0xc74, 0x0186155b, + 0xc78, 0x0000001f, + 0xc7c, 0x00b91612, + 0xc80, 0x40000100, + 0xc84, 0x20f60000, + 0xc88, 0x20000080, + 0xc8c, 0x20200000, + 0xc90, 0x40000100, + 0xc94, 0x00000000, + 0xc98, 0x40000100, + 0xc9c, 0x00000000, + 0xca0, 0x00492492, + 0xca4, 0x00000000, + 0xca8, 0x00000000, + 0xcac, 0x00000000, + 0xcb0, 0x00000000, + 0xcb4, 0x00000000, + 0xcb8, 0x00000000, + 0xcbc, 0x28000000, + 0xcc0, 0x00000000, + 0xcc4, 0x00000000, + 0xcc8, 0x00000000, + 0xccc, 0x00000000, + 0xcd0, 0x00000000, + 0xcd4, 0x00000000, + 0xcd8, 0x64b22427, + 0xcdc, 0x00766932, + 0xce0, 0x00222222, + 0xce4, 0x00000000, + 0xce8, 0x37644302, + 0xcec, 0x2f97d40c, + 0xd00, 0x00000750, + 0xd04, 0x00000403, + 0xd08, 0x0000907f, + 0xd0c, 0x00000001, + 0xd10, 0xa0633333, + 0xd14, 0x33333c63, + 0xd18, 0x6a8f5b6b, + 0xd1c, 0x00000000, + 0xd20, 0x00000000, + 0xd24, 0x00000000, + 0xd28, 0x00000000, + 0xd2c, 0xcc979975, + 0xd30, 0x00000000, + 0xd34, 0x00000000, + 0xd38, 0x00000000, + 0xd3c, 0x00027293, + 0xd40, 0x00000000, + 0xd44, 0x00000000, + 0xd48, 0x00000000, + 0xd50, 0x6437140a, + 0xd54, 0x024dbd02, + 0xd58, 0x00000000, + 0xd5c, 0x30032064, + 0xd60, 0x4653de68, + 0xd64, 0x00518a3c, + 0xd68, 0x00002101, + 0xf14, 0x00000003, + 0xf4c, 0x00000000, + 0xf00, 0x00000300, +}; + +u32 rtl8192sephy_changeto_1t1rarray[PHY_CHANGETO_1T1RARRAYLENGTH] = { + 0x844, 0xffffffff, 0x00010000, + 0x804, 0x0000000f, 0x00000001, + 0x824, 0x00f0000f, 0x00300004, + 0x82c, 0x00f0000f, 0x00100002, + 0x870, 0x04000000, 0x00000001, + 0x864, 0x00000400, 0x00000000, + 0x878, 0x000f000f, 0x00000002, + 0xe74, 0x0f000000, 0x00000002, + 0xe78, 0x0f000000, 0x00000002, + 0xe7c, 0x0f000000, 0x00000002, + 0xe80, 0x0f000000, 0x00000002, + 0x90c, 0x000000ff, 0x00000011, + 0xc04, 0x000000ff, 0x00000011, + 0xd04, 0x0000000f, 0x00000001, + 0x1f4, 0xffff0000, 0x00007777, + 0x234, 0xf8000000, 0x0000000a, +}; + +u32 rtl8192sephy_changeto_1t2rarray[PHY_CHANGETO_1T2RARRAYLENGTH] = { + 0x804, 0x0000000f, 0x00000003, + 0x824, 0x00f0000f, 0x00300004, + 0x82c, 0x00f0000f, 0x00300002, + 0x870, 0x04000000, 0x00000001, + 0x864, 0x00000400, 0x00000000, + 0x878, 0x000f000f, 0x00000002, + 0xe74, 0x0f000000, 0x00000002, + 0xe78, 0x0f000000, 0x00000002, + 0xe7c, 0x0f000000, 0x00000002, + 0xe80, 0x0f000000, 0x00000002, + 0x90c, 0x000000ff, 0x00000011, + 0xc04, 0x000000ff, 0x00000033, + 0xd04, 0x0000000f, 0x00000003, + 0x1f4, 0xffff0000, 0x00007777, + 0x234, 0xf8000000, 0x0000000a, +}; + +u32 rtl8192sephy_reg_array_pg[PHY_REG_ARRAY_PGLENGTH] = { + 0xe00, 0xffffffff, 0x06090909, + 0xe04, 0xffffffff, 0x00030406, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x0a0c0d0e, + 0xe14, 0xffffffff, 0x04070809, + 0xe18, 0xffffffff, 0x0a0c0d0e, + 0xe1c, 0xffffffff, 0x04070809, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x02040404, + 0xe14, 0xffffffff, 0x00000002, + 0xe18, 0xffffffff, 0x02040404, + 0xe1c, 0xffffffff, 0x00000002, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x02040404, + 0xe14, 0xffffffff, 0x00000002, + 0xe18, 0xffffffff, 0x02040404, + 0xe1c, 0xffffffff, 0x00000002, + 0xe00, 0xffffffff, 0x02020202, + 0xe04, 0xffffffff, 0x00020202, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x02020202, + 0xe14, 0xffffffff, 0x00000002, + 0xe18, 0xffffffff, 0x02020202, + 0xe1c, 0xffffffff, 0x00000002, +}; + +u32 rtl8192seradioa_1t_array[RADIOA_1T_ARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00030250, + 0x002, 0x00010000, + 0x010, 0x0008000f, + 0x011, 0x000231fc, + 0x010, 0x000c000f, + 0x011, 0x0003f9f8, + 0x010, 0x0002000f, + 0x011, 0x00020101, + 0x014, 0x0001093e, + 0x014, 0x0009093e, + 0x015, 0x0000f8f4, + 0x017, 0x000f6500, + 0x01a, 0x00013056, + 0x01b, 0x00060000, + 0x01c, 0x00000300, + 0x01e, 0x00031059, + 0x021, 0x00054000, + 0x022, 0x0000083c, + 0x023, 0x00001558, + 0x024, 0x00000060, + 0x025, 0x00022583, + 0x026, 0x0000f200, + 0x027, 0x000eacf1, + 0x028, 0x0009bd54, + 0x029, 0x00004582, + 0x02a, 0x00000001, + 0x02b, 0x00021334, + 0x02a, 0x00000000, + 0x02b, 0x0000000a, + 0x02a, 0x00000001, + 0x02b, 0x00000808, + 0x02b, 0x00053333, + 0x02c, 0x0000000c, + 0x02a, 0x00000002, + 0x02b, 0x00000808, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000003, + 0x02b, 0x00000808, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000004, + 0x02b, 0x00000808, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000005, + 0x02b, 0x00000709, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x00000006, + 0x02b, 0x00000709, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000007, + 0x02b, 0x00000709, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000008, + 0x02b, 0x00000709, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000009, + 0x02b, 0x0000060a, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000a, + 0x02b, 0x0000060a, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000b, + 0x02b, 0x0000060a, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000c, + 0x02b, 0x0000060a, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000d, + 0x02b, 0x0000050b, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000e, + 0x02b, 0x0000050b, + 0x02b, 0x00066623, + 0x02c, 0x0000001a, + 0x02a, 0x000e4000, + 0x030, 0x00020000, + 0x031, 0x000b9631, + 0x032, 0x0000130d, + 0x033, 0x00000187, + 0x013, 0x00019e6c, + 0x013, 0x00015e94, + 0x000, 0x00010159, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x01e, 0x0003105b, + 0x0fe, 0x00000000, + 0x000, 0x00030159, + 0x010, 0x0004000f, + 0x011, 0x000203f9, +}; + +u32 rtl8192seradiob_array[RADIOB_ARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00001041, + 0x002, 0x00011000, + 0x005, 0x00080fc0, + 0x007, 0x000fc803, + 0x013, 0x00017cb0, + 0x013, 0x00011cc0, + 0x013, 0x0000dc60, + 0x013, 0x00008c60, + 0x013, 0x00004450, + 0x013, 0x00000020, +}; + +u32 rtl8192seradiob_gm_array[RADIOB_GM_ARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00001041, + 0x002, 0x00011000, + 0x005, 0x00080fc0, + 0x007, 0x000fc803, +}; + +u32 rtl8192semac_2t_array[MAC_2T_ARRAYLENGTH] = { + 0x020, 0x00000035, + 0x048, 0x0000000e, + 0x049, 0x000000f0, + 0x04a, 0x00000077, + 0x04b, 0x00000083, + 0x0b5, 0x00000021, + 0x0dc, 0x000000ff, + 0x0dd, 0x000000ff, + 0x0de, 0x000000ff, + 0x0df, 0x000000ff, + 0x116, 0x00000000, + 0x117, 0x00000000, + 0x118, 0x00000000, + 0x119, 0x00000000, + 0x11a, 0x00000000, + 0x11b, 0x00000000, + 0x11c, 0x00000000, + 0x11d, 0x00000000, + 0x160, 0x0000000b, + 0x161, 0x0000000b, + 0x162, 0x0000000b, + 0x163, 0x0000000b, + 0x164, 0x0000000b, + 0x165, 0x0000000b, + 0x166, 0x0000000b, + 0x167, 0x0000000b, + 0x168, 0x0000000b, + 0x169, 0x0000000b, + 0x16a, 0x0000000b, + 0x16b, 0x0000000b, + 0x16c, 0x0000000b, + 0x16d, 0x0000000b, + 0x16e, 0x0000000b, + 0x16f, 0x0000000b, + 0x170, 0x0000000b, + 0x171, 0x0000000b, + 0x172, 0x0000000b, + 0x173, 0x0000000b, + 0x174, 0x0000000b, + 0x175, 0x0000000b, + 0x176, 0x0000000b, + 0x177, 0x0000000b, + 0x178, 0x0000000b, + 0x179, 0x0000000b, + 0x17a, 0x0000000b, + 0x17b, 0x0000000b, + 0x17c, 0x0000000b, + 0x17d, 0x0000000b, + 0x17e, 0x0000000b, + 0x17f, 0x0000000b, + 0x236, 0x0000000c, + 0x503, 0x00000022, + 0x560, 0x00000000, +}; + +u32 rtl8192seagctab_array[AGCTAB_ARRAYLENGTH] = { + 0xc78, 0x7f000001, + 0xc78, 0x7f010001, + 0xc78, 0x7e020001, + 0xc78, 0x7d030001, + 0xc78, 0x7c040001, + 0xc78, 0x7b050001, + 0xc78, 0x7a060001, + 0xc78, 0x79070001, + 0xc78, 0x78080001, + 0xc78, 0x77090001, + 0xc78, 0x760a0001, + 0xc78, 0x750b0001, + 0xc78, 0x740c0001, + 0xc78, 0x730d0001, + 0xc78, 0x720e0001, + 0xc78, 0x710f0001, + 0xc78, 0x70100001, + 0xc78, 0x6f110001, + 0xc78, 0x6f120001, + 0xc78, 0x6e130001, + 0xc78, 0x6d140001, + 0xc78, 0x6d150001, + 0xc78, 0x6c160001, + 0xc78, 0x6b170001, + 0xc78, 0x6a180001, + 0xc78, 0x6a190001, + 0xc78, 0x691a0001, + 0xc78, 0x681b0001, + 0xc78, 0x671c0001, + 0xc78, 0x661d0001, + 0xc78, 0x651e0001, + 0xc78, 0x641f0001, + 0xc78, 0x63200001, + 0xc78, 0x4c210001, + 0xc78, 0x4b220001, + 0xc78, 0x4a230001, + 0xc78, 0x49240001, + 0xc78, 0x48250001, + 0xc78, 0x47260001, + 0xc78, 0x46270001, + 0xc78, 0x45280001, + 0xc78, 0x44290001, + 0xc78, 0x2c2a0001, + 0xc78, 0x2b2b0001, + 0xc78, 0x2a2c0001, + 0xc78, 0x292d0001, + 0xc78, 0x282e0001, + 0xc78, 0x272f0001, + 0xc78, 0x26300001, + 0xc78, 0x25310001, + 0xc78, 0x24320001, + 0xc78, 0x23330001, + 0xc78, 0x22340001, + 0xc78, 0x09350001, + 0xc78, 0x08360001, + 0xc78, 0x07370001, + 0xc78, 0x06380001, + 0xc78, 0x05390001, + 0xc78, 0x043a0001, + 0xc78, 0x033b0001, + 0xc78, 0x023c0001, + 0xc78, 0x013d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x7f400001, + 0xc78, 0x7f410001, + 0xc78, 0x7e420001, + 0xc78, 0x7d430001, + 0xc78, 0x7c440001, + 0xc78, 0x7b450001, + 0xc78, 0x7a460001, + 0xc78, 0x79470001, + 0xc78, 0x78480001, + 0xc78, 0x77490001, + 0xc78, 0x764a0001, + 0xc78, 0x754b0001, + 0xc78, 0x744c0001, + 0xc78, 0x734d0001, + 0xc78, 0x724e0001, + 0xc78, 0x714f0001, + 0xc78, 0x70500001, + 0xc78, 0x6f510001, + 0xc78, 0x6f520001, + 0xc78, 0x6e530001, + 0xc78, 0x6d540001, + 0xc78, 0x6d550001, + 0xc78, 0x6c560001, + 0xc78, 0x6b570001, + 0xc78, 0x6a580001, + 0xc78, 0x6a590001, + 0xc78, 0x695a0001, + 0xc78, 0x685b0001, + 0xc78, 0x675c0001, + 0xc78, 0x665d0001, + 0xc78, 0x655e0001, + 0xc78, 0x645f0001, + 0xc78, 0x63600001, + 0xc78, 0x4c610001, + 0xc78, 0x4b620001, + 0xc78, 0x4a630001, + 0xc78, 0x49640001, + 0xc78, 0x48650001, + 0xc78, 0x47660001, + 0xc78, 0x46670001, + 0xc78, 0x45680001, + 0xc78, 0x44690001, + 0xc78, 0x2c6a0001, + 0xc78, 0x2b6b0001, + 0xc78, 0x2a6c0001, + 0xc78, 0x296d0001, + 0xc78, 0x286e0001, + 0xc78, 0x276f0001, + 0xc78, 0x26700001, + 0xc78, 0x25710001, + 0xc78, 0x24720001, + 0xc78, 0x23730001, + 0xc78, 0x22740001, + 0xc78, 0x09750001, + 0xc78, 0x08760001, + 0xc78, 0x07770001, + 0xc78, 0x06780001, + 0xc78, 0x05790001, + 0xc78, 0x047a0001, + 0xc78, 0x037b0001, + 0xc78, 0x027c0001, + 0xc78, 0x017d0001, + 0xc78, 0x007e0001, + 0xc78, 0x007f0001, + 0xc78, 0x3000001e, + 0xc78, 0x3001001e, + 0xc78, 0x3002001e, + 0xc78, 0x3003001e, + 0xc78, 0x3004001e, + 0xc78, 0x3405001e, + 0xc78, 0x3806001e, + 0xc78, 0x3e07001e, + 0xc78, 0x3e08001e, + 0xc78, 0x4409001e, + 0xc78, 0x460a001e, + 0xc78, 0x480b001e, + 0xc78, 0x480c001e, + 0xc78, 0x4e0d001e, + 0xc78, 0x560e001e, + 0xc78, 0x5a0f001e, + 0xc78, 0x5e10001e, + 0xc78, 0x6211001e, + 0xc78, 0x6c12001e, + 0xc78, 0x7213001e, + 0xc78, 0x7214001e, + 0xc78, 0x7215001e, + 0xc78, 0x7216001e, + 0xc78, 0x7217001e, + 0xc78, 0x7218001e, + 0xc78, 0x7219001e, + 0xc78, 0x721a001e, + 0xc78, 0x721b001e, + 0xc78, 0x721c001e, + 0xc78, 0x721d001e, + 0xc78, 0x721e001e, + 0xc78, 0x721f001e, +}; + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/table.h b/drivers/net/wireless/rtlwifi/rtl8192se/table.h new file mode 100644 index 000000000000..b4ed6d951ebb --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/table.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * 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: + * wlanfae + * + * Larry Finger + * + ******************************************************************************/ +#ifndef __INC_HAL8192SE_FW_IMG_H +#define __INC_HAL8192SE_FW_IMG_H + +#include + +/*Created on 2010/ 4/12, 5:56*/ + +#define PHY_REG_2T2RARRAYLENGTH 372 +extern u32 rtl8192sephy_reg_2t2rarray[PHY_REG_2T2RARRAYLENGTH]; +#define PHY_CHANGETO_1T1RARRAYLENGTH 48 +extern u32 rtl8192sephy_changeto_1t1rarray[PHY_CHANGETO_1T1RARRAYLENGTH]; +#define PHY_CHANGETO_1T2RARRAYLENGTH 45 +extern u32 rtl8192sephy_changeto_1t2rarray[PHY_CHANGETO_1T2RARRAYLENGTH]; +#define PHY_REG_ARRAY_PGLENGTH 84 +extern u32 rtl8192sephy_reg_array_pg[PHY_REG_ARRAY_PGLENGTH]; +#define RADIOA_1T_ARRAYLENGTH 202 +extern u32 rtl8192seradioa_1t_array[RADIOA_1T_ARRAYLENGTH]; +#define RADIOB_ARRAYLENGTH 22 +extern u32 rtl8192seradiob_array[RADIOB_ARRAYLENGTH]; +#define RADIOB_GM_ARRAYLENGTH 10 +extern u32 rtl8192seradiob_gm_array[RADIOB_GM_ARRAYLENGTH]; +#define MAC_2T_ARRAYLENGTH 106 +extern u32 rtl8192semac_2t_array[MAC_2T_ARRAYLENGTH]; +#define AGCTAB_ARRAYLENGTH 320 +extern u32 rtl8192seagctab_array[AGCTAB_ARRAYLENGTH]; + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c new file mode 100644 index 000000000000..5cf442373d46 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -0,0 +1,976 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "fw.h" +#include "trx.h" +#include "led.h" + +static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue) +{ + __le16 fc = rtl_get_fc(skb); + + if (unlikely(ieee80211_is_beacon(fc))) + return QSLT_BEACON; + if (ieee80211_is_mgmt(fc)) + return QSLT_MGNT; + if (ieee80211_is_nullfunc(fc)) + return QSLT_HIGH; + + return skb->priority; +} + +static int _rtl92se_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu) +{ + int rate_idx = 0; + + if (first_ampdu) { + if (false == isht) { + switch (desc_rate) { + case DESC92S_RATE1M: + rate_idx = 0; + break; + case DESC92S_RATE2M: + rate_idx = 1; + break; + case DESC92S_RATE5_5M: + rate_idx = 2; + break; + case DESC92S_RATE11M: + rate_idx = 3; + break; + case DESC92S_RATE6M: + rate_idx = 4; + break; + case DESC92S_RATE9M: + rate_idx = 5; + break; + case DESC92S_RATE12M: + rate_idx = 6; + break; + case DESC92S_RATE18M: + rate_idx = 7; + break; + case DESC92S_RATE24M: + rate_idx = 8; + break; + case DESC92S_RATE36M: + rate_idx = 9; + break; + case DESC92S_RATE48M: + rate_idx = 10; + break; + case DESC92S_RATE54M: + rate_idx = 11; + break; + default: + rate_idx = 0; + break; + } + } else { + rate_idx = 11; + } + + return rate_idx; + } + + switch (desc_rate) { + case DESC92S_RATE1M: + rate_idx = 0; + break; + case DESC92S_RATE2M: + rate_idx = 1; + break; + case DESC92S_RATE5_5M: + rate_idx = 2; + break; + case DESC92S_RATE11M: + rate_idx = 3; + break; + case DESC92S_RATE6M: + rate_idx = 4; + break; + case DESC92S_RATE9M: + rate_idx = 5; + break; + case DESC92S_RATE12M: + rate_idx = 6; + break; + case DESC92S_RATE18M: + rate_idx = 7; + break; + case DESC92S_RATE24M: + rate_idx = 8; + break; + case DESC92S_RATE36M: + rate_idx = 9; + break; + case DESC92S_RATE48M: + rate_idx = 10; + break; + case DESC92S_RATE54M: + rate_idx = 11; + break; + default: + rate_idx = 11; + break; + } + return rate_idx; +} + +static u8 _rtl92s_query_rxpwrpercentage(char antpower) +{ + if ((antpower <= -100) || (antpower >= 20)) + return 0; + else if (antpower >= 0) + return 100; + else + return 100 + antpower; +} + +static u8 _rtl92s_evm_db_to_percentage(char value) +{ + char ret_val; + ret_val = value; + + if (ret_val >= 0) + ret_val = 0; + + if (ret_val <= -33) + ret_val = -33; + + ret_val = 0 - ret_val; + ret_val *= 3; + + if (ret_val == 99) + ret_val = 100; + + return ret_val; +} + +static long _rtl92se_translate_todbm(struct ieee80211_hw *hw, + u8 signal_strength_index) +{ + long signal_power; + + signal_power = (long)((signal_strength_index + 1) >> 1); + signal_power -= 95; + return signal_power; +} + +static long _rtl92se_signal_scale_mapping(struct ieee80211_hw *hw, + long currsig) +{ + long retsig = 0; + + /* Step 1. Scale mapping. */ + if (currsig > 47) + retsig = 100; + else if (currsig > 14 && currsig <= 47) + retsig = 100 - ((47 - currsig) * 3) / 2; + else if (currsig > 2 && currsig <= 14) + retsig = 48 - ((14 - currsig) * 15) / 7; + else if (currsig >= 0) + retsig = currsig * 9 + 1; + + return retsig; +} + + +static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, + struct rtl_stats *pstats, u8 *pdesc, + struct rx_fwinfo *p_drvinfo, + bool packet_match_bssid, + bool packet_toself, + bool packet_beacon) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct phy_sts_cck_8192s_t *cck_buf; + s8 rx_pwr_all = 0, rx_pwr[4]; + u8 rf_rx_num = 0, evm, pwdb_all; + u8 i, max_spatial_stream; + u32 rssi, total_rssi = 0; + bool in_powersavemode = false; + bool is_cck_rate; + + is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); + pstats->packet_matchbssid = packet_match_bssid; + pstats->packet_toself = packet_toself; + pstats->is_cck = is_cck_rate; + pstats->packet_beacon = packet_beacon; + pstats->is_cck = is_cck_rate; + pstats->rx_mimo_signalquality[0] = -1; + pstats->rx_mimo_signalquality[1] = -1; + + if (is_cck_rate) { + u8 report, cck_highpwr; + cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; + + if (!in_powersavemode) + cck_highpwr = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + 0x200); + else + cck_highpwr = false; + + if (!cck_highpwr) { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = cck_buf->cck_agc_rpt & 0xc0; + report = report >> 6; + switch (report) { + case 0x3: + rx_pwr_all = -40 - (cck_agc_rpt & 0x3e); + break; + case 0x2: + rx_pwr_all = -20 - (cck_agc_rpt & 0x3e); + break; + case 0x1: + rx_pwr_all = -2 - (cck_agc_rpt & 0x3e); + break; + case 0x0: + rx_pwr_all = 14 - (cck_agc_rpt & 0x3e); + break; + } + } else { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = p_drvinfo->cfosho[0] & 0x60; + report = report >> 5; + switch (report) { + case 0x3: + rx_pwr_all = -40 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x2: + rx_pwr_all = -20 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x1: + rx_pwr_all = -2 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x0: + rx_pwr_all = 14 - ((cck_agc_rpt & 0x1f) << 1); + break; + } + } + + pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all); + + /* CCK gain is smaller than OFDM/MCS gain, */ + /* so we add gain diff by experiences, the val is 6 */ + pwdb_all += 6; + if (pwdb_all > 100) + pwdb_all = 100; + /* modify the offset to make the same gain index with OFDM. */ + if (pwdb_all > 34 && pwdb_all <= 42) + pwdb_all -= 2; + else if (pwdb_all > 26 && pwdb_all <= 34) + pwdb_all -= 6; + else if (pwdb_all > 14 && pwdb_all <= 26) + pwdb_all -= 8; + else if (pwdb_all > 4 && pwdb_all <= 14) + pwdb_all -= 4; + + pstats->rx_pwdb_all = pwdb_all; + pstats->recvsignalpower = rx_pwr_all; + + if (packet_match_bssid) { + u8 sq; + if (pstats->rx_pwdb_all > 40) { + sq = 100; + } else { + sq = cck_buf->sq_rpt; + if (sq > 64) + sq = 0; + else if (sq < 20) + sq = 100; + else + sq = ((64 - sq) * 100) / 44; + } + + pstats->signalquality = sq; + pstats->rx_mimo_signalquality[0] = sq; + pstats->rx_mimo_signalquality[1] = -1; + } + } else { + rtlpriv->dm.rfpath_rxenable[0] = + rtlpriv->dm.rfpath_rxenable[1] = true; + for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) { + if (rtlpriv->dm.rfpath_rxenable[i]) + rf_rx_num++; + + rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & + 0x3f) * 2) - 110; + rssi = _rtl92s_query_rxpwrpercentage(rx_pwr[i]); + total_rssi += rssi; + rtlpriv->stats.rx_snr_db[i] = + (long)(p_drvinfo->rxsnr[i] / 2); + + if (packet_match_bssid) + pstats->rx_mimo_signalstrength[i] = (u8) rssi; + } + + rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110; + pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all); + pstats->rx_pwdb_all = pwdb_all; + pstats->rxpower = rx_pwr_all; + pstats->recvsignalpower = rx_pwr_all; + + if (GET_RX_STATUS_DESC_RX_HT(pdesc) && + GET_RX_STATUS_DESC_RX_MCS(pdesc) >= DESC92S_RATEMCS8 && + GET_RX_STATUS_DESC_RX_MCS(pdesc) <= DESC92S_RATEMCS15) + max_spatial_stream = 2; + else + max_spatial_stream = 1; + + for (i = 0; i < max_spatial_stream; i++) { + evm = _rtl92s_evm_db_to_percentage(p_drvinfo->rxevm[i]); + + if (packet_match_bssid) { + if (i == 0) + pstats->signalquality = (u8)(evm & + 0xff); + pstats->rx_mimo_signalquality[i] = + (u8) (evm & 0xff); + } + } + } + + if (is_cck_rate) + pstats->signalstrength = (u8)(_rtl92se_signal_scale_mapping(hw, + pwdb_all)); + else if (rf_rx_num != 0) + pstats->signalstrength = (u8) (_rtl92se_signal_scale_mapping(hw, + total_rssi /= rf_rx_num)); +} + +static void _rtl92se_process_ui_rssi(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rfpath; + u32 last_rssi, tmpval; + + if (pstats->packet_toself || pstats->packet_beacon) { + rtlpriv->stats.rssi_calculate_cnt++; + + if (rtlpriv->stats.ui_rssi.total_num++ >= + PHY_RSSI_SLID_WIN_MAX) { + rtlpriv->stats.ui_rssi.total_num = + PHY_RSSI_SLID_WIN_MAX; + last_rssi = rtlpriv->stats.ui_rssi.elements[ + rtlpriv->stats.ui_rssi.index]; + rtlpriv->stats.ui_rssi.total_val -= last_rssi; + } + + rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength; + rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++] + = pstats->signalstrength; + + if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX) + rtlpriv->stats.ui_rssi.index = 0; + + tmpval = rtlpriv->stats.ui_rssi.total_val / + rtlpriv->stats.ui_rssi.total_num; + rtlpriv->stats.signal_strength = _rtl92se_translate_todbm(hw, + (u8) tmpval); + pstats->rssi = rtlpriv->stats.signal_strength; + } + + if (!pstats->is_cck && pstats->packet_toself) { + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + pstats->rx_mimo_signalstrength[rfpath]; + + } + + if (pstats->rx_mimo_signalstrength[rfpath] > + rtlpriv->stats.rx_rssi_percentage[rfpath]) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + ((rtlpriv->stats.rx_rssi_percentage[rfpath] + * (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + + rtlpriv->stats.rx_rssi_percentage[rfpath] = + rtlpriv->stats.rx_rssi_percentage[rfpath] + + 1; + } else { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + ((rtlpriv->stats.rx_rssi_percentage[rfpath] + * (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + } + + } + } +} + +static void _rtl92se_update_rxsignalstatistics(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int weighting = 0; + + if (rtlpriv->stats.recv_signal_power == 0) + rtlpriv->stats.recv_signal_power = pstats->recvsignalpower; + + if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power) + weighting = 5; + else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power) + weighting = (-5); + + rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * 5 + + pstats->recvsignalpower + + weighting) / 6; +} + +static void _rtl92se_process_pwdb(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undec_sm_pwdb = 0; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + return; + } else { + undec_sm_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + } + + if (pstats->packet_toself || pstats->packet_beacon) { + if (undec_sm_pwdb < 0) + undec_sm_pwdb = pstats->rx_pwdb_all; + + if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) { + undec_sm_pwdb = + (((undec_sm_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + + undec_sm_pwdb = undec_sm_pwdb + 1; + } else { + undec_sm_pwdb = (((undec_sm_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + (pstats->rx_pwdb_all)) / + (RX_SMOOTH_FACTOR); + } + + rtlpriv->dm.undecorated_smoothed_pwdb = undec_sm_pwdb; + _rtl92se_update_rxsignalstatistics(hw, pstats); + } +} + +static void rtl_92s_process_streams(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 stream; + + for (stream = 0; stream < 2; stream++) { + if (pstats->rx_mimo_signalquality[stream] != -1) { + if (rtlpriv->stats.rx_evm_percentage[stream] == 0) { + rtlpriv->stats.rx_evm_percentage[stream] = + pstats->rx_mimo_signalquality[stream]; + } + + rtlpriv->stats.rx_evm_percentage[stream] = + ((rtlpriv->stats.rx_evm_percentage[stream] * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalquality[stream] * + 1)) / (RX_SMOOTH_FACTOR); + } + } +} + +static void _rtl92se_process_ui_link_quality(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 last_evm = 0, tmpval; + + if (pstats->signalquality != 0) { + if (pstats->packet_toself || pstats->packet_beacon) { + + if (rtlpriv->stats.ui_link_quality.total_num++ >= + PHY_LINKQUALITY_SLID_WIN_MAX) { + rtlpriv->stats.ui_link_quality.total_num = + PHY_LINKQUALITY_SLID_WIN_MAX; + last_evm = + rtlpriv->stats.ui_link_quality.elements[ + rtlpriv->stats.ui_link_quality.index]; + rtlpriv->stats.ui_link_quality.total_val -= + last_evm; + } + + rtlpriv->stats.ui_link_quality.total_val += + pstats->signalquality; + rtlpriv->stats.ui_link_quality.elements[ + rtlpriv->stats.ui_link_quality.index++] = + pstats->signalquality; + + if (rtlpriv->stats.ui_link_quality.index >= + PHY_LINKQUALITY_SLID_WIN_MAX) + rtlpriv->stats.ui_link_quality.index = 0; + + tmpval = rtlpriv->stats.ui_link_quality.total_val / + rtlpriv->stats.ui_link_quality.total_num; + rtlpriv->stats.signal_quality = tmpval; + + rtlpriv->stats.last_sigstrength_inpercent = tmpval; + + rtl_92s_process_streams(hw, pstats); + + } + } +} + +static void _rtl92se_process_phyinfo(struct ieee80211_hw *hw, + u8 *buffer, + struct rtl_stats *pcurrent_stats) +{ + + if (!pcurrent_stats->packet_matchbssid && + !pcurrent_stats->packet_beacon) + return; + + _rtl92se_process_ui_rssi(hw, pcurrent_stats); + _rtl92se_process_pwdb(hw, pcurrent_stats); + _rtl92se_process_ui_link_quality(hw, pcurrent_stats); +} + +static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, struct rtl_stats *pstats, + u8 *pdesc, struct rx_fwinfo *p_drvinfo) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + struct ieee80211_hdr *hdr; + u8 *tmp_buf; + u8 *praddr; + u8 *psaddr; + __le16 fc; + u16 type, cfc; + bool packet_matchbssid, packet_toself, packet_beacon; + + tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; + + hdr = (struct ieee80211_hdr *)tmp_buf; + fc = hdr->frame_control; + cfc = le16_to_cpu(fc); + type = WLAN_FC_GET_TYPE(fc); + praddr = hdr->addr1; + psaddr = hdr->addr2; + + 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)); + + packet_toself = packet_matchbssid && + (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + + if (ieee80211_is_beacon(fc)) + packet_beacon = true; + + _rtl92se_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, + packet_matchbssid, packet_toself, packet_beacon); + _rtl92se_process_phyinfo(hw, tmp_buf, pstats); +} + +bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, u8 *pdesc, + struct sk_buff *skb) +{ + struct rx_fwinfo *p_drvinfo; + u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc); + + stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc); + stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8; + stats->rx_bufshift = (u8)(GET_RX_STATUS_DESC_SHIFT(pdesc) & 0x03); + stats->icv = (u16)GET_RX_STATUS_DESC_ICV(pdesc); + stats->crc = (u16)GET_RX_STATUS_DESC_CRC32(pdesc); + stats->hwerror = (u16)(stats->crc | stats->icv); + stats->decrypted = !GET_RX_STATUS_DESC_SWDEC(pdesc); + + stats->rate = (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc); + stats->shortpreamble = (u16)GET_RX_STATUS_DESC_SPLCP(pdesc); + stats->isampdu = (bool)(GET_RX_STATUS_DESC_PAGGR(pdesc) == 1); + stats->timestamp_low = GET_RX_STATUS_DESC_TSFL(pdesc); + stats->rx_is40Mhzpacket = (bool)GET_RX_STATUS_DESC_BW(pdesc); + + if (stats->hwerror) + return false; + + rx_status->freq = hw->conf.channel->center_freq; + rx_status->band = hw->conf.channel->band; + + if (GET_RX_STATUS_DESC_CRC32(pdesc)) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (!GET_RX_STATUS_DESC_SWDEC(pdesc)) + rx_status->flag |= RX_FLAG_DECRYPTED; + + if (GET_RX_STATUS_DESC_BW(pdesc)) + rx_status->flag |= RX_FLAG_40MHZ; + + if (GET_RX_STATUS_DESC_RX_HT(pdesc)) + rx_status->flag |= RX_FLAG_HT; + + rx_status->flag |= RX_FLAG_MACTIME_MPDU; + + if (stats->decrypted) + rx_status->flag |= RX_FLAG_DECRYPTED; + + rx_status->rate_idx = _rtl92se_rate_mapping((bool) + GET_RX_STATUS_DESC_RX_HT(pdesc), + (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc), + (bool)GET_RX_STATUS_DESC_PAGGR(pdesc)); + + + rx_status->mactime = GET_RX_STATUS_DESC_TSFL(pdesc); + if (phystatus == true) { + p_drvinfo = (struct rx_fwinfo *)(skb->data + + stats->rx_bufshift); + _rtl92se_translate_rx_signal_stuff(hw, skb, stats, pdesc, + p_drvinfo); + } + + /*rx_status->qual = stats->signal; */ + rx_status->signal = stats->rssi + 10; + /*rx_status->noise = -stats->noise; */ + + return true; +} + +void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, struct sk_buff *skb, + u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct ieee80211_sta *sta = info->control.sta; + u8 *pdesc = (u8 *) pdesc_tx; + u16 seq_number; + __le16 fc = hdr->frame_control; + u8 reserved_macid = 0; + u8 fw_qsel = _rtl92se_map_hwqueue_to_fwqueue(skb, hw_queue); + bool firstseg = (!(hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG))); + bool lastseg = (!(hdr->frame_control & + cpu_to_le16(IEEE80211_FCTL_MOREFRAGS))); + dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + u8 bw_40 = 0; + + if (mac->opmode == NL80211_IFTYPE_STATION) { + bw_40 = mac->bw_40; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) + bw_40 = sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } + + seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + + rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); + + CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE_RTL8192S); + + if (firstseg) { + if (rtlpriv->dm.useramask) { + /* set txdesc macId */ + if (ptcb_desc->mac_id < 32) { + SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id); + reserved_macid |= ptcb_desc->mac_id; + } + } + SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid); + + SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >= + DESC92S_RATEMCS0) ? 1 : 0)); + + if (rtlhal->version == VERSION_8192S_ACUT) { + if (ptcb_desc->hw_rate == DESC92S_RATE1M || + ptcb_desc->hw_rate == DESC92S_RATE2M || + ptcb_desc->hw_rate == DESC92S_RATE5_5M || + ptcb_desc->hw_rate == DESC92S_RATE11M) { + ptcb_desc->hw_rate = DESC92S_RATE12M; + } + } + + SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); + + if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble) + SET_TX_DESC_TX_SHORT(pdesc, 0); + + /* Aggregation related */ + if (info->flags & IEEE80211_TX_CTL_AMPDU) + SET_TX_DESC_AGG_ENABLE(pdesc, 1); + + /* For AMPDU, we must insert SSN into TX_DESC */ + SET_TX_DESC_SEQ(pdesc, seq_number); + + /* Protection mode related */ + /* For 92S, if RTS/CTS are set, HW will execute RTS. */ + /* We choose only one protection mode to execute */ + SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable && + !ptcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS_ENABLE(pdesc, ((ptcb_desc->cts_enable) ? + 1 : 0)); + SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); + + SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); + SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0); + SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc); + SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= + DESC92S_RATE54M) ? + (ptcb_desc->rts_use_shortpreamble ? 1 : 0) + : (ptcb_desc->rts_use_shortgi ? 1 : 0))); + + + /* Set Bandwidth and sub-channel settings. */ + if (bw_40) { + if (ptcb_desc->packet_bw) { + SET_TX_DESC_TX_BANDWIDTH(pdesc, 1); + /* use duplicated mode */ + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + } else { + SET_TX_DESC_TX_BANDWIDTH(pdesc, 0); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, + mac->cur_40_prime_sc); + } + } else { + SET_TX_DESC_TX_BANDWIDTH(pdesc, 0); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + } + + /* 3 Fill necessary field in First Descriptor */ + /*DWORD 0*/ + SET_TX_DESC_LINIP(pdesc, 0); + SET_TX_DESC_OFFSET(pdesc, 32); + SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); + + /*DWORD 1*/ + SET_TX_DESC_RA_BRSR_ID(pdesc, ptcb_desc->ratr_index); + + /* Fill security related */ + if (info->control.hw_key) { + struct ieee80211_key_conf *keyconf; + + keyconf = info->control.hw_key; + switch (keyconf->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + SET_TX_DESC_SEC_TYPE(pdesc, 0x1); + break; + case WLAN_CIPHER_SUITE_TKIP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x2); + break; + case WLAN_CIPHER_SUITE_CCMP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x3); + break; + default: + SET_TX_DESC_SEC_TYPE(pdesc, 0x0); + break; + + } + } + + /* Set Packet ID */ + SET_TX_DESC_PACKET_ID(pdesc, 0); + + /* We will assign magement queue to BK. */ + SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel); + + /* Alwasy enable all rate fallback range */ + SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); + + /* Fix: I don't kown why hw use 6.5M to tx when set it */ + SET_TX_DESC_USER_RATE(pdesc, + ptcb_desc->use_driver_rate ? 1 : 0); + + /* Set NON_QOS bit. */ + if (!ieee80211_is_data_qos(fc)) + SET_TX_DESC_NON_QOS(pdesc, 1); + + } + + /* Fill fields that are required to be initialized + * in all of the descriptors */ + /*DWORD 0 */ + SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); + SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); + + /* DWORD 7 */ + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); + + /* DOWRD 8 */ + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, ("\n")); +} + +void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, + bool firstseg, bool lastseg, struct sk_buff *skb) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_tcb_desc *tcb_desc = (struct rtl_tcb_desc *)(skb->cb); + + dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + + /* Clear all status */ + CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_CMDDESC_SIZE_RTL8192S); + + /* This bit indicate this packet is used for FW download. */ + if (tcb_desc->cmd_or_init == DESC_PACKET_TYPE_INIT) { + /* For firmware downlaod we only need to set LINIP */ + SET_TX_DESC_LINIP(pdesc, tcb_desc->last_inipkt); + + /* 92SE must set as 1 for firmware download HW DMA error */ + SET_TX_DESC_FIRST_SEG(pdesc, 1); + SET_TX_DESC_LAST_SEG(pdesc, 1); + + /* 92SE need not to set TX packet size when firmware download */ + SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len)); + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + + SET_TX_DESC_OWN(pdesc, 1); + } else { /* H2C Command Desc format (Host TXCMD) */ + /* 92SE must set as 1 for firmware download HW DMA error */ + SET_TX_DESC_FIRST_SEG(pdesc, 1); + SET_TX_DESC_LAST_SEG(pdesc, 1); + + SET_TX_DESC_OFFSET(pdesc, 0x20); + + /* Buffer size + command header */ + SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len)); + /* Fixed queue of H2C command */ + SET_TX_DESC_QUEUE_SEL(pdesc, 0x13); + + SET_BITS_TO_LE_4BYTE(skb->data, 24, 7, rtlhal->h2c_txcmd_seq); + + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + + SET_TX_DESC_OWN(pdesc, 1); + + } +} + +void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +{ + if (istx == true) { + switch (desc_name) { + case HW_DESC_OWN: + SET_TX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_TX_NEXTDESC_ADDR: + SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val); + break; + default: + RT_ASSERT(false, ("ERR txdesc :%d not process\n", + desc_name)); + break; + } + } else { + switch (desc_name) { + case HW_DESC_RXOWN: + SET_RX_STATUS_DESC_OWN(pdesc, 1); + break; + case HW_DESC_RXBUFF_ADDR: + SET_RX_STATUS__DESC_BUFF_ADDR(pdesc, *(u32 *) val); + break; + case HW_DESC_RXPKT_LEN: + SET_RX_STATUS_DESC_PKT_LEN(pdesc, *(u32 *) val); + break; + case HW_DESC_RXERO: + SET_RX_STATUS_DESC_EOR(pdesc, 1); + break; + default: + RT_ASSERT(false, ("ERR rxdesc :%d not process\n", + desc_name)); + break; + } + } +} + +u32 rtl92se_get_desc(u8 *desc, bool istx, u8 desc_name) +{ + u32 ret = 0; + + if (istx == true) { + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_TX_DESC_OWN(desc); + break; + case HW_DESC_TXBUFF_ADDR: + ret = GET_TX_DESC_TX_BUFFER_ADDRESS(desc); + break; + default: + RT_ASSERT(false, ("ERR txdesc :%d not process\n", + desc_name)); + break; + } + } else { + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_RX_STATUS_DESC_OWN(desc); + break; + case HW_DESC_RXPKT_LEN: + ret = GET_RX_STATUS_DESC_PKT_LEN(desc); + break; + default: + RT_ASSERT(false, ("ERR rxdesc :%d not process\n", + desc_name)); + break; + } + } + return ret; +} + +void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl_write_word(rtlpriv, TP_POLL, BIT(0) << (hw_queue)); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.h b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h new file mode 100644 index 000000000000..05862c51b861 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __REALTEK_PCI92SE_TRX_H__ +#define __REALTEK_PCI92SE_TRX_H__ + +void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, + u8 *pdesc, struct ieee80211_tx_info *info, + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); +void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, + bool lastseg, struct sk_buff *skb); +bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, u8 *pdesc, + struct sk_buff *skb); +void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +u32 rtl92se_get_desc(u8 *pdesc, bool istx, u8 desc_name); +void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); + +#endif diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index f5d85735d642..a9367eba1ea7 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -852,6 +852,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl_tx_desc *pdesc = NULL; + struct rtl_tcb_desc tcb_desc; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); __le16 fc = hdr->frame_control; u8 *pda_addr = hdr->addr1; @@ -860,8 +861,17 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, u8 tid = 0; u16 seq_number = 0; - if (ieee80211_is_mgmt(fc)) - rtl_tx_mgmt_proc(hw, skb); + if (ieee80211_is_auth(fc)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); + rtl_ips_nic_on(hw); + } + + if (rtlpriv->psc.sw_ps_enabled) { + if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && + !ieee80211_has_pm(fc)) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + } + rtl_action_proc(hw, skb, true); if (is_multicast_ether_addr(pda_addr)) rtlpriv->stats.txbytesmulticast += skb->len; @@ -878,7 +888,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, seq_number <<= 4; } rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, skb, - hw_queue); + hw_queue, &tcb_desc); if (!ieee80211_has_morefrags(hdr->frame_control)) { if (qc) mac->tids[tid].seq_number = seq_number; @@ -887,7 +897,8 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); } -static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct rtl_tcb_desc *dummy) { struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h index abadfe918d30..d2a63fb3e1e6 100644 --- a/drivers/net/wireless/rtlwifi/usb.h +++ b/drivers/net/wireless/rtlwifi/usb.h @@ -31,6 +31,8 @@ #include #include +#define RTL_RX_DESC_SIZE 24 + #define RTL_USB_DEVICE(vend, prod, cfg) \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ .idVendor = (vend), \ diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 07db95ff9bc5..693395ee98f9 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -68,6 +68,8 @@ #define QBSS_LOAD_SIZE 5 #define MAX_WMMELE_LENGTH 64 +#define TOTAL_CAM_ENTRY 32 + /*slot time for 11g. */ #define RTL_SLOT_TIME_9 9 #define RTL_SLOT_TIME_20 20 @@ -94,8 +96,10 @@ #define CHANNEL_GROUP_MAX_5G 9 #define CHANNEL_MAX_NUMBER_2G 14 #define AVG_THERMAL_NUM 8 +#define MAX_TID_COUNT 9 /* for early mode */ +#define FCS_LEN 4 #define EM_HDR_LEN 8 enum intf_type { INTF_PCI = 0, @@ -159,6 +163,8 @@ enum hardware_type { (IS_HARDWARE_TYPE_8192DE(rtlhal) || IS_HARDWARE_TYPE_8192DU(rtlhal)) #define IS_HARDWARE_TYPE_8723(rtlhal) \ (IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal)) +#define IS_HARDWARE_TYPE_8723U(rtlhal) \ + (rtlhal->hw_type == HARDWARE_TYPE_RTL8723U) enum scan_operation_backup_opt { SCAN_OPT_BACKUP = 0, @@ -297,6 +303,9 @@ enum hw_variables { HW_VAR_DATA_FILTER, }; +#define HWSET_MAX_SIZE 128 +#define EFUSE_MAX_SECTION 16 + enum _RT_MEDIA_STATUS { RT_MEDIA_DISCONNECT = 0, RT_MEDIA_CONNECT = 1 @@ -766,7 +775,7 @@ struct rtl_rfkill { #define IQK_MATRIX_REG_NUM 8 #define IQK_MATRIX_SETTINGS_NUM (1 + 24 + 21) struct iqk_matrix_regs { - bool b_iqk_done; + bool iqk_done; long value[1][IQK_MATRIX_REG_NUM]; }; @@ -843,6 +852,7 @@ struct rtl_phy { bool apk_done; u32 reg_rf3c[2]; /* pathA / pathB */ + /* bfsync */ u8 framesync; u32 framesync_c34; @@ -852,6 +862,10 @@ struct rtl_phy { }; #define MAX_TID_COUNT 9 +#define RTL_AGG_STOP 0 +#define RTL_AGG_PROGRESS 1 +#define RTL_AGG_START 2 +#define RTL_AGG_OPERATIONAL 3 #define RTL_AGG_OFF 0 #define RTL_AGG_ON 1 #define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA 2 @@ -871,6 +885,13 @@ struct rtl_tid_data { struct rtl_ht_agg agg; }; +struct rtl_sta_info { + u8 ratr_index; + u8 wireless_mode; + u8 mimo_ps; + struct rtl_tid_data tids[MAX_TID_COUNT]; +} __packed; + struct rtl_priv; struct rtl_io { struct device *dev; @@ -894,6 +915,7 @@ struct rtl_io { u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr); int (*readN_sync) (struct rtl_priv *rtlpriv, u32 addr, u16 len, u8 *pdata); + }; struct rtl_mac { @@ -916,6 +938,8 @@ struct rtl_mac { int n_channels; int n_bitrates; + bool offchan_deley; + /*filters */ u32 rx_conf; u16 rx_mgt_filter; @@ -1032,7 +1056,9 @@ struct rtl_security { enum rt_enc_alg pairwise_enc_algorithm; /*Encryption Algorithm for Brocast/Multicast */ enum rt_enc_alg group_enc_algorithm; - + /*Cam Entry Bitmap */ + u32 hwsec_cam_bitmap; + u8 hwsec_cam_sta_addr[TOTAL_CAM_ENTRY][ETH_ALEN]; /*local Key buffer, indx 0 is for pairwise key 1-4 is for agoup key. */ u8 key_buf[KEY_BUF_SIZE][MAX_KEY_LEN]; @@ -1053,7 +1079,7 @@ struct rtl_dm { bool current_turbo_edca; bool is_any_nonbepkts; /*out dm */ bool is_cur_rdlstate; - bool txpower_trackingInit; + bool txpower_trackinginit; bool disable_framebursting; bool cck_inch14; bool txpower_tracking; @@ -1079,7 +1105,6 @@ struct rtl_dm { bool disable_tx_int; char ofdm_index[2]; char cck_index; - u8 power_index_backup[6]; }; #define EFUSE_MAX_LOGICAL_SIZE 256 @@ -1175,6 +1200,7 @@ struct rtl_ps_ctl { * otherwise Offset[560h] = 0x00. * */ bool support_aspm; + bool support_backdoor; /*for LPS */ @@ -1201,7 +1227,6 @@ struct rtl_ps_ctl { /*just for PCIE ASPM */ u8 const_amdpci_aspm; - bool pwrdown_mode; enum rf_pwrstate inactive_pwrstate; @@ -1282,6 +1307,10 @@ struct rt_link_detect { bool busytraffic; bool higher_busytraffic; bool higher_busyrxtraffic; + + u32 tidtx_in4period[MAX_TID_COUNT][4]; + u32 tidtx_inperiod[MAX_TID_COUNT]; + bool higher_busytxtraffic[MAX_TID_COUNT]; }; struct rtl_tcb_desc { @@ -1344,13 +1373,15 @@ struct rtl_hal_ops { u32 add_msr, u32 rm_msr); void (*get_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); - void (*update_rate_table) (struct ieee80211_hw *hw); + void (*update_rate_tbl) (struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level); void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level); void (*fill_tx_desc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, - struct sk_buff *skb, unsigned int queue_index); - void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 * pDesc, + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); + void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 *pDesc, u32 buffer_len, bool bIsPsPoll); void (*fill_tx_cmddesc) (struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, @@ -1370,10 +1401,10 @@ struct rtl_hal_ops { enum led_ctl_mode ledaction); void (*set_desc) (u8 *pdesc, bool istx, u8 desc_name, u8 *val); u32 (*get_desc) (u8 *pdesc, bool istx, u8 desc_name); - void (*tx_polling) (struct ieee80211_hw *hw, unsigned int hw_queue); + void (*tx_polling) (struct ieee80211_hw *hw, u8 hw_queue); void (*enable_hw_sec) (struct ieee80211_hw *hw); void (*set_key) (struct ieee80211_hw *hw, u32 key_index, - u8 *p_macaddr, bool is_group, u8 enc_algo, + u8 *macaddr, bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all); void (*init_sw_leds) (struct ieee80211_hw *hw); void (*deinit_sw_leds) (struct ieee80211_hw *hw); @@ -1384,6 +1415,7 @@ struct rtl_hal_ops { u32 regaddr, u32 bitmask); void (*set_rfreg) (struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask, u32 data); + void (*linked_set_reg) (struct ieee80211_hw *hw); bool (*phy_rf6052_config) (struct ieee80211_hw *hw); void (*phy_rf6052_set_cck_txpower) (struct ieee80211_hw *hw, u8 *powerlevel); @@ -1404,7 +1436,9 @@ struct rtl_intf_ops { int (*adapter_start) (struct ieee80211_hw *hw); void (*adapter_stop) (struct ieee80211_hw *hw); - int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb); + int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb, + struct rtl_tcb_desc *ptcb_desc); + void (*flush)(struct ieee80211_hw *hw, bool drop); int (*reset_trx_ring) (struct ieee80211_hw *hw); bool (*waitq_insert) (struct ieee80211_hw *hw, struct sk_buff *skb); @@ -1418,6 +1452,15 @@ struct rtl_intf_ops { struct rtl_mod_params { /* default: 0 = using hardware encryption */ int sw_crypto; + + /* default: 1 = using no linked power save */ + bool inactiveps; + + /* default: 1 = using linked sw power save */ + bool swctrl_lps; + + /* default: 1 = using linked fw power save */ + bool fwctrl_lps; }; struct rtl_hal_usbint_cfg { @@ -1445,6 +1488,7 @@ struct rtl_hal_usbint_cfg { struct rtl_hal_cfg { u8 bar_id; + bool write_readback; char *name; char *fw_name; struct rtl_hal_ops *ops; @@ -1469,7 +1513,6 @@ struct rtl_locks { spinlock_t rf_lock; spinlock_t lps_lock; spinlock_t waitq_lock; - spinlock_t tx_urb_lock; /*Dual mac*/ spinlock_t cck_and_rw_pagea_lock; @@ -1621,19 +1664,19 @@ struct bt_coexist_info { u32 bt_edca_ul; u32 bt_edca_dl; - bool b_init_set; - bool b_bt_busy_traffic; - bool b_bt_traffic_mode_set; - bool b_bt_non_traffic_mode_set; + bool init_set; + bool bt_busy_traffic; + bool bt_traffic_mode_set; + bool bt_non_traffic_mode_set; - bool b_fw_coexist_all_off; - bool b_sw_coexist_all_off; + bool fw_coexist_all_off; + bool sw_coexist_all_off; u32 current_state; u32 previous_state; u8 bt_pre_rssi_state; - u8 b_reg_bt_iso; - u8 b_reg_bt_sco; + u8 reg_bt_iso; + u8 reg_bt_sco; }; @@ -1653,13 +1696,23 @@ struct bt_coexist_info { #define EF4BYTE(_val) \ (le32_to_cpu(_val)) +/* Read data from memory */ +#define READEF1BYTE(_ptr) \ + EF1BYTE(*((u8 *)(_ptr))) /* Read le16 data from memory and convert to host ordering */ #define READEF2BYTE(_ptr) \ EF2BYTE(*((u16 *)(_ptr))) +#define READEF4BYTE(_ptr) \ + EF4BYTE(*((u32 *)(_ptr))) +/* Write data to memory */ +#define WRITEEF1BYTE(_ptr, _val) \ + (*((u8 *)(_ptr))) = EF1BYTE(_val) /* Write le16 data to memory in host ordering */ #define WRITEEF2BYTE(_ptr, _val) \ (*((u16 *)(_ptr))) = EF2BYTE(_val) +#define WRITEEF4BYTE(_ptr, _val) \ + (*((u16 *)(_ptr))) = EF2BYTE(_val) /* Create a bit mask * Examples: @@ -1698,6 +1751,25 @@ struct bt_coexist_info { #define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \ (EF1BYTE(*((u8 *)(__pstart)))) +/*Description: +Translate subfield (continuous bits in little-endian) of 4-byte +value to host byte ordering.*/ +#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + (LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset)) & \ + BIT_LEN_MASK_32(__bitlen) \ + ) +#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + (LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \ + BIT_LEN_MASK_16(__bitlen) \ + ) +#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + (LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \ + BIT_LEN_MASK_8(__bitlen) \ + ) + /* Description: * Mask subfield (continuous bits in little-endian) of 4-byte value * and return the result in 4-byte value in host byte ordering. @@ -1721,6 +1793,18 @@ struct bt_coexist_info { /* Description: * Set subfield of little-endian 4-byte value to specified value. */ +#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \ + *((u32 *)(__pstart)) = EF4BYTE \ + ( \ + LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \ + ((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \ + ); +#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \ + *((u16 *)(__pstart)) = EF2BYTE \ + ( \ + LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \ + ((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \ + ); #define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \ *((u8 *)(__pstart)) = EF1BYTE \ ( \ @@ -1728,12 +1812,16 @@ struct bt_coexist_info { ((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \ ); +#define N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \ + (__value) : (((__value + __aligment - 1) / __aligment) * __aligment)) + /**************************************** mem access macro define end ****************************************/ #define byte(x, n) ((x >> (8 * n)) & 0xff) +#define packet_get_type(_packet) (EF1BYTE((_packet).octet[0]) & 0xFC) #define RTL_WATCH_DOG_TIME 2000 #define MSECS(t) msecs_to_jiffies(t) #define WLAN_FC_GET_VERS(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_VERS) @@ -1768,6 +1856,15 @@ struct bt_coexist_info { #define container_of_dwork_rtl(x, y, z) \ container_of(container_of(x, struct delayed_work, work), y, z) +#define FILL_OCTET_STRING(_os, _octet, _len) \ + (_os).octet = (u8 *)(_octet); \ + (_os).length = (_len); + +#define CP_MACADDR(des, src) \ + ((des)[0] = (src)[0], (des)[1] = (src)[1],\ + (des)[2] = (src)[2], (des)[3] = (src)[3],\ + (des)[4] = (src)[4], (des)[5] = (src)[5]) + static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr) { return rtlpriv->io.read8_sync(rtlpriv, addr); @@ -1786,17 +1883,26 @@ static inline u32 rtl_read_dword(struct rtl_priv *rtlpriv, u32 addr) static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8) { rtlpriv->io.write8_async(rtlpriv, addr, val8); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read8_sync(rtlpriv, addr); } static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16) { rtlpriv->io.write16_async(rtlpriv, addr, val16); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read16_sync(rtlpriv, addr); } static inline void rtl_write_dword(struct rtl_priv *rtlpriv, u32 addr, u32 val32) { rtlpriv->io.write32_async(rtlpriv, addr, val32); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read32_sync(rtlpriv, addr); } static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw, @@ -1855,4 +1961,31 @@ static inline u8 get_rf_type(struct rtl_phy *rtlphy) return rtlphy->rf_type; } +static inline struct ieee80211_hdr *rtl_get_hdr(struct sk_buff *skb) +{ + return (struct ieee80211_hdr *)(skb->data); +} + +static inline __le16 rtl_get_fc(struct sk_buff *skb) +{ + return rtl_get_hdr(skb)->frame_control; +} + +static inline u16 rtl_get_tid_h(struct ieee80211_hdr *hdr) +{ + return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; +} + +static inline u16 rtl_get_tid(struct sk_buff *skb) +{ + return rtl_get_tid_h(rtl_get_hdr(skb)); +} + +static inline struct ieee80211_sta *get_sta(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u8 *bssid) +{ + return ieee80211_find_sta(vif, bssid); +} + #endif diff --git a/drivers/net/wireless/wl1251/cmd.h b/drivers/net/wireless/wl1251/cmd.h index e5c74c631374..79ca5273c9e9 100644 --- a/drivers/net/wireless/wl1251/cmd.h +++ b/drivers/net/wireless/wl1251/cmd.h @@ -313,8 +313,8 @@ struct wl1251_cmd_vbm_update { } __packed; enum wl1251_cmd_ps_mode { - STATION_ACTIVE_MODE, - STATION_POWER_SAVE_MODE + CHIP_ACTIVE_MODE, + CHIP_POWER_SAVE_MODE }; struct wl1251_cmd_ps_params { diff --git a/drivers/net/wireless/wl1251/event.c b/drivers/net/wireless/wl1251/event.c index dfc4579acb06..9f15ccaf8f05 100644 --- a/drivers/net/wireless/wl1251/event.c +++ b/drivers/net/wireless/wl1251/event.c @@ -68,14 +68,16 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) if (vector & BSS_LOSE_EVENT_ID) { wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); - if (wl->psm_requested && wl->psm) { + if (wl->psm_requested && + wl->station_mode != STATION_ACTIVE_MODE) { ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; } } - if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) { + if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && + wl->station_mode != STATION_ACTIVE_MODE) { wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); /* indicate to the stack, that beacons have been lost */ diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index 12c9e635a6d6..a14a48c99cdc 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -497,7 +497,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) wl->rx_last_id = 0; wl->next_tx_complete = 0; wl->elp = false; - wl->psm = 0; + wl->station_mode = STATION_ACTIVE_MODE; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; wl->rssi_thold = 0; @@ -632,13 +632,29 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) wl->psm_requested = false; - if (wl->psm) { + if (wl->station_mode != STATION_ACTIVE_MODE) { ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) goto out_sleep; } } + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + if (conf->flags & IEEE80211_CONF_IDLE) { + ret = wl1251_ps_set_mode(wl, STATION_IDLE); + if (ret < 0) + goto out_sleep; + } else { + ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + goto out_sleep; + ret = wl1251_join(wl, wl->bss_type, wl->channel, + wl->beacon_int, wl->dtim_period); + if (ret < 0) + goto out_sleep; + } + } + if (conf->power_level != wl->power_level) { ret = wl1251_acx_tx_power(wl, conf->power_level); if (ret < 0) @@ -1384,7 +1400,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void) wl->rx_config = WL1251_DEFAULT_RX_CONFIG; wl->rx_filter = WL1251_DEFAULT_RX_FILTER; wl->elp = false; - wl->psm = 0; + wl->station_mode = STATION_ACTIVE_MODE; wl->psm_requested = false; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; diff --git a/drivers/net/wireless/wl1251/ps.c b/drivers/net/wireless/wl1251/ps.c index 9cc514703d2a..db719f7d2692 100644 --- a/drivers/net/wireless/wl1251/ps.c +++ b/drivers/net/wireless/wl1251/ps.c @@ -39,7 +39,7 @@ void wl1251_elp_work(struct work_struct *work) mutex_lock(&wl->mutex); - if (wl->elp || !wl->psm) + if (wl->elp || wl->station_mode == STATION_ACTIVE_MODE) goto out; wl1251_debug(DEBUG_PSM, "chip to elp"); @@ -57,7 +57,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl) { unsigned long delay; - if (wl->psm) { + if (wl->station_mode != STATION_ACTIVE_MODE) { delay = msecs_to_jiffies(ELP_ENTRY_DELAY); ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); } @@ -104,7 +104,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) return 0; } -int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) +int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode) { int ret; @@ -128,15 +128,24 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) if (ret < 0) return ret; - ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + ret = wl1251_cmd_ps_mode(wl, CHIP_POWER_SAVE_MODE); if (ret < 0) return ret; ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); if (ret < 0) return ret; + break; + case STATION_IDLE: + wl1251_debug(DEBUG_PSM, "entering idle"); - wl->psm = 1; + ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); + if (ret < 0) + return ret; + + ret = wl1251_cmd_template_set(wl, CMD_DISCONNECT, NULL, 0); + if (ret < 0) + return ret; break; case STATION_ACTIVE_MODE: default: @@ -163,13 +172,13 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) if (ret < 0) return ret; - ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + ret = wl1251_cmd_ps_mode(wl, CHIP_ACTIVE_MODE); if (ret < 0) return ret; - wl->psm = 0; break; } + wl->station_mode = mode; return ret; } diff --git a/drivers/net/wireless/wl1251/ps.h b/drivers/net/wireless/wl1251/ps.h index 55c3dda75e69..75efad246d67 100644 --- a/drivers/net/wireless/wl1251/ps.h +++ b/drivers/net/wireless/wl1251/ps.h @@ -26,7 +26,7 @@ #include "wl1251.h" #include "acx.h" -int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode); +int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode); void wl1251_ps_elp_sleep(struct wl1251 *wl); int wl1251_ps_elp_wakeup(struct wl1251 *wl); void wl1251_elp_work(struct work_struct *work); diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h index bb23cd522b22..a77f1bbbed0a 100644 --- a/drivers/net/wireless/wl1251/wl1251.h +++ b/drivers/net/wireless/wl1251/wl1251.h @@ -129,6 +129,12 @@ enum wl1251_partition_type { PART_TABLE_LEN }; +enum wl1251_station_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE, + STATION_IDLE, +}; + struct wl1251_partition { u32 size; u32 start; @@ -358,8 +364,7 @@ struct wl1251 { struct delayed_work elp_work; - /* we can be in psm, but not in elp, we have to differentiate */ - bool psm; + enum wl1251_station_mode station_mode; /* PSM mode requested */ bool psm_requested; diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 692ebff38fc8..35ce7b0f4a60 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -3,7 +3,7 @@ menuconfig WL12XX_MENU depends on MAC80211 && EXPERIMENTAL ---help--- This will enable TI wl12xx driver support for the following chips: - wl1271 and wl1273. + wl1271, wl1273, wl1281 and wl1283. The drivers make use of the mac80211 stack. config WL12XX diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index a3db755ceeda..c6ee530e5bf7 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -325,12 +325,19 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl) return ret; } -int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) +int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold) { struct acx_rts_threshold *rts; int ret; - wl1271_debug(DEBUG_ACX, "acx rts threshold"); + /* + * 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) { @@ -338,7 +345,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) goto out; } - rts->threshold = cpu_to_le16(rts_threshold); + rts->threshold = cpu_to_le16((u16)rts_threshold); ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); if (ret < 0) { @@ -540,13 +547,13 @@ int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable) return ret; } -int wl1271_acx_sg_cfg(struct wl1271 *wl) +int wl1271_acx_sta_sg_cfg(struct wl1271 *wl) { - struct acx_bt_wlan_coex_param *param; + struct acx_sta_bt_wlan_coex_param *param; struct conf_sg_settings *c = &wl->conf.sg; int i, ret; - wl1271_debug(DEBUG_ACX, "acx sg cfg"); + wl1271_debug(DEBUG_ACX, "acx sg sta cfg"); param = kzalloc(sizeof(*param), GFP_KERNEL); if (!param) { @@ -555,8 +562,38 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl) } /* BT-WLAN coext parameters */ - for (i = 0; i < CONF_SG_PARAMS_MAX; i++) - param->params[i] = cpu_to_le32(c->params[i]); + for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++) + param->params[i] = cpu_to_le32(c->sta_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_ap_sg_cfg(struct wl1271 *wl) +{ + struct acx_ap_bt_wlan_coex_param *param; + struct conf_sg_settings *c = &wl->conf.sg; + int i, ret; + + wl1271_debug(DEBUG_ACX, "acx sg ap cfg"); + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + + /* BT-WLAN coext parameters */ + for (i = 0; i < CONF_SG_AP_PARAMS_MAX; i++) + param->params[i] = cpu_to_le32(c->ap_params[i]); param->param_idx = CONF_SG_PARAMS_ALL; ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); @@ -804,7 +841,8 @@ int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, struct acx_ap_rate_policy *acx; int ret = 0; - wl1271_debug(DEBUG_ACX, "acx ap rate policy"); + wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x", + idx, c->enabled_rates); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -898,12 +936,19 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, return ret; } -int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold) +int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold) { struct acx_frag_threshold *acx; int ret = 0; - wl1271_debug(DEBUG_ACX, "acx frag threshold"); + /* + * 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); @@ -912,7 +957,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold) goto out; } - acx->frag_threshold = cpu_to_le16(frag_threshold); + 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); @@ -954,6 +999,7 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl) int wl1271_acx_ap_mem_cfg(struct wl1271 *wl) { struct wl1271_acx_ap_config_memory *mem_conf; + struct conf_memory_settings *mem; int ret; wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); @@ -964,11 +1010,21 @@ int wl1271_acx_ap_mem_cfg(struct wl1271 *wl) goto out; } + if (wl->chip.id == CHIP_ID_1283_PG20) + /* + * FIXME: The 128x AP FW does not yet support dynamic memory. + * Use the base memory configuration for 128x for now. This + * should be fine tuned in the future. + */ + mem = &wl->conf.mem_wl128x; + else + mem = &wl->conf.mem_wl127x; + /* memory config */ - mem_conf->num_stations = wl->conf.mem.num_stations; - mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num; - mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num; - mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles; + 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); ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, @@ -986,6 +1042,7 @@ int wl1271_acx_ap_mem_cfg(struct wl1271 *wl) int wl1271_acx_sta_mem_cfg(struct wl1271 *wl) { struct wl1271_acx_sta_config_memory *mem_conf; + struct conf_memory_settings *mem; int ret; wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); @@ -996,16 +1053,21 @@ int wl1271_acx_sta_mem_cfg(struct wl1271 *wl) 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 = wl->conf.mem.num_stations; - mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num; - mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num; - mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles; + 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 = wl->conf.mem.dynamic_memory; - mem_conf->tx_free_req = wl->conf.mem.min_req_tx_blocks; - mem_conf->rx_free_req = wl->conf.mem.min_req_rx_blocks; - mem_conf->tx_min = wl->conf.mem.tx_min; + 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; ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, sizeof(*mem_conf)); @@ -1019,6 +1081,32 @@ int wl1271_acx_sta_mem_cfg(struct wl1271 *wl) 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; @@ -1567,3 +1655,68 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr) kfree(acx); return ret; } + +int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable) +{ + struct acx_ap_beacon_filter *acx = NULL; + int ret; + + wl1271_debug(DEBUG_ACX, "acx set ap beacon filter: %d", enable); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + acx->enable = enable ? 1 : 0; + + ret = wl1271_cmd_configure(wl, ACX_AP_BEACON_FILTER_OPT, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx set ap beacon filter 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; +} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index dd19b01d807b..9a895e3cc613 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -303,7 +303,6 @@ struct acx_beacon_filter_option { struct acx_header header; u8 enable; - /* * The number of beacons without the unicast TIM * bit set that the firmware buffers before @@ -370,14 +369,23 @@ struct acx_bt_wlan_coex { u8 pad[3]; } __packed; -struct acx_bt_wlan_coex_param { +struct acx_sta_bt_wlan_coex_param { struct acx_header header; - __le32 params[CONF_SG_PARAMS_MAX]; + __le32 params[CONF_SG_STA_PARAMS_MAX]; u8 param_idx; u8 padding[3]; } __packed; +struct acx_ap_bt_wlan_coex_param { + struct acx_header header; + + __le32 params[CONF_SG_AP_PARAMS_MAX]; + u8 param_idx; + u8 padding[3]; +} __packed; + + struct acx_dco_itrim_params { struct acx_header header; @@ -939,6 +947,16 @@ struct wl1271_acx_keep_alive_config { u8 padding; } __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, @@ -1162,6 +1180,72 @@ struct wl1271_acx_inconnection_sta { u8 padding1[2]; } __packed; +struct acx_ap_beacon_filter { + struct acx_header header; + + u8 enable; + u8 pad[3]; +} __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; + enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, @@ -1180,6 +1264,7 @@ enum { ACX_TID_CFG = 0x001A, ACX_PS_RX_STREAMING = 0x001B, ACX_BEACON_FILTER_OPT = 0x001F, + ACX_AP_BEACON_FILTER_OPT = 0x0020, ACX_NOISE_HIST = 0x0021, ACX_HDK_VERSION = 0x0022, /* ??? */ ACX_PD_THRESHOLD = 0x0023, @@ -1191,6 +1276,7 @@ enum { ACX_BCN_DTIM_OPTIONS = 0x0031, ACX_SG_ENABLE = 0x0032, ACX_SG_CFG = 0x0033, + ACX_FM_COEX_CFG = 0x0034, ACX_BEACON_FILTER_TABLE = 0x0038, ACX_ARP_IP_FILTER = 0x0039, ACX_ROAMING_STATISTICS_TBL = 0x003B, @@ -1247,13 +1333,14 @@ int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time); int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, void *mc_list, u32 mc_list_len); int wl1271_acx_service_period_timeout(struct wl1271 *wl); -int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); +int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold); int wl1271_acx_dco_itrim_params(struct wl1271 *wl); int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); int wl1271_acx_beacon_filter_table(struct wl1271 *wl); int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable); int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable); -int wl1271_acx_sg_cfg(struct wl1271 *wl); +int wl1271_acx_sta_sg_cfg(struct wl1271 *wl); +int wl1271_acx_ap_sg_cfg(struct wl1271 *wl); int wl1271_acx_cca_threshold(struct wl1271 *wl); int wl1271_acx_bcn_dtim_options(struct wl1271 *wl); int wl1271_acx_aid(struct wl1271 *wl, u16 aid); @@ -1270,11 +1357,12 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, int wl1271_acx_tid_cfg(struct wl1271 *wl, 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, u16 frag_threshold); +int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold); int wl1271_acx_tx_config_options(struct wl1271 *wl); int wl1271_acx_ap_mem_cfg(struct wl1271 *wl); int wl1271_acx_sta_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, bool enable); @@ -1299,5 +1387,7 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); int wl1271_acx_max_tx_retry(struct wl1271 *wl); int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); +int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable); +int wl1271_acx_fm_coex(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 6934dffd5174..b07f8b7e5f11 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -22,6 +22,7 @@ */ #include +#include #include "acx.h" #include "reg.h" @@ -243,33 +244,57 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) if (wl->nvs == NULL) return -ENODEV; - /* - * 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) { - /* for now 11a is unsupported in AP mode */ - if (wl->bss_type != BSS_TYPE_AP_BSS && - wl->nvs->general_params.dual_mode_select) - wl->enable_11a = true; - } + 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 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; - } + 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(wl->nvs->nvs); - nvs_ptr = (u8 *)wl->nvs->nvs; + /* 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) { + /* for now 11a is unsupported in AP mode */ + if (wl->bss_type != BSS_TYPE_AP_BSS && + 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->mac_addr[0]; @@ -319,10 +344,13 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) /* * 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->nvs + - ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4); - nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; + nvs_ptr = (u8 *)wl->nvs + + ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4); + nvs_len -= nvs_ptr - (u8 *)wl->nvs; /* Now we must set the partition correctly */ wl1271_set_partition(wl, &part_table[PART_WORK]); @@ -450,10 +478,14 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) DISCONNECT_EVENT_COMPLETE_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | PSPOLL_DELIVERY_FAILURE_EVENT_ID | - SOFT_GEMINI_SENSE_EVENT_ID; + SOFT_GEMINI_SENSE_EVENT_ID | + PERIODIC_SCAN_REPORT_EVENT_ID | + PERIODIC_SCAN_COMPLETE_EVENT_ID; if (wl->bss_type == BSS_TYPE_AP_BSS) wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; + else + wl->event_mask |= DUMMY_PACKET_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { @@ -493,24 +525,159 @@ static void wl1271_boot_hw_version(struct wl1271 *wl) wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; } -/* uploads NVS and firmware */ -int wl1271_load_firmware(struct wl1271 *wl) +static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) { - int ret = 0; - u32 tmp, clk, pause; + 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; wl1271_boot_hw_version(wl); - if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4) + 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 == 1 || wl->ref_clock == 3) + 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 != 0) { + 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); @@ -540,6 +707,26 @@ int wl1271_load_firmware(struct wl1271 *wl) 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); @@ -555,7 +742,12 @@ int wl1271_load_firmware(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); - clk |= (wl->ref_clock << 1) << 4; + 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, &part_table[PART_WORK]); @@ -585,16 +777,12 @@ int wl1271_load_firmware(struct wl1271 *wl) /* 6. read the EEPROM parameters */ tmp = wl1271_read32(wl, SCR_PAD2); - ret = wl1271_boot_write_irq_polarity(wl); - if (ret < 0) - goto out; - - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, - WL1271_ACX_ALL_EVENTS_VECTOR); - /* WL1271: The reference driver skips steps 7 to 10 (jumps directly * to upload_fw) */ + 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; @@ -618,6 +806,13 @@ int wl1271_boot(struct wl1271 *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); diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h index 17229b86fc71..e8f8255bbabe 100644 --- a/drivers/net/wireless/wl12xx/boot.h +++ b/drivers/net/wireless/wl12xx/boot.h @@ -74,4 +74,56 @@ struct wl1271_static_data { #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/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 96324336f936..42935ac72663 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -76,7 +76,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, if (time_after(jiffies, timeout)) { wl1271_error("command complete timeout"); ret = -ETIMEDOUT; - goto out; + goto fail; } poll_count++; @@ -96,21 +96,25 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, status = le16_to_cpu(cmd->status); if (status != CMD_STATUS_SUCCESS) { wl1271_error("command execute failure %d", status); - ieee80211_queue_work(wl->hw, &wl->recovery_work); ret = -EIO; + goto fail; } wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); + return 0; -out: +fail: + WARN_ON(1); + ieee80211_queue_work(wl->hw, &wl->recovery_work); return ret; } int wl1271_cmd_general_parms(struct wl1271 *wl) { struct wl1271_general_parms_cmd *gen_parms; - struct wl1271_ini_general_params *gp = &wl->nvs->general_params; + struct wl1271_ini_general_params *gp = + &((struct wl1271_nvs_file *)wl->nvs)->general_params; bool answer = false; int ret; @@ -128,6 +132,52 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) 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; + + 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; + + 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"); @@ -147,8 +197,9 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) 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 = &wl->nvs->general_params; + struct wl1271_ini_general_params *gp = &nvs->general_params; int ret; if (!wl->nvs) @@ -161,18 +212,18 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; /* 2.4GHz parameters */ - memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2, + memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, sizeof(struct wl1271_ini_band_params_2)); memcpy(&radio_parms->dyn_params_2, - &wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, + &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, - &wl->nvs->stat_radio_params_5, + &nvs->stat_radio_params_5, sizeof(struct wl1271_ini_band_params_5)); memcpy(&radio_parms->dyn_params_5, - &wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, + &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: ", @@ -186,6 +237,50 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) 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; diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 54c12e71417e..5cac95d9480c 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -32,7 +32,9 @@ 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 wl1271_cmd_join(struct wl1271 *wl, u8 bss_type); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); @@ -415,6 +417,21 @@ struct wl1271_general_parms_cmd { 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; @@ -431,6 +448,23 @@ struct wl1271_radio_parms_cmd { 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; diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 8a8323896eec..1ab6c86aac40 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -396,12 +396,43 @@ enum { CONF_SG_TEMP_PARAM_3, CONF_SG_TEMP_PARAM_4, CONF_SG_TEMP_PARAM_5, - CONF_SG_PARAMS_MAX, + + /* + * AP beacon miss + * + * Range: 0 - 255 + */ + CONF_SG_AP_BEACON_MISS_TX, + + /* + * AP RX window length + * + * Range: 0 - 50 + */ + CONF_SG_RX_WINDOW_LENGTH, + + /* + * AP connection protection time + * + * Range: 0 - 5000 + */ + CONF_SG_AP_CONNECTION_PROTECTION_TIME, + + 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_STA_PARAMS_MAX = CONF_SG_TEMP_PARAM_5 + 1, + CONF_SG_AP_PARAMS_MAX = CONF_SG_TEMP_PARAM_10 + 1, + CONF_SG_PARAMS_ALL = 0xff }; struct conf_sg_settings { - u32 params[CONF_SG_PARAMS_MAX]; + u32 sta_params[CONF_SG_STA_PARAMS_MAX]; + u32 ap_params[CONF_SG_AP_PARAMS_MAX]; u8 state; }; @@ -509,6 +540,12 @@ struct conf_rx_settings { CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ CONF_HW_BIT_RATE_54MBPS) +#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) + + /* * Default rates for management traffic when operating in AP mode. This * should be configured according to the basic rate set of the AP @@ -516,6 +553,13 @@ struct conf_rx_settings { #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. use 11b rates + */ +#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); + struct conf_tx_rate_class { /* @@ -666,22 +710,6 @@ struct conf_tx_settings { u8 ac_conf_count; struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT]; - /* - * Configuration for rate classes in AP-mode. These rate classes - * are for the AC TX queues - */ - struct conf_tx_rate_class ap_rc_conf[CONF_TX_MAX_AC_COUNT]; - - /* - * Management TX rate class for AP-mode. - */ - struct conf_tx_rate_class ap_mgmt_conf; - - /* - * Broadcast TX rate class for AP-mode. - */ - struct conf_tx_rate_class ap_bcst_conf; - /* * AP-mode - allow this number of TX retries to a station before an * event is triggered from FW. @@ -1004,7 +1032,9 @@ 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_52_E, + CONF_REF_CLK_38_4_M_XTAL, + CONF_REF_CLK_26_M_XTAL, }; enum single_dual_band_enum { @@ -1018,15 +1048,6 @@ enum single_dual_band_enum { #define CONF_NUMBER_OF_CHANNELS_2_4 14 #define CONF_NUMBER_OF_CHANNELS_5 35 -struct conf_radio_parms { - /* - * FEM parameter set to use - * - * Range: 0 or 1 - */ - u8 fem; -}; - struct conf_itrim_settings { /* enable dco itrim */ u8 enable; @@ -1126,6 +1147,26 @@ struct conf_scan_settings { }; +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; + + /* 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 @@ -1191,6 +1232,19 @@ struct conf_memory_settings { 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_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1200,9 +1254,13 @@ struct conf_drv_settings { 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; + struct conf_memory_settings mem_wl127x; + struct conf_memory_settings mem_wl128x; + struct conf_fm_coex fm_coex; + u8 hci_io_ds; }; #endif diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 8e75b09723b9..f1f8df9b6cd7 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -267,7 +267,7 @@ static ssize_t gpio_power_write(struct file *file, } buf[len] = '\0'; - ret = strict_strtoul(buf, 0, &value); + ret = kstrtoul(buf, 0, &value); if (ret < 0) { wl1271_warning("illegal value in gpio_power"); return -EINVAL; @@ -291,6 +291,242 @@ static const struct file_operations gpio_power_ops = { .llseek = default_llseek, }; +static ssize_t start_recovery_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + + mutex_lock(&wl->mutex); + ieee80211_queue_work(wl->hw, &wl->recovery_work); + mutex_unlock(&wl->mutex); + + return count; +} + +static const struct file_operations start_recovery_ops = { + .write = start_recovery_write, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + +static ssize_t driver_state_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + int res = 0; + char buf[1024]; + + mutex_lock(&wl->mutex); + +#define DRIVER_STATE_PRINT(x, fmt) \ + (res += scnprintf(buf + res, sizeof(buf) - res,\ + #x " = " fmt "\n", wl->x)) + +#define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld") +#define DRIVER_STATE_PRINT_INT(x) DRIVER_STATE_PRINT(x, "%d") +#define DRIVER_STATE_PRINT_STR(x) DRIVER_STATE_PRINT(x, "%s") +#define DRIVER_STATE_PRINT_LHEX(x) DRIVER_STATE_PRINT(x, "0x%lx") +#define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x") + + DRIVER_STATE_PRINT_INT(tx_blocks_available); + DRIVER_STATE_PRINT_INT(tx_allocated_blocks); + DRIVER_STATE_PRINT_INT(tx_frames_cnt); + DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]); + DRIVER_STATE_PRINT_INT(tx_queue_count); + DRIVER_STATE_PRINT_INT(tx_packets_count); + DRIVER_STATE_PRINT_INT(tx_results_count); + DRIVER_STATE_PRINT_LHEX(flags); + DRIVER_STATE_PRINT_INT(tx_blocks_freed[0]); + DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]); + DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]); + DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]); + DRIVER_STATE_PRINT_INT(tx_security_last_seq); + DRIVER_STATE_PRINT_INT(rx_counter); + DRIVER_STATE_PRINT_INT(session_counter); + DRIVER_STATE_PRINT_INT(state); + DRIVER_STATE_PRINT_INT(bss_type); + DRIVER_STATE_PRINT_INT(channel); + DRIVER_STATE_PRINT_HEX(rate_set); + DRIVER_STATE_PRINT_HEX(basic_rate_set); + DRIVER_STATE_PRINT_HEX(basic_rate); + DRIVER_STATE_PRINT_INT(band); + DRIVER_STATE_PRINT_INT(beacon_int); + DRIVER_STATE_PRINT_INT(psm_entry_retry); + DRIVER_STATE_PRINT_INT(ps_poll_failures); + DRIVER_STATE_PRINT_HEX(filters); + DRIVER_STATE_PRINT_HEX(rx_config); + DRIVER_STATE_PRINT_HEX(rx_filter); + DRIVER_STATE_PRINT_INT(power_level); + DRIVER_STATE_PRINT_INT(rssi_thold); + DRIVER_STATE_PRINT_INT(last_rssi_event); + DRIVER_STATE_PRINT_INT(sg_enabled); + DRIVER_STATE_PRINT_INT(enable_11a); + DRIVER_STATE_PRINT_INT(noise); + DRIVER_STATE_PRINT_LHEX(ap_hlid_map[0]); + DRIVER_STATE_PRINT_INT(last_tx_hlid); + DRIVER_STATE_PRINT_INT(ba_support); + DRIVER_STATE_PRINT_HEX(ba_rx_bitmap); + DRIVER_STATE_PRINT_HEX(ap_fw_ps_map); + DRIVER_STATE_PRINT_LHEX(ap_ps_map); + DRIVER_STATE_PRINT_HEX(quirks); + DRIVER_STATE_PRINT_HEX(irq); + DRIVER_STATE_PRINT_HEX(ref_clock); + DRIVER_STATE_PRINT_HEX(tcxo_clock); + DRIVER_STATE_PRINT_HEX(hw_pg_ver); + DRIVER_STATE_PRINT_HEX(platform_quirks); + DRIVER_STATE_PRINT_HEX(chip.id); + DRIVER_STATE_PRINT_STR(chip.fw_ver_str); + DRIVER_STATE_PRINT_INT(sched_scanning); + +#undef DRIVER_STATE_PRINT_INT +#undef DRIVER_STATE_PRINT_LONG +#undef DRIVER_STATE_PRINT_HEX +#undef DRIVER_STATE_PRINT_LHEX +#undef DRIVER_STATE_PRINT_STR +#undef DRIVER_STATE_PRINT + + mutex_unlock(&wl->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, res); +} + +static const struct file_operations driver_state_ops = { + .read = driver_state_read, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + +static ssize_t dtim_interval_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + u8 value; + + if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_DTIM || + wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM) + value = wl->conf.conn.listen_interval; + else + value = 0; + + return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value); +} + +static ssize_t dtim_interval_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + char buf[10]; + size_t len; + unsigned long value; + int ret; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + ret = kstrtoul(buf, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value for dtim_interval"); + return -EINVAL; + } + + if (value < 1 || value > 10) { + wl1271_warning("dtim value is not in valid range"); + return -ERANGE; + } + + mutex_lock(&wl->mutex); + + wl->conf.conn.listen_interval = value; + /* for some reason there are different event types for 1 and >1 */ + if (value == 1) + wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_DTIM; + else + wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM; + + /* + * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only + * take effect on the next time we enter psm. + */ + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations dtim_interval_ops = { + .read = dtim_interval_read, + .write = dtim_interval_write, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + +static ssize_t beacon_interval_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + u8 value; + + if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_BEACON || + wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_BEACONS) + value = wl->conf.conn.listen_interval; + else + value = 0; + + return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value); +} + +static ssize_t beacon_interval_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + char buf[10]; + size_t len; + unsigned long value; + int ret; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + ret = kstrtoul(buf, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value for beacon_interval"); + return -EINVAL; + } + + if (value < 1 || value > 255) { + wl1271_warning("beacon interval value is not in valid range"); + return -ERANGE; + } + + mutex_lock(&wl->mutex); + + wl->conf.conn.listen_interval = value; + /* for some reason there are different event types for 1 and >1 */ + if (value == 1) + wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_BEACON; + else + wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_BEACONS; + + /* + * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only + * take effect on the next time we enter psm. + */ + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations beacon_interval_ops = { + .read = beacon_interval_read, + .write = beacon_interval_write, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + static int wl1271_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { @@ -399,6 +635,10 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(excessive_retries, rootdir); DEBUGFS_ADD(gpio_power, rootdir); + DEBUGFS_ADD(start_recovery, rootdir); + DEBUGFS_ADD(driver_state, rootdir); + DEBUGFS_ADD(dtim_interval, rootdir); + DEBUGFS_ADD(beacon_interval, rootdir); return 0; diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 1b170c5cc595..c3c554cd6580 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -33,6 +33,7 @@ void wl1271_pspoll_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; + int ret; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, pspoll_work); @@ -55,8 +56,13 @@ void wl1271_pspoll_work(struct work_struct *work) * delivery failure occurred, and no-one changed state since, so * we should go back to powersave. */ + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); + wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); }; @@ -132,8 +138,10 @@ static int wl1271_event_ps_report(struct wl1271 *wl, if (ret < 0) break; - /* go to extremely low power mode */ - wl1271_ps_elp_sleep(wl); + if (wl->ps_compl) { + complete(wl->ps_compl); + wl->ps_compl = NULL; + } break; default: break; @@ -187,6 +195,22 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_scan_stm(wl); } + if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT " + "(status 0x%0x)", mbox->scheduled_scan_status); + + wl1271_scan_sched_scan_results(wl); + } + + if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT " + "(status 0x%0x)", mbox->scheduled_scan_status); + if (wl->sched_scanning) { + wl1271_scan_sched_scan_stop(wl); + ieee80211_sched_scan_stopped(wl->hw); + } + } + /* disable dynamic PS when requested by the firmware */ if (vector & SOFT_GEMINI_SENSE_EVENT_ID && wl->bss_type == BSS_TYPE_STA_BSS) { @@ -228,6 +252,12 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_event_rssi_trigger(wl, mbox); } + if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) { + wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); + if (wl->vif) + wl1271_tx_dummy_packet(wl); + } + if (wl->vif && beacon_loss) ieee80211_connection_loss(wl->vif); diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h index 0e80886f3031..b6cf06e565a4 100644 --- a/drivers/net/wireless/wl12xx/event.h +++ b/drivers/net/wireless/wl12xx/event.h @@ -59,7 +59,10 @@ enum { BSS_LOSE_EVENT_ID = BIT(18), REGAINED_BSS_EVENT_ID = BIT(19), ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), - STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), /* AP */ + /* STA: dummy paket for dynamic mem blocks */ + DUMMY_PACKET_EVENT_ID = BIT(21), + /* AP: STA remove complete */ + STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), diff --git a/drivers/net/wireless/wl12xx/ini.h b/drivers/net/wireless/wl12xx/ini.h index c330a2583dfd..1420c842b8f1 100644 --- a/drivers/net/wireless/wl12xx/ini.h +++ b/drivers/net/wireless/wl12xx/ini.h @@ -41,6 +41,28 @@ struct wl1271_ini_general_params { u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM]; } __packed; +#define WL128X_INI_MAX_SETTINGS_PARAM 4 + +struct wl128x_ini_general_params { + u8 ref_clock; + u8 settling_time; + u8 clk_valid_on_wakeup; + u8 tcxo_ref_clock; + u8 tcxo_settling_time; + u8 tcxo_valid_on_wakeup; + u8 tcxo_ldo_voltage; + u8 xtal_itrim_val; + u8 platform_conf; + u8 dual_mode_select; + u8 tx_bip_fem_auto_detect; + u8 tx_bip_fem_manufacturer; + u8 general_settings[WL128X_INI_MAX_SETTINGS_PARAM]; + u8 sr_state; + u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM]; +} __packed; + #define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15 struct wl1271_ini_band_params_2 { @@ -49,9 +71,16 @@ struct wl1271_ini_band_params_2 { u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; } __packed; -#define WL1271_INI_RATE_GROUP_COUNT 6 #define WL1271_INI_CHANNEL_COUNT_2 14 +struct wl128x_ini_band_params_2 { + u8 rx_trace_insertion_loss; + u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_2]; + u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; +} __packed; + +#define WL1271_INI_RATE_GROUP_COUNT 6 + struct wl1271_ini_fem_params_2 { __le16 tx_bip_ref_pd_voltage; u8 tx_bip_ref_power; @@ -68,6 +97,28 @@ struct wl1271_ini_fem_params_2 { u8 normal_to_degraded_high_thr; } __packed; +#define WL128X_INI_RATE_GROUP_COUNT 7 +/* low and high temperatures */ +#define WL128X_INI_PD_VS_TEMPERATURE_RANGES 2 + +struct wl128x_ini_fem_params_2 { + __le16 tx_bip_ref_pd_voltage; + u8 tx_bip_ref_power; + u8 tx_bip_ref_offset; + u8 tx_per_rate_pwr_limits_normal[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2]; + u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2]; + u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT + 1]; + u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_2]; + u8 tx_pd_vs_temperature[WL128X_INI_PD_VS_TEMPERATURE_RANGES]; + u8 rx_fem_insertion_loss; + u8 degraded_low_to_normal_thr; + u8 normal_to_degraded_high_thr; +} __packed; + #define WL1271_INI_CHANNEL_COUNT_5 35 #define WL1271_INI_SUB_BAND_COUNT_5 7 @@ -77,6 +128,12 @@ struct wl1271_ini_band_params_5 { u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; } __packed; +struct wl128x_ini_band_params_5 { + u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_5]; + u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; +} __packed; + struct wl1271_ini_fem_params_5 { __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5]; u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5]; @@ -92,6 +149,23 @@ struct wl1271_ini_fem_params_5 { u8 normal_to_degraded_high_thr; } __packed; +struct wl128x_ini_fem_params_5 { + __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_per_rate_pwr_limits_normal[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5]; + u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_5]; + u8 tx_pd_vs_temperature[WL1271_INI_SUB_BAND_COUNT_5 * + WL128X_INI_PD_VS_TEMPERATURE_RANGES]; + u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; + u8 degraded_low_to_normal_thr; + u8 normal_to_degraded_high_thr; +} __packed; /* NVS data structure */ #define WL1271_INI_NVS_SECTION_SIZE 468 @@ -100,7 +174,7 @@ struct wl1271_ini_fem_params_5 { #define WL1271_INI_LEGACY_NVS_FILE_SIZE 800 struct wl1271_nvs_file { - /* NVS section */ + /* NVS section - must be first! */ u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; /* INI section */ @@ -120,4 +194,24 @@ struct wl1271_nvs_file { } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; } __packed; +struct wl128x_nvs_file { + /* NVS section - must be first! */ + u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; + + /* INI section */ + struct wl128x_ini_general_params general_params; + u8 fem_vendor_and_options; + struct wl128x_ini_band_params_2 stat_radio_params_2; + u8 padding2; + struct { + struct wl128x_ini_fem_params_2 params; + u8 padding; + } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT]; + struct wl128x_ini_band_params_5 stat_radio_params_5; + u8 padding3; + struct { + struct wl128x_ini_fem_params_5 params; + u8 padding; + } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; +} __packed; #endif diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 6072fe457135..a8f4f156c055 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -31,6 +31,7 @@ #include "cmd.h" #include "reg.h" #include "tx.h" +#include "io.h" int wl1271_sta_init_templates_config(struct wl1271 *wl) { @@ -257,7 +258,7 @@ int wl1271_init_phy_config(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_rts_threshold(wl, wl->conf.rx.rts_threshold); + ret = wl1271_acx_rts_threshold(wl, wl->hw->wiphy->rts_threshold); if (ret < 0) return ret; @@ -284,7 +285,10 @@ int wl1271_init_pta(struct wl1271 *wl) { int ret; - ret = wl1271_acx_sg_cfg(wl); + if (wl->bss_type == BSS_TYPE_AP_BSS) + ret = wl1271_acx_ap_sg_cfg(wl); + else + ret = wl1271_acx_sta_sg_cfg(wl); if (ret < 0) return ret; @@ -321,9 +325,11 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) { int ret; - ret = wl1271_cmd_ext_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; + } /* PS config */ ret = wl1271_acx_config_ps(wl); @@ -348,8 +354,8 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - /* Bluetooth WLAN coexistence */ - ret = wl1271_init_pta(wl); + /* FM WLAN coexistence */ + ret = wl1271_acx_fm_coex(wl); if (ret < 0) return ret; @@ -407,7 +413,7 @@ static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl) static int wl1271_ap_hw_init(struct wl1271 *wl) { - int ret, i; + int ret; ret = wl1271_ap_init_templates_config(wl); if (ret < 0) @@ -418,23 +424,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - /* Configure initial TX rate classes */ - for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { - ret = wl1271_acx_ap_rate_policy(wl, - &wl->conf.tx.ap_rc_conf[i], i); - if (ret < 0) - return ret; - } - - ret = wl1271_acx_ap_rate_policy(wl, - &wl->conf.tx.ap_mgmt_conf, - ACX_TX_AP_MODE_MGMT_RATE); - if (ret < 0) - return ret; - - ret = wl1271_acx_ap_rate_policy(wl, - &wl->conf.tx.ap_bcst_conf, - ACX_TX_AP_MODE_BCST_RATE); + ret = wl1271_init_ap_rates(wl); if (ret < 0) return ret; @@ -449,7 +439,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) return 0; } -static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) +int wl1271_ap_init_templates(struct wl1271 *wl) { int ret; @@ -465,6 +455,70 @@ static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) if (ret < 0) return ret; + /* + * when operating as AP we want to receive external beacons for + * configuring ERP protection. + */ + ret = wl1271_acx_set_ap_beacon_filter(wl, false); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) +{ + return wl1271_ap_init_templates(wl); +} + +int wl1271_init_ap_rates(struct wl1271 *wl) +{ + int i, ret; + struct conf_tx_rate_class rc; + u32 supported_rates; + + wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", wl->basic_rate_set); + + if (wl->basic_rate_set == 0) + return -EINVAL; + + rc.enabled_rates = wl->basic_rate_set; + rc.long_retry_limit = 10; + rc.short_retry_limit = 10; + rc.aflags = 0; + ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_MGMT_RATE); + if (ret < 0) + return ret; + + /* use the min basic rate for AP broadcast/multicast */ + rc.enabled_rates = wl1271_tx_min_rate_get(wl); + rc.short_retry_limit = 10; + rc.long_retry_limit = 10; + rc.aflags = 0; + ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_BCST_RATE); + 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 ((wl->basic_rate_set & CONF_TX_OFDM_RATES)) + supported_rates = CONF_TX_OFDM_RATES; + else + supported_rates = CONF_TX_AP_ENABLED_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, i); + if (ret < 0) + return ret; + } + return 0; } @@ -504,6 +558,27 @@ static int wl1271_set_ba_policies(struct wl1271 *wl) return ret; } +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_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; +} + + int wl1271_hw_init(struct wl1271 *wl) { struct conf_tx_ac_category *conf_ac; @@ -511,11 +586,22 @@ int wl1271_hw_init(struct wl1271 *wl) int ret, i; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); - ret = wl1271_cmd_general_parms(wl); + 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; - ret = wl1271_cmd_radio_parms(wl); + 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; + + /* Chip-specific init */ + ret = wl1271_chip_specific_init(wl); if (ret < 0) return ret; @@ -528,6 +614,11 @@ int wl1271_hw_init(struct wl1271 *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) @@ -567,7 +658,7 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; /* Default fragmentation threshold */ - ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold); + ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold); if (ret < 0) goto out_free_memmap; diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h index 3a8bd3f426d2..3a3c230fd292 100644 --- a/drivers/net/wireless/wl12xx/init.h +++ b/drivers/net/wireless/wl12xx/init.h @@ -31,6 +31,9 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl); int wl1271_init_phy_config(struct wl1271 *wl); int wl1271_init_pta(struct wl1271 *wl); int wl1271_init_energy_detection(struct wl1271 *wl); +int wl1271_chip_specific_init(struct wl1271 *wl); int wl1271_hw_init(struct wl1271 *wl); +int wl1271_init_ap_rates(struct wl1271 *wl); +int wl1271_ap_init_templates(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c index d557f73e7c19..da5c1ad942a4 100644 --- a/drivers/net/wireless/wl12xx/io.c +++ b/drivers/net/wireless/wl12xx/io.c @@ -29,6 +29,7 @@ #include "wl12xx.h" #include "wl12xx_80211.h" #include "io.h" +#include "tx.h" #define OCP_CMD_LOOP 32 @@ -43,6 +44,16 @@ #define OCP_STATUS_REQ_FAILED 0x20000 #define OCP_STATUS_RESP_ERROR 0x30000 +bool wl1271_set_block_size(struct wl1271 *wl) +{ + if (wl->if_ops->set_block_size) { + wl->if_ops->set_block_size(wl, WL12XX_BUS_BLOCK_SIZE); + return true; + } + + return false; +} + void wl1271_disable_interrupts(struct wl1271 *wl) { wl->if_ops->disable_irq(wl); diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h index 00c771ea70bf..beed621a8ae0 100644 --- a/drivers/net/wireless/wl12xx/io.h +++ b/drivers/net/wireless/wl12xx/io.h @@ -169,5 +169,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl); struct ieee80211_hw *wl1271_alloc_hw(void); int wl1271_free_hw(struct wl1271 *wl); irqreturn_t wl1271_irq(int irq, void *data); +bool wl1271_set_block_size(struct wl1271 *wl); +int wl1271_tx_dummy_packet(struct wl1271 *wl); +void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters); #endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 8b3c8d196b03..bc00e52f6445 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "wl12xx.h" #include "wl12xx_80211.h" @@ -50,11 +51,11 @@ static struct conf_drv_settings default_conf = { .sg = { - .params = { + .sta_params = { [CONF_SG_BT_PER_THRESHOLD] = 7500, [CONF_SG_HV3_MAX_OVERRIDE] = 0, [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, - [CONF_SG_BT_LOAD_RATIO] = 50, + [CONF_SG_BT_LOAD_RATIO] = 200, [CONF_SG_AUTO_PS_MODE] = 1, [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, @@ -100,6 +101,61 @@ static struct conf_drv_settings default_conf = { [CONF_SG_DHCP_TIME] = 5000, [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, }, + .ap_params = { + [CONF_SG_BT_PER_THRESHOLD] = 7500, + [CONF_SG_HV3_MAX_OVERRIDE] = 0, + [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, + [CONF_SG_BT_LOAD_RATIO] = 50, + [CONF_SG_AUTO_PS_MODE] = 1, + [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, + [CONF_SG_ANTENNA_CONFIGURATION] = 0, + [CONF_SG_BEACON_MISS_PERCENT] = 60, + [CONF_SG_RATE_ADAPT_THRESH] = 64, + [CONF_SG_RATE_ADAPT_SNR] = 1, + [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10, + [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25, + [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25, + [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20, + [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25, + [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25, + [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7, + [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25, + [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25, + [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8, + [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25, + [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25, + [CONF_SG_RXT] = 1200, + [CONF_SG_TXT] = 1000, + [CONF_SG_ADAPTIVE_RXT_TXT] = 1, + [CONF_SG_PS_POLL_TIMEOUT] = 10, + [CONF_SG_UPSD_TIMEOUT] = 10, + [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7, + [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15, + [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15, + [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8, + [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20, + [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15, + [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20, + [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50, + [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10, + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800, + [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75, + [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15, + [CONF_SG_HV3_MAX_SERVED] = 6, + [CONF_SG_DHCP_TIME] = 5000, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, + [CONF_SG_TEMP_PARAM_1] = 0, + [CONF_SG_TEMP_PARAM_2] = 0, + [CONF_SG_TEMP_PARAM_3] = 0, + [CONF_SG_TEMP_PARAM_4] = 0, + [CONF_SG_TEMP_PARAM_5] = 0, + [CONF_SG_AP_BEACON_MISS_TX] = 3, + [CONF_SG_RX_WINDOW_LENGTH] = 6, + [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50, + [CONF_SG_TEMP_PARAM_6] = 1, + }, .state = CONF_SG_PROTECTIVE, }, .rx = { @@ -107,7 +163,7 @@ static struct conf_drv_settings default_conf = { .packet_detection_threshold = 0, .ps_poll_timeout = 15, .upsd_timeout = 15, - .rts_threshold = 2347, + .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, .rx_cca_threshold = 0, .irq_blk_threshold = 0xFFFF, .irq_pkt_threshold = 0, @@ -153,44 +209,6 @@ static struct conf_drv_settings default_conf = { .tx_op_limit = 1504, }, }, - .ap_rc_conf = { - [0] = { - .enabled_rates = CONF_TX_AP_ENABLED_RATES, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, - [1] = { - .enabled_rates = CONF_TX_AP_ENABLED_RATES, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, - [2] = { - .enabled_rates = CONF_TX_AP_ENABLED_RATES, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, - [3] = { - .enabled_rates = CONF_TX_AP_ENABLED_RATES, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, - }, - .ap_mgmt_conf = { - .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, - .ap_bcst_conf = { - .enabled_rates = CONF_HW_BIT_RATE_1MBPS, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, .ap_max_tx_retries = 100, .tid_conf_count = 4, .tid_conf = { @@ -239,12 +257,16 @@ static struct conf_drv_settings default_conf = { .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, .listen_interval = 1, .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, - .bcn_filt_ie_count = 1, + .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, @@ -254,9 +276,9 @@ static struct conf_drv_settings default_conf = { .ps_poll_threshold = 10, .ps_poll_recovery_period = 700, .bet_enable = CONF_BET_MODE_ENABLE, - .bet_max_consecutive = 10, + .bet_max_consecutive = 50, .psm_entry_retries = 5, - .psm_exit_retries = 255, + .psm_exit_retries = 16, .psm_entry_nullfunc_retries = 3, .psm_entry_hangover_period = 1, .keep_alive_interval = 55000, @@ -284,6 +306,15 @@ static struct conf_drv_settings default_conf = { .max_dwell_time_passive = 100000, .num_probe_reqs = 2, }, + .sched_scan = { + /* sched_scan requires dwell times in TU instead of TU/1000 */ + .min_dwell_time_active = 8, + .max_dwell_time_active = 30, + .dwell_time_passive = 100, + .num_probe_reqs = 2, + .rssi_threshold = -90, + .snr_threshold = 0, + }, .rf = { .tx_per_channel_power_compensation_2 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -298,19 +329,43 @@ static struct conf_drv_settings default_conf = { .tx_ba_win_size = 64, .inactivity_timeout = 10000, }, - .mem = { + .mem_wl127x = { .num_stations = 1, .ssid_profiles = 1, .rx_block_num = 70, .tx_min_block_num = 40, - .dynamic_memory = 0, + .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 */ + }, + .hci_io_ds = HCI_IO_DS_6MA, }; -static void __wl1271_op_remove_interface(struct wl1271 *wl); +static void __wl1271_op_remove_interface(struct wl1271 *wl, + bool reset_tx_queues); static void wl1271_free_ap_keys(struct wl1271 *wl); @@ -329,6 +384,7 @@ static struct platform_device wl1271_device = { }, }; +static DEFINE_MUTEX(wl_list_mutex); static LIST_HEAD(wl_list); static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, @@ -359,10 +415,12 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, return NOTIFY_DONE; wl_temp = hw->priv; + mutex_lock(&wl_list_mutex); list_for_each_entry(wl, &wl_list, list) { if (wl == wl_temp) break; } + mutex_unlock(&wl_list_mutex); if (wl != wl_temp) return NOTIFY_DONE; @@ -438,15 +496,30 @@ static int wl1271_plt_init(struct wl1271 *wl) struct conf_tx_tid *conf_tid; int ret, i; - ret = wl1271_cmd_general_parms(wl); + 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; - ret = wl1271_cmd_radio_parms(wl); + 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; - ret = wl1271_cmd_ext_radio_parms(wl); + if (wl->chip.id != CHIP_ID_1283_PG20) { + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + } + if (ret < 0) + return ret; + + /* Chip-specific initializations */ + ret = wl1271_chip_specific_init(wl); if (ret < 0) return ret; @@ -477,6 +550,11 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; + /* FM WLAN coexistence */ + ret = wl1271_acx_fm_coex(wl); + if (ret < 0) + goto out_free_memmap; + /* Energy detection */ ret = wl1271_init_energy_detection(wl); if (ret < 0) @@ -593,15 +671,17 @@ static void wl1271_fw_status(struct wl1271 *wl, { struct wl1271_fw_common_status *status = &full_status->common; struct timespec ts; - u32 total = 0; + u32 old_tx_blk_count = wl->tx_blocks_available; + u32 freed_blocks = 0; int i; - if (wl->bss_type == BSS_TYPE_AP_BSS) + if (wl->bss_type == BSS_TYPE_AP_BSS) { wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(struct wl1271_fw_ap_status), false); - else + } else { wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(struct wl1271_fw_sta_status), false); + } wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " "drv_rx_counter = %d, tx_results_counter = %d)", @@ -612,23 +692,38 @@ static void wl1271_fw_status(struct wl1271 *wl, /* update number of available TX blocks */ for (i = 0; i < NUM_TX_QUEUES; i++) { - u32 cnt = le32_to_cpu(status->tx_released_blks[i]) - - wl->tx_blocks_freed[i]; + freed_blocks += le32_to_cpu(status->tx_released_blks[i]) - + wl->tx_blocks_freed[i]; wl->tx_blocks_freed[i] = le32_to_cpu(status->tx_released_blks[i]); - wl->tx_blocks_available += cnt; - total += cnt; + } + + wl->tx_allocated_blocks -= freed_blocks; + + if (wl->bss_type == BSS_TYPE_AP_BSS) { + /* Update num of allocated TX blocks per link and ps status */ + wl1271_irq_update_links_status(wl, &full_status->ap); + wl->tx_blocks_available += freed_blocks; + } else { + int avail = full_status->sta.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 (total) + 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 */ - if (wl->bss_type == BSS_TYPE_AP_BSS) - wl1271_irq_update_links_status(wl, &full_status->ap); - /* update the host-chipset time offset */ getnstimeofday(&ts); wl->time_offset = (timespec_to_ns(&ts) >> 10) - @@ -674,6 +769,13 @@ irqreturn_t wl1271_irq(int irq, void *cookie) 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"); @@ -785,11 +887,17 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) switch (wl->bss_type) { case BSS_TYPE_AP_BSS: - fw_name = WL1271_AP_FW_NAME; + if (wl->chip.id == CHIP_ID_1283_PG20) + fw_name = WL128X_AP_FW_NAME; + else + fw_name = WL127X_AP_FW_NAME; break; case BSS_TYPE_IBSS: case BSS_TYPE_STA_BSS: - fw_name = WL1271_FW_NAME; + if (wl->chip.id == CHIP_ID_1283_PG20) + fw_name = WL128X_FW_NAME; + else + fw_name = WL1271_FW_NAME; break; default: wl1271_error("no compatible firmware for bss_type %d", @@ -838,14 +946,14 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) const struct firmware *fw; int ret; - ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl)); + ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl)); if (ret < 0) { wl1271_error("could not get nvs file: %d", ret); return ret; } - wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); + wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); if (!wl->nvs) { wl1271_error("could not allocate memory for the nvs file"); @@ -871,15 +979,30 @@ static void wl1271_recovery_work(struct work_struct *work) if (wl->state != WL1271_STATE_ON) goto out; - wl1271_info("Hardware recovery in progress."); + wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x", + wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4)); if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) ieee80211_connection_loss(wl->vif); + /* 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 */ - __wl1271_op_remove_interface(wl); + __wl1271_op_remove_interface(wl, false); 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); + out: mutex_unlock(&wl->mutex); } @@ -950,10 +1073,25 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", wl->chip.id); + /* end-of-transaction flag should be set in wl127x AP mode */ + if (wl->bss_type == BSS_TYPE_AP_BSS) + wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; + ret = wl1271_setup(wl); if (ret < 0) goto out; 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; + if (wl1271_set_block_size(wl)) + wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT; + break; + case CHIP_ID_1283_PG10: default: wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); ret = -ENODEV; @@ -978,6 +1116,24 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) return ret; } +static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl) +{ + unsigned int quirks = 0; + unsigned int *fw_ver = wl->chip.fw_ver; + + /* Only for wl127x */ + if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) && + /* Check STA version */ + (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && + (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) || + /* Check AP version */ + ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) && + (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN)))) + quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS; + + return quirks; +} + int wl1271_plt_start(struct wl1271 *wl) { int retries = WL1271_BOOT_RETRIES; @@ -1013,6 +1169,9 @@ int wl1271_plt_start(struct wl1271 *wl) wl->state = WL1271_STATE_PLT; wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver_str); + + /* Check if any quirks are needed with older fw versions */ + wl->quirks |= wl1271_get_fw_ver_quirks(wl); goto out; irq_disable: @@ -1040,7 +1199,7 @@ int wl1271_plt_start(struct wl1271 *wl) return ret; } -int __wl1271_plt_stop(struct wl1271 *wl) +static int __wl1271_plt_stop(struct wl1271 *wl) { int ret = 0; @@ -1124,10 +1283,219 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) spin_unlock_irqrestore(&wl->wl_lock, flags); } +int wl1271_tx_dummy_packet(struct wl1271 *wl) +{ + unsigned long flags; + + spin_lock_irqsave(&wl->wl_lock, flags); + set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); + wl->tx_queue_count++; + 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; +} + + static struct notifier_block wl1271_dev_notifier = { .notifier_call = wl1271_dev_notify, }; +#ifdef CONFIG_PM +static int wl1271_configure_suspend(struct wl1271 *wl) +{ + int ret; + + if (wl->bss_type != BSS_TYPE_STA_BSS) + return 0; + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + + /* enter psm if needed*/ + if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { + DECLARE_COMPLETION_ONSTACK(compl); + + wl->ps_compl = &compl; + ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, + wl->basic_rate, true); + if (ret < 0) + goto out_sleep; + + /* we must unlock here so we will be able to get events */ + wl1271_ps_elp_sleep(wl); + mutex_unlock(&wl->mutex); + + ret = wait_for_completion_timeout( + &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT)); + if (ret <= 0) { + wl1271_warning("couldn't enter ps mode!"); + ret = -EBUSY; + goto out; + } + + /* take mutex again, and wakeup */ + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + } +out_sleep: + wl1271_ps_elp_sleep(wl); +out_unlock: + mutex_unlock(&wl->mutex); +out: + return ret; + +} + +static void wl1271_configure_resume(struct wl1271 *wl) +{ + int ret; + + if (wl->bss_type != BSS_TYPE_STA_BSS) + return; + + mutex_lock(&wl->mutex); + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + /* exit psm if it wasn't configured */ + if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) + wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, + wl->basic_rate, true); + + 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; + wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); + wl->wow_enabled = !!wow; + if (wl->wow_enabled) { + int ret; + ret = wl1271_configure_suspend(wl); + if (ret < 0) { + wl1271_warning("couldn't prepare device to suspend"); + return ret; + } + /* flush any remaining work */ + wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); + flush_delayed_work(&wl->scan_complete_work); + + /* + * 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->pspoll_work); + flush_delayed_work(&wl->elp_work); + } + return 0; +} + +static int wl1271_op_resume(struct ieee80211_hw *hw) +{ + struct wl1271 *wl = hw->priv; + wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", + wl->wow_enabled); + + /* + * re-enable irq_work enqueuing, and call irq_work directly if + * there is a pending work. + */ + if (wl->wow_enabled) { + struct wl1271 *wl = hw->priv; + unsigned long flags; + bool run_irq_work = false; + + 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); + } + + wl1271_configure_resume(wl); + } + + return 0; +} +#endif + static int wl1271_op_start(struct ieee80211_hw *hw) { wl1271_debug(DEBUG_MAC80211, "mac80211 start"); @@ -1174,6 +1542,16 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } + /* + * 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_IF_INITIALIZED, &wl->flags)) { + ret = -EBUSY; + goto out; + } + switch (vif->type) { case NL80211_IFTYPE_STATION: wl->bss_type = BSS_TYPE_STA_BSS; @@ -1242,6 +1620,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, wl->vif = vif; wl->state = WL1271_STATE_ON; + set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags); wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str); /* update hw/fw version info in wiphy struct */ @@ -1249,6 +1628,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, strncpy(wiphy->fw_version, wl->chip.fw_ver_str, sizeof(wiphy->fw_version)); + /* Check if any quirks are needed with older fw versions */ + wl->quirks |= wl1271_get_fw_ver_quirks(wl); + /* * Now we know if 11a is supported (info from the NVS), so disable * 11a channels if not supported @@ -1262,23 +1644,30 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, out: mutex_unlock(&wl->mutex); + mutex_lock(&wl_list_mutex); if (!ret) list_add(&wl->list, &wl_list); + mutex_unlock(&wl_list_mutex); return ret; } -static void __wl1271_op_remove_interface(struct wl1271 *wl) +static void __wl1271_op_remove_interface(struct wl1271 *wl, + bool reset_tx_queues) { int i; wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); + /* because of hardware recovery, we may get here twice */ + if (wl->state != WL1271_STATE_ON) + return; + wl1271_info("down"); + mutex_lock(&wl_list_mutex); list_del(&wl->list); - - WARN_ON(wl->state != WL1271_STATE_ON); + mutex_unlock(&wl_list_mutex); /* enable dyn ps just in case (if left on due to fw crash etc) */ if (wl->bss_type == BSS_TYPE_STA_BSS) @@ -1286,12 +1675,15 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { wl->scan.state = WL1271_SCAN_STATE_IDLE; - kfree(wl->scan.scanned_ch); - wl->scan.scanned_ch = NULL; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, true); } + /* + * 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); @@ -1307,7 +1699,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) mutex_lock(&wl->mutex); /* let's notify MAC80211 about the remaining pending TX frames */ - wl1271_tx_reset(wl); + wl1271_tx_reset(wl, reset_tx_queues); wl1271_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); @@ -1321,6 +1713,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl->psm_entry_retry = 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->tx_security_last_seq = 0; @@ -1328,13 +1721,20 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl->time_offset = 0; wl->session_counter = 0; wl->rate_set = CONF_TX_RATE_MASK_BASIC; - wl->flags = 0; wl->vif = NULL; wl->filters = 0; wl1271_free_ap_keys(wl); memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); wl->ap_fw_ps_map = 0; wl->ap_ps_map = 0; + wl->sched_scanning = false; + + /* + * 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; for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_blocks_freed[i] = 0; @@ -1361,14 +1761,14 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, */ if (wl->vif) { WARN_ON(wl->vif != vif); - __wl1271_op_remove_interface(wl); + __wl1271_op_remove_interface(wl, true); } mutex_unlock(&wl->mutex); cancel_work_sync(&wl->recovery_work); } -static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) +void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) { wl1271_set_default_filters(wl); @@ -1431,10 +1831,10 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc) * 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 there is no supported scenario for JOIN during - * association - if it becomes a supported scenario, the WPA/WPA2 keys - * must be handled somehow. - * + * 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(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) wl1271_info("JOIN while associated."); @@ -1490,7 +1890,7 @@ static int wl1271_unjoin(struct wl1271 *wl) clear_bit(WL1271_FLAG_JOINED, &wl->flags); memset(wl->bssid, 0, ETH_ALEN); - /* stop filterting packets based on bssid */ + /* stop filtering packets based on bssid */ wl1271_configure_filters(wl, FIF_OTHER_BSS); out: @@ -1530,6 +1930,13 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) wl->session_counter++; if (wl->session_counter >= SESSION_COUNTER_MAX) wl->session_counter = 0; + + /* 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 = wl1271_dummy_join(wl); if (ret < 0) goto out; @@ -1569,7 +1976,12 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; + /* we support configuring the channel and band while off */ + if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) { + wl->band = conf->channel->band; + wl->channel = channel; + } + goto out; } @@ -2077,6 +2489,60 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, return ret; } +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; + int ret; + + wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start"); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_scan_sched_scan_config(wl, req, ies); + if (ret < 0) + goto out_sleep; + + ret = wl1271_scan_sched_scan_start(wl); + 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); + + 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; @@ -2093,7 +2559,7 @@ static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) if (ret < 0) goto out; - ret = wl1271_acx_frag_threshold(wl, (u16)value); + ret = wl1271_acx_frag_threshold(wl, value); if (ret < 0) wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret); @@ -2121,7 +2587,7 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) if (ret < 0) goto out; - ret = wl1271_acx_rts_threshold(wl, (u16) value); + ret = wl1271_acx_rts_threshold(wl, value); if (ret < 0) wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret); @@ -2136,20 +2602,24 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, int offset) { - u8 *ptr = skb->data + offset; + u8 ssid_len; + const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, + skb->len - offset); - /* find the location of the ssid in the beacon */ - while (ptr < skb->data + skb->len) { - if (ptr[0] == WLAN_EID_SSID) { - wl->ssid_len = ptr[1]; - memcpy(wl->ssid, ptr+2, wl->ssid_len); - return 0; - } - ptr += (ptr[1] + 2); + if (!ptr) { + wl1271_error("No SSID in IEs!"); + return -ENOENT; } - wl1271_error("No SSID in IEs!\n"); - return -ENOENT; + ssid_len = ptr[1]; + if (ssid_len > IEEE80211_MAX_SSID_LEN) { + wl1271_error("SSID is too long!"); + return -EINVAL; + } + + wl->ssid_len = ssid_len; + memcpy(wl->ssid, ptr+2, ssid_len); + return 0; } static int wl1271_bss_erp_info_changed(struct wl1271 *wl, @@ -2264,24 +2734,19 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, if ((changed & BSS_CHANGED_BASIC_RATES)) { u32 rates = bss_conf->basic_rates; - struct conf_tx_rate_class mgmt_rc; wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates); wl->basic_rate = wl1271_tx_min_rate_get(wl); - wl1271_debug(DEBUG_AP, "basic rates: 0x%x", - wl->basic_rate_set); - /* update the AP management rate policy with the new rates */ - mgmt_rc.enabled_rates = wl->basic_rate_set; - mgmt_rc.long_retry_limit = 10; - mgmt_rc.short_retry_limit = 10; - mgmt_rc.aflags = 0; - ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc, - ACX_TX_AP_MODE_MGMT_RATE); + ret = wl1271_init_ap_rates(wl); if (ret < 0) { - wl1271_error("AP mgmt policy change failed %d", ret); + wl1271_error("AP rate policy change failed %d", ret); goto out; } + + ret = wl1271_ap_init_templates(wl); + if (ret < 0) + goto out; } ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed); @@ -2314,6 +2779,24 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, } } + 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; + wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, + rates); + wl->basic_rate = wl1271_tx_min_rate_get(wl); + + /* by default, use 11b rates */ + wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES; + ret = wl1271_acx_sta_rate_policies(wl); + if (ret < 0) + goto out; + } + } + ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed); if (ret < 0) goto out; @@ -2503,8 +2986,10 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, } } else { /* use defaults when not associated */ + bool was_assoc = + !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED, + &wl->flags); clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags); - clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); wl->aid = 0; /* free probe-request template */ @@ -2530,8 +3015,10 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, goto out; /* restore the bssid filter and go to dummy bssid */ - wl1271_unjoin(wl); - wl1271_dummy_join(wl); + if (was_assoc) { + wl1271_unjoin(wl); + wl1271_dummy_join(wl); + } } } @@ -2650,32 +3137,31 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY; conf_tid->apsd_conf[0] = 0; conf_tid->apsd_conf[1] = 0; - } else { - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; + goto out; + } - /* - * the txop is confed in units of 32us by the mac80211, - * we need us - */ - ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), - params->cw_min, params->cw_max, - params->aifs, params->txop << 5); - if (ret < 0) - goto out_sleep; + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; - ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), - CONF_CHANNEL_TYPE_EDCF, - wl1271_tx_get_queue(queue), - ps_scheme, CONF_ACK_POLICY_LEGACY, - 0, 0); - if (ret < 0) - goto out_sleep; + /* + * the txop is confed in units of 32us by the mac80211, + * we need us + */ + ret = wl1271_acx_ac_cfg(wl, 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, 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); - } + wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -2847,10 +3333,11 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw, return ret; } -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) +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; int ret; @@ -2907,6 +3394,28 @@ int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return ret; } +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 = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0); + + /* the above is appropriate for STA mode for PS purposes */ + WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + /* can't be const, mac80211 writes to this */ static struct ieee80211_rate wl1271_rates[] = { { .bitrate = 10, @@ -3003,7 +3512,8 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { #ifdef CONFIG_WL12XX_HT #define WL12XX_HT_CAP { \ - .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \ + .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, \ @@ -3142,12 +3652,18 @@ static const struct ieee80211_ops wl1271_ops = { .stop = wl1271_op_stop, .add_interface = wl1271_op_add_interface, .remove_interface = wl1271_op_remove_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, + .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, @@ -3157,6 +3673,7 @@ static const struct ieee80211_ops wl1271_ops = { .sta_add = wl1271_op_sta_add, .sta_remove = wl1271_op_sta_remove, .ampdu_action = wl1271_op_ampdu_action, + .tx_frames_pending = wl1271_tx_frames_pending, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; @@ -3207,8 +3724,7 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, unsigned long res; int ret; - ret = strict_strtoul(buf, 10, &res); - + ret = kstrtoul(buf, 10, &res); if (ret < 0) { wl1271_warning("incorrect value written to bt_coex_mode"); return count; @@ -3273,7 +3789,11 @@ int wl1271_register_hw(struct wl1271 *wl) ret = wl1271_fetch_nvs(wl); if (ret == 0) { - u8 *nvs_ptr = (u8 *)wl->nvs->nvs; + /* 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; wl->mac_addr[0] = nvs_ptr[11]; wl->mac_addr[1] = nvs_ptr[10]; @@ -3342,6 +3862,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_SUPPORTS_CQM_RSSI | IEEE80211_HW_REPORTS_TX_ACK_STATUS | + IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_AP_LINK_PS; wl->hw->wiphy->cipher_suites = cipher_suites; @@ -3358,6 +3879,10 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - sizeof(struct ieee80211_header); + /* 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. @@ -3458,6 +3983,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->ap_ps_map = 0; wl->ap_fw_ps_map = 0; wl->quirks = 0; + wl->platform_quirks = 0; + wl->sched_scanning = false; memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) @@ -3478,11 +4005,17 @@ struct ieee80211_hw *wl1271_alloc_hw(void) goto err_hw; } + wl->dummy_packet = wl12xx_alloc_dummy_packet(wl); + if (!wl->dummy_packet) { + ret = -ENOMEM; + goto err_aggr; + } + /* Register platform device */ ret = platform_device_register(wl->plat_dev); if (ret) { wl1271_error("couldn't register platform device"); - goto err_aggr; + goto err_dummy_packet; } dev_set_drvdata(&wl->plat_dev->dev, wl); @@ -3508,6 +4041,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void) err_platform: platform_device_unregister(wl->plat_dev); +err_dummy_packet: + dev_kfree_skb(wl->dummy_packet); + err_aggr: free_pages((unsigned long)wl->aggr_buf, order); @@ -3527,6 +4063,7 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw); int wl1271_free_hw(struct wl1271 *wl) { platform_device_unregister(wl->plat_dev); + dev_kfree_skb(wl->dummy_packet); free_pages((unsigned long)wl->aggr_buf, get_order(WL1271_AGGR_BUFFER_SIZE)); kfree(wl->plat_dev); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 971f13e792da..b59b67711a17 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -43,6 +43,10 @@ void wl1271_elp_work(struct work_struct *work) if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; + /* our work might have been already cancelled */ + if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) + goto out; + if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || (!test_bit(WL1271_FLAG_PSM, &wl->flags) && !test_bit(WL1271_FLAG_IDLE, &wl->flags))) @@ -61,12 +65,16 @@ void wl1271_elp_work(struct work_struct *work) /* Routines to toggle sleep mode while in ELP */ void wl1271_ps_elp_sleep(struct wl1271 *wl) { - if (test_bit(WL1271_FLAG_PSM, &wl->flags) || - test_bit(WL1271_FLAG_IDLE, &wl->flags)) { - cancel_delayed_work(&wl->elp_work); - ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, - msecs_to_jiffies(ELP_ENTRY_DELAY)); - } + /* we shouldn't get consecutive sleep requests */ + if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) + return; + + if (!test_bit(WL1271_FLAG_PSM, &wl->flags) && + !test_bit(WL1271_FLAG_IDLE, &wl->flags)) + return; + + ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, + msecs_to_jiffies(ELP_ENTRY_DELAY)); } int wl1271_ps_elp_wakeup(struct wl1271 *wl) @@ -77,6 +85,16 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl) u32 start_time = jiffies; bool pending = false; + /* + * we might try to wake up even if we didn't go to sleep + * before (e.g. on boot) + */ + if (!test_and_clear_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)) + return 0; + + /* don't cancel_sync as it might contend for a mutex and deadlock */ + cancel_delayed_work(&wl->elp_work); + if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) return 0; @@ -149,9 +167,6 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, case STATION_ACTIVE_MODE: default: wl1271_debug(DEBUG_PSM, "leaving psm"); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - return ret; /* disable beacon early termination */ ret = wl1271_acx_bet_enable(wl, false); diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h index c41bd0a711bc..25eb9bc9b628 100644 --- a/drivers/net/wireless/wl12xx/ps.h +++ b/drivers/net/wireless/wl12xx/ps.h @@ -35,4 +35,6 @@ void wl1271_elp_work(struct work_struct *work); void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues); void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid); +#define WL1271_PS_COMPLETE_TIMEOUT 500 + #endif /* __WL1271_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h index 990960771528..440a4ee9cb42 100644 --- a/drivers/net/wireless/wl12xx/reg.h +++ b/drivers/net/wireless/wl12xx/reg.h @@ -207,6 +207,8 @@ #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) @@ -452,24 +454,11 @@ #define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 #define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 -/* - * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile - * for platforms using active high interrupt level - */ -#ifdef USE_ACTIVE_HIGH #define HI_CFG_DEF_VAL \ (HI_CFG_UART_ENABLE | \ HI_CFG_RST232_ENABLE | \ HI_CFG_CLOCK_REQ_SELECT | \ HI_CFG_HOST_INT_ENABLE) -#else -#define HI_CFG_DEF_VAL \ - (HI_CFG_UART_ENABLE | \ - HI_CFG_RST232_ENABLE | \ - HI_CFG_CLOCK_REQ_SELECT | \ - HI_CFG_HOST_INT_ENABLE) - -#endif #define REF_FREQ_19_2 0 #define REF_FREQ_26_0 1 diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 919b59f00301..70091035e019 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -48,18 +48,14 @@ static void wl1271_rx_status(struct wl1271 *wl, struct ieee80211_rx_status *status, u8 beacon) { - enum ieee80211_band desc_band; - memset(status, 0, sizeof(struct ieee80211_rx_status)); - status->band = wl->band; - if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) - desc_band = IEEE80211_BAND_2GHZ; + status->band = IEEE80211_BAND_2GHZ; else - desc_band = IEEE80211_BAND_5GHZ; + status->band = IEEE80211_BAND_5GHZ; - status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band); + status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band); #ifdef CONFIG_WL12XX_HT /* 11n support */ @@ -76,15 +72,19 @@ static void wl1271_rx_status(struct wl1271 *wl, */ wl->noise = desc->rssi - (desc->snr >> 1); - status->freq = ieee80211_channel_to_frequency(desc->channel, desc_band); + status->freq = ieee80211_channel_to_frequency(desc->channel, + status->band); if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { - status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK; - if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL))) - status->flag |= RX_FLAG_DECRYPTED; - if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL)) + 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"); + } } } @@ -103,6 +103,25 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) if (unlikely(wl->state == WL1271_STATE_PLT)) return -EINVAL; + /* the data read starts with the descriptor */ + desc = (struct wl1271_rx_descriptor *) data; + + 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 = __dev_alloc_skb(length, GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); @@ -112,9 +131,6 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) buf = skb_put(skb, length); memcpy(buf, data, length); - /* the data read starts with the descriptor */ - desc = (struct wl1271_rx_descriptor *) buf; - /* now we pull the descriptor out of the buffer */ skb_pull(skb, sizeof(*desc)); @@ -124,7 +140,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); - wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, + wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, + skb->len - desc->pad_len, beacon ? "beacon" : ""); skb_trim(skb, skb->len - desc->pad_len); @@ -163,18 +180,25 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) break; } - /* - * 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 = wl1271_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); + 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 = wl1271_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, diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 420653a2859c..f37e5a391976 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -48,8 +48,7 @@ void wl1271_scan_complete_work(struct work_struct *work) goto out; wl->scan.state = WL1271_SCAN_STATE_IDLE; - kfree(wl->scan.scanned_ch); - wl->scan.scanned_ch = NULL; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, false); @@ -87,7 +86,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, flags = req->channels[i]->flags; - if (!wl->scan.scanned_ch[i] && + if (!test_bit(i, wl->scan.scanned_ch) && !(flags & IEEE80211_CHAN_DISABLED) && ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && (req->channels[i]->band == band)) { @@ -124,7 +123,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, memset(&channels[j].bssid_msb, 0xff, 2); /* Mark the channels we already used */ - wl->scan.scanned_ch[i] = true; + set_bit(i, wl->scan.scanned_ch); j++; } @@ -291,6 +290,12 @@ void wl1271_scan_stm(struct wl1271 *wl) int wl1271_scan(struct wl1271 *wl, 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; @@ -304,10 +309,8 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, } wl->scan.req = req; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); - wl->scan.scanned_ch = kcalloc(req->n_channels, - sizeof(*wl->scan.scanned_ch), - GFP_KERNEL); /* we assume failure so that timeout scenarios are handled correctly */ wl->scan.failed = true; ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, @@ -317,3 +320,246 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, return 0; } + +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) +{ + struct conf_sched_scan_settings *c = &wl->conf.sched_scan; + int i, j; + u32 flags; + + for (i = 0, j = start; + i < req->n_channels && j < MAX_CHANNELS_ALL_BANDS; + i++) { + flags = req->channels[i]->flags; + + if (!(flags & IEEE80211_CHAN_DISABLED) && + ((flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive) && + ((flags & IEEE80211_CHAN_RADAR) == radar) && + (req->channels[i]->band == band)) { + 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_PASSIVE_SCAN) { + channels[j].passive_duration = + cpu_to_le16(c->dwell_time_passive); + } else { + 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[j]->max_power; + channels[j].channel = req->channels[i]->hw_value; + + j++; + } + } + + return j - start; +} + +static int +wl1271_scan_sched_scan_channels(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req, + struct wl1271_cmd_sched_scan_config *cfg) +{ + int idx = 0; + + cfg->passive[0] = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + IEEE80211_BAND_2GHZ, + false, true, idx); + idx += cfg->passive[0]; + + cfg->active[0] = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + IEEE80211_BAND_2GHZ, + false, false, idx); + idx += cfg->active[0]; + + cfg->passive[1] = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + IEEE80211_BAND_5GHZ, + false, true, idx); + idx += cfg->passive[1]; + + cfg->active[1] = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + IEEE80211_BAND_5GHZ, + false, false, 14); + idx += cfg->active[1]; + + cfg->dfs = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + IEEE80211_BAND_5GHZ, + true, false, idx); + idx += cfg->dfs; + + 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]); + + return idx; +} + +int wl1271_scan_sched_scan_config(struct wl1271 *wl, + 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, total_channels, ret; + + 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); + + if (req->ssids[0].ssid_len && req->ssids[0].ssid) { + cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC; + cfg->ssid_len = req->ssids[0].ssid_len; + memcpy(cfg->ssid, req->ssids[0].ssid, + req->ssids[0].ssid_len); + } else { + cfg->filter_type = SCAN_SSID_FILTER_ANY; + cfg->ssid_len = 0; + } + + total_channels = wl1271_scan_sched_scan_channels(wl, req, cfg); + if (total_channels == 0) { + wl1271_error("scan channel list is empty"); + ret = -EINVAL; + goto out; + } + + if (cfg->active[0]) { + ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid, + req->ssids[0].ssid_len, + ies->ie[IEEE80211_BAND_2GHZ], + ies->len[IEEE80211_BAND_2GHZ], + IEEE80211_BAND_2GHZ); + if (ret < 0) { + wl1271_error("2.4GHz PROBE request template failed"); + goto out; + } + } + + if (cfg->active[1]) { + ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid, + req->ssids[0].ssid_len, + ies->ie[IEEE80211_BAND_5GHZ], + ies->len[IEEE80211_BAND_5GHZ], + IEEE80211_BAND_5GHZ); + 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 wl1271_cmd_sched_scan_start *start; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd periodic scan start"); + + if (wl->bss_type != BSS_TYPE_STA_BSS) + return -EOPNOTSUPP; + + if (!test_bit(WL1271_FLAG_IDLE, &wl->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; + } + wl->sched_scanning = false; + +out_free: + kfree(stop); +} diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h index 421a750add5a..c83319579ca3 100644 --- a/drivers/net/wireless/wl12xx/scan.h +++ b/drivers/net/wireless/wl12xx/scan.h @@ -33,6 +33,12 @@ int wl1271_scan_build_probe_req(struct wl1271 *wl, const u8 *ie, size_t ie_len, u8 band); void wl1271_scan_stm(struct wl1271 *wl); void wl1271_scan_complete_work(struct work_struct *work); +int wl1271_scan_sched_scan_config(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req, + struct ieee80211_sched_scan_ies *ies); +int wl1271_scan_sched_scan_start(struct wl1271 *wl); +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 @@ -106,4 +112,112 @@ struct wl1271_cmd_trigger_scan_to { __le32 timeout; } __packed; +#define MAX_CHANNELS_ALL_BANDS 41 +#define SCAN_MAX_CYCLE_INTERVALS 16 +#define SCAN_MAX_BANDS 3 + +enum { + SCAN_CHANNEL_TYPE_2GHZ_PASSIVE, + SCAN_CHANNEL_TYPE_2GHZ_ACTIVE, + SCAN_CHANNEL_TYPE_5GHZ_PASSIVE, + SCAN_CHANNEL_TYPE_5GHZ_ACTIVE, + SCAN_CHANNEL_TYPE_5GHZ_DFS, +}; + +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, +}; + +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[IW_ESSID_MAX_SIZE]; + + 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[MAX_CHANNELS_ALL_BANDS]; +} __packed; + + +#define SCHED_SCAN_MAX_SSIDS 8 + +enum { + SCAN_SSID_TYPE_PUBLIC = 0, + SCAN_SSID_TYPE_HIDDEN = 1, +}; + +struct wl1271_ssid { + u8 type; + u8 len; + u8 ssid[IW_ESSID_MAX_SIZE]; + /* 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/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index b1c7d031c391..536e5065454b 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -51,6 +51,13 @@ static const struct sdio_device_id wl1271_devices[] = { }; MODULE_DEVICE_TABLE(sdio, wl1271_devices); +static void wl1271_sdio_set_block_size(struct wl1271 *wl, unsigned int blksz) +{ + sdio_claim_host(wl->if_priv); + sdio_set_block_size(wl->if_priv, blksz); + sdio_release_host(wl->if_priv); +} + static inline struct sdio_func *wl_to_func(struct wl1271 *wl) { return wl->if_priv; @@ -75,6 +82,16 @@ static irqreturn_t wl1271_hardirq(int irq, void *cookie) 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(wl1271_sdio_wl_to_dev(wl), 0); + spin_unlock_irqrestore(&wl->wl_lock, flags); + return IRQ_HANDLED; + } spin_unlock_irqrestore(&wl->wl_lock, flags); return IRQ_WAKE_THREAD; @@ -203,7 +220,8 @@ static struct wl1271_if_operations sdio_ops = { .power = wl1271_sdio_set_power, .dev = wl1271_sdio_wl_to_dev, .enable_irq = wl1271_sdio_enable_interrupts, - .disable_irq = wl1271_sdio_disable_interrupts + .disable_irq = wl1271_sdio_disable_interrupts, + .set_block_size = wl1271_sdio_set_block_size, }; static int __devinit wl1271_probe(struct sdio_func *func, @@ -212,6 +230,8 @@ static int __devinit wl1271_probe(struct sdio_func *func, struct ieee80211_hw *hw; const struct wl12xx_platform_data *wlan_data; struct wl1271 *wl; + unsigned long irqflags; + mmc_pm_flag_t mmcflags; int ret; /* We are only able to handle the wlan function */ @@ -230,6 +250,9 @@ static int __devinit wl1271_probe(struct sdio_func *func, /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + /* Use block mode for transferring over one block size of data */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + wlan_data = wl12xx_get_platform_data(); if (IS_ERR(wlan_data)) { ret = PTR_ERR(wlan_data); @@ -239,17 +262,34 @@ static int __devinit wl1271_probe(struct sdio_func *func, wl->irq = wlan_data->irq; wl->ref_clock = wlan_data->board_ref_clock; + wl->tcxo_clock = wlan_data->board_tcxo_clock; + wl->platform_quirks = wlan_data->platform_quirks; + + 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, wl1271_hardirq, wl1271_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + irqflags, DRIVER_NAME, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); goto out_free; } + enable_irq_wake(wl->irq); + device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1); + disable_irq(wl->irq); + /* if sdio can keep power while host is suspended, enable wow */ + mmcflags = sdio_get_host_pm_caps(func); + wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags); + + if (mmcflags & MMC_PM_KEEP_POWER) + hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; + ret = wl1271_init_ieee80211(wl); if (ret) goto out_irq; @@ -284,19 +324,61 @@ static void __devexit wl1271_remove(struct sdio_func *func) pm_runtime_get_noresume(&func->dev); wl1271_unregister_hw(wl); + device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0); + disable_irq_wake(wl->irq); free_irq(wl->irq, wl); wl1271_free_hw(wl); } +#ifdef CONFIG_PM static int wl1271_suspend(struct device *dev) { /* Tell MMC/SDIO core it's OK to power down the card * (if it isn't already), but not to remove it completely */ - return 0; + struct sdio_func *func = dev_to_sdio_func(dev); + struct wl1271 *wl = sdio_get_drvdata(func); + mmc_pm_flag_t sdio_flags; + int ret = 0; + + wl1271_debug(DEBUG_MAC80211, "wl1271 suspend. wow_enabled: %d", + wl->wow_enabled); + + /* check whether sdio should keep power */ + if (wl->wow_enabled) { + sdio_flags = sdio_get_host_pm_caps(func); + + if (!(sdio_flags & MMC_PM_KEEP_POWER)) { + wl1271_error("can't keep power while host " + "is suspended"); + ret = -EINVAL; + goto out; + } + + /* keep power while host suspended */ + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (ret) { + wl1271_error("error while trying to keep power"); + goto out; + } + + /* release host */ + sdio_release_host(func); + } +out: + return ret; } static int wl1271_resume(struct device *dev) { + struct sdio_func *func = dev_to_sdio_func(dev); + struct wl1271 *wl = sdio_get_drvdata(func); + + wl1271_debug(DEBUG_MAC80211, "wl1271 resume"); + if (wl->wow_enabled) { + /* claim back host */ + sdio_claim_host(func); + } + return 0; } @@ -304,15 +386,18 @@ static const struct dev_pm_ops wl1271_sdio_pm_ops = { .suspend = wl1271_suspend, .resume = wl1271_resume, }; +#endif static struct sdio_driver wl1271_sdio_driver = { .name = "wl1271_sdio", .id_table = wl1271_devices, .probe = wl1271_probe, .remove = __devexit_p(wl1271_remove), +#ifdef CONFIG_PM .drv = { .pm = &wl1271_sdio_pm_ops, }, +#endif }; static int __init wl1271_init(void) @@ -343,4 +428,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); MODULE_FIRMWARE(WL1271_FW_NAME); -MODULE_FIRMWARE(WL1271_AP_FW_NAME); +MODULE_FIRMWARE(WL128X_FW_NAME); +MODULE_FIRMWARE(WL127X_AP_FW_NAME); +MODULE_FIRMWARE(WL128X_AP_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index 9fcbd3dd8490..f28915392877 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c @@ -189,7 +189,12 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) const struct firmware *fw; int ret; - ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl)); + if (wl->chip.id == CHIP_ID_1283_PG20) + ret = request_firmware(&fw, WL128X_FW_NAME, + wl1271_wl_to_dev(wl)); + else + ret = request_firmware(&fw, WL1271_FW_NAME, + wl1271_wl_to_dev(wl)); if (ret < 0) { wl1271_error("could not get firmware: %d", ret); @@ -227,14 +232,14 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) const struct firmware *fw; int ret; - ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl)); + ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl)); if (ret < 0) { wl1271_error("could not get nvs file: %d", ret); return ret; } - wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); + wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); if (!wl->nvs) { wl1271_error("could not allocate memory for the nvs file"); @@ -288,6 +293,11 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) wl1271_notice("chip id 0x%x (1271 PG20)", wl->chip.id); break; + case CHIP_ID_1283_PG20: + wl1271_notice("chip id 0x%x (1283 PG20)", + wl->chip.id); + break; + case CHIP_ID_1283_PG10: default: wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); return -ENODEV; @@ -407,6 +417,9 @@ static int __devinit wl1271_probe(struct sdio_func *func, /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + /* Use block mode for transferring over one block size of data */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + wlan_data = wl12xx_get_platform_data(); if (IS_ERR(wlan_data)) { ret = PTR_ERR(wlan_data); @@ -416,6 +429,7 @@ static int __devinit wl1271_probe(struct sdio_func *func, wl->irq = wlan_data->irq; wl->ref_clock = wlan_data->board_ref_clock; + wl->tcxo_clock = wlan_data->board_tcxo_clock; sdio_set_drvdata(func, wl_test); diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index ffc745b17f4d..51662bb68019 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -355,7 +355,8 @@ static struct wl1271_if_operations spi_ops = { .power = wl1271_spi_set_power, .dev = wl1271_spi_wl_to_dev, .enable_irq = wl1271_spi_enable_interrupts, - .disable_irq = wl1271_spi_disable_interrupts + .disable_irq = wl1271_spi_disable_interrupts, + .set_block_size = NULL, }; static int __devinit wl1271_probe(struct spi_device *spi) @@ -363,6 +364,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) struct wl12xx_platform_data *pdata; struct ieee80211_hw *hw; struct wl1271 *wl; + unsigned long irqflags; int ret; pdata = spi->dev.platform_data; @@ -400,6 +402,13 @@ static int __devinit wl1271_probe(struct spi_device *spi) } wl->ref_clock = pdata->board_ref_clock; + wl->tcxo_clock = pdata->board_tcxo_clock; + wl->platform_quirks = pdata->platform_quirks; + + if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) + irqflags = IRQF_TRIGGER_RISING; + else + irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; wl->irq = spi->irq; if (wl->irq < 0) { @@ -409,7 +418,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) } ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + irqflags, DRIVER_NAME, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); @@ -490,5 +499,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); MODULE_FIRMWARE(WL1271_FW_NAME); -MODULE_FIRMWARE(WL1271_AP_FW_NAME); +MODULE_FIRMWARE(WL128X_FW_NAME); +MODULE_FIRMWARE(WL127X_AP_FW_NAME); +MODULE_FIRMWARE(WL128X_AP_FW_NAME); MODULE_ALIAS("spi:wl1271"); diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c index 6ec06a4a4c6d..da351d7cd1f2 100644 --- a/drivers/net/wireless/wl12xx/testmode.c +++ b/drivers/net/wireless/wl12xx/testmode.c @@ -27,6 +27,7 @@ #include "wl12xx.h" #include "acx.h" +#include "reg.h" #define WL1271_TM_MAX_DATA_LENGTH 1024 @@ -204,7 +205,10 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) kfree(wl->nvs); - if (len != sizeof(struct wl1271_nvs_file)) + if ((wl->chip.id == CHIP_ID_1283_PG20) && + (len != sizeof(struct wl128x_nvs_file))) + return -EINVAL; + else if (len != sizeof(struct wl1271_nvs_file)) return -EINVAL; wl->nvs = kzalloc(len, GFP_KERNEL); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 5e9ef7d53e7e..ca3ab1c1acef 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -65,11 +65,36 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) 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 int wl1271_tx_update_filters(struct wl1271 *wl, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)(skb->data + + sizeof(struct wl1271_tx_hw_descr)); + + /* + * stop bssid-based filtering before transmitting authentication + * requests. this way the hw will never drop authentication + * responses coming from BSSIDs it isn't familiar with (e.g. on + * roaming) + */ + if (!ieee80211_is_auth(hdr->frame_control)) + return 0; + + wl1271_configure_filters(wl, FIF_OTHER_BSS); + + return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); +} + static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, struct sk_buff *skb) { @@ -127,13 +152,29 @@ u8 wl1271_tx_get_hlid(struct sk_buff *skb) } } +static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, + unsigned int packet_length) +{ + if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) + return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); + else + return ALIGN(packet_length, WL1271_TX_ALIGN_TO); +} + static int wl1271_tx_allocate(struct wl1271 *wl, 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; + u32 spare_blocks; + + if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS)) + spare_blocks = 2; + else + spare_blocks = 1; if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) return -EAGAIN; @@ -145,17 +186,27 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, /* approximate the number of blocks required for this packet in the firmware */ - total_blocks = total_len + TX_HW_BLOCK_SIZE - 1; - total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE; + len = wl12xx_calc_packet_alignment(wl, total_len); + + 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); - desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; - desc->total_mem_blocks = total_blocks; + /* 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 (wl->bss_type == BSS_TYPE_AP_BSS) wl->links[hlid].allocated_blks += total_blocks; @@ -172,13 +223,18 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, return ret; } +static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) +{ + return wl->dummy_packet == skb; +} + static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, u32 extra, struct ieee80211_tx_info *control, u8 hlid) { struct timespec ts; struct wl1271_tx_hw_descr *desc; - int pad, ac, rate_idx; + int aligned_len, ac, rate_idx; s64 hosttime; u16 tx_attr; @@ -202,12 +258,25 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, else desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); - /* configure the tx attributes */ - tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; - - /* queue (we use same identifiers for tid's and ac's */ + /* queue */ ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - desc->tid = ac; + desc->tid = skb->priority; + + if (wl12xx_is_dummy_packet(wl, skb)) { + /* + * 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 = ((~wl->session_counter) << + TX_HW_ATTR_OFST_SESSION_COUNTER) & + TX_HW_ATTR_SESSION_COUNTER; + + tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; + } else { + /* configure the tx attributes */ + tx_attr = + wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; + } if (wl->bss_type != BSS_TYPE_AP_BSS) { desc->aid = hlid; @@ -237,20 +306,37 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; desc->reserved = 0; - /* align the length (and store in terms of words) */ - pad = ALIGN(skb->len, WL1271_TX_ALIGN_TO); - desc->length = cpu_to_le16(pad >> 2); + aligned_len = wl12xx_calc_packet_alignment(wl, skb->len); - /* calculate number of padding bytes */ - pad = pad - skb->len; - tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; + 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); + } desc->tx_attr = cpu_to_le16(tx_attr); - - wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " - "tx_attr: 0x%x len: %d life: %d mem: %d", pad, desc->hlid, - le16_to_cpu(desc->tx_attr), le16_to_cpu(desc->length), - le16_to_cpu(desc->life_time), desc->total_mem_blocks); } /* caller must hold wl->mutex */ @@ -300,19 +386,29 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, if (wl->bss_type == BSS_TYPE_AP_BSS) { wl1271_tx_ap_update_inconnection_sta(wl, skb); wl1271_tx_regulate_link(wl, hlid); + } else { + wl1271_tx_update_filters(wl, skb); } wl1271_tx_fill_hdr(wl, skb, extra, info, 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 + * 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 = ALIGN(skb->len, WL1271_TX_ALIGN_TO); + 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 (wl12xx_is_dummy_packet(wl, skb)) + skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); + return total_len; } @@ -425,10 +521,23 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) { - if (wl->bss_type == BSS_TYPE_AP_BSS) - return wl1271_ap_skb_dequeue(wl); + unsigned long flags; + struct sk_buff *skb = NULL; - return wl1271_sta_skb_dequeue(wl); + if (wl->bss_type == BSS_TYPE_AP_BSS) + skb = wl1271_ap_skb_dequeue(wl); + else + skb = wl1271_sta_skb_dequeue(wl); + + if (!skb && + test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { + skb = wl->dummy_packet; + spin_lock_irqsave(&wl->wl_lock, flags); + wl->tx_queue_count--; + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + + return skb; } static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) @@ -436,7 +545,9 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) unsigned long flags; int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - if (wl->bss_type == BSS_TYPE_AP_BSS) { + if (wl12xx_is_dummy_packet(wl, skb)) { + set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); + } else if (wl->bss_type == BSS_TYPE_AP_BSS) { u8 hlid = wl1271_tx_get_hlid(skb); skb_queue_head(&wl->links[hlid].tx_queue[q], skb); @@ -454,22 +565,14 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) void wl1271_tx_work_locked(struct wl1271 *wl) { struct sk_buff *skb; - bool woken_up = false; u32 buf_offset = 0; bool sent_packets = false; int ret; if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; + return; while ((skb = wl1271_skb_dequeue(wl))) { - if (!woken_up) { - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out_ack; - woken_up = true; - } - ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); if (ret == -EAGAIN) { /* @@ -516,18 +619,22 @@ void wl1271_tx_work_locked(struct wl1271 *wl) wl1271_handle_tx_low_watermark(wl); } - -out: - if (woken_up) - wl1271_ps_elp_sleep(wl); } 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); } @@ -549,6 +656,11 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, skb = wl->tx_frames[id]; info = IEEE80211_SKB_CB(skb); + if (wl12xx_is_dummy_packet(wl, skb)) { + wl1271_free_tx_id(wl, id); + return; + } + /* update the TX status info */ if (result->status == TX_SUCCESS) { if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) @@ -657,8 +769,8 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) wl1271_handle_tx_low_watermark(wl); } -/* caller must hold wl->mutex */ -void wl1271_tx_reset(struct wl1271 *wl) +/* caller must hold wl->mutex and TX must be stopped */ +void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) { int i; struct sk_buff *skb; @@ -678,10 +790,13 @@ void wl1271_tx_reset(struct wl1271 *wl) while ((skb = skb_dequeue(&wl->tx_queue[i]))) { wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); - info = IEEE80211_SKB_CB(skb); - info->status.rates[0].idx = -1; - info->status.rates[0].count = 0; - ieee80211_tx_status(wl->hw, 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(wl->hw, skb); + } } } } @@ -691,8 +806,10 @@ void wl1271_tx_reset(struct wl1271 *wl) /* * 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. */ - wl1271_handle_tx_low_watermark(wl); + if (reset_tx_queues) + wl1271_handle_tx_low_watermark(wl); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) { if (wl->tx_frames[i] == NULL) @@ -702,21 +819,27 @@ void wl1271_tx_reset(struct wl1271 *wl) wl1271_free_tx_id(wl, i); wl1271_debug(DEBUG_TX, "freeing skb 0x%p", 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_TKIP_IV_SPACE, skb->data, - hdrlen); - skb_pull(skb, WL1271_TKIP_IV_SPACE); + 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_TKIP_IV_SPACE, + skb->data, hdrlen); + skb_pull(skb, WL1271_TKIP_IV_SPACE); + } + + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; + + ieee80211_tx_status(wl->hw, skb); } - - info->status.rates[0].idx = -1; - info->status.rates[0].count = 0; - - ieee80211_tx_status(wl->hw, skb); } } diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 02f07fa66e82..832f9258d675 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -25,7 +25,6 @@ #ifndef __TX_H__ #define __TX_H__ -#define TX_HW_BLOCK_SPARE 2 #define TX_HW_BLOCK_SIZE 252 #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 @@ -41,6 +40,7 @@ BIT(8) | BIT(9)) #define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) #define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) +#define TX_HW_ATTR_TX_DUMMY_REQ BIT(13) #define TX_HW_ATTR_OFST_SAVE_RETRIES 0 #define TX_HW_ATTR_OFST_HEADER_PAD 1 @@ -55,20 +55,60 @@ #define WL1271_TX_ALIGN_TO 4 #define WL1271_TKIP_IV_SPACE 4 +/* Used for management frames and dummy packets */ +#define WL1271_TID_MGMT 7 + +struct wl127x_tx_mem { + /* + * Number of extra memory blocks to allocate for this packet + * in addition to the number of blocks derived from the packet + * length. + */ + u8 extra_blocks; + /* + * Total number of memory blocks allocated by the host for + * this packet. Must be equal or greater than the actual + * blocks number allocated by HW. + */ + u8 total_mem_blocks; +} __packed; + +struct wl128x_tx_mem { + /* + * Total number of memory blocks allocated by the host for + * this packet. + */ + u8 total_mem_blocks; + /* + * Number of extra bytes, at the end of the frame. the host + * uses this padding to complete each frame to integer number + * of SDIO blocks. + */ + u8 extra_bytes; +} __packed; + +/* + * On wl128x based devices, when TX packets are aggregated, each packet + * size must be aligned to the SDIO block size. The maximum block size + * is bounded by the type of the padded bytes field that is sent to the + * FW. Currently the type is u8, so the maximum block size is 256 bytes. + */ +#define WL12XX_BUS_BLOCK_SIZE min(512u, \ + (1u << (8 * sizeof(((struct wl128x_tx_mem *) 0)->extra_bytes)))) + struct wl1271_tx_hw_descr { /* Length of packet in words, including descriptor+header+data */ __le16 length; - /* Number of extra memory blocks to allocate for this packet in - addition to the number of blocks derived from the packet length */ - u8 extra_mem_blocks; - /* Total number of memory blocks allocated by the host for this packet. - Must be equal or greater than the actual blocks number allocated by - HW!! */ - u8 total_mem_blocks; + union { + struct wl127x_tx_mem wl127x_mem; + struct wl128x_tx_mem wl128x_mem; + } __packed; /* Device time (in us) when the packet arrived to the driver */ __le32 start_time; - /* Max delay in TUs until transmission. The last device time the - packet can be transmitted is: startTime+(1024*LifeTime) */ + /* + * Max delay in TUs until transmission. The last device time the + * packet can be transmitted is: start_time + (1024 * life_time) + */ __le16 life_time; /* Bitwise fields - see TX_ATTR... definitions above. */ __le16 tx_attr; @@ -145,7 +185,7 @@ static inline int wl1271_tx_get_queue(int queue) void wl1271_tx_work(struct work_struct *work); void wl1271_tx_work_locked(struct wl1271 *wl); void wl1271_tx_complete(struct wl1271 *wl); -void wl1271_tx_reset(struct wl1271 *wl); +void wl1271_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); u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 86be83e25ec5..fbe8f46d1232 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -131,9 +131,16 @@ extern u32 wl12xx_debug_level; #define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin" -#define WL1271_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin" +#define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin" +#define WL127X_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin" +#define WL128X_AP_FW_NAME "ti-connectivity/wl128x-fw-ap.bin" -#define WL1271_NVS_NAME "ti-connectivity/wl1271-nvs.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)) @@ -200,13 +207,29 @@ struct wl1271_partition_set { struct wl1271; -#define WL12XX_NUM_FW_VER 5 +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 -/* FIXME: I'm not sure about this structure name */ struct wl1271_chip { u32 id; char fw_ver_str[ETHTOOL_BUSINFO_LEN]; - unsigned int fw_ver[WL12XX_NUM_FW_VER]; + unsigned int fw_ver[NUM_FW_VER]; }; struct wl1271_stats { @@ -261,6 +284,8 @@ struct wl1271_fw_sta_status { u8 tx_total; u8 reserved1; __le16 reserved2; + /* Total structure size is 68 bytes */ + u32 padding; } __packed; struct wl1271_fw_full_status { @@ -277,9 +302,10 @@ struct wl1271_rx_mem_pool_addr { u32 addr_extra; }; +#define WL1271_MAX_CHANNELS 64 struct wl1271_scan { struct cfg80211_scan_request *req; - bool *scanned_ch; + unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)]; bool failed; u8 state; u8 ssid[IW_ESSID_MAX_SIZE+1]; @@ -297,6 +323,7 @@ struct wl1271_if_operations { struct device* (*dev)(struct wl1271 *wl); void (*enable_irq)(struct wl1271 *wl); void (*disable_irq)(struct wl1271 *wl); + void (*set_block_size) (struct wl1271 *wl, unsigned int blksz); }; #define MAX_NUM_KEYS 14 @@ -319,15 +346,19 @@ enum wl12xx_flags { WL1271_FLAG_TX_QUEUE_STOPPED, WL1271_FLAG_TX_PENDING, WL1271_FLAG_IN_ELP, + WL1271_FLAG_ELP_REQUESTED, WL1271_FLAG_PSM, WL1271_FLAG_PSM_REQUESTED, WL1271_FLAG_IRQ_RUNNING, WL1271_FLAG_IDLE, - WL1271_FLAG_IDLE_REQUESTED, WL1271_FLAG_PSPOLL_FAILURE, WL1271_FLAG_STA_STATE_SENT, WL1271_FLAG_FW_TX_BUSY, - WL1271_FLAG_AP_STARTED + WL1271_FLAG_AP_STARTED, + WL1271_FLAG_IF_INITIALIZED, + WL1271_FLAG_DUMMY_PACKET_PENDING, + WL1271_FLAG_SUSPENDED, + WL1271_FLAG_PENDING_WORK, }; struct wl1271_link { @@ -371,7 +402,7 @@ struct wl1271 { u8 *fw; size_t fw_len; u8 fw_bss_type; - struct wl1271_nvs_file *nvs; + void *nvs; size_t nvs_len; s8 hw_pg_ver; @@ -389,6 +420,7 @@ struct wl1271 { /* Accounting for allocated / available TX blocks on HW */ u32 tx_blocks_freed[NUM_TX_QUEUES]; u32 tx_blocks_available; + u32 tx_allocated_blocks; u32 tx_results_count; /* Transmitted TX packets counter for chipset interface */ @@ -430,6 +462,9 @@ struct wl1271 { /* 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; @@ -446,6 +481,8 @@ struct wl1271 { struct wl1271_scan scan; struct delayed_work scan_complete_work; + bool sched_scanning; + /* probe-req template for the current AP */ struct sk_buff *probereq; @@ -476,6 +513,7 @@ struct wl1271 { unsigned int rx_filter; struct completion *elp_compl; + struct completion *ps_compl; struct delayed_work elp_work; struct delayed_work pspoll_work; @@ -527,6 +565,14 @@ struct wl1271 { bool ba_support; u8 ba_rx_bitmap; + int tcxo_clock; + + /* + * wowlan trigger was configured during suspend. + * (currently, only "ANY" trigger is supported) + */ + bool wow_enabled; + /* * AP-mode - links indexed by HLID. The global and broadcast links * are always active. @@ -544,6 +590,9 @@ struct wl1271 { /* Quirks of specific hardware revisions */ unsigned int quirks; + + /* Platform limitations */ + unsigned int platform_quirks; }; struct wl1271_station { @@ -576,6 +625,15 @@ int wl1271_plt_stop(struct wl1271 *wl); /* Quirks */ /* Each RX/TX transaction requires an end-of-transaction transfer */ -#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) +#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) + +/* + * Older firmwares use 2 spare TX blocks + * (for STA < 6.1.3.50.58 or for AP < 6.2.0.0.47) + */ +#define WL12XX_QUIRK_USE_2_SPARE_BLOCKS BIT(1) + +/* WL128X requires aggregated packets to be aligned to the SDIO block size */ +#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2) #endif diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index a73a305d3cba..ff306d763e37 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -557,7 +557,7 @@ int zd_chip_unlock_phy_regs(struct zd_chip *chip) return r; } -/* CR157 can be optionally patched by the EEPROM for original ZD1211 */ +/* ZD_CR157 can be optionally patched by the EEPROM for original ZD1211 */ static int patch_cr157(struct zd_chip *chip) { int r; @@ -571,7 +571,7 @@ static int patch_cr157(struct zd_chip *chip) return r; dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8); - return zd_iowrite32_locked(chip, value >> 8, CR157); + return zd_iowrite32_locked(chip, value >> 8, ZD_CR157); } /* @@ -593,8 +593,8 @@ static int patch_6m_band_edge(struct zd_chip *chip, u8 channel) int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) { struct zd_ioreq16 ioreqs[] = { - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR47, 0x1e }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR47, 0x1e }, }; /* FIXME: Channel 11 is not the edge for all regulatory domains. */ @@ -608,69 +608,69 @@ int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) static int zd1211_hw_reset_phy(struct zd_chip *chip) { static const struct zd_ioreq16 ioreqs[] = { - { CR0, 0x0a }, { CR1, 0x06 }, { CR2, 0x26 }, - { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xa0 }, - { CR10, 0x81 }, { CR11, 0x00 }, { CR12, 0x7f }, - { CR13, 0x8c }, { CR14, 0x80 }, { CR15, 0x3d }, - { CR16, 0x20 }, { CR17, 0x1e }, { CR18, 0x0a }, - { CR19, 0x48 }, { CR20, 0x0c }, { CR21, 0x0c }, - { CR22, 0x23 }, { CR23, 0x90 }, { CR24, 0x14 }, - { CR25, 0x40 }, { CR26, 0x10 }, { CR27, 0x19 }, - { CR28, 0x7f }, { CR29, 0x80 }, { CR30, 0x4b }, - { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, - { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, - { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, - { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 }, - { CR43, 0x10 }, { CR44, 0x12 }, { CR46, 0xff }, - { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b }, - { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 }, - { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 }, - { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff }, - { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 }, - { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 }, - { CR79, 0x68 }, { CR80, 0x64 }, { CR81, 0x64 }, - { CR82, 0x00 }, { CR83, 0x00 }, { CR84, 0x00 }, - { CR85, 0x02 }, { CR86, 0x00 }, { CR87, 0x00 }, - { CR88, 0xff }, { CR89, 0xfc }, { CR90, 0x00 }, - { CR91, 0x00 }, { CR92, 0x00 }, { CR93, 0x08 }, - { CR94, 0x00 }, { CR95, 0x00 }, { CR96, 0xff }, - { CR97, 0xe7 }, { CR98, 0x00 }, { CR99, 0x00 }, - { CR100, 0x00 }, { CR101, 0xae }, { CR102, 0x02 }, - { CR103, 0x00 }, { CR104, 0x03 }, { CR105, 0x65 }, - { CR106, 0x04 }, { CR107, 0x00 }, { CR108, 0x0a }, - { CR109, 0xaa }, { CR110, 0xaa }, { CR111, 0x25 }, - { CR112, 0x25 }, { CR113, 0x00 }, { CR119, 0x1e }, - { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 }, + { ZD_CR0, 0x0a }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, + { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xa0 }, + { ZD_CR10, 0x81 }, { ZD_CR11, 0x00 }, { ZD_CR12, 0x7f }, + { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, { ZD_CR15, 0x3d }, + { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, { ZD_CR18, 0x0a }, + { ZD_CR19, 0x48 }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0c }, + { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, { ZD_CR24, 0x14 }, + { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, { ZD_CR27, 0x19 }, + { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, { ZD_CR30, 0x4b }, + { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, + { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, + { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, + { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, + { ZD_CR43, 0x10 }, { ZD_CR44, 0x12 }, { ZD_CR46, 0xff }, + { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, + { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, + { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, + { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, + { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, + { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, + { ZD_CR79, 0x68 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, + { ZD_CR82, 0x00 }, { ZD_CR83, 0x00 }, { ZD_CR84, 0x00 }, + { ZD_CR85, 0x02 }, { ZD_CR86, 0x00 }, { ZD_CR87, 0x00 }, + { ZD_CR88, 0xff }, { ZD_CR89, 0xfc }, { ZD_CR90, 0x00 }, + { ZD_CR91, 0x00 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x08 }, + { ZD_CR94, 0x00 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0xff }, + { ZD_CR97, 0xe7 }, { ZD_CR98, 0x00 }, { ZD_CR99, 0x00 }, + { ZD_CR100, 0x00 }, { ZD_CR101, 0xae }, { ZD_CR102, 0x02 }, + { ZD_CR103, 0x00 }, { ZD_CR104, 0x03 }, { ZD_CR105, 0x65 }, + { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, { ZD_CR108, 0x0a }, + { ZD_CR109, 0xaa }, { ZD_CR110, 0xaa }, { ZD_CR111, 0x25 }, + { ZD_CR112, 0x25 }, { ZD_CR113, 0x00 }, { ZD_CR119, 0x1e }, + { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, { }, - { CR5, 0x00 }, { CR6, 0x00 }, { CR7, 0x00 }, - { CR8, 0x00 }, { CR9, 0x20 }, { CR12, 0xf0 }, - { CR20, 0x0e }, { CR21, 0x0e }, { CR27, 0x10 }, - { CR44, 0x33 }, { CR47, 0x1E }, { CR83, 0x24 }, - { CR84, 0x04 }, { CR85, 0x00 }, { CR86, 0x0C }, - { CR87, 0x12 }, { CR88, 0x0C }, { CR89, 0x00 }, - { CR90, 0x10 }, { CR91, 0x08 }, { CR93, 0x00 }, - { CR94, 0x01 }, { CR95, 0x00 }, { CR96, 0x50 }, - { CR97, 0x37 }, { CR98, 0x35 }, { CR101, 0x13 }, - { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 }, - { CR105, 0x12 }, { CR109, 0x27 }, { CR110, 0x27 }, - { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, - { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, - { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f }, - { CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 }, - { CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C }, - { CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 }, - { CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 }, - { CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c }, - { CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 }, - { CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe }, - { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, - { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, - { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, - { CR170, 0xba }, { CR171, 0xba }, - /* Note: CR204 must lead the CR203 */ - { CR204, 0x7d }, + { ZD_CR5, 0x00 }, { ZD_CR6, 0x00 }, { ZD_CR7, 0x00 }, + { ZD_CR8, 0x00 }, { ZD_CR9, 0x20 }, { ZD_CR12, 0xf0 }, + { ZD_CR20, 0x0e }, { ZD_CR21, 0x0e }, { ZD_CR27, 0x10 }, + { ZD_CR44, 0x33 }, { ZD_CR47, 0x1E }, { ZD_CR83, 0x24 }, + { ZD_CR84, 0x04 }, { ZD_CR85, 0x00 }, { ZD_CR86, 0x0C }, + { ZD_CR87, 0x12 }, { ZD_CR88, 0x0C }, { ZD_CR89, 0x00 }, + { ZD_CR90, 0x10 }, { ZD_CR91, 0x08 }, { ZD_CR93, 0x00 }, + { ZD_CR94, 0x01 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0x50 }, + { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, { ZD_CR101, 0x13 }, + { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, + { ZD_CR105, 0x12 }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, + { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, + { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR120, 0x4f }, + { ZD_CR125, 0xaa }, { ZD_CR127, 0x03 }, { ZD_CR128, 0x14 }, + { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, { ZD_CR131, 0x0C }, + { ZD_CR136, 0xdf }, { ZD_CR137, 0x40 }, { ZD_CR138, 0xa0 }, + { ZD_CR139, 0xb0 }, { ZD_CR140, 0x99 }, { ZD_CR141, 0x82 }, + { ZD_CR142, 0x54 }, { ZD_CR143, 0x1c }, { ZD_CR144, 0x6c }, + { ZD_CR147, 0x07 }, { ZD_CR148, 0x4c }, { ZD_CR149, 0x50 }, + { ZD_CR150, 0x0e }, { ZD_CR151, 0x18 }, { ZD_CR160, 0xfe }, + { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, + { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, + { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, + { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, + /* Note: ZD_CR204 must lead the ZD_CR203 */ + { ZD_CR204, 0x7d }, { }, - { CR203, 0x30 }, + { ZD_CR203, 0x30 }, }; int r, t; @@ -697,62 +697,62 @@ static int zd1211_hw_reset_phy(struct zd_chip *chip) static int zd1211b_hw_reset_phy(struct zd_chip *chip) { static const struct zd_ioreq16 ioreqs[] = { - { CR0, 0x14 }, { CR1, 0x06 }, { CR2, 0x26 }, - { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xe0 }, - { CR10, 0x81 }, - /* power control { { CR11, 1 << 6 }, */ - { CR11, 0x00 }, - { CR12, 0xf0 }, { CR13, 0x8c }, { CR14, 0x80 }, - { CR15, 0x3d }, { CR16, 0x20 }, { CR17, 0x1e }, - { CR18, 0x0a }, { CR19, 0x48 }, - { CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ - { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 }, - { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 }, - { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 }, - { CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ - { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, - { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, - { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, - { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 }, - { CR43, 0x10 }, { CR44, 0x33 }, { CR46, 0xff }, - { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b }, - { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 }, - { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 }, - { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff }, - { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 }, - { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 }, - { CR79, 0xf0 }, { CR80, 0x64 }, { CR81, 0x64 }, - { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 }, - { CR85, 0x00 }, { CR86, 0x0c }, { CR87, 0x12 }, - { CR88, 0x0c }, { CR89, 0x00 }, { CR90, 0x58 }, - { CR91, 0x04 }, { CR92, 0x00 }, { CR93, 0x00 }, - { CR94, 0x01 }, - { CR95, 0x20 }, /* ZD1211B */ - { CR96, 0x50 }, { CR97, 0x37 }, { CR98, 0x35 }, - { CR99, 0x00 }, { CR100, 0x01 }, { CR101, 0x13 }, - { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 }, - { CR105, 0x12 }, { CR106, 0x04 }, { CR107, 0x00 }, - { CR108, 0x0a }, { CR109, 0x27 }, { CR110, 0x27 }, - { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, - { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, - { CR117, 0xfc }, { CR118, 0xfa }, { CR119, 0x1e }, - { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 }, - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR131, 0x0c }, { CR136, 0xdf }, { CR137, 0xa0 }, - { CR138, 0xa8 }, { CR139, 0xb4 }, { CR140, 0x98 }, - { CR141, 0x82 }, { CR142, 0x53 }, { CR143, 0x1c }, - { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x40 }, - { CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ - { CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ - { CR151, 0x18 }, { CR159, 0x70 }, { CR160, 0xfe }, - { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, - { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, - { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, - { CR170, 0xba }, { CR171, 0xba }, - /* Note: CR204 must lead the CR203 */ - { CR204, 0x7d }, + { ZD_CR0, 0x14 }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, + { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xe0 }, + { ZD_CR10, 0x81 }, + /* power control { { ZD_CR11, 1 << 6 }, */ + { ZD_CR11, 0x00 }, + { ZD_CR12, 0xf0 }, { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, + { ZD_CR15, 0x3d }, { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, + { ZD_CR18, 0x0a }, { ZD_CR19, 0x48 }, + { ZD_CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ + { ZD_CR21, 0x0e }, { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, + { ZD_CR24, 0x14 }, { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, + { ZD_CR27, 0x10 }, { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, + { ZD_CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ + { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, + { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, + { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, + { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, + { ZD_CR43, 0x10 }, { ZD_CR44, 0x33 }, { ZD_CR46, 0xff }, + { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, + { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, + { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, + { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, + { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, + { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, + { ZD_CR79, 0xf0 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, + { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, + { ZD_CR85, 0x00 }, { ZD_CR86, 0x0c }, { ZD_CR87, 0x12 }, + { ZD_CR88, 0x0c }, { ZD_CR89, 0x00 }, { ZD_CR90, 0x58 }, + { ZD_CR91, 0x04 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x00 }, + { ZD_CR94, 0x01 }, + { ZD_CR95, 0x20 }, /* ZD1211B */ + { ZD_CR96, 0x50 }, { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, + { ZD_CR99, 0x00 }, { ZD_CR100, 0x01 }, { ZD_CR101, 0x13 }, + { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, + { ZD_CR105, 0x12 }, { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, + { ZD_CR108, 0x0a }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, + { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, + { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x1e }, + { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR131, 0x0c }, { ZD_CR136, 0xdf }, { ZD_CR137, 0xa0 }, + { ZD_CR138, 0xa8 }, { ZD_CR139, 0xb4 }, { ZD_CR140, 0x98 }, + { ZD_CR141, 0x82 }, { ZD_CR142, 0x53 }, { ZD_CR143, 0x1c }, + { ZD_CR144, 0x6c }, { ZD_CR147, 0x07 }, { ZD_CR148, 0x40 }, + { ZD_CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ + { ZD_CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ + { ZD_CR151, 0x18 }, { ZD_CR159, 0x70 }, { ZD_CR160, 0xfe }, + { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, + { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, + { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, + { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, + /* Note: ZD_CR204 must lead the ZD_CR203 */ + { ZD_CR204, 0x7d }, {}, - { CR203, 0x30 }, + { ZD_CR203, 0x30 }, }; int r, t; @@ -1200,24 +1200,24 @@ int zd_chip_init_hw(struct zd_chip *chip) static int update_pwr_int(struct zd_chip *chip, u8 channel) { u8 value = chip->pwr_int_values[channel - 1]; - return zd_iowrite16_locked(chip, value, CR31); + return zd_iowrite16_locked(chip, value, ZD_CR31); } static int update_pwr_cal(struct zd_chip *chip, u8 channel) { u8 value = chip->pwr_cal_values[channel-1]; - return zd_iowrite16_locked(chip, value, CR68); + return zd_iowrite16_locked(chip, value, ZD_CR68); } static int update_ofdm_cal(struct zd_chip *chip, u8 channel) { struct zd_ioreq16 ioreqs[3]; - ioreqs[0].addr = CR67; + ioreqs[0].addr = ZD_CR67; ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1]; - ioreqs[1].addr = CR66; + ioreqs[1].addr = ZD_CR66; ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1]; - ioreqs[2].addr = CR65; + ioreqs[2].addr = ZD_CR65; ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1]; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -1236,9 +1236,9 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip, return r; if (zd_chip_is_zd1211b(chip)) { static const struct zd_ioreq16 ioreqs[] = { - { CR69, 0x28 }, + { ZD_CR69, 0x28 }, {}, - { CR69, 0x2a }, + { ZD_CR69, 0x2a }, }; r = update_ofdm_cal(chip, channel); @@ -1269,7 +1269,7 @@ static int patch_cck_gain(struct zd_chip *chip) if (r) return r; dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff); - return zd_iowrite16_locked(chip, value & 0xff, CR47); + return zd_iowrite16_locked(chip, value & 0xff, ZD_CR47); } int zd_chip_set_channel(struct zd_chip *chip, u8 channel) @@ -1505,9 +1505,9 @@ int zd_rfwritev_locked(struct zd_chip *chip, int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value) { const struct zd_ioreq16 ioreqs[] = { - { CR244, (value >> 16) & 0xff }, - { CR243, (value >> 8) & 0xff }, - { CR242, value & 0xff }, + { ZD_CR244, (value >> 16) & 0xff }, + { ZD_CR243, (value >> 8) & 0xff }, + { ZD_CR242, value & 0xff }, }; ZD_ASSERT(mutex_is_locked(&chip->mutex)); return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 14e4402a6111..4be7c3b5b265 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -61,277 +61,288 @@ enum { #define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset))) /* 8-bit hardware registers */ -#define CR0 CTL_REG(0x0000) -#define CR1 CTL_REG(0x0004) -#define CR2 CTL_REG(0x0008) -#define CR3 CTL_REG(0x000C) +#define ZD_CR0 CTL_REG(0x0000) +#define ZD_CR1 CTL_REG(0x0004) +#define ZD_CR2 CTL_REG(0x0008) +#define ZD_CR3 CTL_REG(0x000C) -#define CR5 CTL_REG(0x0010) +#define ZD_CR5 CTL_REG(0x0010) /* bit 5: if set short preamble used * bit 6: filter band - Japan channel 14 on, else off */ -#define CR6 CTL_REG(0x0014) -#define CR7 CTL_REG(0x0018) -#define CR8 CTL_REG(0x001C) +#define ZD_CR6 CTL_REG(0x0014) +#define ZD_CR7 CTL_REG(0x0018) +#define ZD_CR8 CTL_REG(0x001C) -#define CR4 CTL_REG(0x0020) +#define ZD_CR4 CTL_REG(0x0020) -#define CR9 CTL_REG(0x0024) -/* bit 2: antenna switch (together with CR10) */ -#define CR10 CTL_REG(0x0028) -/* bit 1: antenna switch (together with CR9) - * RF2959 controls with CR11 radion on and off +#define ZD_CR9 CTL_REG(0x0024) +/* bit 2: antenna switch (together with ZD_CR10) */ +#define ZD_CR10 CTL_REG(0x0028) +/* bit 1: antenna switch (together with ZD_CR9) + * RF2959 controls with ZD_CR11 radion on and off */ -#define CR11 CTL_REG(0x002C) +#define ZD_CR11 CTL_REG(0x002C) /* bit 6: TX power control for OFDM - * RF2959 controls with CR10 radio on and off + * RF2959 controls with ZD_CR10 radio on and off */ -#define CR12 CTL_REG(0x0030) -#define CR13 CTL_REG(0x0034) -#define CR14 CTL_REG(0x0038) -#define CR15 CTL_REG(0x003C) -#define CR16 CTL_REG(0x0040) -#define CR17 CTL_REG(0x0044) -#define CR18 CTL_REG(0x0048) -#define CR19 CTL_REG(0x004C) -#define CR20 CTL_REG(0x0050) -#define CR21 CTL_REG(0x0054) -#define CR22 CTL_REG(0x0058) -#define CR23 CTL_REG(0x005C) -#define CR24 CTL_REG(0x0060) /* CCA threshold */ -#define CR25 CTL_REG(0x0064) -#define CR26 CTL_REG(0x0068) -#define CR27 CTL_REG(0x006C) -#define CR28 CTL_REG(0x0070) -#define CR29 CTL_REG(0x0074) -#define CR30 CTL_REG(0x0078) -#define CR31 CTL_REG(0x007C) /* TX power control for RF in CCK mode */ -#define CR32 CTL_REG(0x0080) -#define CR33 CTL_REG(0x0084) -#define CR34 CTL_REG(0x0088) -#define CR35 CTL_REG(0x008C) -#define CR36 CTL_REG(0x0090) -#define CR37 CTL_REG(0x0094) -#define CR38 CTL_REG(0x0098) -#define CR39 CTL_REG(0x009C) -#define CR40 CTL_REG(0x00A0) -#define CR41 CTL_REG(0x00A4) -#define CR42 CTL_REG(0x00A8) -#define CR43 CTL_REG(0x00AC) -#define CR44 CTL_REG(0x00B0) -#define CR45 CTL_REG(0x00B4) -#define CR46 CTL_REG(0x00B8) -#define CR47 CTL_REG(0x00BC) /* CCK baseband gain - * (patch value might be in EEPROM) - */ -#define CR48 CTL_REG(0x00C0) -#define CR49 CTL_REG(0x00C4) -#define CR50 CTL_REG(0x00C8) -#define CR51 CTL_REG(0x00CC) /* TX power control for RF in 6-36M modes */ -#define CR52 CTL_REG(0x00D0) /* TX power control for RF in 48M mode */ -#define CR53 CTL_REG(0x00D4) /* TX power control for RF in 54M mode */ -#define CR54 CTL_REG(0x00D8) -#define CR55 CTL_REG(0x00DC) -#define CR56 CTL_REG(0x00E0) -#define CR57 CTL_REG(0x00E4) -#define CR58 CTL_REG(0x00E8) -#define CR59 CTL_REG(0x00EC) -#define CR60 CTL_REG(0x00F0) -#define CR61 CTL_REG(0x00F4) -#define CR62 CTL_REG(0x00F8) -#define CR63 CTL_REG(0x00FC) -#define CR64 CTL_REG(0x0100) -#define CR65 CTL_REG(0x0104) /* OFDM 54M calibration */ -#define CR66 CTL_REG(0x0108) /* OFDM 48M calibration */ -#define CR67 CTL_REG(0x010C) /* OFDM 36M calibration */ -#define CR68 CTL_REG(0x0110) /* CCK calibration */ -#define CR69 CTL_REG(0x0114) -#define CR70 CTL_REG(0x0118) -#define CR71 CTL_REG(0x011C) -#define CR72 CTL_REG(0x0120) -#define CR73 CTL_REG(0x0124) -#define CR74 CTL_REG(0x0128) -#define CR75 CTL_REG(0x012C) -#define CR76 CTL_REG(0x0130) -#define CR77 CTL_REG(0x0134) -#define CR78 CTL_REG(0x0138) -#define CR79 CTL_REG(0x013C) -#define CR80 CTL_REG(0x0140) -#define CR81 CTL_REG(0x0144) -#define CR82 CTL_REG(0x0148) -#define CR83 CTL_REG(0x014C) -#define CR84 CTL_REG(0x0150) -#define CR85 CTL_REG(0x0154) -#define CR86 CTL_REG(0x0158) -#define CR87 CTL_REG(0x015C) -#define CR88 CTL_REG(0x0160) -#define CR89 CTL_REG(0x0164) -#define CR90 CTL_REG(0x0168) -#define CR91 CTL_REG(0x016C) -#define CR92 CTL_REG(0x0170) -#define CR93 CTL_REG(0x0174) -#define CR94 CTL_REG(0x0178) -#define CR95 CTL_REG(0x017C) -#define CR96 CTL_REG(0x0180) -#define CR97 CTL_REG(0x0184) -#define CR98 CTL_REG(0x0188) -#define CR99 CTL_REG(0x018C) -#define CR100 CTL_REG(0x0190) -#define CR101 CTL_REG(0x0194) -#define CR102 CTL_REG(0x0198) -#define CR103 CTL_REG(0x019C) -#define CR104 CTL_REG(0x01A0) -#define CR105 CTL_REG(0x01A4) -#define CR106 CTL_REG(0x01A8) -#define CR107 CTL_REG(0x01AC) -#define CR108 CTL_REG(0x01B0) -#define CR109 CTL_REG(0x01B4) -#define CR110 CTL_REG(0x01B8) -#define CR111 CTL_REG(0x01BC) -#define CR112 CTL_REG(0x01C0) -#define CR113 CTL_REG(0x01C4) -#define CR114 CTL_REG(0x01C8) -#define CR115 CTL_REG(0x01CC) -#define CR116 CTL_REG(0x01D0) -#define CR117 CTL_REG(0x01D4) -#define CR118 CTL_REG(0x01D8) -#define CR119 CTL_REG(0x01DC) -#define CR120 CTL_REG(0x01E0) -#define CR121 CTL_REG(0x01E4) -#define CR122 CTL_REG(0x01E8) -#define CR123 CTL_REG(0x01EC) -#define CR124 CTL_REG(0x01F0) -#define CR125 CTL_REG(0x01F4) -#define CR126 CTL_REG(0x01F8) -#define CR127 CTL_REG(0x01FC) -#define CR128 CTL_REG(0x0200) -#define CR129 CTL_REG(0x0204) -#define CR130 CTL_REG(0x0208) -#define CR131 CTL_REG(0x020C) -#define CR132 CTL_REG(0x0210) -#define CR133 CTL_REG(0x0214) -#define CR134 CTL_REG(0x0218) -#define CR135 CTL_REG(0x021C) -#define CR136 CTL_REG(0x0220) -#define CR137 CTL_REG(0x0224) -#define CR138 CTL_REG(0x0228) -#define CR139 CTL_REG(0x022C) -#define CR140 CTL_REG(0x0230) -#define CR141 CTL_REG(0x0234) -#define CR142 CTL_REG(0x0238) -#define CR143 CTL_REG(0x023C) -#define CR144 CTL_REG(0x0240) -#define CR145 CTL_REG(0x0244) -#define CR146 CTL_REG(0x0248) -#define CR147 CTL_REG(0x024C) -#define CR148 CTL_REG(0x0250) -#define CR149 CTL_REG(0x0254) -#define CR150 CTL_REG(0x0258) -#define CR151 CTL_REG(0x025C) -#define CR152 CTL_REG(0x0260) -#define CR153 CTL_REG(0x0264) -#define CR154 CTL_REG(0x0268) -#define CR155 CTL_REG(0x026C) -#define CR156 CTL_REG(0x0270) -#define CR157 CTL_REG(0x0274) -#define CR158 CTL_REG(0x0278) -#define CR159 CTL_REG(0x027C) -#define CR160 CTL_REG(0x0280) -#define CR161 CTL_REG(0x0284) -#define CR162 CTL_REG(0x0288) -#define CR163 CTL_REG(0x028C) -#define CR164 CTL_REG(0x0290) -#define CR165 CTL_REG(0x0294) -#define CR166 CTL_REG(0x0298) -#define CR167 CTL_REG(0x029C) -#define CR168 CTL_REG(0x02A0) -#define CR169 CTL_REG(0x02A4) -#define CR170 CTL_REG(0x02A8) -#define CR171 CTL_REG(0x02AC) -#define CR172 CTL_REG(0x02B0) -#define CR173 CTL_REG(0x02B4) -#define CR174 CTL_REG(0x02B8) -#define CR175 CTL_REG(0x02BC) -#define CR176 CTL_REG(0x02C0) -#define CR177 CTL_REG(0x02C4) -#define CR178 CTL_REG(0x02C8) -#define CR179 CTL_REG(0x02CC) -#define CR180 CTL_REG(0x02D0) -#define CR181 CTL_REG(0x02D4) -#define CR182 CTL_REG(0x02D8) -#define CR183 CTL_REG(0x02DC) -#define CR184 CTL_REG(0x02E0) -#define CR185 CTL_REG(0x02E4) -#define CR186 CTL_REG(0x02E8) -#define CR187 CTL_REG(0x02EC) -#define CR188 CTL_REG(0x02F0) -#define CR189 CTL_REG(0x02F4) -#define CR190 CTL_REG(0x02F8) -#define CR191 CTL_REG(0x02FC) -#define CR192 CTL_REG(0x0300) -#define CR193 CTL_REG(0x0304) -#define CR194 CTL_REG(0x0308) -#define CR195 CTL_REG(0x030C) -#define CR196 CTL_REG(0x0310) -#define CR197 CTL_REG(0x0314) -#define CR198 CTL_REG(0x0318) -#define CR199 CTL_REG(0x031C) -#define CR200 CTL_REG(0x0320) -#define CR201 CTL_REG(0x0324) -#define CR202 CTL_REG(0x0328) -#define CR203 CTL_REG(0x032C) /* I2C bus template value & flash control */ -#define CR204 CTL_REG(0x0330) -#define CR205 CTL_REG(0x0334) -#define CR206 CTL_REG(0x0338) -#define CR207 CTL_REG(0x033C) -#define CR208 CTL_REG(0x0340) -#define CR209 CTL_REG(0x0344) -#define CR210 CTL_REG(0x0348) -#define CR211 CTL_REG(0x034C) -#define CR212 CTL_REG(0x0350) -#define CR213 CTL_REG(0x0354) -#define CR214 CTL_REG(0x0358) -#define CR215 CTL_REG(0x035C) -#define CR216 CTL_REG(0x0360) -#define CR217 CTL_REG(0x0364) -#define CR218 CTL_REG(0x0368) -#define CR219 CTL_REG(0x036C) -#define CR220 CTL_REG(0x0370) -#define CR221 CTL_REG(0x0374) -#define CR222 CTL_REG(0x0378) -#define CR223 CTL_REG(0x037C) -#define CR224 CTL_REG(0x0380) -#define CR225 CTL_REG(0x0384) -#define CR226 CTL_REG(0x0388) -#define CR227 CTL_REG(0x038C) -#define CR228 CTL_REG(0x0390) -#define CR229 CTL_REG(0x0394) -#define CR230 CTL_REG(0x0398) -#define CR231 CTL_REG(0x039C) -#define CR232 CTL_REG(0x03A0) -#define CR233 CTL_REG(0x03A4) -#define CR234 CTL_REG(0x03A8) -#define CR235 CTL_REG(0x03AC) -#define CR236 CTL_REG(0x03B0) +#define ZD_CR12 CTL_REG(0x0030) +#define ZD_CR13 CTL_REG(0x0034) +#define ZD_CR14 CTL_REG(0x0038) +#define ZD_CR15 CTL_REG(0x003C) +#define ZD_CR16 CTL_REG(0x0040) +#define ZD_CR17 CTL_REG(0x0044) +#define ZD_CR18 CTL_REG(0x0048) +#define ZD_CR19 CTL_REG(0x004C) +#define ZD_CR20 CTL_REG(0x0050) +#define ZD_CR21 CTL_REG(0x0054) +#define ZD_CR22 CTL_REG(0x0058) +#define ZD_CR23 CTL_REG(0x005C) +#define ZD_CR24 CTL_REG(0x0060) /* CCA threshold */ +#define ZD_CR25 CTL_REG(0x0064) +#define ZD_CR26 CTL_REG(0x0068) +#define ZD_CR27 CTL_REG(0x006C) +#define ZD_CR28 CTL_REG(0x0070) +#define ZD_CR29 CTL_REG(0x0074) +#define ZD_CR30 CTL_REG(0x0078) +#define ZD_CR31 CTL_REG(0x007C) /* TX power control for RF in + * CCK mode + */ +#define ZD_CR32 CTL_REG(0x0080) +#define ZD_CR33 CTL_REG(0x0084) +#define ZD_CR34 CTL_REG(0x0088) +#define ZD_CR35 CTL_REG(0x008C) +#define ZD_CR36 CTL_REG(0x0090) +#define ZD_CR37 CTL_REG(0x0094) +#define ZD_CR38 CTL_REG(0x0098) +#define ZD_CR39 CTL_REG(0x009C) +#define ZD_CR40 CTL_REG(0x00A0) +#define ZD_CR41 CTL_REG(0x00A4) +#define ZD_CR42 CTL_REG(0x00A8) +#define ZD_CR43 CTL_REG(0x00AC) +#define ZD_CR44 CTL_REG(0x00B0) +#define ZD_CR45 CTL_REG(0x00B4) +#define ZD_CR46 CTL_REG(0x00B8) +#define ZD_CR47 CTL_REG(0x00BC) /* CCK baseband gain + * (patch value might be in EEPROM) + */ +#define ZD_CR48 CTL_REG(0x00C0) +#define ZD_CR49 CTL_REG(0x00C4) +#define ZD_CR50 CTL_REG(0x00C8) +#define ZD_CR51 CTL_REG(0x00CC) /* TX power control for RF in + * 6-36M modes + */ +#define ZD_CR52 CTL_REG(0x00D0) /* TX power control for RF in + * 48M mode + */ +#define ZD_CR53 CTL_REG(0x00D4) /* TX power control for RF in + * 54M mode + */ +#define ZD_CR54 CTL_REG(0x00D8) +#define ZD_CR55 CTL_REG(0x00DC) +#define ZD_CR56 CTL_REG(0x00E0) +#define ZD_CR57 CTL_REG(0x00E4) +#define ZD_CR58 CTL_REG(0x00E8) +#define ZD_CR59 CTL_REG(0x00EC) +#define ZD_CR60 CTL_REG(0x00F0) +#define ZD_CR61 CTL_REG(0x00F4) +#define ZD_CR62 CTL_REG(0x00F8) +#define ZD_CR63 CTL_REG(0x00FC) +#define ZD_CR64 CTL_REG(0x0100) +#define ZD_CR65 CTL_REG(0x0104) /* OFDM 54M calibration */ +#define ZD_CR66 CTL_REG(0x0108) /* OFDM 48M calibration */ +#define ZD_CR67 CTL_REG(0x010C) /* OFDM 36M calibration */ +#define ZD_CR68 CTL_REG(0x0110) /* CCK calibration */ +#define ZD_CR69 CTL_REG(0x0114) +#define ZD_CR70 CTL_REG(0x0118) +#define ZD_CR71 CTL_REG(0x011C) +#define ZD_CR72 CTL_REG(0x0120) +#define ZD_CR73 CTL_REG(0x0124) +#define ZD_CR74 CTL_REG(0x0128) +#define ZD_CR75 CTL_REG(0x012C) +#define ZD_CR76 CTL_REG(0x0130) +#define ZD_CR77 CTL_REG(0x0134) +#define ZD_CR78 CTL_REG(0x0138) +#define ZD_CR79 CTL_REG(0x013C) +#define ZD_CR80 CTL_REG(0x0140) +#define ZD_CR81 CTL_REG(0x0144) +#define ZD_CR82 CTL_REG(0x0148) +#define ZD_CR83 CTL_REG(0x014C) +#define ZD_CR84 CTL_REG(0x0150) +#define ZD_CR85 CTL_REG(0x0154) +#define ZD_CR86 CTL_REG(0x0158) +#define ZD_CR87 CTL_REG(0x015C) +#define ZD_CR88 CTL_REG(0x0160) +#define ZD_CR89 CTL_REG(0x0164) +#define ZD_CR90 CTL_REG(0x0168) +#define ZD_CR91 CTL_REG(0x016C) +#define ZD_CR92 CTL_REG(0x0170) +#define ZD_CR93 CTL_REG(0x0174) +#define ZD_CR94 CTL_REG(0x0178) +#define ZD_CR95 CTL_REG(0x017C) +#define ZD_CR96 CTL_REG(0x0180) +#define ZD_CR97 CTL_REG(0x0184) +#define ZD_CR98 CTL_REG(0x0188) +#define ZD_CR99 CTL_REG(0x018C) +#define ZD_CR100 CTL_REG(0x0190) +#define ZD_CR101 CTL_REG(0x0194) +#define ZD_CR102 CTL_REG(0x0198) +#define ZD_CR103 CTL_REG(0x019C) +#define ZD_CR104 CTL_REG(0x01A0) +#define ZD_CR105 CTL_REG(0x01A4) +#define ZD_CR106 CTL_REG(0x01A8) +#define ZD_CR107 CTL_REG(0x01AC) +#define ZD_CR108 CTL_REG(0x01B0) +#define ZD_CR109 CTL_REG(0x01B4) +#define ZD_CR110 CTL_REG(0x01B8) +#define ZD_CR111 CTL_REG(0x01BC) +#define ZD_CR112 CTL_REG(0x01C0) +#define ZD_CR113 CTL_REG(0x01C4) +#define ZD_CR114 CTL_REG(0x01C8) +#define ZD_CR115 CTL_REG(0x01CC) +#define ZD_CR116 CTL_REG(0x01D0) +#define ZD_CR117 CTL_REG(0x01D4) +#define ZD_CR118 CTL_REG(0x01D8) +#define ZD_CR119 CTL_REG(0x01DC) +#define ZD_CR120 CTL_REG(0x01E0) +#define ZD_CR121 CTL_REG(0x01E4) +#define ZD_CR122 CTL_REG(0x01E8) +#define ZD_CR123 CTL_REG(0x01EC) +#define ZD_CR124 CTL_REG(0x01F0) +#define ZD_CR125 CTL_REG(0x01F4) +#define ZD_CR126 CTL_REG(0x01F8) +#define ZD_CR127 CTL_REG(0x01FC) +#define ZD_CR128 CTL_REG(0x0200) +#define ZD_CR129 CTL_REG(0x0204) +#define ZD_CR130 CTL_REG(0x0208) +#define ZD_CR131 CTL_REG(0x020C) +#define ZD_CR132 CTL_REG(0x0210) +#define ZD_CR133 CTL_REG(0x0214) +#define ZD_CR134 CTL_REG(0x0218) +#define ZD_CR135 CTL_REG(0x021C) +#define ZD_CR136 CTL_REG(0x0220) +#define ZD_CR137 CTL_REG(0x0224) +#define ZD_CR138 CTL_REG(0x0228) +#define ZD_CR139 CTL_REG(0x022C) +#define ZD_CR140 CTL_REG(0x0230) +#define ZD_CR141 CTL_REG(0x0234) +#define ZD_CR142 CTL_REG(0x0238) +#define ZD_CR143 CTL_REG(0x023C) +#define ZD_CR144 CTL_REG(0x0240) +#define ZD_CR145 CTL_REG(0x0244) +#define ZD_CR146 CTL_REG(0x0248) +#define ZD_CR147 CTL_REG(0x024C) +#define ZD_CR148 CTL_REG(0x0250) +#define ZD_CR149 CTL_REG(0x0254) +#define ZD_CR150 CTL_REG(0x0258) +#define ZD_CR151 CTL_REG(0x025C) +#define ZD_CR152 CTL_REG(0x0260) +#define ZD_CR153 CTL_REG(0x0264) +#define ZD_CR154 CTL_REG(0x0268) +#define ZD_CR155 CTL_REG(0x026C) +#define ZD_CR156 CTL_REG(0x0270) +#define ZD_CR157 CTL_REG(0x0274) +#define ZD_CR158 CTL_REG(0x0278) +#define ZD_CR159 CTL_REG(0x027C) +#define ZD_CR160 CTL_REG(0x0280) +#define ZD_CR161 CTL_REG(0x0284) +#define ZD_CR162 CTL_REG(0x0288) +#define ZD_CR163 CTL_REG(0x028C) +#define ZD_CR164 CTL_REG(0x0290) +#define ZD_CR165 CTL_REG(0x0294) +#define ZD_CR166 CTL_REG(0x0298) +#define ZD_CR167 CTL_REG(0x029C) +#define ZD_CR168 CTL_REG(0x02A0) +#define ZD_CR169 CTL_REG(0x02A4) +#define ZD_CR170 CTL_REG(0x02A8) +#define ZD_CR171 CTL_REG(0x02AC) +#define ZD_CR172 CTL_REG(0x02B0) +#define ZD_CR173 CTL_REG(0x02B4) +#define ZD_CR174 CTL_REG(0x02B8) +#define ZD_CR175 CTL_REG(0x02BC) +#define ZD_CR176 CTL_REG(0x02C0) +#define ZD_CR177 CTL_REG(0x02C4) +#define ZD_CR178 CTL_REG(0x02C8) +#define ZD_CR179 CTL_REG(0x02CC) +#define ZD_CR180 CTL_REG(0x02D0) +#define ZD_CR181 CTL_REG(0x02D4) +#define ZD_CR182 CTL_REG(0x02D8) +#define ZD_CR183 CTL_REG(0x02DC) +#define ZD_CR184 CTL_REG(0x02E0) +#define ZD_CR185 CTL_REG(0x02E4) +#define ZD_CR186 CTL_REG(0x02E8) +#define ZD_CR187 CTL_REG(0x02EC) +#define ZD_CR188 CTL_REG(0x02F0) +#define ZD_CR189 CTL_REG(0x02F4) +#define ZD_CR190 CTL_REG(0x02F8) +#define ZD_CR191 CTL_REG(0x02FC) +#define ZD_CR192 CTL_REG(0x0300) +#define ZD_CR193 CTL_REG(0x0304) +#define ZD_CR194 CTL_REG(0x0308) +#define ZD_CR195 CTL_REG(0x030C) +#define ZD_CR196 CTL_REG(0x0310) +#define ZD_CR197 CTL_REG(0x0314) +#define ZD_CR198 CTL_REG(0x0318) +#define ZD_CR199 CTL_REG(0x031C) +#define ZD_CR200 CTL_REG(0x0320) +#define ZD_CR201 CTL_REG(0x0324) +#define ZD_CR202 CTL_REG(0x0328) +#define ZD_CR203 CTL_REG(0x032C) /* I2C bus template value & flash + * control + */ +#define ZD_CR204 CTL_REG(0x0330) +#define ZD_CR205 CTL_REG(0x0334) +#define ZD_CR206 CTL_REG(0x0338) +#define ZD_CR207 CTL_REG(0x033C) +#define ZD_CR208 CTL_REG(0x0340) +#define ZD_CR209 CTL_REG(0x0344) +#define ZD_CR210 CTL_REG(0x0348) +#define ZD_CR211 CTL_REG(0x034C) +#define ZD_CR212 CTL_REG(0x0350) +#define ZD_CR213 CTL_REG(0x0354) +#define ZD_CR214 CTL_REG(0x0358) +#define ZD_CR215 CTL_REG(0x035C) +#define ZD_CR216 CTL_REG(0x0360) +#define ZD_CR217 CTL_REG(0x0364) +#define ZD_CR218 CTL_REG(0x0368) +#define ZD_CR219 CTL_REG(0x036C) +#define ZD_CR220 CTL_REG(0x0370) +#define ZD_CR221 CTL_REG(0x0374) +#define ZD_CR222 CTL_REG(0x0378) +#define ZD_CR223 CTL_REG(0x037C) +#define ZD_CR224 CTL_REG(0x0380) +#define ZD_CR225 CTL_REG(0x0384) +#define ZD_CR226 CTL_REG(0x0388) +#define ZD_CR227 CTL_REG(0x038C) +#define ZD_CR228 CTL_REG(0x0390) +#define ZD_CR229 CTL_REG(0x0394) +#define ZD_CR230 CTL_REG(0x0398) +#define ZD_CR231 CTL_REG(0x039C) +#define ZD_CR232 CTL_REG(0x03A0) +#define ZD_CR233 CTL_REG(0x03A4) +#define ZD_CR234 CTL_REG(0x03A8) +#define ZD_CR235 CTL_REG(0x03AC) +#define ZD_CR236 CTL_REG(0x03B0) -#define CR240 CTL_REG(0x03C0) -/* bit 7: host-controlled RF register writes - * CR241-CR245: for hardware controlled writing of RF bits, not needed for - * USB +#define ZD_CR240 CTL_REG(0x03C0) +/* bit 7: host-controlled RF register writes + * ZD_CR241-ZD_CR245: for hardware controlled writing of RF bits, not needed for + * USB */ -#define CR241 CTL_REG(0x03C4) -#define CR242 CTL_REG(0x03C8) -#define CR243 CTL_REG(0x03CC) -#define CR244 CTL_REG(0x03D0) -#define CR245 CTL_REG(0x03D4) +#define ZD_CR241 CTL_REG(0x03C4) +#define ZD_CR242 CTL_REG(0x03C8) +#define ZD_CR243 CTL_REG(0x03CC) +#define ZD_CR244 CTL_REG(0x03D0) +#define ZD_CR245 CTL_REG(0x03D4) -#define CR251 CTL_REG(0x03EC) /* only used for activation and deactivation of - * Airoha RFs AL2230 and AL7230B - */ -#define CR252 CTL_REG(0x03F0) -#define CR253 CTL_REG(0x03F4) -#define CR254 CTL_REG(0x03F8) -#define CR255 CTL_REG(0x03FC) +#define ZD_CR251 CTL_REG(0x03EC) /* only used for activation and + * deactivation of Airoha RFs AL2230 + * and AL7230B + */ +#define ZD_CR252 CTL_REG(0x03F0) +#define ZD_CR253 CTL_REG(0x03F4) +#define ZD_CR254 CTL_REG(0x03F8) +#define ZD_CR255 CTL_REG(0x03FC) #define CR_MAX_PHY_REG 255 diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h index 79dc1035592d..725b7c99b23d 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/drivers/net/wireless/zd1211rw/zd_rf.h @@ -55,7 +55,7 @@ struct zd_rf { * defaults to 1 (yes) */ u8 update_channel_int:1; - /* whether CR47 should be patched from the EEPROM, if the appropriate + /* whether ZD_CR47 should be patched from the EEPROM, if the appropriate * flag is set in the POD. The vendor driver suggests that this should * be done for all RF's, but a bug in their code prevents but their * HW_OverWritePhyRegFromE2P() routine from ever taking effect. */ diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c index 74a8f7a55591..12babcb633c3 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c @@ -61,31 +61,31 @@ static const u32 zd1211b_al2230_table[][3] = { }; static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = { - { CR240, 0x57 }, { CR9, 0xe0 }, + { ZD_CR240, 0x57 }, { ZD_CR9, 0xe0 }, }; static const struct zd_ioreq16 ioreqs_init_al2230s[] = { - { CR47, 0x1e }, /* MARK_002 */ - { CR106, 0x22 }, - { CR107, 0x2a }, /* MARK_002 */ - { CR109, 0x13 }, /* MARK_002 */ - { CR118, 0xf8 }, /* MARK_002 */ - { CR119, 0x12 }, { CR122, 0xe0 }, - { CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ - { CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ - { CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ + { ZD_CR47, 0x1e }, /* MARK_002 */ + { ZD_CR106, 0x22 }, + { ZD_CR107, 0x2a }, /* MARK_002 */ + { ZD_CR109, 0x13 }, /* MARK_002 */ + { ZD_CR118, 0xf8 }, /* MARK_002 */ + { ZD_CR119, 0x12 }, { ZD_CR122, 0xe0 }, + { ZD_CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ + { ZD_CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ + { ZD_CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ }; static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) { int r; static const struct zd_ioreq16 ioreqs[] = { - { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, - { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, - { CR203, 0x06 }, + { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, + { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, + { ZD_CR203, 0x06 }, { }, - { CR240, 0x80 }, + { ZD_CR240, 0x80 }, }; r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -94,12 +94,12 @@ static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) /* related to antenna selection? */ if (chip->new_phy_layout) { - r = zd_iowrite16_locked(chip, 0xe1, CR9); + r = zd_iowrite16_locked(chip, 0xe1, ZD_CR9); if (r) return r; } - return zd_iowrite16_locked(chip, 0x06, CR203); + return zd_iowrite16_locked(chip, 0x06, ZD_CR203); } static int zd1211_al2230_init_hw(struct zd_rf *rf) @@ -108,40 +108,40 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs_init[] = { - { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, - { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, - { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a }, - { CR109, 0x09 }, { CR110, 0x27 }, { CR111, 0x2b }, - { CR112, 0x2b }, { CR119, 0x0a }, { CR10, 0x89 }, + { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, + { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR44, 0x33 }, { ZD_CR106, 0x2a }, { ZD_CR107, 0x1a }, + { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, { ZD_CR111, 0x2b }, + { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, { ZD_CR10, 0x89 }, /* for newest (3rd cut) AL2300 */ - { CR17, 0x28 }, - { CR26, 0x93 }, { CR34, 0x30 }, + { ZD_CR17, 0x28 }, + { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 }, /* for newest (3rd cut) AL2300 */ - { CR35, 0x3e }, - { CR41, 0x24 }, { CR44, 0x32 }, + { ZD_CR35, 0x3e }, + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, /* for newest (3rd cut) AL2300 */ - { CR46, 0x96 }, - { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, - { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, - { CR92, 0x0a }, { CR99, 0x28 }, { CR100, 0x00 }, - { CR101, 0x13 }, { CR102, 0x27 }, { CR106, 0x24 }, - { CR107, 0x2a }, { CR109, 0x09 }, { CR110, 0x13 }, - { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x27 }, + { ZD_CR46, 0x96 }, + { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, + { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 }, + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR106, 0x24 }, + { ZD_CR107, 0x2a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x13 }, + { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, /* for newest (3rd cut) AL2300 */ - { CR115, 0x24 }, - { CR116, 0x24 }, { CR117, 0xf4 }, { CR118, 0xfc }, - { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 }, - { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff }, - { CR253, 0xff }, + { ZD_CR115, 0x24 }, + { ZD_CR116, 0x24 }, { ZD_CR117, 0xf4 }, { ZD_CR118, 0xfc }, + { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, { ZD_CR121, 0x77 }, + { ZD_CR122, 0xe0 }, { ZD_CR137, 0x88 }, { ZD_CR252, 0xff }, + { ZD_CR253, 0xff }, }; static const struct zd_ioreq16 ioreqs_pll[] = { /* shdnb(PLL_ON)=0 */ - { CR251, 0x2f }, + { ZD_CR251, 0x2f }, /* shdnb(PLL_ON)=1 */ - { CR251, 0x3f }, - { CR138, 0x28 }, { CR203, 0x06 }, + { ZD_CR251, 0x3f }, + { ZD_CR138, 0x28 }, { ZD_CR203, 0x06 }, }; static const u32 rv1[] = { @@ -161,7 +161,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) 0x0805b6, 0x011687, 0x000688, - 0x0403b9, /* external control TX power (CR31) */ + 0x0403b9, /* external control TX power (ZD_CR31) */ 0x00dbba, 0x00099b, 0x0bdffc, @@ -221,52 +221,54 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs1[] = { - { CR10, 0x89 }, { CR15, 0x20 }, - { CR17, 0x2B }, /* for newest(3rd cut) AL2230 */ - { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, - { CR28, 0x3e }, { CR29, 0x00 }, - { CR33, 0x28 }, /* 5621 */ - { CR34, 0x30 }, - { CR35, 0x3e }, /* for newest(3rd cut) AL2230 */ - { CR41, 0x24 }, { CR44, 0x32 }, - { CR46, 0x99 }, /* for newest(3rd cut) AL2230 */ - { CR47, 0x1e }, + { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 }, + { ZD_CR17, 0x2B }, /* for newest(3rd cut) AL2230 */ + { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, + { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR33, 0x28 }, /* 5621 */ + { ZD_CR34, 0x30 }, + { ZD_CR35, 0x3e }, /* for newest(3rd cut) AL2230 */ + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + { ZD_CR46, 0x99 }, /* for newest(3rd cut) AL2230 */ + { ZD_CR47, 0x1e }, /* ZD1211B 05.06.10 */ - { CR48, 0x06 }, { CR49, 0xf9 }, { CR51, 0x01 }, - { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, - { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, - { CR69, 0x28 }, + { ZD_CR48, 0x06 }, { ZD_CR49, 0xf9 }, { ZD_CR51, 0x01 }, + { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 }, + { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 }, + { ZD_CR69, 0x28 }, - { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, - { CR87, 0x0a }, { CR89, 0x04 }, - { CR91, 0x00 }, /* 5621 */ - { CR92, 0x0a }, - { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ - { CR99, 0x00 }, /* 5621 */ - { CR101, 0x13 }, { CR102, 0x27 }, - { CR106, 0x24 }, /* for newest(3rd cut) AL2230 */ - { CR107, 0x2a }, - { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ - { CR110, 0x1f }, /* 4804, for 1212 new algorithm */ - { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x27 }, - { CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */ - { CR116, 0x24 }, - { CR117, 0xfa }, /* for 1211b */ - { CR118, 0xfa }, /* for 1211b */ - { CR119, 0x10 }, - { CR120, 0x4f }, - { CR121, 0x6c }, /* for 1211b */ - { CR122, 0xfc }, /* E0->FC at 4902 */ - { CR123, 0x57 }, /* 5623 */ - { CR125, 0xad }, /* 4804, for 1212 new algorithm */ - { CR126, 0x6c }, /* 5614 */ - { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ - { CR137, 0x50 }, /* 5614 */ - { CR138, 0xa8 }, - { CR144, 0xac }, /* 5621 */ - { CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 }, + { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, + { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR91, 0x00 }, /* 5621 */ + { ZD_CR92, 0x0a }, + { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */ + { ZD_CR99, 0x00 }, /* 5621 */ + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, + { ZD_CR106, 0x24 }, /* for newest(3rd cut) AL2230 */ + { ZD_CR107, 0x2a }, + { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */ + { ZD_CR110, 0x1f }, /* 4804, for 1212 new algorithm */ + { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, + { ZD_CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) + * AL2230 + */ + { ZD_CR116, 0x24 }, + { ZD_CR117, 0xfa }, /* for 1211b */ + { ZD_CR118, 0xfa }, /* for 1211b */ + { ZD_CR119, 0x10 }, + { ZD_CR120, 0x4f }, + { ZD_CR121, 0x6c }, /* for 1211b */ + { ZD_CR122, 0xfc }, /* E0->FC at 4902 */ + { ZD_CR123, 0x57 }, /* 5623 */ + { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */ + { ZD_CR126, 0x6c }, /* 5614 */ + { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */ + { ZD_CR137, 0x50 }, /* 5614 */ + { ZD_CR138, 0xa8 }, + { ZD_CR144, 0xac }, /* 5621 */ + { ZD_CR150, 0x0d }, { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 }, }; static const u32 rv1[] = { @@ -284,7 +286,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) 0x6da010, /* Reg6 update for MP versio */ 0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */ 0x116000, - 0x9dc020, /* External control TX power (CR31) */ + 0x9dc020, /* External control TX power (ZD_CR31) */ 0x5ddb00, /* RegA update for MP version */ 0xd99000, /* RegB update for MP version */ 0x3ffbd0, /* RegC update for MP version */ @@ -295,8 +297,8 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) }; static const struct zd_ioreq16 ioreqs2[] = { - { CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ - { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ + { ZD_CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ + { ZD_CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ }; static const u32 rv3[] = { @@ -308,7 +310,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) static const struct zd_ioreq16 ioreqs3[] = { /* related to 6M band edge patching, happens unconditionally */ - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, }; r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1, @@ -361,8 +363,8 @@ static int zd1211_al2230_set_channel(struct zd_rf *rf, u8 channel) const u32 *rv = zd1211_al2230_table[channel-1]; struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR138, 0x28 }, - { CR203, 0x06 }, + { ZD_CR138, 0x28 }, + { ZD_CR203, 0x06 }, }; r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS); @@ -393,8 +395,8 @@ static int zd1211_al2230_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x3f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x3f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -404,8 +406,8 @@ static int zd1211b_al2230_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x7f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x7f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -415,8 +417,8 @@ static int al2230_switch_radio_off(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x04 }, - { CR251, 0x2f }, + { ZD_CR11, 0x04 }, + { ZD_CR251, 0x2f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c index 65095d661e6b..385c670d1293 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c @@ -68,19 +68,19 @@ static const u32 rv_init2[] = { }; static const struct zd_ioreq16 ioreqs_sw[] = { - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, }; static int zd1211b_al7230b_finalize(struct zd_chip *chip) { int r; static const struct zd_ioreq16 ioreqs[] = { - { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, - { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, - { CR203, 0x04 }, + { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, + { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, + { ZD_CR203, 0x04 }, { }, - { CR240, 0x80 }, + { ZD_CR240, 0x80 }, }; r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -89,12 +89,12 @@ static int zd1211b_al7230b_finalize(struct zd_chip *chip) if (chip->new_phy_layout) { /* antenna selection? */ - r = zd_iowrite16_locked(chip, 0xe5, CR9); + r = zd_iowrite16_locked(chip, 0xe5, ZD_CR9); if (r) return r; } - return zd_iowrite16_locked(chip, 0x04, CR203); + return zd_iowrite16_locked(chip, 0x04, ZD_CR203); } static int zd1211_al7230b_init_hw(struct zd_rf *rf) @@ -106,66 +106,66 @@ static int zd1211_al7230b_init_hw(struct zd_rf *rf) * specified */ static const struct zd_ioreq16 ioreqs_1[] = { /* This one is 7230-specific, and happens before the rest */ - { CR240, 0x57 }, + { ZD_CR240, 0x57 }, { }, - { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, - { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, - { CR44, 0x33 }, + { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, + { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR44, 0x33 }, /* This value is different for 7230 (was: 0x2a) */ - { CR106, 0x22 }, - { CR107, 0x1a }, { CR109, 0x09 }, { CR110, 0x27 }, - { CR111, 0x2b }, { CR112, 0x2b }, { CR119, 0x0a }, + { ZD_CR106, 0x22 }, + { ZD_CR107, 0x1a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, + { ZD_CR111, 0x2b }, { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, /* This happened further down in AL2230, * and the value changed (was: 0xe0) */ - { CR122, 0xfc }, - { CR10, 0x89 }, + { ZD_CR122, 0xfc }, + { ZD_CR10, 0x89 }, /* for newest (3rd cut) AL2300 */ - { CR17, 0x28 }, - { CR26, 0x93 }, { CR34, 0x30 }, + { ZD_CR17, 0x28 }, + { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 }, /* for newest (3rd cut) AL2300 */ - { CR35, 0x3e }, - { CR41, 0x24 }, { CR44, 0x32 }, + { ZD_CR35, 0x3e }, + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, /* for newest (3rd cut) AL2300 */ - { CR46, 0x96 }, - { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, - { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, - { CR92, 0x0a }, { CR99, 0x28 }, + { ZD_CR46, 0x96 }, + { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, + { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, /* This value is different for 7230 (was: 0x00) */ - { CR100, 0x02 }, - { CR101, 0x13 }, { CR102, 0x27 }, + { ZD_CR100, 0x02 }, + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, /* This value is different for 7230 (was: 0x24) */ - { CR106, 0x22 }, + { ZD_CR106, 0x22 }, /* This value is different for 7230 (was: 0x2a) */ - { CR107, 0x3f }, - { CR109, 0x09 }, + { ZD_CR107, 0x3f }, + { ZD_CR109, 0x09 }, /* This value is different for 7230 (was: 0x13) */ - { CR110, 0x1f }, - { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x27 }, + { ZD_CR110, 0x1f }, + { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, /* for newest (3rd cut) AL2300 */ - { CR115, 0x24 }, + { ZD_CR115, 0x24 }, /* This value is different for 7230 (was: 0x24) */ - { CR116, 0x3f }, + { ZD_CR116, 0x3f }, /* This value is different for 7230 (was: 0xf4) */ - { CR117, 0xfa }, - { CR118, 0xfc }, { CR119, 0x10 }, { CR120, 0x4f }, - { CR121, 0x77 }, { CR137, 0x88 }, + { ZD_CR117, 0xfa }, + { ZD_CR118, 0xfc }, { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, + { ZD_CR121, 0x77 }, { ZD_CR137, 0x88 }, /* This one is 7230-specific */ - { CR138, 0xa8 }, + { ZD_CR138, 0xa8 }, /* This value is different for 7230 (was: 0xff) */ - { CR252, 0x34 }, + { ZD_CR252, 0x34 }, /* This value is different for 7230 (was: 0xff) */ - { CR253, 0x34 }, + { ZD_CR253, 0x34 }, /* PLL_OFF */ - { CR251, 0x2f }, + { ZD_CR251, 0x2f }, }; static const struct zd_ioreq16 ioreqs_2[] = { - { CR251, 0x3f }, /* PLL_ON */ - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, + { ZD_CR251, 0x3f }, /* PLL_ON */ + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, }; r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); @@ -192,10 +192,10 @@ static int zd1211_al7230b_init_hw(struct zd_rf *rf) if (r) return r; - r = zd_iowrite16_locked(chip, 0x06, CR203); + r = zd_iowrite16_locked(chip, 0x06, ZD_CR203); if (r) return r; - r = zd_iowrite16_locked(chip, 0x80, CR240); + r = zd_iowrite16_locked(chip, 0x80, ZD_CR240); if (r) return r; @@ -208,79 +208,79 @@ static int zd1211b_al7230b_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs_1[] = { - { CR240, 0x57 }, { CR9, 0x9 }, + { ZD_CR240, 0x57 }, { ZD_CR9, 0x9 }, { }, - { CR10, 0x8b }, { CR15, 0x20 }, - { CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ - { CR20, 0x10 }, /* 4N25->Stone Request */ - { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, - { CR28, 0x3e }, { CR29, 0x00 }, - { CR33, 0x28 }, /* 5613 */ - { CR34, 0x30 }, - { CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ - { CR41, 0x24 }, { CR44, 0x32 }, - { CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ - { CR47, 0x1e }, + { ZD_CR10, 0x8b }, { ZD_CR15, 0x20 }, + { ZD_CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ + { ZD_CR20, 0x10 }, /* 4N25->Stone Request */ + { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, + { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR33, 0x28 }, /* 5613 */ + { ZD_CR34, 0x30 }, + { ZD_CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + { ZD_CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ + { ZD_CR47, 0x1e }, /* ZD1215 5610 */ - { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 }, - { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, - { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, - { CR69, 0x28 }, + { ZD_CR48, 0x00 }, { ZD_CR49, 0x00 }, { ZD_CR51, 0x01 }, + { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 }, + { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 }, + { ZD_CR69, 0x28 }, - { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, - { CR87, 0x0A }, { CR89, 0x04 }, - { CR90, 0x58 }, /* 5112 */ - { CR91, 0x00 }, /* 5613 */ - { CR92, 0x0a }, - { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ - { CR99, 0x00 }, { CR100, 0x02 }, { CR101, 0x13 }, - { CR102, 0x27 }, - { CR106, 0x20 }, /* change to 0x24 for AL7230B */ - { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ - { CR112, 0x1f }, + { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, + { ZD_CR87, 0x0A }, { ZD_CR89, 0x04 }, + { ZD_CR90, 0x58 }, /* 5112 */ + { ZD_CR91, 0x00 }, /* 5613 */ + { ZD_CR92, 0x0a }, + { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */ + { ZD_CR99, 0x00 }, { ZD_CR100, 0x02 }, { ZD_CR101, 0x13 }, + { ZD_CR102, 0x27 }, + { ZD_CR106, 0x20 }, /* change to 0x24 for AL7230B */ + { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */ + { ZD_CR112, 0x1f }, }; static const struct zd_ioreq16 ioreqs_new_phy[] = { - { CR107, 0x28 }, - { CR110, 0x1f }, /* 5127, 0x13->0x1f */ - { CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ - { CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 }, - { CR121, 0x6c }, /* 5613 */ + { ZD_CR107, 0x28 }, + { ZD_CR110, 0x1f }, /* 5127, 0x13->0x1f */ + { ZD_CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ + { ZD_CR116, 0x2a }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x12 }, + { ZD_CR121, 0x6c }, /* 5613 */ }; static const struct zd_ioreq16 ioreqs_old_phy[] = { - { CR107, 0x24 }, - { CR110, 0x13 }, /* 5127, 0x13->0x1f */ - { CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ - { CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 }, - { CR121, 0x6a }, /* 5613 */ + { ZD_CR107, 0x24 }, + { ZD_CR110, 0x13 }, /* 5127, 0x13->0x1f */ + { ZD_CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ + { ZD_CR116, 0x24 }, { ZD_CR118, 0xfc }, { ZD_CR119, 0x11 }, + { ZD_CR121, 0x6a }, /* 5613 */ }; static const struct zd_ioreq16 ioreqs_2[] = { - { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 }, - { CR117, 0xfa }, { CR120, 0x4f }, - { CR122, 0xfc }, /* E0->FCh at 4901 */ - { CR123, 0x57 }, /* 5613 */ - { CR125, 0xad }, /* 4804, for 1212 new algorithm */ - { CR126, 0x6c }, /* 5613 */ - { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ - { CR130, 0x10 }, - { CR131, 0x00 }, /* 5112 */ - { CR137, 0x50 }, /* 5613 */ - { CR138, 0xa8 }, /* 5112 */ - { CR144, 0xac }, /* 5613 */ - { CR148, 0x40 }, /* 5112 */ - { CR149, 0x40 }, /* 4O07, 50->40 */ - { CR150, 0x1a }, /* 5112, 0C->1A */ - { CR252, 0x34 }, { CR253, 0x34 }, - { CR251, 0x2f }, /* PLL_OFF */ + { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x24 }, + { ZD_CR117, 0xfa }, { ZD_CR120, 0x4f }, + { ZD_CR122, 0xfc }, /* E0->FCh at 4901 */ + { ZD_CR123, 0x57 }, /* 5613 */ + { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */ + { ZD_CR126, 0x6c }, /* 5613 */ + { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */ + { ZD_CR130, 0x10 }, + { ZD_CR131, 0x00 }, /* 5112 */ + { ZD_CR137, 0x50 }, /* 5613 */ + { ZD_CR138, 0xa8 }, /* 5112 */ + { ZD_CR144, 0xac }, /* 5613 */ + { ZD_CR148, 0x40 }, /* 5112 */ + { ZD_CR149, 0x40 }, /* 4O07, 50->40 */ + { ZD_CR150, 0x1a }, /* 5112, 0C->1A */ + { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 }, + { ZD_CR251, 0x2f }, /* PLL_OFF */ }; static const struct zd_ioreq16 ioreqs_3[] = { - { CR251, 0x7f }, /* PLL_ON */ - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, + { ZD_CR251, 0x7f }, /* PLL_ON */ + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, }; r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); @@ -331,16 +331,16 @@ static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel) static const struct zd_ioreq16 ioreqs[] = { /* PLL_ON */ - { CR251, 0x3f }, - { CR203, 0x06 }, { CR240, 0x08 }, + { ZD_CR251, 0x3f }, + { ZD_CR203, 0x06 }, { ZD_CR240, 0x08 }, }; - r = zd_iowrite16_locked(chip, 0x57, CR240); + r = zd_iowrite16_locked(chip, 0x57, ZD_CR240); if (r) return r; /* PLL_OFF */ - r = zd_iowrite16_locked(chip, 0x2f, CR251); + r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251); if (r) return r; @@ -376,15 +376,15 @@ static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel) const u32 *rv = chan_rv[channel-1]; struct zd_chip *chip = zd_rf_to_chip(rf); - r = zd_iowrite16_locked(chip, 0x57, CR240); + r = zd_iowrite16_locked(chip, 0x57, ZD_CR240); if (r) return r; - r = zd_iowrite16_locked(chip, 0xe4, CR9); + r = zd_iowrite16_locked(chip, 0xe4, ZD_CR9); if (r) return r; /* PLL_OFF */ - r = zd_iowrite16_locked(chip, 0x2f, CR251); + r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251); if (r) return r; r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); @@ -410,7 +410,7 @@ static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel) if (r) return r; - r = zd_iowrite16_locked(chip, 0x7f, CR251); + r = zd_iowrite16_locked(chip, 0x7f, ZD_CR251); if (r) return r; @@ -421,8 +421,8 @@ static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x3f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x3f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -432,8 +432,8 @@ static int zd1211b_al7230b_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x7f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x7f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -443,8 +443,8 @@ static int al7230b_switch_radio_off(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x04 }, - { CR251, 0x2f }, + { ZD_CR11, 0x04 }, + { ZD_CR251, 0x2f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -456,7 +456,7 @@ static int zd1211b_al7230b_patch_6m(struct zd_rf *rf, u8 channel) { struct zd_chip *chip = zd_rf_to_chip(rf); struct zd_ioreq16 ioreqs[] = { - { CR128, 0x14 }, { CR129, 0x12 }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, }; /* FIXME: Channel 11 is not the edge for all regulatory domains. */ diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c index e36117486c91..784d9ccb8fef 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c @@ -152,44 +152,44 @@ static int rf2959_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR2, 0x1E }, { CR9, 0x20 }, { CR10, 0x89 }, - { CR11, 0x00 }, { CR15, 0xD0 }, { CR17, 0x68 }, - { CR19, 0x4a }, { CR20, 0x0c }, { CR21, 0x0E }, - { CR23, 0x48 }, + { ZD_CR2, 0x1E }, { ZD_CR9, 0x20 }, { ZD_CR10, 0x89 }, + { ZD_CR11, 0x00 }, { ZD_CR15, 0xD0 }, { ZD_CR17, 0x68 }, + { ZD_CR19, 0x4a }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0E }, + { ZD_CR23, 0x48 }, /* normal size for cca threshold */ - { CR24, 0x14 }, - /* { CR24, 0x20 }, */ - { CR26, 0x90 }, { CR27, 0x30 }, { CR29, 0x20 }, - { CR31, 0xb2 }, { CR32, 0x43 }, { CR33, 0x28 }, - { CR38, 0x30 }, { CR34, 0x0f }, { CR35, 0xF0 }, - { CR41, 0x2a }, { CR46, 0x7F }, { CR47, 0x1E }, - { CR51, 0xc5 }, { CR52, 0xc5 }, { CR53, 0xc5 }, - { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, - { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 }, - { CR85, 0x00 }, { CR86, 0x10 }, { CR87, 0x2A }, - { CR88, 0x10 }, { CR89, 0x24 }, { CR90, 0x18 }, - /* { CR91, 0x18 }, */ + { ZD_CR24, 0x14 }, + /* { ZD_CR24, 0x20 }, */ + { ZD_CR26, 0x90 }, { ZD_CR27, 0x30 }, { ZD_CR29, 0x20 }, + { ZD_CR31, 0xb2 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x28 }, + { ZD_CR38, 0x30 }, { ZD_CR34, 0x0f }, { ZD_CR35, 0xF0 }, + { ZD_CR41, 0x2a }, { ZD_CR46, 0x7F }, { ZD_CR47, 0x1E }, + { ZD_CR51, 0xc5 }, { ZD_CR52, 0xc5 }, { ZD_CR53, 0xc5 }, + { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, + { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, + { ZD_CR85, 0x00 }, { ZD_CR86, 0x10 }, { ZD_CR87, 0x2A }, + { ZD_CR88, 0x10 }, { ZD_CR89, 0x24 }, { ZD_CR90, 0x18 }, + /* { ZD_CR91, 0x18 }, */ /* should solve continuous CTS frame problems */ - { CR91, 0x00 }, - { CR92, 0x0a }, { CR93, 0x00 }, { CR94, 0x01 }, - { CR95, 0x00 }, { CR96, 0x40 }, { CR97, 0x37 }, - { CR98, 0x05 }, { CR99, 0x28 }, { CR100, 0x00 }, - { CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 }, - { CR104, 0x18 }, { CR105, 0x12 }, + { ZD_CR91, 0x00 }, + { ZD_CR92, 0x0a }, { ZD_CR93, 0x00 }, { ZD_CR94, 0x01 }, + { ZD_CR95, 0x00 }, { ZD_CR96, 0x40 }, { ZD_CR97, 0x37 }, + { ZD_CR98, 0x05 }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 }, + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, + { ZD_CR104, 0x18 }, { ZD_CR105, 0x12 }, /* normal size */ - { CR106, 0x1a }, - /* { CR106, 0x22 }, */ - { CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 }, - { CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 }, - { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 }, - { CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 }, - { CR119, 0x16 }, + { ZD_CR106, 0x1a }, + /* { ZD_CR106, 0x22 }, */ + { ZD_CR107, 0x24 }, { ZD_CR108, 0x0a }, { ZD_CR109, 0x13 }, + { ZD_CR110, 0x2F }, { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, + { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x40 }, + { ZD_CR116, 0x40 }, { ZD_CR117, 0xF0 }, { ZD_CR118, 0xF0 }, + { ZD_CR119, 0x16 }, /* no TX continuation */ - { CR122, 0x00 }, - /* { CR122, 0xff }, */ - { CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 }, - { CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB }, - { CR170, 0xBB }, + { ZD_CR122, 0x00 }, + /* { ZD_CR122, 0xff }, */ + { ZD_CR127, 0x03 }, { ZD_CR131, 0x08 }, { ZD_CR138, 0x28 }, + { ZD_CR148, 0x44 }, { ZD_CR150, 0x10 }, { ZD_CR169, 0xBB }, + { ZD_CR170, 0xBB }, }; static const u32 rv[] = { @@ -210,7 +210,7 @@ static int rf2959_init_hw(struct zd_rf *rf) */ 0x294128, /* internal power */ /* 0x28252c, */ /* External control TX power */ - /* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */ + /* ZD_CR31_CCK, ZD_CR51_6-36M, ZD_CR52_48M, ZD_CR53_54M */ 0x2c0000, 0x300000, 0x340000, /* REG13(0xD) */ @@ -245,8 +245,8 @@ static int rf2959_set_channel(struct zd_rf *rf, u8 channel) static int rf2959_switch_radio_on(struct zd_rf *rf) { static const struct zd_ioreq16 ioreqs[] = { - { CR10, 0x89 }, - { CR11, 0x00 }, + { ZD_CR10, 0x89 }, + { ZD_CR11, 0x00 }, }; struct zd_chip *chip = zd_rf_to_chip(rf); @@ -256,8 +256,8 @@ static int rf2959_switch_radio_on(struct zd_rf *rf) static int rf2959_switch_radio_off(struct zd_rf *rf) { static const struct zd_ioreq16 ioreqs[] = { - { CR10, 0x15 }, - { CR11, 0x81 }, + { ZD_CR10, 0x15 }, + { ZD_CR11, 0x81 }, }; struct zd_chip *chip = zd_rf_to_chip(rf); diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c index ba0a0ccb1fa0..c4d324e19c24 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c @@ -314,42 +314,44 @@ static int uw2453_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR10, 0x89 }, { CR15, 0x20 }, - { CR17, 0x28 }, /* 6112 no change */ - { CR23, 0x38 }, { CR24, 0x20 }, { CR26, 0x93 }, - { CR27, 0x15 }, { CR28, 0x3e }, { CR29, 0x00 }, - { CR33, 0x28 }, { CR34, 0x30 }, - { CR35, 0x43 }, /* 6112 3e->43 */ - { CR41, 0x24 }, { CR44, 0x32 }, - { CR46, 0x92 }, /* 6112 96->92 */ - { CR47, 0x1e }, - { CR48, 0x04 }, /* 5602 Roger */ - { CR49, 0xfa }, { CR79, 0x58 }, { CR80, 0x30 }, - { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, - { CR91, 0x00 }, { CR92, 0x0a }, { CR98, 0x8d }, - { CR99, 0x28 }, { CR100, 0x02 }, - { CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */ - { CR102, 0x27 }, - { CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f 6221 1f->1c */ - { CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */ - { CR109, 0x13 }, - { CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */ - { CR111, 0x13 }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x23 }, /* 6221 27->23 */ - { CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */ - { CR116, 0x24 }, /* 6220 1c->24 */ - { CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */ - { CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */ - { CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */ - { CR120, 0x4f }, - { CR121, 0x1f }, /* 6220 4f->1f */ - { CR122, 0xf0 }, { CR123, 0x57 }, { CR125, 0xad }, - { CR126, 0x6c }, { CR127, 0x03 }, - { CR128, 0x14 }, /* 6302 12->11 */ - { CR129, 0x12 }, /* 6301 10->0f */ - { CR130, 0x10 }, { CR137, 0x50 }, { CR138, 0xa8 }, - { CR144, 0xac }, { CR146, 0x20 }, { CR252, 0xff }, - { CR253, 0xff }, + { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 }, + { ZD_CR17, 0x28 }, /* 6112 no change */ + { ZD_CR23, 0x38 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, + { ZD_CR27, 0x15 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR33, 0x28 }, { ZD_CR34, 0x30 }, + { ZD_CR35, 0x43 }, /* 6112 3e->43 */ + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + { ZD_CR46, 0x92 }, /* 6112 96->92 */ + { ZD_CR47, 0x1e }, + { ZD_CR48, 0x04 }, /* 5602 Roger */ + { ZD_CR49, 0xfa }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, + { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR91, 0x00 }, { ZD_CR92, 0x0a }, { ZD_CR98, 0x8d }, + { ZD_CR99, 0x28 }, { ZD_CR100, 0x02 }, + { ZD_CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */ + { ZD_CR102, 0x27 }, + { ZD_CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f + * 6221 1f->1c + */ + { ZD_CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */ + { ZD_CR109, 0x13 }, + { ZD_CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */ + { ZD_CR111, 0x13 }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x23 }, /* 6221 27->23 */ + { ZD_CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */ + { ZD_CR116, 0x24 }, /* 6220 1c->24 */ + { ZD_CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */ + { ZD_CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */ + { ZD_CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */ + { ZD_CR120, 0x4f }, + { ZD_CR121, 0x1f }, /* 6220 4f->1f */ + { ZD_CR122, 0xf0 }, { ZD_CR123, 0x57 }, { ZD_CR125, 0xad }, + { ZD_CR126, 0x6c }, { ZD_CR127, 0x03 }, + { ZD_CR128, 0x14 }, /* 6302 12->11 */ + { ZD_CR129, 0x12 }, /* 6301 10->0f */ + { ZD_CR130, 0x10 }, { ZD_CR137, 0x50 }, { ZD_CR138, 0xa8 }, + { ZD_CR144, 0xac }, { ZD_CR146, 0x20 }, { ZD_CR252, 0xff }, + { ZD_CR253, 0xff }, }; static const u32 rv[] = { @@ -433,7 +435,7 @@ static int uw2453_init_hw(struct zd_rf *rf) * the one that produced a lock. */ UW2453_PRIV(rf)->config = found_config + 1; - return zd_iowrite16_locked(chip, 0x06, CR203); + return zd_iowrite16_locked(chip, 0x06, ZD_CR203); } static int uw2453_set_channel(struct zd_rf *rf, u8 channel) @@ -445,8 +447,8 @@ static int uw2453_set_channel(struct zd_rf *rf, u8 channel) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, - { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, + { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, + { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, }; r = uw2453_synth_set_channel(chip, channel, autocal); @@ -474,7 +476,7 @@ static int uw2453_set_channel(struct zd_rf *rf, u8 channel) if (r) return r; - return zd_iowrite16_locked(chip, 0x06, CR203); + return zd_iowrite16_locked(chip, 0x06, ZD_CR203); } static int uw2453_switch_radio_on(struct zd_rf *rf) @@ -482,7 +484,7 @@ static int uw2453_switch_radio_on(struct zd_rf *rf) int r; struct zd_chip *chip = zd_rf_to_chip(rf); struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, { CR251, 0x3f }, + { ZD_CR11, 0x00 }, { ZD_CR251, 0x3f }, }; /* enter RXTX mode */ @@ -501,7 +503,7 @@ static int uw2453_switch_radio_off(struct zd_rf *rf) int r; struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x04 }, { CR251, 0x2f }, + { ZD_CR11, 0x04 }, { ZD_CR251, 0x2f }, }; /* enter IDLE mode */ diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index ab607bbd6291..0e819943b9e4 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -1893,10 +1893,10 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits); - r = zd_usb_ioread16(usb, &bit_value_template, CR203); + r = zd_usb_ioread16(usb, &bit_value_template, ZD_CR203); if (r) { dev_dbg_f(zd_usb_dev(usb), - "error %d: Couldn't read CR203\n", r); + "error %d: Couldn't read ZD_CR203\n", r); return r; } bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index 325d0f989257..bf942843b733 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -109,7 +109,7 @@ struct usb_req_rfwrite { __le16 bits; /* RF2595: 24 */ __le16 bit_values[0]; - /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ + /* (ZD_CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ } __packed; /* USB interrupt */ diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 5d7bbf2b2ee7..161f207786a4 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -73,9 +73,6 @@ struct xenvif { struct vm_struct *tx_comms_area; struct vm_struct *rx_comms_area; - /* Flags that must not be set in dev->features */ - u32 features_disabled; - /* Frontend feature information. */ u8 can_sg:1; u8 gso:1; @@ -109,8 +106,8 @@ struct xenvif { wait_queue_head_t waiting_to_free; }; -#define XEN_NETIF_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE) -#define XEN_NETIF_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE) +#define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE) +#define XEN_NETIF_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE) struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index de569cc19da4..0ca86f9ec4ed 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -165,69 +165,18 @@ static int xenvif_change_mtu(struct net_device *dev, int mtu) return 0; } -static void xenvif_set_features(struct xenvif *vif) -{ - struct net_device *dev = vif->dev; - u32 features = dev->features; - - if (vif->can_sg) - features |= NETIF_F_SG; - if (vif->gso || vif->gso_prefix) - features |= NETIF_F_TSO; - if (vif->csum) - features |= NETIF_F_IP_CSUM; - - features &= ~(vif->features_disabled); - - if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN) - dev->mtu = ETH_DATA_LEN; - - dev->features = features; -} - -static int xenvif_set_tx_csum(struct net_device *dev, u32 data) +static u32 xenvif_fix_features(struct net_device *dev, u32 features) { struct xenvif *vif = netdev_priv(dev); - if (data) { - if (!vif->csum) - return -EOPNOTSUPP; - vif->features_disabled &= ~NETIF_F_IP_CSUM; - } else { - vif->features_disabled |= NETIF_F_IP_CSUM; - } - xenvif_set_features(vif); - return 0; -} + if (!vif->can_sg) + features &= ~NETIF_F_SG; + if (!vif->gso && !vif->gso_prefix) + features &= ~NETIF_F_TSO; + if (!vif->csum) + features &= ~NETIF_F_IP_CSUM; -static int xenvif_set_sg(struct net_device *dev, u32 data) -{ - struct xenvif *vif = netdev_priv(dev); - if (data) { - if (!vif->can_sg) - return -EOPNOTSUPP; - vif->features_disabled &= ~NETIF_F_SG; - } else { - vif->features_disabled |= NETIF_F_SG; - } - - xenvif_set_features(vif); - return 0; -} - -static int xenvif_set_tso(struct net_device *dev, u32 data) -{ - struct xenvif *vif = netdev_priv(dev); - if (data) { - if (!vif->gso && !vif->gso_prefix) - return -EOPNOTSUPP; - vif->features_disabled &= ~NETIF_F_TSO; - } else { - vif->features_disabled |= NETIF_F_TSO; - } - - xenvif_set_features(vif); - return 0; + return features; } static const struct xenvif_stat { @@ -274,12 +223,6 @@ static void xenvif_get_strings(struct net_device *dev, u32 stringset, u8 * data) } static struct ethtool_ops xenvif_ethtool_ops = { - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = xenvif_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = xenvif_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = xenvif_set_tso, .get_link = ethtool_op_get_link, .get_sset_count = xenvif_get_sset_count, @@ -293,6 +236,7 @@ static struct net_device_ops xenvif_netdev_ops = { .ndo_open = xenvif_open, .ndo_stop = xenvif_close, .ndo_change_mtu = xenvif_change_mtu, + .ndo_fix_features = xenvif_fix_features, }; struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, @@ -331,7 +275,8 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, vif->credit_timeout.expires = jiffies; dev->netdev_ops = &xenvif_netdev_ops; - xenvif_set_features(vif); + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; + dev->features = dev->hw_features; SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops); dev->tx_queue_len = XENVIF_QUEUE_LENGTH; @@ -367,8 +312,6 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, if (vif->irq) return 0; - xenvif_set_features(vif); - err = xen_netbk_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); if (err < 0) goto err; @@ -384,9 +327,12 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, xenvif_get(vif); rtnl_lock(); - netif_carrier_on(vif->dev); if (netif_running(vif->dev)) xenvif_up(vif); + if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN) + dev_set_mtu(vif->dev, ETH_DATA_LEN); + netdev_update_features(vif->dev); + netif_carrier_on(vif->dev); rtnl_unlock(); return 0; diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 22b8c3505991..1ce729d6af75 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -26,7 +26,7 @@ struct backend_info { struct xenvif *vif; enum xenbus_state frontend_state; struct xenbus_watch hotplug_status_watch; - int have_hotplug_status_watch:1; + u8 have_hotplug_status_watch:1; }; static int connect_rings(struct backend_info *); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 5c8d9c385be0..db9a763aaa7f 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1140,6 +1140,42 @@ static void xennet_uninit(struct net_device *dev) gnttab_free_grant_references(np->gref_rx_head); } +static u32 xennet_fix_features(struct net_device *dev, u32 features) +{ + struct netfront_info *np = netdev_priv(dev); + int val; + + if (features & NETIF_F_SG) { + if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg", + "%d", &val) < 0) + val = 0; + + if (!val) + features &= ~NETIF_F_SG; + } + + if (features & NETIF_F_TSO) { + if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, + "feature-gso-tcpv4", "%d", &val) < 0) + val = 0; + + if (!val) + features &= ~NETIF_F_TSO; + } + + return features; +} + +static int xennet_set_features(struct net_device *dev, u32 features) +{ + if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN) { + netdev_info(dev, "Reducing MTU because no SG offload"); + dev->mtu = ETH_DATA_LEN; + } + + return 0; +} + static const struct net_device_ops xennet_netdev_ops = { .ndo_open = xennet_open, .ndo_uninit = xennet_uninit, @@ -1148,6 +1184,8 @@ static const struct net_device_ops xennet_netdev_ops = { .ndo_change_mtu = xennet_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, + .ndo_fix_features = xennet_fix_features, + .ndo_set_features = xennet_set_features, }; static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev) @@ -1209,7 +1247,17 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev netdev->netdev_ops = &xennet_netdev_ops; netif_napi_add(netdev, &np->napi, xennet_poll, 64); - netdev->features = NETIF_F_IP_CSUM; + netdev->features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM | + NETIF_F_GSO_ROBUST; + netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO; + + /* + * Assume that all hw features are available for now. This set + * will be adjusted by the call to netdev_update_features() in + * xennet_connect() which is the earliest point where we can + * negotiate with the backend regarding supported features. + */ + netdev->features |= netdev->hw_features; SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops); SET_NETDEV_DEV(netdev, &dev->dev); @@ -1416,8 +1464,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info) goto fail; err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt, - IRQF_SAMPLE_RANDOM, netdev->name, - netdev); + 0, netdev->name, netdev); if (err < 0) goto fail; netdev->irq = err; @@ -1510,54 +1557,6 @@ static int talk_to_netback(struct xenbus_device *dev, return err; } -static int xennet_set_sg(struct net_device *dev, u32 data) -{ - if (data) { - struct netfront_info *np = netdev_priv(dev); - int val; - - if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg", - "%d", &val) < 0) - val = 0; - if (!val) - return -ENOSYS; - } else if (dev->mtu > ETH_DATA_LEN) - dev->mtu = ETH_DATA_LEN; - - return ethtool_op_set_sg(dev, data); -} - -static int xennet_set_tso(struct net_device *dev, u32 data) -{ - if (data) { - struct netfront_info *np = netdev_priv(dev); - int val; - - if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, - "feature-gso-tcpv4", "%d", &val) < 0) - val = 0; - if (!val) - return -ENOSYS; - } - - return ethtool_op_set_tso(dev, data); -} - -static void xennet_set_features(struct net_device *dev) -{ - /* Turn off all GSO bits except ROBUST. */ - dev->features &= ~NETIF_F_GSO_MASK; - dev->features |= NETIF_F_GSO_ROBUST; - xennet_set_sg(dev, 0); - - /* We need checksum offload to enable scatter/gather and TSO. */ - if (!(dev->features & NETIF_F_IP_CSUM)) - return; - - if (!xennet_set_sg(dev, 1)) - xennet_set_tso(dev, 1); -} - static int xennet_connect(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); @@ -1582,7 +1581,7 @@ static int xennet_connect(struct net_device *dev) if (err) return err; - xennet_set_features(dev); + netdev_update_features(dev); spin_lock_bh(&np->rx_lock); spin_lock_irq(&np->tx_lock); @@ -1710,9 +1709,6 @@ static void xennet_get_strings(struct net_device *dev, u32 stringset, u8 * data) static const struct ethtool_ops xennet_ethtool_ops = { - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = xennet_set_sg, - .set_tso = xennet_set_tso, .get_link = ethtool_op_get_link, .get_sset_count = xennet_get_sset_count, diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index b78a38d9172a..8c7c522a056a 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -126,7 +126,7 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z, board = z->resource.start; ioaddr = board+cards[i].offset; - dev = alloc_ei_netdev(); + dev = ____alloc_ei_netdev(0); if (!dev) return -ENOMEM; if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) { @@ -146,15 +146,15 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z, static const struct net_device_ops zorro8390_netdev_ops = { .ndo_open = zorro8390_open, .ndo_stop = zorro8390_close, - .ndo_start_xmit = ei_start_xmit, - .ndo_tx_timeout = ei_tx_timeout, - .ndo_get_stats = ei_get_stats, - .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_start_xmit = __ei_start_xmit, + .ndo_tx_timeout = __ei_tx_timeout, + .ndo_get_stats = __ei_get_stats, + .ndo_set_multicast_list = __ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ei_poll, + .ndo_poll_controller = __ei_poll, #endif }; diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 75b0d3cb7676..9f689f1da0fc 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -56,7 +56,7 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map); * Returns a pointer to the interrupt parent node, or NULL if the interrupt * parent could not be determined. */ -static struct device_node *of_irq_find_parent(struct device_node *child) +struct device_node *of_irq_find_parent(struct device_node *child) { struct device_node *p; const __be32 *parp; diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index a3755ffc03d4..bc8ce48f0778 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -2550,7 +2550,6 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, const struct parport_pc_via_data *via) { short inta_addr[6] = { 0x2A0, 0x2C0, 0x220, 0x240, 0x1E0 }; - struct resource *base_res; u32 ite8872set; u32 ite8872_lpt, ite8872_lpthi; u8 ite8872_irq, type; @@ -2561,8 +2560,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, /* make sure which one chip */ for (i = 0; i < 5; i++) { - base_res = request_region(inta_addr[i], 32, "it887x"); - if (base_res) { + if (request_region(inta_addr[i], 32, "it887x")) { int test; pci_write_config_dword(pdev, 0x60, 0xe5000000 | inta_addr[i]); @@ -2571,7 +2569,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, test = inb(inta_addr[i]); if (test != 0xff) break; - release_region(inta_addr[i], 0x8); + release_region(inta_addr[i], 32); } } if (i >= 5) { @@ -2635,7 +2633,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, /* * Release the resource so that parport_pc_probe_port can get it. */ - release_resource(base_res); + release_region(inta_addr[i], 32); if (parport_pc_probe_port(ite8872_lpt, ite8872_lpthi, irq, PARPORT_DMA_NONE, &pdev->dev, 0)) { printk(KERN_INFO diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index c8ff646c0b05..0fa466a91bf4 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -88,4 +88,6 @@ config PCI_IOAPIC depends on HOTPLUG default y -select NLS if (DMI || ACPI) +config PCI_LABEL + def_bool y if (DMI || ACPI) + select NLS diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 98d61c8e984b..c85f744270a5 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -56,10 +56,10 @@ obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o # ACPI Related PCI FW Functions # ACPI _DSM provided firmware instance and string name # -obj-$(CONFIG_ACPI) += pci-acpi.o pci-label.o +obj-$(CONFIG_ACPI) += pci-acpi.o # SMBIOS provided firmware instance and labels -obj-$(CONFIG_DMI) += pci-label.o +obj-$(CONFIG_PCI_LABEL) += pci-label.o # Cardbus & CompactPCI use setup-bus obj-$(CONFIG_HOTPLUG) += setup-bus.o diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 505c1c7075f0..6af6b628175b 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include "pci.h" @@ -1299,7 +1300,7 @@ static void iommu_detach_domain(struct dmar_domain *domain, static struct iova_domain reserved_iova_list; static struct lock_class_key reserved_rbtree_key; -static void dmar_init_reserved_ranges(void) +static int dmar_init_reserved_ranges(void) { struct pci_dev *pdev = NULL; struct iova *iova; @@ -1313,8 +1314,10 @@ static void dmar_init_reserved_ranges(void) /* IOAPIC ranges shouldn't be accessed by DMA */ iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START), IOVA_PFN(IOAPIC_RANGE_END)); - if (!iova) + if (!iova) { printk(KERN_ERR "Reserve IOAPIC range failed\n"); + return -ENODEV; + } /* Reserve all PCI MMIO to avoid peer-to-peer access */ for_each_pci_dev(pdev) { @@ -1327,11 +1330,13 @@ static void dmar_init_reserved_ranges(void) iova = reserve_iova(&reserved_iova_list, IOVA_PFN(r->start), IOVA_PFN(r->end)); - if (!iova) + if (!iova) { printk(KERN_ERR "Reserve iova failed\n"); + return -ENODEV; + } } } - + return 0; } static void domain_reserve_special_ranges(struct dmar_domain *domain) @@ -1835,7 +1840,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) ret = iommu_attach_domain(domain, iommu); if (ret) { - domain_exit(domain); + free_domain_mem(domain); goto error; } @@ -2213,7 +2218,7 @@ static int __init iommu_prepare_static_identity_mapping(int hw) return 0; } -int __init init_dmars(void) +static int __init init_dmars(int force_on) { struct dmar_drhd_unit *drhd; struct dmar_rmrr_unit *rmrr; @@ -2393,8 +2398,15 @@ int __init init_dmars(void) * enable translation */ for_each_drhd_unit(drhd) { - if (drhd->ignored) + if (drhd->ignored) { + /* + * we always have to disable PMRs or DMA may fail on + * this device + */ + if (force_on) + iommu_disable_protect_mem_regions(drhd->iommu); continue; + } iommu = drhd->iommu; iommu_flush_write_buffer(iommu); @@ -3240,9 +3252,15 @@ static int device_notifier(struct notifier_block *nb, if (!domain) return 0; - if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) + if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) { domain_remove_one_dev_info(domain, pdev); + if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) && + !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) && + list_empty(&domain->devices)) + domain_exit(domain); + } + return 0; } @@ -3277,12 +3295,21 @@ int __init intel_iommu_init(void) if (no_iommu || dmar_disabled) return -ENODEV; - iommu_init_mempool(); - dmar_init_reserved_ranges(); + if (iommu_init_mempool()) { + if (force_on) + panic("tboot: Failed to initialize iommu memory\n"); + return -ENODEV; + } + + if (dmar_init_reserved_ranges()) { + if (force_on) + panic("tboot: Failed to reserve iommu ranges\n"); + return -ENODEV; + } init_no_remapping_devices(); - ret = init_dmars(); + ret = init_dmars(force_on); if (ret) { if (force_on) panic("tboot: Failed to initialize DMARs\n"); @@ -3391,6 +3418,11 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain, domain->iommu_count--; domain_update_iommu_cap(domain); spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags); + + spin_lock_irqsave(&iommu->lock, tmp_flags); + clear_bit(domain->id, iommu->domain_ids); + iommu->domains[domain->id] = NULL; + spin_unlock_irqrestore(&iommu->lock, tmp_flags); } spin_unlock_irqrestore(&device_domain_lock, flags); @@ -3607,9 +3639,9 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, pte = dmar_domain->pgd; if (dma_pte_present(pte)) { - free_pgtable_page(dmar_domain->pgd); dmar_domain->pgd = (struct dma_pte *) phys_to_virt(dma_pte_addr(pte)); + free_pgtable_page(pte); } dmar_domain->agaw--; } diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 553d8ee55c1c..42fae4776515 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "pci.h" #define VIRTFN_ID_LEN 16 diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index a6ec200fe5ee..4020025f854e 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -250,15 +250,6 @@ struct pci_sriov { u8 __iomem *mstate; /* VF Migration State Array */ }; -/* Address Translation Service */ -struct pci_ats { - int pos; /* capability position */ - int stu; /* Smallest Translation Unit */ - int qdep; /* Invalidate Queue Depth */ - int ref_cnt; /* Physical Function reference count */ - unsigned int is_enabled:1; /* Enable bit is set */ -}; - #ifdef CONFIG_PCI_IOV extern int pci_iov_init(struct pci_dev *dev); extern void pci_iov_release(struct pci_dev *dev); @@ -269,19 +260,6 @@ extern resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, extern void pci_restore_iov_state(struct pci_dev *dev); extern int pci_iov_bus_range(struct pci_bus *bus); -extern int pci_enable_ats(struct pci_dev *dev, int ps); -extern void pci_disable_ats(struct pci_dev *dev); -extern int pci_ats_queue_depth(struct pci_dev *dev); -/** - * pci_ats_enabled - query the ATS status - * @dev: the PCI device - * - * Returns 1 if ATS capability is enabled, or 0 if not. - */ -static inline int pci_ats_enabled(struct pci_dev *dev) -{ - return dev->ats && dev->ats->is_enabled; -} #else static inline int pci_iov_init(struct pci_dev *dev) { @@ -304,21 +282,6 @@ static inline int pci_iov_bus_range(struct pci_bus *bus) return 0; } -static inline int pci_enable_ats(struct pci_dev *dev, int ps) -{ - return -ENODEV; -} -static inline void pci_disable_ats(struct pci_dev *dev) -{ -} -static inline int pci_ats_queue_depth(struct pci_dev *dev) -{ - return -ENODEV; -} -static inline int pci_ats_enabled(struct pci_dev *dev) -{ - return 0; -} #endif /* CONFIG_PCI_IOV */ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev, diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index ebf51ad1b714..a806cb321d2e 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -579,7 +579,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, } size0 = calculate_iosize(size, min_size, size1, resource_size(b_res), 4096); - size1 = !add_size? size0: + size1 = (!add_head || (add_head && !add_size)) ? size0 : calculate_iosize(size, min_size+add_size, size1, resource_size(b_res), 4096); if (!size0 && !size1) { @@ -677,7 +677,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, align += aligns[order]; } size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); - size1 = !add_size ? size : + size1 = (!add_head || (add_head && !add_size)) ? size0 : calculate_memsize(size, min_size+add_size, 0, resource_size(b_res), min_align); if (!size0 && !size1) { diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index fe77e8223841..e8c19def1b0f 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -173,7 +173,7 @@ static int pcmcia_access_config(struct pcmcia_device *p_dev, c = p_dev->function_config; if (!(c->state & CONFIG_LOCKED)) { - dev_dbg(&p_dev->dev, "Configuration isn't't locked\n"); + dev_dbg(&p_dev->dev, "Configuration isn't locked\n"); mutex_unlock(&s->ops_mutex); return -EACCES; } diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 5f2dd386152b..2c1abf63957f 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -585,8 +585,9 @@ static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc) return true; } -static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) +static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle) { + struct pci_dev *port; struct pci_dev *dev; struct pci_bus *bus; bool blocked = eeepc_wlan_rfkill_blocked(eeepc); @@ -599,9 +600,16 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) mutex_lock(&eeepc->hotplug_lock); if (eeepc->hotplug_slot) { - bus = pci_find_bus(0, 1); + port = acpi_get_pci_dev(handle); + if (!port) { + pr_warning("Unable to find port\n"); + goto out_unlock; + } + + bus = port->subordinate; + if (!bus) { - pr_warning("Unable to find PCI bus 1?\n"); + pr_warning("Unable to find PCI bus?\n"); goto out_unlock; } @@ -609,6 +617,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) pr_err("Unable to read PCI config space?\n"); goto out_unlock; } + absent = (l == 0xffffffff); if (blocked != absent) { @@ -647,6 +656,17 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) mutex_unlock(&eeepc->hotplug_lock); } +static void eeepc_rfkill_hotplug_update(struct eeepc_laptop *eeepc, char *node) +{ + acpi_status status = AE_OK; + acpi_handle handle; + + status = acpi_get_handle(NULL, node, &handle); + + if (ACPI_SUCCESS(status)) + eeepc_rfkill_hotplug(eeepc, handle); +} + static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) { struct eeepc_laptop *eeepc = data; @@ -654,7 +674,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) if (event != ACPI_NOTIFY_BUS_CHECK) return; - eeepc_rfkill_hotplug(eeepc); + eeepc_rfkill_hotplug(eeepc, handle); } static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc, @@ -672,6 +692,11 @@ static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc, eeepc); if (ACPI_FAILURE(status)) pr_warning("Failed to register notify on %s\n", node); + /* + * Refresh pci hotplug in case the rfkill state was + * changed during setup. + */ + eeepc_rfkill_hotplug(eeepc, handle); } else return -ENODEV; @@ -693,6 +718,12 @@ static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc, if (ACPI_FAILURE(status)) pr_err("Error removing rfkill notify handler %s\n", node); + /* + * Refresh pci hotplug in case the rfkill + * state was changed after + * eeepc_unregister_rfkill_notifier() + */ + eeepc_rfkill_hotplug(eeepc, handle); } } @@ -816,11 +847,7 @@ static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc) rfkill_destroy(eeepc->wlan_rfkill); eeepc->wlan_rfkill = NULL; } - /* - * Refresh pci hotplug in case the rfkill state was changed after - * eeepc_unregister_rfkill_notifier() - */ - eeepc_rfkill_hotplug(eeepc); + if (eeepc->hotplug_slot) pci_hp_deregister(eeepc->hotplug_slot); @@ -889,11 +916,6 @@ static int eeepc_rfkill_init(struct eeepc_laptop *eeepc) eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); - /* - * Refresh pci hotplug in case the rfkill state was changed during - * setup. - */ - eeepc_rfkill_hotplug(eeepc); exit: if (result && result != -ENODEV) @@ -928,8 +950,11 @@ static int eeepc_hotk_restore(struct device *device) struct eeepc_laptop *eeepc = dev_get_drvdata(device); /* Refresh both wlan rfkill state and pci hotplug */ - if (eeepc->wlan_rfkill) - eeepc_rfkill_hotplug(eeepc); + if (eeepc->wlan_rfkill) { + eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P5"); + eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P6"); + eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P7"); + } if (eeepc->bluetooth_rfkill) rfkill_set_sw_state(eeepc->bluetooth_rfkill, diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 8f709aec4da0..6fe8cd6e23b5 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -934,6 +934,14 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, /* * Backlight device */ +struct sony_backlight_props { + struct backlight_device *dev; + int handle; + u8 offset; + u8 maxlvl; +}; +struct sony_backlight_props sony_bl_props; + static int sony_backlight_update_status(struct backlight_device *bd) { return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", @@ -954,21 +962,26 @@ static int sony_nc_get_brightness_ng(struct backlight_device *bd) { int result; int *handle = (int *)bl_get_data(bd); + struct sony_backlight_props *sdev = + (struct sony_backlight_props *)bl_get_data(bd); - sony_call_snc_handle(*handle, 0x0200, &result); + sony_call_snc_handle(sdev->handle, 0x0200, &result); - return result & 0xff; + return (result & 0xff) - sdev->offset; } static int sony_nc_update_status_ng(struct backlight_device *bd) { int value, result; int *handle = (int *)bl_get_data(bd); + struct sony_backlight_props *sdev = + (struct sony_backlight_props *)bl_get_data(bd); - value = bd->props.brightness; - sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result); + value = bd->props.brightness + sdev->offset; + if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result)) + return -EIO; - return sony_nc_get_brightness_ng(bd); + return value; } static const struct backlight_ops sony_backlight_ops = { @@ -981,8 +994,6 @@ static const struct backlight_ops sony_backlight_ng_ops = { .update_status = sony_nc_update_status_ng, .get_brightness = sony_nc_get_brightness_ng, }; -static int backlight_ng_handle; -static struct backlight_device *sony_backlight_device; /* * New SNC-only Vaios event mapping to driver known keys @@ -1549,6 +1560,75 @@ static void sony_nc_kbd_backlight_resume(void) &ignore); } +static void sony_nc_backlight_ng_read_limits(int handle, + struct sony_backlight_props *props) +{ + int offset; + acpi_status status; + u8 brlvl, i; + u8 min = 0xff, max = 0x00; + struct acpi_object_list params; + union acpi_object in_obj; + union acpi_object *lvl_enum; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + props->handle = handle; + props->offset = 0; + props->maxlvl = 0xff; + + offset = sony_find_snc_handle(handle); + if (offset < 0) + return; + + /* try to read the boundaries from ACPI tables, if we fail the above + * defaults should be reasonable + */ + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = offset; + status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms, + &buffer); + if (ACPI_FAILURE(status)) + return; + + lvl_enum = (union acpi_object *) buffer.pointer; + if (!lvl_enum) { + pr_err("No SN06 return object."); + return; + } + if (lvl_enum->type != ACPI_TYPE_BUFFER) { + pr_err("Invalid SN06 return object 0x%.2x\n", + lvl_enum->type); + goto out_invalid; + } + + /* the buffer lists brightness levels available, brightness levels are + * from 0 to 8 in the array, other values are used by ALS control. + */ + for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) { + + brlvl = *(lvl_enum->buffer.pointer + i); + dprintk("Brightness level: %d\n", brlvl); + + if (!brlvl) + break; + + if (brlvl > max) + max = brlvl; + if (brlvl < min) + min = brlvl; + } + props->offset = min; + props->maxlvl = max; + dprintk("Brightness levels: min=%d max=%d\n", props->offset, + props->maxlvl); + +out_invalid: + kfree(buffer.pointer); + return; +} + static void sony_nc_backlight_setup(void) { acpi_handle unused; @@ -1557,14 +1637,14 @@ static void sony_nc_backlight_setup(void) struct backlight_properties props; if (sony_find_snc_handle(0x12f) != -1) { - backlight_ng_handle = 0x12f; ops = &sony_backlight_ng_ops; - max_brightness = 0xff; + sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props); + max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; } else if (sony_find_snc_handle(0x137) != -1) { - backlight_ng_handle = 0x137; ops = &sony_backlight_ng_ops; - max_brightness = 0xff; + sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props); + max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &unused))) { @@ -1577,22 +1657,22 @@ static void sony_nc_backlight_setup(void) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_PLATFORM; props.max_brightness = max_brightness; - sony_backlight_device = backlight_device_register("sony", NULL, - &backlight_ng_handle, - ops, &props); + sony_bl_props.dev = backlight_device_register("sony", NULL, + &sony_bl_props, + ops, &props); - if (IS_ERR(sony_backlight_device)) { - pr_warning(DRV_PFX "unable to register backlight device\n"); - sony_backlight_device = NULL; + if (IS_ERR(sony_bl_props.dev)) { + pr_warn(DRV_PFX "unable to register backlight device\n"); + sony_bl_props.dev = NULL; } else - sony_backlight_device->props.brightness = - ops->get_brightness(sony_backlight_device); + sony_bl_props.dev->props.brightness = + ops->get_brightness(sony_bl_props.dev); } static void sony_nc_backlight_cleanup(void) { - if (sony_backlight_device) - backlight_device_unregister(sony_backlight_device); + if (sony_bl_props.dev) + backlight_device_unregister(sony_bl_props.dev); } static int sony_nc_add(struct acpi_device *device) @@ -2590,7 +2670,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, mutex_lock(&spic_dev.lock); switch (cmd) { case SONYPI_IOCGBRT: - if (sony_backlight_device == NULL) { + if (sony_bl_props.dev == NULL) { ret = -EIO; break; } @@ -2603,7 +2683,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, ret = -EFAULT; break; case SONYPI_IOCSBRT: - if (sony_backlight_device == NULL) { + if (sony_bl_props.dev == NULL) { ret = -EIO; break; } @@ -2617,8 +2697,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, break; } /* sync the backlight device status */ - sony_backlight_device->props.brightness = - sony_backlight_get_brightness(sony_backlight_device); + sony_bl_props.dev->props.brightness = + sony_backlight_get_brightness(sony_bl_props.dev); break; case SONYPI_IOCGBAT1CAP: if (ec_read16(SONYPI_BAT1_FULL, &val16)) { diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index efb3b6b9bcdb..562fcf0dd2b5 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -128,7 +128,8 @@ enum { }; /* ACPI HIDs */ -#define TPACPI_ACPI_HKEY_HID "IBM0068" +#define TPACPI_ACPI_IBM_HKEY_HID "IBM0068" +#define TPACPI_ACPI_LENOVO_HKEY_HID "LEN0068" #define TPACPI_ACPI_EC_HID "PNP0C09" /* Input IDs */ @@ -3879,7 +3880,8 @@ static int hotkey_write(char *buf) } static const struct acpi_device_id ibm_htk_device_ids[] = { - {TPACPI_ACPI_HKEY_HID, 0}, + {TPACPI_ACPI_IBM_HKEY_HID, 0}, + {TPACPI_ACPI_LENOVO_HKEY_HID, 0}, {"", 0}, }; diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c index ac2701b22e71..043ee3136e40 100644 --- a/drivers/rapidio/switches/idt_gen2.c +++ b/drivers/rapidio/switches/idt_gen2.c @@ -95,6 +95,9 @@ idtg2_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, else table++; + if (route_port == RIO_INVALID_ROUTE) + route_port = IDT_DEFAULT_ROUTE; + rio_mport_write_config_32(mport, destid, hopcount, LOCAL_RTE_CONF_DESTID_SEL, table); @@ -411,6 +414,12 @@ static int idtg2_switch_init(struct rio_dev *rdev, int do_enum) rdev->rswitch->em_handle = idtg2_em_handler; rdev->rswitch->sw_sysfs = idtg2_sysfs; + if (do_enum) { + /* Ensure that default routing is disabled on startup */ + rio_write_config_32(rdev, + RIO_STD_RTE_DEFAULT_PORT, IDT_NO_ROUTE); + } + return 0; } diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c index 3a971077e7bf..d06ee2d44b44 100644 --- a/drivers/rapidio/switches/idtcps.c +++ b/drivers/rapidio/switches/idtcps.c @@ -26,6 +26,9 @@ idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, { u32 result; + if (route_port == RIO_INVALID_ROUTE) + route_port = CPS_DEFAULT_ROUTE; + if (table == RIO_GLOBAL_TABLE) { rio_mport_write_config_32(mport, destid, hopcount, RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); @@ -130,6 +133,9 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum) /* set TVAL = ~50us */ rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); + /* Ensure that default routing is disabled on startup */ + rio_write_config_32(rdev, + RIO_STD_RTE_DEFAULT_PORT, CPS_NO_ROUTE); } return 0; diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c index 1a62934bfebc..db8b8028988d 100644 --- a/drivers/rapidio/switches/tsi57x.c +++ b/drivers/rapidio/switches/tsi57x.c @@ -303,6 +303,12 @@ static int tsi57x_switch_init(struct rio_dev *rdev, int do_enum) rdev->rswitch->em_init = tsi57x_em_init; rdev->rswitch->em_handle = tsi57x_em_handler; + if (do_enum) { + /* Ensure that default routing is disabled on startup */ + rio_write_config_32(rdev, RIO_STD_RTE_DEFAULT_PORT, + RIO_INVALID_ROUTE); + } + return 0; } diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e1878877399c..42891726ea72 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -3,10 +3,10 @@ # config RTC_LIB - tristate + bool menuconfig RTC_CLASS - tristate "Real Time Clock" + bool "Real Time Clock" default n depends on !S390 select RTC_LIB @@ -15,9 +15,6 @@ menuconfig RTC_CLASS be allowed to plug one or more RTCs to your system. You will probably want to enable one or more of the interfaces below. - This driver can also be built as a module. If so, the module - will be called rtc-core. - if RTC_CLASS config RTC_HCTOSYS diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 39013867cbd6..4194e59e14cd 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -41,26 +41,21 @@ static void rtc_device_release(struct device *dev) * system's wall clock; restore it on resume(). */ -static struct timespec delta; static time_t oldtime; +static struct timespec oldts; static int rtc_suspend(struct device *dev, pm_message_t mesg) { struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; - struct timespec ts = current_kernel_time(); if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; rtc_read_time(rtc, &tm); + ktime_get_ts(&oldts); rtc_tm_to_time(&tm, &oldtime); - /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */ - set_normalized_timespec(&delta, - ts.tv_sec - oldtime, - ts.tv_nsec - (NSEC_PER_SEC >> 1)); - return 0; } @@ -70,10 +65,12 @@ static int rtc_resume(struct device *dev) struct rtc_time tm; time_t newtime; struct timespec time; + struct timespec newts; if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; + ktime_get_ts(&newts); rtc_read_time(rtc, &tm); if (rtc_valid_tm(&tm) != 0) { pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); @@ -85,15 +82,13 @@ static int rtc_resume(struct device *dev) pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); return 0; } + /* calculate the RTC time delta */ + set_normalized_timespec(&time, newtime - oldtime, 0); - /* restore wall clock using delta against this RTC; - * adjust again for avg 1/2 second RTC sampling error - */ - set_normalized_timespec(&time, - newtime + delta.tv_sec, - (NSEC_PER_SEC >> 1) + delta.tv_nsec); - do_settimeofday(&time); + /* subtract kernel time between rtc_suspend to rtc_resume */ + time = timespec_sub(time, timespec_sub(newts, oldts)); + timekeeping_inject_sleeptime(&time); return 0; } diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 316f484999b5..80f9c88214c5 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -220,6 +220,7 @@ static int __init coh901331_probe(struct platform_device *pdev) } clk_disable(rtap->clk); + platform_set_drvdata(pdev, rtap); rtap->rtc = rtc_device_register("coh901331", &pdev->dev, &coh901331_ops, THIS_MODULE); if (IS_ERR(rtap->rtc)) { @@ -227,11 +228,10 @@ static int __init coh901331_probe(struct platform_device *pdev) goto out_no_rtc; } - platform_set_drvdata(pdev, rtap); - return 0; out_no_rtc: + platform_set_drvdata(pdev, NULL); out_no_clk_enable: clk_put(rtap->clk); out_no_clk: diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index 8d46838dff8a..755e1fe914af 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -524,6 +524,8 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) goto fail2; } + platform_set_drvdata(pdev, davinci_rtc); + davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &davinci_rtc_ops, THIS_MODULE); if (IS_ERR(davinci_rtc->rtc)) { @@ -553,8 +555,6 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) rtcss_write(davinci_rtc, PRTCSS_RTC_CCTRL_CAEN, PRTCSS_RTC_CCTRL); - platform_set_drvdata(pdev, davinci_rtc); - device_init_wakeup(&pdev->dev, 0); return 0; @@ -562,6 +562,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) fail4: rtc_device_unregister(davinci_rtc->rtc); fail3: + platform_set_drvdata(pdev, NULL); iounmap(davinci_rtc->base); fail2: release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c index 60ce69600828..47e681df31e2 100644 --- a/drivers/rtc/rtc-ds1286.c +++ b/drivers/rtc/rtc-ds1286.c @@ -355,6 +355,7 @@ static int __devinit ds1286_probe(struct platform_device *pdev) goto out; } spin_lock_init(&priv->lock); + platform_set_drvdata(pdev, priv); rtc = rtc_device_register("ds1286", &pdev->dev, &ds1286_ops, THIS_MODULE); if (IS_ERR(rtc)) { @@ -362,7 +363,6 @@ static int __devinit ds1286_probe(struct platform_device *pdev) goto out; } priv->rtc = rtc; - platform_set_drvdata(pdev, priv); return 0; out: diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 11ae64dcbf3c..335551d333b2 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -151,6 +151,7 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) return -ENXIO; pdev->dev.platform_data = ep93xx_rtc; + platform_set_drvdata(pdev, rtc); rtc = rtc_device_register(pdev->name, &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE); @@ -159,8 +160,6 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) goto exit; } - platform_set_drvdata(pdev, rtc); - err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files); if (err) goto fail; @@ -168,9 +167,9 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) return 0; fail: - platform_set_drvdata(pdev, NULL); rtc_device_unregister(rtc); exit: + platform_set_drvdata(pdev, NULL); pdev->dev.platform_data = NULL; return err; } diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 69fe664a2228..eda128fc1d38 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -783,6 +783,9 @@ static int m41t80_probe(struct i2c_client *client, goto exit; } + clientdata->features = id->driver_data; + i2c_set_clientdata(client, clientdata); + rtc = rtc_device_register(client->name, &client->dev, &m41t80_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { @@ -792,8 +795,6 @@ static int m41t80_probe(struct i2c_client *client, } clientdata->rtc = rtc; - clientdata->features = id->driver_data; - i2c_set_clientdata(client, clientdata); /* Make sure HT (Halt Update) bit is cleared */ rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR); diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 174036dda786..3bc046f427e0 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -257,6 +257,10 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) goto out_irq; } + dev_set_drvdata(&pdev->dev, info); + /* XXX - isn't this redundant? */ + platform_set_drvdata(pdev, info); + info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev, &max8925_rtc_ops, THIS_MODULE); ret = PTR_ERR(info->rtc_dev); @@ -265,11 +269,9 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) goto out_rtc; } - dev_set_drvdata(&pdev->dev, info); - platform_set_drvdata(pdev, info); - return 0; out_rtc: + platform_set_drvdata(pdev, NULL); free_irq(chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info); out_irq: kfree(info); diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index 3f7bc6b9fefa..2e48aa604273 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c @@ -265,6 +265,8 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) info->rtc = max8998->rtc; info->irq = max8998->irq_base + MAX8998_IRQ_ALARM0; + platform_set_drvdata(pdev, info); + info->rtc_dev = rtc_device_register("max8998-rtc", &pdev->dev, &max8998_rtc_ops, THIS_MODULE); @@ -274,8 +276,6 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) goto out_rtc; } - platform_set_drvdata(pdev, info); - ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0, "rtc-alarm0", info); @@ -293,6 +293,7 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) return 0; out_rtc: + platform_set_drvdata(pdev, NULL); kfree(info); return ret; } diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index c5ac03793e79..a1a278bc340d 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c @@ -349,11 +349,15 @@ static int __devinit mc13xxx_rtc_probe(struct platform_device *pdev) if (ret) goto err_alarm_irq_request; + mc13xxx_unlock(mc13xxx); + priv->rtc = rtc_device_register(pdev->name, &pdev->dev, &mc13xxx_rtc_ops, THIS_MODULE); if (IS_ERR(priv->rtc)) { ret = PTR_ERR(priv->rtc); + mc13xxx_lock(mc13xxx); + mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv); err_alarm_irq_request: @@ -365,12 +369,12 @@ static int __devinit mc13xxx_rtc_probe(struct platform_device *pdev) mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv); err_reset_irq_request: + mc13xxx_unlock(mc13xxx); + platform_set_drvdata(pdev, NULL); kfree(priv); } - mc13xxx_unlock(mc13xxx); - return ret; } diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c index 67820626e18f..fcb113c11122 100644 --- a/drivers/rtc/rtc-msm6242.c +++ b/drivers/rtc/rtc-msm6242.c @@ -214,6 +214,7 @@ static int __init msm6242_rtc_probe(struct platform_device *dev) error = -ENOMEM; goto out_free_priv; } + platform_set_drvdata(dev, priv); rtc = rtc_device_register("rtc-msm6242", &dev->dev, &msm6242_rtc_ops, THIS_MODULE); @@ -223,10 +224,10 @@ static int __init msm6242_rtc_probe(struct platform_device *dev) } priv->rtc = rtc; - platform_set_drvdata(dev, priv); return 0; out_unmap: + platform_set_drvdata(dev, NULL); iounmap(priv->regs); out_free_priv: kfree(priv); diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 826ab64a8fa9..d814417bee8c 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -418,14 +418,6 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) goto exit_put_clk; } - rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, - THIS_MODULE); - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); - goto exit_put_clk; - } - - pdata->rtc = rtc; platform_set_drvdata(pdev, pdata); /* Configure and enable the RTC */ @@ -438,8 +430,19 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) pdata->irq = -1; } + rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto exit_clr_drvdata; + } + + pdata->rtc = rtc; + return 0; +exit_clr_drvdata: + platform_set_drvdata(pdev, NULL); exit_put_clk: clk_disable(pdata->clk); clk_put(pdata->clk); diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index de0dd7b1f146..bcae8dd41496 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -394,7 +394,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) return 0; fail2: - free_irq(omap_rtc_timer, NULL); + free_irq(omap_rtc_timer, rtc); fail1: rtc_device_unregister(rtc); fail0: diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c index a633abc42896..cd4f198cc2ef 100644 --- a/drivers/rtc/rtc-pcap.c +++ b/drivers/rtc/rtc-pcap.c @@ -151,6 +151,8 @@ static int __devinit pcap_rtc_probe(struct platform_device *pdev) pcap_rtc->pcap = dev_get_drvdata(pdev->dev.parent); + platform_set_drvdata(pdev, pcap_rtc); + pcap_rtc->rtc = rtc_device_register("pcap", &pdev->dev, &pcap_rtc_ops, THIS_MODULE); if (IS_ERR(pcap_rtc->rtc)) { @@ -158,7 +160,6 @@ static int __devinit pcap_rtc_probe(struct platform_device *pdev) goto fail_rtc; } - platform_set_drvdata(pdev, pcap_rtc); timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ); alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA); @@ -177,6 +178,7 @@ static int __devinit pcap_rtc_probe(struct platform_device *pdev) fail_timer: rtc_device_unregister(pcap_rtc->rtc); fail_rtc: + platform_set_drvdata(pdev, NULL); kfree(pcap_rtc); return err; } diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index 694da39b6dd2..359da6d020b9 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c @@ -249,15 +249,15 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) spin_lock_init(&priv->lock); + platform_set_drvdata(dev, priv); + rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { error = PTR_ERR(rtc); goto out_unmap; } - priv->rtc = rtc; - platform_set_drvdata(dev, priv); error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr); if (error) @@ -268,6 +268,7 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) out_unregister: rtc_device_unregister(rtc); out_unmap: + platform_set_drvdata(dev, NULL); iounmap(priv->regs); out_free_priv: kfree(priv); diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index b3466c491cd3..16512ecae31a 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -46,6 +46,7 @@ static struct clk *rtc_clk; static void __iomem *s3c_rtc_base; static int s3c_rtc_alarmno = NO_IRQ; static int s3c_rtc_tickno = NO_IRQ; +static bool wake_en; static enum s3c_cpu_type s3c_rtc_cpu_type; static DEFINE_SPINLOCK(s3c_rtc_pie_lock); @@ -562,8 +563,12 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) } s3c_rtc_enable(pdev, 0); - if (device_may_wakeup(&pdev->dev)) - enable_irq_wake(s3c_rtc_alarmno); + if (device_may_wakeup(&pdev->dev) && !wake_en) { + if (enable_irq_wake(s3c_rtc_alarmno) == 0) + wake_en = true; + else + dev_err(&pdev->dev, "enable_irq_wake failed\n"); + } return 0; } @@ -579,8 +584,10 @@ static int s3c_rtc_resume(struct platform_device *pdev) writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); } - if (device_may_wakeup(&pdev->dev)) + if (device_may_wakeup(&pdev->dev) && wake_en) { disable_irq_wake(s3c_rtc_alarmno); + wake_en = false; + } return 0; } diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4d2df2f76ea0..86b6f1cc1b10 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1742,11 +1742,20 @@ int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr) static inline int _dasd_term_running_cqr(struct dasd_device *device) { struct dasd_ccw_req *cqr; + int rc; if (list_empty(&device->ccw_queue)) return 0; cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); - return device->discipline->term_IO(cqr); + rc = device->discipline->term_IO(cqr); + if (!rc) + /* + * CQR terminated because a more important request is pending. + * Undo decreasing of retry counter because this is + * not an error case. + */ + cqr->retries++; + return rc; } int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) @@ -2314,15 +2323,14 @@ static void dasd_flush_request_queue(struct dasd_block *block) static int dasd_open(struct block_device *bdev, fmode_t mode) { - struct dasd_block *block = bdev->bd_disk->private_data; struct dasd_device *base; int rc; - if (!block) + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) return -ENODEV; - base = block->base; - atomic_inc(&block->open_count); + atomic_inc(&base->block->open_count); if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { rc = -ENODEV; goto unlock; @@ -2355,21 +2363,28 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) goto out; } + dasd_put_device(base); return 0; out: module_put(base->discipline->owner); unlock: - atomic_dec(&block->open_count); + atomic_dec(&base->block->open_count); + dasd_put_device(base); return rc; } static int dasd_release(struct gendisk *disk, fmode_t mode) { - struct dasd_block *block = disk->private_data; + struct dasd_device *base; - atomic_dec(&block->open_count); - module_put(block->base->discipline->owner); + base = dasd_device_from_gendisk(disk); + if (!base) + return -ENODEV; + + atomic_dec(&base->block->open_count); + module_put(base->discipline->owner); + dasd_put_device(base); return 0; } @@ -2378,20 +2393,20 @@ static int dasd_release(struct gendisk *disk, fmode_t mode) */ static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct dasd_block *block; struct dasd_device *base; - block = bdev->bd_disk->private_data; - if (!block) + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) return -ENODEV; - base = block->base; if (!base->discipline || - !base->discipline->fill_geometry) + !base->discipline->fill_geometry) { + dasd_put_device(base); return -EINVAL; - - base->discipline->fill_geometry(block, geo); - geo->start = get_start_sect(bdev) >> block->s2b_shift; + } + base->discipline->fill_geometry(base->block, geo); + geo->start = get_start_sect(bdev) >> base->block->s2b_shift; + dasd_put_device(base); return 0; } @@ -2528,7 +2543,6 @@ void dasd_generic_remove(struct ccw_device *cdev) dasd_set_target_state(device, DASD_STATE_NEW); /* dasd_delete_device destroys the device reference. */ block = device->block; - device->block = NULL; dasd_delete_device(device); /* * life cycle of block is bound to device, so delete it after @@ -2650,7 +2664,6 @@ int dasd_generic_set_offline(struct ccw_device *cdev) dasd_set_target_state(device, DASD_STATE_NEW); /* dasd_delete_device destroys the device reference. */ block = device->block; - device->block = NULL; dasd_delete_device(device); /* * life cycle of block is bound to device, so delete it after diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 42e1bf35f689..d71511c7850a 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -674,6 +674,36 @@ dasd_device_from_cdev(struct ccw_device *cdev) return device; } +void dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device) +{ + struct dasd_devmap *devmap; + + devmap = dasd_find_busid(dev_name(&device->cdev->dev)); + if (IS_ERR(devmap)) + return; + spin_lock(&dasd_devmap_lock); + gdp->private_data = devmap; + spin_unlock(&dasd_devmap_lock); +} + +struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp) +{ + struct dasd_device *device; + struct dasd_devmap *devmap; + + if (!gdp->private_data) + return NULL; + device = NULL; + spin_lock(&dasd_devmap_lock); + devmap = gdp->private_data; + if (devmap && devmap->device) { + device = devmap->device; + dasd_get_device(device); + } + spin_unlock(&dasd_devmap_lock); + return device; +} + /* * SECTION: files in sysfs */ diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 29143eda9dd9..85dddb1e4126 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -239,7 +239,6 @@ static void dasd_ext_handler(unsigned int ext_int_code, addr_t ip; int rc; - kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++; switch (ext_int_code >> 24) { case DASD_DIAG_CODE_31BIT: ip = (addr_t) param32; @@ -250,6 +249,7 @@ static void dasd_ext_handler(unsigned int ext_int_code, default: return; } + kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++; if (!ip) { /* no intparm: unsolicited interrupt */ DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited " "interrupt"); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index db8005d9f2fd..3ebdf5f92f8f 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2037,7 +2037,7 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device, return; /* summary unit check */ - if ((sense[7] == 0x0D) && + if ((sense[27] & DASD_SENSE_BIT_0) && (sense[7] == 0x0D) && (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) { dasd_alias_handle_summary_unit_check(device, irb); return; @@ -2053,7 +2053,8 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device, /* loss of device reservation is handled via base devices only * as alias devices may be used with several bases */ - if (device->block && (sense[7] == 0x3F) && + if (device->block && (sense[27] & DASD_SENSE_BIT_0) && + (sense[7] == 0x3F) && (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) { if (device->features & DASD_FEATURE_FAILONSLCK) diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 5505bc07e1e7..19a1ff03d65e 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -73,7 +73,7 @@ int dasd_gendisk_alloc(struct dasd_block *block) if (base->features & DASD_FEATURE_READONLY || test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) set_disk_ro(gdp, 1); - gdp->private_data = block; + dasd_add_link_to_gendisk(gdp, base); gdp->queue = block->request_queue; block->gdp = gdp; set_capacity(block->gdp, 0); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index df9f6999411d..d1e4f2c1264c 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -686,6 +686,9 @@ struct dasd_device *dasd_device_from_cdev(struct ccw_device *); struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *); struct dasd_device *dasd_device_from_devindex(int); +void dasd_add_link_to_gendisk(struct gendisk *, struct dasd_device *); +struct dasd_device *dasd_device_from_gendisk(struct gendisk *); + int dasd_parse(void); int dasd_busid_known(const char *); diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 26075e95b1ba..72261e4c516d 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -42,16 +42,22 @@ dasd_ioctl_api_version(void __user *argp) static int dasd_ioctl_enable(struct block_device *bdev) { - struct dasd_block *block = bdev->bd_disk->private_data; + struct dasd_device *base; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - dasd_enable_device(block->base); + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + + dasd_enable_device(base); /* Formatting the dasd device can change the capacity. */ mutex_lock(&bdev->bd_mutex); - i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9); + i_size_write(bdev->bd_inode, + (loff_t)get_capacity(base->block->gdp) << 9); mutex_unlock(&bdev->bd_mutex); + dasd_put_device(base); return 0; } @@ -62,11 +68,14 @@ dasd_ioctl_enable(struct block_device *bdev) static int dasd_ioctl_disable(struct block_device *bdev) { - struct dasd_block *block = bdev->bd_disk->private_data; + struct dasd_device *base; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; /* * Man this is sick. We don't do a real disable but only downgrade * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses @@ -75,7 +84,7 @@ dasd_ioctl_disable(struct block_device *bdev) * using the BIODASDFMT ioctl. Therefore the correct state for the * device is DASD_STATE_BASIC that allows to do basic i/o. */ - dasd_set_target_state(block->base, DASD_STATE_BASIC); + dasd_set_target_state(base, DASD_STATE_BASIC); /* * Set i_size to zero, since read, write, etc. check against this * value. @@ -83,6 +92,7 @@ dasd_ioctl_disable(struct block_device *bdev) mutex_lock(&bdev->bd_mutex); i_size_write(bdev->bd_inode, 0); mutex_unlock(&bdev->bd_mutex); + dasd_put_device(base); return 0; } @@ -191,26 +201,36 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) static int dasd_ioctl_format(struct block_device *bdev, void __user *argp) { - struct dasd_block *block = bdev->bd_disk->private_data; + struct dasd_device *base; struct format_data_t fdata; + int rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!argp) return -EINVAL; - - if (block->base->features & DASD_FEATURE_READONLY || - test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + if (base->features & DASD_FEATURE_READONLY || + test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { + dasd_put_device(base); return -EROFS; - if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) + } + if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) { + dasd_put_device(base); return -EFAULT; + } if (bdev != bdev->bd_contains) { pr_warning("%s: The specified DASD is a partition and cannot " "be formatted\n", - dev_name(&block->base->cdev->dev)); + dev_name(&base->cdev->dev)); + dasd_put_device(base); return -EINVAL; } - return dasd_format(block, &fdata); + rc = dasd_format(base->block, &fdata); + dasd_put_device(base); + return rc; } #ifdef CONFIG_DASD_PROFILE @@ -340,8 +360,8 @@ static int dasd_ioctl_information(struct dasd_block *block, static int dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) { - struct dasd_block *block = bdev->bd_disk->private_data; - int intval; + struct dasd_device *base; + int intval, rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -350,10 +370,17 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) return -EINVAL; if (get_user(intval, (int __user *)argp)) return -EFAULT; - if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { + dasd_put_device(base); return -EROFS; + } set_disk_ro(bdev->bd_disk, intval); - return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval); + rc = dasd_set_feature(base->cdev, DASD_FEATURE_READONLY, intval); + dasd_put_device(base); + return rc; } static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, @@ -372,59 +399,78 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, int dasd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct dasd_block *block = bdev->bd_disk->private_data; + struct dasd_block *block; + struct dasd_device *base; void __user *argp; + int rc; if (is_compat_task()) argp = compat_ptr(arg); else argp = (void __user *)arg; - if (!block) - return -ENODEV; - if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) { PRINT_DEBUG("empty data ptr"); return -EINVAL; } + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + block = base->block; + rc = 0; switch (cmd) { case BIODASDDISABLE: - return dasd_ioctl_disable(bdev); + rc = dasd_ioctl_disable(bdev); + break; case BIODASDENABLE: - return dasd_ioctl_enable(bdev); + rc = dasd_ioctl_enable(bdev); + break; case BIODASDQUIESCE: - return dasd_ioctl_quiesce(block); + rc = dasd_ioctl_quiesce(block); + break; case BIODASDRESUME: - return dasd_ioctl_resume(block); + rc = dasd_ioctl_resume(block); + break; case BIODASDFMT: - return dasd_ioctl_format(bdev, argp); + rc = dasd_ioctl_format(bdev, argp); + break; case BIODASDINFO: - return dasd_ioctl_information(block, cmd, argp); + rc = dasd_ioctl_information(block, cmd, argp); + break; case BIODASDINFO2: - return dasd_ioctl_information(block, cmd, argp); + rc = dasd_ioctl_information(block, cmd, argp); + break; case BIODASDPRRD: - return dasd_ioctl_read_profile(block, argp); + rc = dasd_ioctl_read_profile(block, argp); + break; case BIODASDPRRST: - return dasd_ioctl_reset_profile(block); + rc = dasd_ioctl_reset_profile(block); + break; case BLKROSET: - return dasd_ioctl_set_ro(bdev, argp); + rc = dasd_ioctl_set_ro(bdev, argp); + break; case DASDAPIVER: - return dasd_ioctl_api_version(argp); + rc = dasd_ioctl_api_version(argp); + break; case BIODASDCMFENABLE: - return enable_cmf(block->base->cdev); + rc = enable_cmf(base->cdev); + break; case BIODASDCMFDISABLE: - return disable_cmf(block->base->cdev); + rc = disable_cmf(base->cdev); + break; case BIODASDREADALLCMB: - return dasd_ioctl_readall_cmb(block, cmd, argp); + rc = dasd_ioctl_readall_cmb(block, cmd, argp); + break; default: /* if the discipline has an ioctl method try it. */ - if (block->base->discipline->ioctl) { - int rval = block->base->discipline->ioctl(block, cmd, argp); - if (rval != -ENOIOCTLCMD) - return rval; - } - - return -EINVAL; + if (base->discipline->ioctl) { + rc = base->discipline->ioctl(block, cmd, argp); + if (rc == -ENOIOCTLCMD) + rc = -EINVAL; + } else + rc = -EINVAL; } + dasd_put_device(base); + return rc; } diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 4b60ede07f0e..be55fb2b1b1c 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -518,6 +518,8 @@ static void __init insert_increment(u16 rn, int standby, int assigned) return; new_incr->rn = rn; new_incr->standby = standby; + if (!standby) + new_incr->usecount = 1; last_rn = 0; prev = &sclp_mem_list; list_for_each_entry(incr, &sclp_mem_list, list) { diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 83cea9a55e2f..1b3924c2fffd 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -236,7 +236,6 @@ tapeblock_setup_device(struct tape_device * device) disk->major = tapeblock_major; disk->first_minor = device->first_minor; disk->fops = &tapeblock_fops; - disk->events = DISK_EVENT_MEDIA_CHANGE; disk->private_data = tape_get_device(device); disk->queue = blkdat->request_queue; set_capacity(disk, 0); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index c532ba929ccd..e8f267eb8887 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -407,8 +407,11 @@ static inline void account_sbals(struct qdio_q *q, int count) q->q_stats.nr_sbals[pos]++; } -static void announce_buffer_error(struct qdio_q *q, int count) +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; /* special handling for no target buffer empty */ @@ -426,6 +429,12 @@ static void announce_buffer_error(struct qdio_q *q, int count) DBF_ERROR("F14:%2x F15:%2x", q->sbal[q->first_to_check]->element[14].flags & 0xff, q->sbal[q->first_to_check]->element[15].flags & 0xff); + + /* + * Interrupts may be avoided as long as the error is present + * so change the buffer state immediately to avoid starvation. + */ + set_buf_states(q, q->first_to_check, state, count); } static inline void inbound_primed(struct qdio_q *q, int count) @@ -506,8 +515,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) account_sbals(q, count); break; case SLSB_P_INPUT_ERROR: - announce_buffer_error(q, count); - /* process the buffer, the upper layer will take care of it */ + process_buffer_error(q, count); q->first_to_check = add_buf(q->first_to_check, count); atomic_sub(count, &q->nr_buf_used); if (q->irq_ptr->perf_stat_enabled) @@ -677,8 +685,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) account_sbals(q, count); break; case SLSB_P_OUTPUT_ERROR: - announce_buffer_error(q, count); - /* process the buffer, the upper layer will take care of it */ + process_buffer_error(q, count); q->first_to_check = add_buf(q->first_to_check, count); atomic_sub(count, &q->nr_buf_used); if (q->irq_ptr->perf_stat_enabled) diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 414427d64a8f..607998f0b7d8 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -381,10 +381,10 @@ static void kvm_extint_handler(unsigned int ext_int_code, u16 subcode; u32 param; - kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; subcode = ext_int_code >> 16; if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) return; + kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; /* The LSB might be overloaded, we have to mask it */ vq = (struct virtqueue *)(param64 & ~1UL); diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index da8aa75bb20b..f1fa2483ae6b 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -845,12 +845,10 @@ claw_irq_tasklet ( unsigned long data ) { struct chbk * p_ch; struct net_device *dev; - struct claw_privbk * privptr; p_ch = (struct chbk *) data; dev = (struct net_device *)p_ch->ndev; CLAW_DBF_TEXT(4, trace, "IRQtask"); - privptr = (struct claw_privbk *)dev->ml_priv; unpack_read(dev); clear_bit(CLAW_BH_ACTIVE, (void *)&p_ch->flag_a); CLAW_DBF_TEXT(4, trace, "TskletXt"); @@ -1026,7 +1024,6 @@ claw_write_next ( struct chbk * p_ch ) struct net_device *dev; struct claw_privbk *privptr=NULL; struct sk_buff *pk_skb; - int rc; CLAW_DBF_TEXT(4, trace, "claw_wrt"); if (p_ch->claw_state == CLAW_STOP) @@ -1038,7 +1035,7 @@ claw_write_next ( struct chbk * p_ch ) !skb_queue_empty(&p_ch->collect_queue)) { pk_skb = claw_pack_skb(privptr); while (pk_skb != NULL) { - rc = claw_hw_tx( pk_skb, dev,1); + claw_hw_tx(pk_skb, dev, 1); if (privptr->write_free_count > 0) { pk_skb = claw_pack_skb(privptr); } else @@ -1322,15 +1319,12 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid) unsigned char *pDataAddress; struct endccw *pEnd; struct ccw1 tempCCW; - struct chbk *p_ch; struct claw_env *p_env; - int lock; struct clawph *pk_head; struct chbk *ch; CLAW_DBF_TEXT(4, trace, "hw_tx"); privptr = (struct claw_privbk *)(dev->ml_priv); - p_ch = (struct chbk *)&privptr->channel[WRITE_CHANNEL]; p_env =privptr->p_env; claw_free_wrt_buf(dev); /* Clean up free chain if posible */ /* scan the write queue to free any completed write packets */ @@ -1511,12 +1505,6 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid) } /* endif (p_first_ccw!=NULL) */ dev_kfree_skb_any(skb); - if (linkid==0) { - lock=LOCK_NO; - } - else { - lock=LOCK_YES; - } claw_strt_out_IO(dev ); /* if write free count is zero , set NOBUFFER */ if (privptr->write_free_count==0) { @@ -2821,15 +2809,11 @@ claw_free_wrt_buf( struct net_device *dev ) { struct claw_privbk *privptr = (struct claw_privbk *)dev->ml_priv; - struct ccwbk*p_first_ccw; - struct ccwbk*p_last_ccw; struct ccwbk*p_this_ccw; struct ccwbk*p_next_ccw; CLAW_DBF_TEXT(4, trace, "freewrtb"); /* scan the write queue to free any completed write packets */ - p_first_ccw=NULL; - p_last_ccw=NULL; p_this_ccw=privptr->p_write_active_first; while ( (p_this_ccw!=NULL) && (p_this_ccw->header.flag!=CLAW_PENDING)) { @@ -3072,7 +3056,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev) { struct claw_privbk *priv; struct net_device *ndev; - int ret; + int ret = 0; CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev)); priv = dev_get_drvdata(&cgdev->dev); @@ -3095,7 +3079,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev) } ccw_device_set_offline(cgdev->cdev[1]); ccw_device_set_offline(cgdev->cdev[0]); - return 0; + return ret; } static void diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index c189296763a4..426787efc492 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -672,7 +672,6 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb) int ccw_idx; unsigned long hi; unsigned long saveflags = 0; /* avoids compiler warning */ - __u16 block_len; CTCM_PR_DEBUG("Enter %s: %s, cp=%i ch=0x%p id=%s state=%s\n", __func__, dev->name, smp_processor_id(), ch, @@ -719,7 +718,6 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb) */ atomic_inc(&skb->users); - block_len = skb->len + TH_HEADER_LENGTH + PDU_HEADER_LENGTH; /* * IDAL support in CTCM is broken, so we have to * care about skb's above 2G ourselves. diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c index b64881f33f23..da4c747335e7 100644 --- a/drivers/s390/net/ctcm_mpc.c +++ b/drivers/s390/net/ctcm_mpc.c @@ -653,7 +653,6 @@ static void ctcmpc_send_sweep_resp(struct channel *rch) struct net_device *dev = rch->netdev; struct ctcm_priv *priv = dev->ml_priv; struct mpc_group *grp = priv->mpcg; - int rc = 0; struct th_sweep *header; struct sk_buff *sweep_skb; struct channel *ch = priv->channel[CTCM_WRITE]; @@ -665,16 +664,14 @@ static void ctcmpc_send_sweep_resp(struct channel *rch) CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR, "%s(%s): sweep_skb allocation ERROR\n", CTCM_FUNTAIL, rch->id); - rc = -ENOMEM; - goto done; + goto done; } header = kmalloc(sizeof(struct th_sweep), gfp_type()); if (!header) { dev_kfree_skb_any(sweep_skb); - rc = -ENOMEM; - goto done; + goto done; } header->th.th_seg = 0x00 ; @@ -1370,8 +1367,7 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg) struct net_device *dev = arg; struct ctcm_priv *priv; struct mpc_group *grp; - int rc = 0; - struct channel *wch, *rch; + struct channel *wch; BUG_ON(dev == NULL); CTCM_PR_DEBUG("Enter %s: %s\n", __func__, dev->name); @@ -1396,7 +1392,6 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg) fsm_deltimer(&priv->restart_timer); wch = priv->channel[CTCM_WRITE]; - rch = priv->channel[CTCM_READ]; switch (grp->saved_state) { case MPCG_STATE_RESET: @@ -1435,7 +1430,7 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg) if (grp->send_qllc_disc == 1) { grp->send_qllc_disc = 0; - rc = mpc_send_qllc_discontact(dev); + mpc_send_qllc_discontact(dev); } /* DO NOT issue DEV_EVENT_STOP directly out of this code */ diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 49d1cfc3217e..c3b8064a102d 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1483,7 +1483,6 @@ lcs_tasklet(unsigned long data) struct lcs_channel *channel; struct lcs_buffer *iob; int buf_idx; - int rc; channel = (struct lcs_channel *) data; LCS_DBF_TEXT_(5, trace, "tlet%s", dev_name(&channel->ccwdev->dev)); @@ -1500,14 +1499,11 @@ lcs_tasklet(unsigned long data) channel->buf_idx = buf_idx; if (channel->state == LCS_CH_STATE_STOPPED) - // FIXME: what if rc != 0 ?? - rc = lcs_start_channel(channel); + lcs_start_channel(channel); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); if (channel->state == LCS_CH_STATE_SUSPENDED && - channel->iob[channel->io_idx].state == LCS_BUF_STATE_READY) { - // FIXME: what if rc != 0 ?? - rc = __lcs_resume_channel(channel); - } + channel->iob[channel->io_idx].state == LCS_BUF_STATE_READY) + __lcs_resume_channel(channel); spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); /* Something happened on the channel. Wake up waiters. */ diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index b6a6356d09b3..3251333a23df 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1994,8 +1994,6 @@ static struct net_device *netiucv_init_netdevice(char *username) netiucv_setup_netdevice); if (!dev) return NULL; - if (dev_alloc_name(dev, dev->name) < 0) - goto out_netdev; privptr = netdev_priv(dev); privptr->fsm = init_fsm("netiucvdev", dev_state_names, diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index af3f7b095647..55c6aa1c9704 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -407,12 +407,6 @@ struct qeth_qdio_q { int next_buf_to_init; } __attribute__ ((aligned(256))); -/* possible types of qeth large_send support */ -enum qeth_large_send_types { - QETH_LARGE_SEND_NO, - QETH_LARGE_SEND_TSO, -}; - struct qeth_qdio_out_buffer { struct qdio_buffer *buffer; atomic_t state; @@ -637,6 +631,8 @@ struct qeth_card_info { __u32 csum_mask; __u32 tx_csum_mask; enum qeth_ipa_promisc_modes promisc_mode; + __u32 diagass_support; + __u32 hwtrap; }; struct qeth_card_options { @@ -645,13 +641,11 @@ struct qeth_card_options { struct qeth_ipa_info adp; /*Adapter parameters*/ struct qeth_routing_info route6; struct qeth_ipa_info ipa6; - enum qeth_checksum_types checksum_type; int broadcast_mode; int macaddr_mode; int fake_broadcast; int add_hhlen; int layer2; - enum qeth_large_send_types large_send; int performance_stats; int rx_sg_cb; enum qeth_ipa_isolation_modes isolation; @@ -760,6 +754,14 @@ struct qeth_card_list_struct { rwlock_t rwlock; }; +struct qeth_trap_id { + __u16 lparnr; + char vmname[8]; + __u8 chpid; + __u8 ssid; + __u16 devno; +} __packed; + /*some helper functions*/ #define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "") @@ -794,6 +796,12 @@ static inline void qeth_put_buffer_pool_entry(struct qeth_card *card, list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list); } +static inline int qeth_is_diagass_supported(struct qeth_card *card, + enum qeth_diags_cmds cmd) +{ + return card->info.diagass_support & (__u32)cmd; +} + extern struct ccwgroup_driver qeth_l2_ccwgroup_driver; extern struct ccwgroup_driver qeth_l3_ccwgroup_driver; const char *qeth_get_cardname_short(struct qeth_card *); @@ -879,6 +887,8 @@ void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...); int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *); int qeth_set_access_ctrl_online(struct qeth_card *card); int qeth_hdr_chk_and_bounce(struct sk_buff *, int); +int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action); +int qeth_query_ipassists(struct qeth_card *, enum qeth_prot_versions prot); /* exports for OSN */ int qeth_osn_assist(struct net_device *, void *, int); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 85cc53117ea6..503678a30981 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -24,6 +24,7 @@ #include #include +#include #include "qeth_core.h" @@ -349,6 +350,8 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, card->info.chpid); netif_carrier_on(card->dev); card->lan_online = 1; + if (card->info.hwtrap) + card->info.hwtrap = 2; qeth_schedule_recovery(card); return NULL; case IPA_CMD_MODCCID: @@ -1039,7 +1042,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.checksum_type = QETH_CHECKSUM_DEFAULT; card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS; card->options.macaddr_mode = QETH_TR_MACADDR_NONCANONICAL; card->options.fake_broadcast = 0; @@ -2574,6 +2576,142 @@ int qeth_query_setadapterparms(struct qeth_card *card) } EXPORT_SYMBOL_GPL(qeth_query_setadapterparms); +static int qeth_query_ipassists_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) +{ + struct qeth_ipa_cmd *cmd; + + QETH_DBF_TEXT(SETUP, 2, "qipasscb"); + + cmd = (struct qeth_ipa_cmd *) data; + if (cmd->hdr.prot_version == QETH_PROT_IPV4) { + card->options.ipa4.supported_funcs = cmd->hdr.ipa_supported; + card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled; + } else { + card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported; + card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled; + } + QETH_DBF_TEXT(SETUP, 2, "suppenbl"); + QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_supported); + QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_enabled); + return 0; +} + +int qeth_query_ipassists(struct qeth_card *card, enum qeth_prot_versions prot) +{ + int rc; + struct qeth_cmd_buffer *iob; + + QETH_DBF_TEXT_(SETUP, 2, "qipassi%i", prot); + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_QIPASSIST, prot); + rc = qeth_send_ipa_cmd(card, iob, qeth_query_ipassists_cb, NULL); + return rc; +} +EXPORT_SYMBOL_GPL(qeth_query_ipassists); + +static int qeth_query_setdiagass_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) +{ + struct qeth_ipa_cmd *cmd; + __u16 rc; + + cmd = (struct qeth_ipa_cmd *)data; + rc = cmd->hdr.return_code; + if (rc) + QETH_CARD_TEXT_(card, 2, "diagq:%x", rc); + else + card->info.diagass_support = cmd->data.diagass.ext; + return 0; +} + +static int qeth_query_setdiagass(struct qeth_card *card) +{ + struct qeth_cmd_buffer *iob; + struct qeth_ipa_cmd *cmd; + + QETH_DBF_TEXT(SETUP, 2, "qdiagass"); + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.diagass.subcmd_len = 16; + cmd->data.diagass.subcmd = QETH_DIAGS_CMD_QUERY; + return qeth_send_ipa_cmd(card, iob, qeth_query_setdiagass_cb, NULL); +} + +static void qeth_get_trap_id(struct qeth_card *card, struct qeth_trap_id *tid) +{ + unsigned long info = get_zeroed_page(GFP_KERNEL); + struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info; + struct sysinfo_3_2_2 *info322 = (struct sysinfo_3_2_2 *)info; + struct ccw_dev_id ccwid; + int level, rc; + + tid->chpid = card->info.chpid; + ccw_device_get_id(CARD_RDEV(card), &ccwid); + tid->ssid = ccwid.ssid; + tid->devno = ccwid.devno; + if (!info) + return; + + rc = stsi(NULL, 0, 0, 0); + if (rc == -ENOSYS) + level = rc; + else + level = (((unsigned int) rc) >> 28); + + if ((level >= 2) && (stsi(info222, 2, 2, 2) != -ENOSYS)) + tid->lparnr = info222->lpar_number; + + if ((level >= 3) && (stsi(info322, 3, 2, 2) != -ENOSYS)) { + EBCASC(info322->vm[0].name, sizeof(info322->vm[0].name)); + memcpy(tid->vmname, info322->vm[0].name, sizeof(tid->vmname)); + } + free_page(info); + return; +} + +static int qeth_hw_trap_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) +{ + struct qeth_ipa_cmd *cmd; + __u16 rc; + + cmd = (struct qeth_ipa_cmd *)data; + rc = cmd->hdr.return_code; + if (rc) + QETH_CARD_TEXT_(card, 2, "trapc:%x", rc); + return 0; +} + +int qeth_hw_trap(struct qeth_card *card, enum qeth_diags_trap_action action) +{ + struct qeth_cmd_buffer *iob; + struct qeth_ipa_cmd *cmd; + + QETH_DBF_TEXT(SETUP, 2, "diagtrap"); + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.diagass.subcmd_len = 80; + cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRAP; + cmd->data.diagass.type = 1; + cmd->data.diagass.action = action; + switch (action) { + case QETH_DIAGS_TRAP_ARM: + cmd->data.diagass.options = 0x0003; + cmd->data.diagass.ext = 0x00010000 + + sizeof(struct qeth_trap_id); + qeth_get_trap_id(card, + (struct qeth_trap_id *)cmd->data.diagass.cdata); + break; + case QETH_DIAGS_TRAP_DISARM: + cmd->data.diagass.options = 0x0001; + break; + case QETH_DIAGS_TRAP_CAPTURE: + break; + } + return qeth_send_ipa_cmd(card, iob, qeth_hw_trap_cb, NULL); +} +EXPORT_SYMBOL_GPL(qeth_hw_trap); + int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf, unsigned int qdio_error, const char *dbftext) { @@ -3903,6 +4041,7 @@ MODULE_DEVICE_TABLE(ccw, qeth_ids); static struct ccw_driver qeth_ccw_driver = { .driver = { + .owner = THIS_MODULE, .name = "qeth", }, .ids = qeth_ids, @@ -3984,6 +4123,15 @@ int qeth_core_hardsetup_card(struct qeth_card *card) QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); goto out; } + + card->options.ipa4.supported_funcs = 0; + card->options.adp.supported_funcs = 0; + card->info.diagass_support = 0; + qeth_query_ipassists(card, QETH_PROT_IPV4); + if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) + qeth_query_setadapterparms(card); + if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) + qeth_query_setdiagass(card); return 0; out: dev_warn(&card->gdev->dev, "The qeth device driver failed to recover " diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 07d588867b57..e5a9d1c03839 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -80,14 +80,6 @@ enum qeth_tr_broadcast_modes { QETH_TR_BROADCAST_LOCAL = 1, }; -/* these values match CHECKSUM_* in include/linux/skbuff.h */ -enum qeth_checksum_types { - SW_CHECKSUMMING = 0, /* TODO: set to bit flag used in IPA Command */ - HW_CHECKSUMMING = 1, - NO_CHECKSUMMING = 2, -}; -#define QETH_CHECKSUM_DEFAULT SW_CHECKSUMMING - /* * Routing stuff */ @@ -456,6 +448,12 @@ enum qeth_diags_trace_cmds { QETH_DIAGS_CMD_TRACE_QUERY = 0x0010, }; +enum qeth_diags_trap_action { + QETH_DIAGS_TRAP_ARM = 0x01, + QETH_DIAGS_TRAP_DISARM = 0x02, + QETH_DIAGS_TRAP_CAPTURE = 0x04, +}; + struct qeth_ipacmd_diagass { __u32 host_tod2; __u32:32; @@ -465,7 +463,8 @@ struct qeth_ipacmd_diagass { __u8 type; __u8 action; __u16 options; - __u32:32; + __u32 ext; + __u8 cdata[64]; } __attribute__ ((packed)); /* Header for each IPA command */ diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index b5e967cf7e2d..0a8e86c1b0ea 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -530,6 +530,66 @@ static ssize_t qeth_dev_isolation_store(struct device *dev, static DEVICE_ATTR(isolation, 0644, qeth_dev_isolation_show, qeth_dev_isolation_store); +static ssize_t qeth_hw_trap_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.hwtrap) + return snprintf(buf, 5, "arm\n"); + else + return snprintf(buf, 8, "disarm\n"); +} + +static ssize_t qeth_hw_trap_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct qeth_card *card = dev_get_drvdata(dev); + int rc = 0; + char *tmp, *curtoken; + int state = 0; + curtoken = (char *)buf; + + if (!card) + return -EINVAL; + + mutex_lock(&card->conf_mutex); + if (card->state == CARD_STATE_SOFTSETUP || card->state == CARD_STATE_UP) + state = 1; + tmp = strsep(&curtoken, "\n"); + + if (!strcmp(tmp, "arm") && !card->info.hwtrap) { + if (state) { + if (qeth_is_diagass_supported(card, + QETH_DIAGS_CMD_TRAP)) { + rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM); + if (!rc) + card->info.hwtrap = 1; + } else + rc = -EINVAL; + } else + card->info.hwtrap = 1; + } else if (!strcmp(tmp, "disarm") && card->info.hwtrap) { + if (state) { + rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); + if (!rc) + card->info.hwtrap = 0; + } else + card->info.hwtrap = 0; + } else if (!strcmp(tmp, "trap") && state && card->info.hwtrap) + rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_CAPTURE); + else + rc = -EINVAL; + + mutex_unlock(&card->conf_mutex); + return rc ? rc : count; +} + +static DEVICE_ATTR(hw_trap, 0644, qeth_hw_trap_show, + qeth_hw_trap_store); + static ssize_t qeth_dev_blkt_show(char *buf, struct qeth_card *card, int value) { @@ -653,6 +713,7 @@ static struct attribute *qeth_device_attrs[] = { &dev_attr_performance_stats.attr, &dev_attr_layer2.attr, &dev_attr_isolation.attr, + &dev_attr_hw_trap.attr, NULL, }; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 6fbaacb21943..b70b47fbd6cd 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -420,10 +420,7 @@ static int qeth_l2_process_inbound_buffer(struct qeth_card *card, case QETH_HEADER_TYPE_LAYER2: skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, skb->dev); - if (card->options.checksum_type == NO_CHECKSUMMING) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb->ip_summed = CHECKSUM_NONE; + skb->ip_summed = CHECKSUM_NONE; if (skb->protocol == htons(ETH_P_802_2)) *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno; len = skb->len; @@ -879,6 +876,7 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev) INIT_LIST_HEAD(&card->vid_list); 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; @@ -997,6 +995,13 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) if (card->info.type != QETH_CARD_TYPE_OSN) qeth_l2_send_setmac(card, &card->dev->dev_addr[0]); + if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) { + if (card->info.hwtrap && + qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM)) + card->info.hwtrap = 0; + } else + card->info.hwtrap = 0; + card->state = CARD_STATE_HARDSETUP; memset(&card->rx, 0, sizeof(struct qeth_rx)); qeth_print_status_message(card); @@ -1095,6 +1100,10 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev, if (card->dev && netif_carrier_ok(card->dev)) netif_carrier_off(card->dev); recover_flag = card->state; + if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) { + qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); + card->info.hwtrap = 1; + } qeth_l2_stop_card(card, recovery_mode); rc = ccw_device_set_offline(CARD_DDEV(card)); rc2 = ccw_device_set_offline(CARD_WDEV(card)); @@ -1160,6 +1169,8 @@ static void __exit qeth_l2_exit(void) static void qeth_l2_shutdown(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if ((gdev->state == CCWGROUP_ONLINE) && card->info.hwtrap) + qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); qeth_qdio_clear_card(card, 0); qeth_clear_qdio_buffers(card); } @@ -1175,6 +1186,8 @@ static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev) if (gdev->state == CCWGROUP_OFFLINE) return 0; if (card->state == CARD_STATE_UP) { + if (card->info.hwtrap) + qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); __qeth_l2_set_offline(card->gdev, 1); } else __qeth_l2_set_offline(card->gdev, 0); diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index e705b27ec7dc..14a43aeb0c2a 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h @@ -62,8 +62,6 @@ void qeth_l3_del_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *); int qeth_l3_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *); void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions, const u8 *); -int qeth_l3_set_large_send(struct qeth_card *, enum qeth_large_send_types); -int qeth_l3_set_rx_csum(struct qeth_card *, enum qeth_checksum_types); int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *, struct qeth_ipaddr *); #endif /* __QETH_L3_H__ */ diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 142e5f6ef4f3..fd69da3fa6b4 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -43,33 +43,6 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *, static int __qeth_l3_set_online(struct ccwgroup_device *, int); static int __qeth_l3_set_offline(struct ccwgroup_device *, int); -int qeth_l3_set_large_send(struct qeth_card *card, - enum qeth_large_send_types type) -{ - int rc = 0; - - card->options.large_send = type; - if (card->dev == NULL) - return 0; - - if (card->options.large_send == QETH_LARGE_SEND_TSO) { - if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { - card->dev->features |= NETIF_F_TSO | NETIF_F_SG | - NETIF_F_IP_CSUM; - } else { - card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | - NETIF_F_IP_CSUM); - card->options.large_send = QETH_LARGE_SEND_NO; - rc = -EOPNOTSUPP; - } - } else { - card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | - NETIF_F_IP_CSUM); - card->options.large_send = QETH_LARGE_SEND_NO; - } - return rc; -} - static int qeth_l3_isxdigit(char *buf) { while (*buf) { @@ -1304,39 +1277,6 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card) return rc; } -static int qeth_l3_query_ipassists_cb(struct qeth_card *card, - struct qeth_reply *reply, unsigned long data) -{ - struct qeth_ipa_cmd *cmd; - - QETH_DBF_TEXT(SETUP, 2, "qipasscb"); - - cmd = (struct qeth_ipa_cmd *) data; - if (cmd->hdr.prot_version == QETH_PROT_IPV4) { - card->options.ipa4.supported_funcs = cmd->hdr.ipa_supported; - card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled; - } else { - card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported; - card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled; - } - QETH_DBF_TEXT(SETUP, 2, "suppenbl"); - QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_supported); - QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_enabled); - return 0; -} - -static int qeth_l3_query_ipassists(struct qeth_card *card, - enum qeth_prot_versions prot) -{ - int rc; - struct qeth_cmd_buffer *iob; - - QETH_DBF_TEXT_(SETUP, 2, "qipassi%i", prot); - iob = qeth_get_ipacmd_buffer(card, IPA_CMD_QIPASSIST, prot); - rc = qeth_send_ipa_cmd(card, iob, qeth_l3_query_ipassists_cb, NULL); - return rc; -} - #ifdef CONFIG_QETH_IPV6 static int qeth_l3_softsetup_ipv6(struct qeth_card *card) { @@ -1347,7 +1287,7 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card) if (card->info.type == QETH_CARD_TYPE_IQD) goto out; - rc = qeth_l3_query_ipassists(card, QETH_PROT_IPV6); + rc = qeth_query_ipassists(card, QETH_PROT_IPV6); if (rc) { dev_err(&card->gdev->dev, "Activating IPv6 support for %s failed\n", @@ -1472,68 +1412,38 @@ static int qeth_l3_send_checksum_command(struct qeth_card *card) return 0; } -int qeth_l3_set_rx_csum(struct qeth_card *card, - enum qeth_checksum_types csum_type) +int qeth_l3_set_rx_csum(struct qeth_card *card, int on) { int rc = 0; - if (card->options.checksum_type == HW_CHECKSUMMING) { - if ((csum_type != HW_CHECKSUMMING) && - (card->state != CARD_STATE_DOWN)) { - rc = qeth_l3_send_simple_setassparms(card, - IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0); - if (rc) - return -EIO; - } + if (on) { + rc = qeth_l3_send_checksum_command(card); + if (rc) + return -EIO; + dev_info(&card->gdev->dev, + "HW Checksumming (inbound) enabled\n"); } else { - if (csum_type == HW_CHECKSUMMING) { - if (card->state != CARD_STATE_DOWN) { - if (!qeth_is_supported(card, - IPA_INBOUND_CHECKSUM)) - return -EPERM; - rc = qeth_l3_send_checksum_command(card); - if (rc) - return -EIO; - } - } + rc = qeth_l3_send_simple_setassparms(card, + IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0); + if (rc) + return -EIO; } - card->options.checksum_type = csum_type; - return rc; + + return 0; } static int qeth_l3_start_ipa_checksum(struct qeth_card *card) { - int rc = 0; - QETH_CARD_TEXT(card, 3, "strtcsum"); - if (card->options.checksum_type == NO_CHECKSUMMING) { - dev_info(&card->gdev->dev, - "Using no checksumming on %s.\n", - QETH_CARD_IFNAME(card)); - return 0; + if (card->dev->features & NETIF_F_RXCSUM) { + rtnl_lock(); + /* force set_features call */ + card->dev->features &= ~NETIF_F_RXCSUM; + netdev_update_features(card->dev); + rtnl_unlock(); } - if (card->options.checksum_type == SW_CHECKSUMMING) { - dev_info(&card->gdev->dev, - "Using SW checksumming on %s.\n", - QETH_CARD_IFNAME(card)); - return 0; - } - if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) { - dev_info(&card->gdev->dev, - "Inbound HW Checksumming not " - "supported on %s,\ncontinuing " - "using Inbound SW Checksumming\n", - QETH_CARD_IFNAME(card)); - card->options.checksum_type = SW_CHECKSUMMING; - return 0; - } - rc = qeth_l3_send_checksum_command(card); - if (!rc) - dev_info(&card->gdev->dev, - "HW Checksumming (inbound) enabled\n"); - - return rc; + return 0; } static int qeth_l3_start_ipa_tx_checksum(struct qeth_card *card) @@ -1580,10 +1490,8 @@ static int qeth_l3_start_ipa_tso(struct qeth_card *card) dev_info(&card->gdev->dev, "Outbound TSO enabled\n"); } - if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)) { - card->options.large_send = QETH_LARGE_SEND_NO; - card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); - } + if (rc) + card->dev->features &= ~NETIF_F_TSO; return rc; } @@ -2064,14 +1972,7 @@ static inline int qeth_l3_rebuild_skb(struct qeth_card *card, is_vlan = 1; } - switch (card->options.checksum_type) { - case SW_CHECKSUMMING: - skb->ip_summed = CHECKSUM_NONE; - break; - case NO_CHECKSUMMING: - skb->ip_summed = CHECKSUM_UNNECESSARY; - break; - case HW_CHECKSUMMING: + if (card->dev->features & NETIF_F_RXCSUM) { if ((hdr->hdr.l3.ext_flags & (QETH_HDR_EXT_CSUM_HDR_REQ | QETH_HDR_EXT_CSUM_TRANSP_REQ)) == @@ -2080,7 +1981,8 @@ static inline int qeth_l3_rebuild_skb(struct qeth_card *card, skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; - } + } else + skb->ip_summed = CHECKSUM_NONE; return is_vlan; } @@ -3024,7 +2926,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct qeth_qdio_out_q *queue = card->qdio.out_qs [qeth_get_priority_queue(card, skb, ipv, cast_type)]; int tx_bytes = skb->len; - enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; + bool large_send; int data_offset = -1; int nr_frags; @@ -3046,8 +2948,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) card->perf_stats.outbound_start_time = qeth_get_micros(); } - if (skb_is_gso(skb)) - large_send = card->options.large_send; + large_send = skb_is_gso(skb); if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && (skb_shinfo(skb)->nr_frags == 0)) { @@ -3096,7 +2997,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) /* fix hardware limitation: as long as we do not have sbal * chaining we can not send long frag lists */ - if (large_send == QETH_LARGE_SEND_TSO) { + if (large_send) { if (qeth_l3_tso_elements(new_skb) + 1 > 16) { if (skb_linearize(new_skb)) goto tx_drop; @@ -3105,8 +3006,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } } - if ((large_send == QETH_LARGE_SEND_TSO) && - (cast_type == RTN_UNSPEC)) { + if (large_send && (cast_type == RTN_UNSPEC)) { hdr = (struct qeth_hdr *)skb_push(new_skb, sizeof(struct qeth_hdr_tso)); memset(hdr, 0, sizeof(struct qeth_hdr_tso)); @@ -3141,7 +3041,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (card->info.type != QETH_CARD_TYPE_IQD) { int len; - if (large_send == QETH_LARGE_SEND_TSO) + if (large_send) len = ((unsigned long)tcp_hdr(new_skb) + tcp_hdr(new_skb)->doff * 4) - (unsigned long)new_skb->data; @@ -3162,7 +3062,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (new_skb != skb) dev_kfree_skb_any(skb); if (card->options.performance_stats) { - if (large_send != QETH_LARGE_SEND_NO) { + if (large_send) { card->perf_stats.large_send_bytes += tx_bytes; card->perf_stats.large_send_cnt++; } @@ -3248,65 +3148,42 @@ static int qeth_l3_stop(struct net_device *dev) return 0; } -static u32 qeth_l3_ethtool_get_rx_csum(struct net_device *dev) +static u32 qeth_l3_fix_features(struct net_device *dev, u32 features) { struct qeth_card *card = dev->ml_priv; - return (card->options.checksum_type == HW_CHECKSUMMING); + if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) + features &= ~NETIF_F_IP_CSUM; + if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) + features &= ~NETIF_F_TSO; + if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) + features &= ~NETIF_F_RXCSUM; + + return features; } -static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data) +static int qeth_l3_set_features(struct net_device *dev, u32 features) { struct qeth_card *card = dev->ml_priv; - enum qeth_checksum_types csum_type; + u32 changed = dev->features ^ features; + int err; - if (data) - csum_type = HW_CHECKSUMMING; - else - csum_type = SW_CHECKSUMMING; + if (!(changed & NETIF_F_RXCSUM)) + return 0; - return qeth_l3_set_rx_csum(card, csum_type); -} + if (card->state == CARD_STATE_DOWN || + card->state == CARD_STATE_RECOVER) + return 0; -static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) -{ - struct qeth_card *card = dev->ml_priv; - int rc = 0; + err = qeth_l3_set_rx_csum(card, features & NETIF_F_RXCSUM); + if (err) + dev->features = features ^ NETIF_F_RXCSUM; - if (data) { - rc = qeth_l3_set_large_send(card, QETH_LARGE_SEND_TSO); - } else { - dev->features &= ~NETIF_F_TSO; - card->options.large_send = QETH_LARGE_SEND_NO; - } - return rc; -} - -static int qeth_l3_ethtool_set_tx_csum(struct net_device *dev, u32 data) -{ - struct qeth_card *card = dev->ml_priv; - - if (data) { - if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) - dev->features |= NETIF_F_IP_CSUM; - else - return -EPERM; - } else - dev->features &= ~NETIF_F_IP_CSUM; - - return 0; + return err; } static const struct ethtool_ops qeth_l3_ethtool_ops = { .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = qeth_l3_ethtool_set_tx_csum, - .get_rx_csum = qeth_l3_ethtool_get_rx_csum, - .set_rx_csum = qeth_l3_ethtool_set_rx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = qeth_l3_ethtool_set_tso, .get_strings = qeth_core_get_strings, .get_ethtool_stats = qeth_core_get_ethtool_stats, .get_sset_count = qeth_core_get_sset_count, @@ -3347,6 +3224,8 @@ static const struct net_device_ops qeth_l3_netdev_ops = { .ndo_set_multicast_list = qeth_l3_set_multicast_list, .ndo_do_ioctl = qeth_l3_do_ioctl, .ndo_change_mtu = qeth_change_mtu, + .ndo_fix_features = qeth_l3_fix_features, + .ndo_set_features = qeth_l3_set_features, .ndo_vlan_rx_register = qeth_l3_vlan_rx_register, .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid, @@ -3362,6 +3241,8 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { .ndo_set_multicast_list = qeth_l3_set_multicast_list, .ndo_do_ioctl = qeth_l3_do_ioctl, .ndo_change_mtu = qeth_change_mtu, + .ndo_fix_features = qeth_l3_fix_features, + .ndo_set_features = qeth_l3_set_features, .ndo_vlan_rx_register = qeth_l3_vlan_rx_register, .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid, @@ -3392,8 +3273,12 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD)) card->dev->dev_id = card->info.unique_id & 0xffff; - if (!card->info.guestlan) - card->dev->features |= NETIF_F_GRO; + if (!card->info.guestlan) { + card->dev->hw_features = NETIF_F_SG | + NETIF_F_RXCSUM | NETIF_F_IP_CSUM | + NETIF_F_TSO; + card->dev->features = NETIF_F_RXCSUM; + } } } else if (card->info.type == QETH_CARD_TYPE_IQD) { card->dev = alloc_netdev(0, "hsi%d", ether_setup); @@ -3426,15 +3311,13 @@ 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; - if ((card->info.type == QETH_CARD_TYPE_OSD) || - (card->info.type == QETH_CARD_TYPE_OSX)) - card->options.checksum_type = HW_CHECKSUMMING; return 0; } @@ -3480,13 +3363,18 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) goto out_remove; } - qeth_l3_query_ipassists(card, QETH_PROT_IPV4); - if (!card->dev && qeth_l3_setup_netdev(card)) { rc = -ENODEV; goto out_remove; } + if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) { + if (card->info.hwtrap && + qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM)) + card->info.hwtrap = 0; + } else + card->info.hwtrap = 0; + card->state = CARD_STATE_HARDSETUP; memset(&card->rx, 0, sizeof(struct qeth_rx)); qeth_print_status_message(card); @@ -3516,7 +3404,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) rc = qeth_l3_start_ipassists(card); if (rc) QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); - qeth_l3_set_large_send(card, card->options.large_send); rc = qeth_l3_setrouting_v4(card); if (rc) QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); @@ -3589,6 +3476,10 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev, if (card->dev && netif_carrier_ok(card->dev)) netif_carrier_off(card->dev); recover_flag = card->state; + if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) { + qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); + card->info.hwtrap = 1; + } qeth_l3_stop_card(card, recovery_mode); rc = ccw_device_set_offline(CARD_DDEV(card)); rc2 = ccw_device_set_offline(CARD_WDEV(card)); @@ -3644,6 +3535,8 @@ static int qeth_l3_recover(void *ptr) static void qeth_l3_shutdown(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if ((gdev->state == CCWGROUP_ONLINE) && card->info.hwtrap) + qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); qeth_qdio_clear_card(card, 0); qeth_clear_qdio_buffers(card); } @@ -3659,6 +3552,8 @@ static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev) if (gdev->state == CCWGROUP_OFFLINE) return 0; if (card->state == CARD_STATE_UP) { + if (card->info.hwtrap) + qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); __qeth_l3_set_offline(card->gdev, 1); } else __qeth_l3_set_offline(card->gdev, 0); diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index 67cfa68dcf1b..cd99210296e2 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -15,16 +15,6 @@ #define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store) -static const char *qeth_l3_get_checksum_str(struct qeth_card *card) -{ - if (card->options.checksum_type == SW_CHECKSUMMING) - return "sw"; - else if (card->options.checksum_type == HW_CHECKSUMMING) - return "hw"; - else - return "no"; -} - static ssize_t qeth_l3_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route, char *buf) { @@ -295,51 +285,6 @@ static ssize_t qeth_l3_dev_canonical_macaddr_store(struct device *dev, static DEVICE_ATTR(canonical_macaddr, 0644, qeth_l3_dev_canonical_macaddr_show, qeth_l3_dev_canonical_macaddr_store); -static ssize_t qeth_l3_dev_checksum_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct qeth_card *card = dev_get_drvdata(dev); - - if (!card) - return -EINVAL; - - return sprintf(buf, "%s checksumming\n", - qeth_l3_get_checksum_str(card)); -} - -static ssize_t qeth_l3_dev_checksum_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct qeth_card *card = dev_get_drvdata(dev); - enum qeth_checksum_types csum_type; - char *tmp; - int rc = 0; - - if (!card) - return -EINVAL; - - mutex_lock(&card->conf_mutex); - tmp = strsep((char **) &buf, "\n"); - if (!strcmp(tmp, "sw_checksumming")) - csum_type = SW_CHECKSUMMING; - else if (!strcmp(tmp, "hw_checksumming")) - csum_type = HW_CHECKSUMMING; - else if (!strcmp(tmp, "no_checksumming")) - csum_type = NO_CHECKSUMMING; - else { - rc = -EINVAL; - goto out; - } - - rc = qeth_l3_set_rx_csum(card, csum_type); -out: - mutex_unlock(&card->conf_mutex); - return rc ? rc : count; -} - -static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show, - qeth_l3_dev_checksum_store); - static ssize_t qeth_l3_dev_sniffer_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -402,61 +347,13 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show, qeth_l3_dev_sniffer_store); -static ssize_t qeth_l3_dev_large_send_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct qeth_card *card = dev_get_drvdata(dev); - - if (!card) - return -EINVAL; - - switch (card->options.large_send) { - case QETH_LARGE_SEND_NO: - return sprintf(buf, "%s\n", "no"); - case QETH_LARGE_SEND_TSO: - return sprintf(buf, "%s\n", "TSO"); - default: - return sprintf(buf, "%s\n", "N/A"); - } -} - -static ssize_t qeth_l3_dev_large_send_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct qeth_card *card = dev_get_drvdata(dev); - enum qeth_large_send_types type; - int rc = 0; - char *tmp; - - if (!card) - return -EINVAL; - tmp = strsep((char **) &buf, "\n"); - if (!strcmp(tmp, "no")) - type = QETH_LARGE_SEND_NO; - else if (!strcmp(tmp, "TSO")) - type = QETH_LARGE_SEND_TSO; - else - return -EINVAL; - - mutex_lock(&card->conf_mutex); - if (card->options.large_send != type) - rc = qeth_l3_set_large_send(card, type); - mutex_unlock(&card->conf_mutex); - return rc ? rc : count; -} - -static DEVICE_ATTR(large_send, 0644, qeth_l3_dev_large_send_show, - qeth_l3_dev_large_send_store); - 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_checksumming.attr, &dev_attr_sniffer.attr, - &dev_attr_large_send.attr, NULL, }; diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index da7b9887ec48..f980600f78a8 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -75,8 +75,10 @@ MODULE_AUTHOR("Nick Cheng "); MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapter"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(ARCMSR_DRIVER_VERSION); -static int sleeptime = 10; -static int retrycount = 12; + +#define ARCMSR_SLEEPTIME 10 +#define ARCMSR_RETRYCOUNT 12 + wait_queue_head_t wait_q; static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd); @@ -171,24 +173,6 @@ static struct pci_driver arcmsr_pci_driver = { **************************************************************************** **************************************************************************** */ -int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *shost = NULL; - int i, isleep; - shost = cmd->device->host; - isleep = sleeptime / 10; - if (isleep > 0) { - for (i = 0; i < isleep; i++) { - msleep(10000); - } - } - - isleep = sleeptime % 10; - if (isleep > 0) { - msleep(isleep*1000); - } - return 0; -} static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb) { @@ -323,66 +307,64 @@ static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb) default: acb->adapter_type = ACB_ADAPTER_TYPE_A; } -} +} static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; - uint32_t Index; - uint8_t Retries = 0x00; - do { - for (Index = 0; Index < 100; Index++) { - if (readl(®->outbound_intstatus) & - ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { - writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, - ®->outbound_intstatus); - return true; - } - msleep(10); - }/*max 1 seconds*/ + int i; + + for (i = 0; i < 2000; i++) { + if (readl(®->outbound_intstatus) & + ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { + writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, + ®->outbound_intstatus); + return true; + } + msleep(10); + } /* max 20 seconds */ - } while (Retries++ < 20);/*max 20 sec*/ return false; } static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; - uint32_t Index; - uint8_t Retries = 0x00; - do { - for (Index = 0; Index < 100; Index++) { - if (readl(reg->iop2drv_doorbell) - & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { - writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN - , reg->iop2drv_doorbell); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); - return true; - } - msleep(10); - }/*max 1 seconds*/ + int i; + + for (i = 0; i < 2000; i++) { + if (readl(reg->iop2drv_doorbell) + & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, + reg->iop2drv_doorbell); + writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, + reg->drv2iop_doorbell); + return true; + } + msleep(10); + } /* max 20 seconds */ - } while (Retries++ < 20);/*max 20 sec*/ return false; } static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB) { struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; - unsigned char Retries = 0x00; - uint32_t Index; - do { - for (Index = 0; Index < 100; Index++) { - if (readl(&phbcmu->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { - writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &phbcmu->outbound_doorbell_clear);/*clear interrupt*/ - return true; - } - /* one us delay */ - msleep(10); - } /*max 1 seconds*/ - } while (Retries++ < 20); /*max 20 sec*/ + int i; + + for (i = 0; i < 2000; i++) { + if (readl(&phbcmu->outbound_doorbell) + & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, + &phbcmu->outbound_doorbell_clear); /*clear interrupt*/ + return true; + } + msleep(10); + } /* max 20 seconds */ + return false; } + static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; @@ -459,10 +441,11 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) struct CommandControlBlock *ccb_tmp; int i = 0, j = 0; dma_addr_t cdb_phyaddr; - unsigned long roundup_ccbsize = 0, offset; + unsigned long roundup_ccbsize; unsigned long max_xfer_len; unsigned long max_sg_entrys; uint32_t firm_config_version; + for (i = 0; i < ARCMSR_MAX_TARGETID; i++) for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) acb->devstate[i][j] = ARECA_RAID_GONE; @@ -472,23 +455,20 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) firm_config_version = acb->firm_cfg_version; if((firm_config_version & 0xFF) >= 3){ max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */ - max_sg_entrys = (max_xfer_len/4096); + max_sg_entrys = (max_xfer_len/4096); } acb->host->max_sectors = max_xfer_len/512; acb->host->sg_tablesize = max_sg_entrys; roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32); - acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM + 32; + acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM; dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); if(!dma_coherent){ - printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error \n", acb->host->host_no); + printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error\n", acb->host->host_no); return -ENOMEM; } acb->dma_coherent = dma_coherent; acb->dma_coherent_handle = dma_coherent_handle; memset(dma_coherent, 0, acb->uncache_size); - offset = roundup((unsigned long)dma_coherent, 32) - (unsigned long)dma_coherent; - dma_coherent_handle = dma_coherent_handle + offset; - dma_coherent = (struct CommandControlBlock *)dma_coherent + offset; ccb_tmp = dma_coherent; acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle; for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){ @@ -2602,12 +2582,8 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) if (cdb_phyaddr_hi32 != 0) { struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; - if (cdb_phyaddr_hi32 != 0) { - unsigned char Retries = 0x00; - do { - printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x \n", acb->adapter_index, cdb_phyaddr_hi32); - } while (Retries++ < 100); - } + printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x\n", + acb->adapter_index, cdb_phyaddr_hi32); writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->msgcode_rwbuffer[0]); writel(cdb_phyaddr_hi32, ®->msgcode_rwbuffer[1]); writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); @@ -2955,12 +2931,12 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd) arcmsr_hardware_reset(acb); acb->acb_flags &= ~ACB_F_IOP_INITED; sleep_again: - arcmsr_sleep_for_bus_reset(cmd); + ssleep(ARCMSR_SLEEPTIME); if ((readl(®->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) { - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count); - if (retry_count > retrycount) { + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d\n", acb->host->host_no, retry_count); + if (retry_count > ARCMSR_RETRYCOUNT) { acb->fw_flag = FW_DEADLOCK; - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no); + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!!\n", acb->host->host_no); return FAILED; } retry_count++; @@ -3025,12 +3001,12 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd) arcmsr_hardware_reset(acb); acb->acb_flags &= ~ACB_F_IOP_INITED; sleep: - arcmsr_sleep_for_bus_reset(cmd); + ssleep(ARCMSR_SLEEPTIME); if ((readl(®->host_diagnostic) & 0x04) != 0) { - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count); - if (retry_count > retrycount) { + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d\n", acb->host->host_no, retry_count); + if (retry_count > ARCMSR_RETRYCOUNT) { acb->fw_flag = FW_DEADLOCK; - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no); + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!!\n", acb->host->host_no); return FAILED; } retry_count++; diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index 1cb8a5e85c7f..1d7b976c850f 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -8,11 +8,11 @@ * Public License is included in this distribution in the file called COPYING. * * Contact Information: - * linux-drivers@serverengines.com + * linux-drivers@emulex.com * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #ifndef BEISCSI_H diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index ad246369d373..b8a82f2c62c8 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -8,11 +8,11 @@ * Public License is included in this distribution in the file called COPYING. * * Contact Information: - * linux-drivers@serverengines.com + * linux-drivers@emulex.com * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #include "be.h" @@ -458,6 +458,7 @@ void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, req_hdr->opcode = opcode; req_hdr->subsystem = subsystem; req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr)); + req_hdr->timeout = 120; } static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages, diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index fbd1dc2c15f7..497eb29e5c9e 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -8,11 +8,11 @@ * Public License is included in this distribution in the file called COPYING. * * Contact Information: - * linux-drivers@serverengines.com + * linux-drivers@emulex.com * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #ifndef BEISCSI_CMDS_H diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 868cc5590145..3cad10605023 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,15 +7,14 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) * * Contact Information: - * linux-drivers@serverengines.com - * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * linux-drivers@emulex.com * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #include diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h index 9c532797c29e..ff60b7fd92d6 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.h +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,15 +7,14 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) * * Contact Information: - * linux-drivers@serverengines.com - * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * linux-drivers@emulex.com * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #ifndef _BE_ISCSI_ diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 24e20ba9633c..cea9b275965c 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,16 +7,16 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) * * Contact Information: - * linux-drivers@serverengines.com - * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * linux-drivers@emulex.com * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ + #include #include #include @@ -420,7 +420,8 @@ static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) return 0; free_kset: - iscsi_boot_destroy_kset(phba->boot_kset); + if (phba->boot_kset) + iscsi_boot_destroy_kset(phba->boot_kset); return -ENOMEM; } @@ -3464,23 +3465,23 @@ static void hwi_enable_intr(struct beiscsi_hba *phba) addr = (u8 __iomem *) ((u8 __iomem *) ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); reg = ioread32(addr); - SE_DEBUG(DBG_LVL_8, "reg =x%08x\n", reg); enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; if (!enabled) { reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p\n", reg, addr); iowrite32(reg, addr); - if (!phba->msix_enabled) { - eq = &phwi_context->be_eq[0].q; + } + + if (!phba->msix_enabled) { + eq = &phwi_context->be_eq[0].q; + SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id); + hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); + } else { + for (i = 0; i <= phba->num_cpus; i++) { + eq = &phwi_context->be_eq[i].q; SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id); hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); - } else { - for (i = 0; i <= phba->num_cpus; i++) { - eq = &phwi_context->be_eq[i].q; - SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id); - hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); - } } } } @@ -4019,12 +4020,17 @@ static int beiscsi_mtask(struct iscsi_task *task) hwi_write_buffer(pwrb, task); break; case ISCSI_OP_NOOP_OUT: - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_RD_CMD); - if (task->hdr->ttt == ISCSI_RESERVED_TAG) + if (task->hdr->ttt != ISCSI_RESERVED_TAG) { + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + TGT_DM_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, + pwrb, 0); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); - else + } else { + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_RD_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 1); + } hwi_write_buffer(pwrb, task); break; case ISCSI_OP_TEXT: @@ -4144,10 +4150,11 @@ static void beiscsi_remove(struct pci_dev *pcidev) phba->ctrl.mbox_mem_alloced.size, phba->ctrl.mbox_mem_alloced.va, phba->ctrl.mbox_mem_alloced.dma); + if (phba->boot_kset) + iscsi_boot_destroy_kset(phba->boot_kset); iscsi_host_remove(phba->shost); pci_dev_put(phba->pcidev); iscsi_host_free(phba->shost); - iscsi_boot_destroy_kset(phba->boot_kset); } static void beiscsi_msix_enable(struct beiscsi_hba *phba) diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 90eb74f6bcab..081c171a1ed6 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,15 +7,14 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) * * Contact Information: - * linux-drivers@serverengines.com - * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * linux-drivers@emulex.com * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #ifndef _BEISCSI_MAIN_ @@ -35,7 +34,7 @@ #include "be.h" #define DRV_NAME "be2iscsi" -#define BUILD_STR "2.0.549.0" +#define BUILD_STR "2.103.298.0" #define BE_NAME "ServerEngines BladeEngine2" \ "Linux iSCSI Driver version" BUILD_STR #define DRV_DESC BE_NAME " " "Driver" diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 877324fc594c..44762cfa3e12 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,15 +7,14 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) * * Contact Information: - * linux-drivers@serverengines.com - * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * linux-drivers@emulex.com * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #include "be_mgmt.h" @@ -203,8 +202,8 @@ int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute) OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req)); req->chute = chute; - req->hdr_ring_id = 0; - req->data_ring_id = 0; + req->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba)); + req->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba)); status = be_mcc_notify_wait(phba); if (status) diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index b9acedf78653..08428824ace2 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,15 +7,14 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) * * Contact Information: - * linux-drivers@serverengines.com - * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * linux-drivers@emulex.com * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #ifndef _BEISCSI_MGMT_ diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 0fd510a01561..59b5e9b61d71 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -57,9 +57,19 @@ int pcie_max_read_reqsz; int bfa_debugfs_enable = 1; int msix_disable_cb = 0, msix_disable_ct = 0; +/* Firmware releated */ u32 bfi_image_ct_fc_size, bfi_image_ct_cna_size, bfi_image_cb_fc_size; u32 *bfi_image_ct_fc, *bfi_image_ct_cna, *bfi_image_cb_fc; +#define BFAD_FW_FILE_CT_FC "ctfw_fc.bin" +#define BFAD_FW_FILE_CT_CNA "ctfw_cna.bin" +#define BFAD_FW_FILE_CB_FC "cbfw_fc.bin" + +static u32 *bfad_load_fwimg(struct pci_dev *pdev); +static void bfad_free_fwimg(void); +static void bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, + u32 *bfi_image_size, char *fw_name); + static const char *msix_name_ct[] = { "cpe0", "cpe1", "cpe2", "cpe3", "rme0", "rme1", "rme2", "rme3", @@ -222,6 +232,9 @@ bfad_sm_created(struct bfad_s *bfad, enum bfad_sm_event event) if ((bfad->bfad_flags & BFAD_HAL_INIT_DONE)) { bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS); } else { + printk(KERN_WARNING + "bfa %s: bfa init failed\n", + bfad->pci_name); bfad->bfad_flags |= BFAD_HAL_INIT_FAIL; bfa_sm_send_event(bfad, BFAD_E_INIT_FAILED); } @@ -991,10 +1004,6 @@ bfad_cfg_pport(struct bfad_s *bfad, enum bfa_lport_role role) bfad->pport.roles |= BFA_LPORT_ROLE_FCP_IM; } - /* Setup the debugfs node for this scsi_host */ - if (bfa_debugfs_enable) - bfad_debugfs_init(&bfad->pport); - bfad->bfad_flags |= BFAD_CFG_PPORT_DONE; out: @@ -1004,10 +1013,6 @@ bfad_cfg_pport(struct bfad_s *bfad, enum bfa_lport_role role) void bfad_uncfg_pport(struct bfad_s *bfad) { - /* Remove the debugfs node for this scsi_host */ - kfree(bfad->regdata); - bfad_debugfs_exit(&bfad->pport); - if ((supported_fc4s & BFA_LPORT_ROLE_FCP_IM) && (bfad->pport.roles & BFA_LPORT_ROLE_FCP_IM)) { bfad_im_scsi_host_free(bfad, bfad->pport.im_port); @@ -1389,6 +1394,10 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) bfad->pport.bfad = bfad; INIT_LIST_HEAD(&bfad->pbc_vport_list); + /* Setup the debugfs node for this bfad */ + if (bfa_debugfs_enable) + bfad_debugfs_init(&bfad->pport); + retval = bfad_drv_init(bfad); if (retval != BFA_STATUS_OK) goto out_drv_init_failure; @@ -1404,6 +1413,9 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) bfa_detach(&bfad->bfa); bfad_hal_mem_release(bfad); out_drv_init_failure: + /* Remove the debugfs node for this bfad */ + kfree(bfad->regdata); + bfad_debugfs_exit(&bfad->pport); mutex_lock(&bfad_mutex); bfad_inst--; list_del(&bfad->list_entry); @@ -1445,6 +1457,10 @@ bfad_pci_remove(struct pci_dev *pdev) spin_unlock_irqrestore(&bfad->bfad_lock, flags); bfad_hal_mem_release(bfad); + /* Remove the debugfs node for this bfad */ + kfree(bfad->regdata); + bfad_debugfs_exit(&bfad->pport); + /* Cleaning the BFAD instance */ mutex_lock(&bfad_mutex); bfad_inst--; @@ -1550,7 +1566,7 @@ bfad_exit(void) } /* Firmware handling */ -u32 * +static void bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, u32 *bfi_image_size, char *fw_name) { @@ -1558,27 +1574,25 @@ bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, if (request_firmware(&fw, fw_name, &pdev->dev)) { printk(KERN_ALERT "Can't locate firmware %s\n", fw_name); - goto error; + *bfi_image = NULL; + goto out; } *bfi_image = vmalloc(fw->size); if (NULL == *bfi_image) { printk(KERN_ALERT "Fail to allocate buffer for fw image " "size=%x!\n", (u32) fw->size); - goto error; + goto out; } memcpy(*bfi_image, fw->data, fw->size); *bfi_image_size = fw->size/sizeof(u32); - - return *bfi_image; - -error: - return NULL; +out: + release_firmware(fw); } -u32 * -bfad_get_firmware_buf(struct pci_dev *pdev) +static u32 * +bfad_load_fwimg(struct pci_dev *pdev) { if (pdev->device == BFA_PCI_DEVICE_ID_CT_FC) { if (bfi_image_ct_fc_size == 0) @@ -1598,6 +1612,17 @@ bfad_get_firmware_buf(struct pci_dev *pdev) } } +static void +bfad_free_fwimg(void) +{ + if (bfi_image_ct_fc_size && bfi_image_ct_fc) + vfree(bfi_image_ct_fc); + if (bfi_image_ct_cna_size && bfi_image_ct_cna) + vfree(bfi_image_ct_cna); + if (bfi_image_cb_fc_size && bfi_image_cb_fc) + vfree(bfi_image_cb_fc); +} + module_init(bfad_init); module_exit(bfad_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c index c66e32eced7b..48be0c54f2de 100644 --- a/drivers/scsi/bfa/bfad_debugfs.c +++ b/drivers/scsi/bfa/bfad_debugfs.c @@ -28,10 +28,10 @@ * mount -t debugfs none /sys/kernel/debug * * BFA Hierarchy: - * - bfa/host# - * where the host number corresponds to the one under /sys/class/scsi_host/host# + * - bfa/pci_dev: + * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bfa * - * Debugging service available per host: + * Debugging service available per pci_dev: * fwtrc: To collect current firmware trace. * drvtrc: To collect current driver trace * fwsave: To collect last saved fw trace as a result of firmware crash. @@ -489,11 +489,9 @@ static atomic_t bfa_debugfs_port_count; inline void bfad_debugfs_init(struct bfad_port_s *port) { - struct bfad_im_port_s *im_port = port->im_port; - struct bfad_s *bfad = im_port->bfad; - struct Scsi_Host *shost = im_port->shost; + struct bfad_s *bfad = port->bfad; const struct bfad_debugfs_entry *file; - char name[16]; + char name[64]; int i; if (!bfa_debugfs_enable) @@ -510,17 +508,15 @@ bfad_debugfs_init(struct bfad_port_s *port) } } - /* - * Setup the host# directory for the port, - * corresponds to the scsi_host num of this port. - */ - snprintf(name, sizeof(name), "host%d", shost->host_no); + /* Setup the pci_dev debugfs directory for the port */ + snprintf(name, sizeof(name), "pci_dev:%s", bfad->pci_name); if (!port->port_debugfs_root) { port->port_debugfs_root = debugfs_create_dir(name, bfa_debugfs_root); if (!port->port_debugfs_root) { printk(KERN_WARNING - "BFA host root dir creation failed\n"); + "bfa %s: debugfs root creation failed\n", + bfad->pci_name); goto err; } @@ -536,8 +532,8 @@ bfad_debugfs_init(struct bfad_port_s *port) file->fops); if (!bfad->bfad_dentry_files[i]) { printk(KERN_WARNING - "BFA host%d: create %s entry failed\n", - shost->host_no, file->name); + "bfa %s: debugfs %s creation failed\n", + bfad->pci_name, file->name); goto err; } } @@ -550,8 +546,7 @@ bfad_debugfs_init(struct bfad_port_s *port) inline void bfad_debugfs_exit(struct bfad_port_s *port) { - struct bfad_im_port_s *im_port = port->im_port; - struct bfad_s *bfad = im_port->bfad; + struct bfad_s *bfad = port->bfad; int i; for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) { @@ -562,9 +557,7 @@ bfad_debugfs_exit(struct bfad_port_s *port) } /* - * Remove the host# directory for the port, - * corresponds to the scsi_host num of this port. - */ + * Remove the pci_dev debugfs directory for the port */ if (port->port_debugfs_root) { debugfs_remove(port->port_debugfs_root); port->port_debugfs_root = NULL; diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h index bfee63b16fa9..c296c8968511 100644 --- a/drivers/scsi/bfa/bfad_im.h +++ b/drivers/scsi/bfa/bfad_im.h @@ -141,29 +141,4 @@ extern struct device_attribute *bfad_im_vport_attrs[]; irqreturn_t bfad_intx(int irq, void *dev_id); -/* Firmware releated */ -#define BFAD_FW_FILE_CT_FC "ctfw_fc.bin" -#define BFAD_FW_FILE_CT_CNA "ctfw_cna.bin" -#define BFAD_FW_FILE_CB_FC "cbfw_fc.bin" - -u32 *bfad_get_firmware_buf(struct pci_dev *pdev); -u32 *bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, - u32 *bfi_image_size, char *fw_name); - -static inline u32 * -bfad_load_fwimg(struct pci_dev *pdev) -{ - return bfad_get_firmware_buf(pdev); -} - -static inline void -bfad_free_fwimg(void) -{ - if (bfi_image_ct_fc_size && bfi_image_ct_fc) - vfree(bfi_image_ct_fc); - if (bfi_image_ct_cna_size && bfi_image_ct_cna) - vfree(bfi_image_ct_cna); - if (bfi_image_cb_fc_size && bfi_image_cb_fc) - vfree(bfi_image_cb_fc); -} #endif diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index b6d350ac4288..0a404bfb44fe 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -130,7 +130,7 @@ #define BNX2FC_TM_TIMEOUT 60 /* secs */ #define BNX2FC_IO_TIMEOUT 20000UL /* msecs */ -#define BNX2FC_WAIT_CNT 120 +#define BNX2FC_WAIT_CNT 1200 #define BNX2FC_FW_TIMEOUT (3 * HZ) #define PORT_MAX 2 diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index e2e647509a73..ab255fbc7f36 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -664,7 +664,7 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport) struct fcoe_port *port = lport_priv(lport); struct bnx2fc_hba *hba = port->priv; struct net_device *netdev = hba->netdev; - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; + struct ethtool_cmd ecmd; if (!dev_ethtool_get_settings(netdev, &ecmd)) { lport->link_supported_speeds &= @@ -675,12 +675,15 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport) if (ecmd.supported & SUPPORTED_10000baseT_Full) lport->link_supported_speeds |= FC_PORTSPEED_10GBIT; - if (ecmd.speed == SPEED_1000) + switch (ethtool_cmd_speed(&ecmd)) { + case SPEED_1000: lport->link_speed = FC_PORTSPEED_1GBIT; - if (ecmd.speed == SPEED_10000) + break; + case SPEED_10000: lport->link_speed = FC_PORTSPEED_10GBIT; + break; + } } - return; } static int bnx2fc_link_ok(struct fc_lport *lport) { @@ -1130,7 +1133,7 @@ static void bnx2fc_interface_release(struct kref *kref) struct net_device *phys_dev; hba = container_of(kref, struct bnx2fc_hba, kref); - BNX2FC_HBA_DBG(hba->ctlr.lp, "Interface is being released\n"); + BNX2FC_MISC_DBG("Interface is being released\n"); netdev = hba->netdev; phys_dev = hba->phys_dev; @@ -1254,20 +1257,17 @@ static int bnx2fc_interface_setup(struct bnx2fc_hba *hba, static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, struct device *parent, int npiv) { - struct fc_lport *lport = NULL; + struct fc_lport *lport, *n_port; struct fcoe_port *port; struct Scsi_Host *shost; struct fc_vport *vport = dev_to_vport(parent); int rc = 0; /* Allocate Scsi_Host structure */ - if (!npiv) { - lport = libfc_host_alloc(&bnx2fc_shost_template, - sizeof(struct fcoe_port)); - } else { - lport = libfc_vport_create(vport, - sizeof(struct fcoe_port)); - } + if (!npiv) + lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port)); + else + lport = libfc_vport_create(vport, sizeof(*port)); if (!lport) { printk(KERN_ERR PFX "could not allocate scsi host structure\n"); @@ -1285,7 +1285,6 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, goto lp_config_err; if (npiv) { - vport = dev_to_vport(parent); printk(KERN_ERR PFX "Setting vport names, 0x%llX 0x%llX\n", vport->node_name, vport->port_name); fc_set_wwnn(lport, vport->node_name); @@ -1314,12 +1313,17 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN; /* Allocate exchange manager */ - if (!npiv) { + if (!npiv) rc = bnx2fc_em_config(lport); - if (rc) { - printk(KERN_ERR PFX "Error on bnx2fc_em_config\n"); - goto shost_err; - } + else { + shost = vport_to_shost(vport); + n_port = shost_priv(shost); + rc = fc_exch_mgr_list_clone(n_port, lport); + } + + if (rc) { + printk(KERN_ERR PFX "Error on bnx2fc_em_config\n"); + goto shost_err; } bnx2fc_interface_get(hba); @@ -1352,8 +1356,6 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) /* Free existing transmit skbs */ fcoe_clean_pending_queue(lport); - bnx2fc_interface_put(hba); - /* Free queued packets for the receive thread */ bnx2fc_clean_rx_queue(lport); @@ -1372,6 +1374,8 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) /* Release Scsi_Host */ scsi_host_put(lport->host); + + bnx2fc_interface_put(hba); } /** diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 1b680e288c56..f756d5f85c7a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -522,6 +522,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, fp = fc_frame_alloc(lport, payload_len); if (!fp) { printk(KERN_ERR PFX "fc_frame_alloc failure\n"); + kfree(unsol_els); return; } @@ -547,6 +548,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, */ printk(KERN_ERR PFX "dropping ELS 0x%x\n", op); kfree_skb(skb); + kfree(unsol_els); return; } } @@ -563,6 +565,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, } else { BNX2FC_HBA_DBG(lport, "fh_r_ctl = 0x%x\n", fh->fh_r_ctl); kfree_skb(skb); + kfree(unsol_els); } } diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 1decefbf32e3..b5b5c346d779 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1663,6 +1663,12 @@ int bnx2fc_queuecommand(struct Scsi_Host *host, tgt = (struct bnx2fc_rport *)&rp[1]; if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) { + if (test_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags)) { + sc_cmd->result = DID_NO_CONNECT << 16; + sc_cmd->scsi_done(sc_cmd); + return 0; + + } /* * Session is not offloaded yet. Let SCSI-ml retry * the command. diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index d0c82340f0e2..60d2ef291646 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -772,6 +772,7 @@ static const struct error_info additional[] = {0x3802, "Esn - power management class event"}, {0x3804, "Esn - media class event"}, {0x3806, "Esn - device busy class event"}, + {0x3807, "Thin Provisioning soft threshold reached"}, {0x3900, "Saving parameters not supported"}, diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index de764ea7419d..a2a9c7c6c643 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -450,12 +450,13 @@ static struct cxgbi_sock *cxgbi_sock_create(struct cxgbi_device *cdev) return csk; } -static struct rtable *find_route_ipv4(__be32 saddr, __be32 daddr, +static struct rtable *find_route_ipv4(struct flowi4 *fl4, + __be32 saddr, __be32 daddr, __be16 sport, __be16 dport, u8 tos) { struct rtable *rt; - rt = ip_route_output_ports(&init_net, NULL, daddr, saddr, + rt = ip_route_output_ports(&init_net, fl4, NULL, daddr, saddr, dport, sport, IPPROTO_TCP, tos, 0); if (IS_ERR(rt)) return NULL; @@ -470,6 +471,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) struct net_device *ndev; struct cxgbi_device *cdev; struct rtable *rt = NULL; + struct flowi4 fl4; struct cxgbi_sock *csk = NULL; unsigned int mtu = 0; int port = 0xFFFF; @@ -482,7 +484,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) goto err_out; } - rt = find_route_ipv4(0, daddr->sin_addr.s_addr, 0, daddr->sin_port, 0); + rt = find_route_ipv4(&fl4, 0, daddr->sin_addr.s_addr, 0, daddr->sin_port, 0); if (!rt) { pr_info("no route to ipv4 0x%x, port %u.\n", daddr->sin_addr.s_addr, daddr->sin_port); @@ -531,7 +533,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) csk->daddr.sin_addr.s_addr = daddr->sin_addr.s_addr; csk->daddr.sin_port = daddr->sin_port; csk->daddr.sin_family = daddr->sin_family; - csk->saddr.sin_addr.s_addr = rt->rt_src; + csk->saddr.sin_addr.s_addr = fl4.saddr; return csk; diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index b10b3841535c..f5b718d3c31b 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -778,8 +778,8 @@ static void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) static void srb_waiting_insert(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_waiting_insert: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + dprintkdbg(DBG_0, "srb_waiting_insert: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_add(&srb->list, &dcb->srb_waiting_list); } @@ -787,16 +787,16 @@ static void srb_waiting_insert(struct DeviceCtlBlk *dcb, static void srb_waiting_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_waiting_append: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + dprintkdbg(DBG_0, "srb_waiting_append: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_add_tail(&srb->list, &dcb->srb_waiting_list); } static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_going_append: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + dprintkdbg(DBG_0, "srb_going_append: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_add_tail(&srb->list, &dcb->srb_going_list); } @@ -805,8 +805,8 @@ static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { struct ScsiReqBlk *i; struct ScsiReqBlk *tmp; - dprintkdbg(DBG_0, "srb_going_remove: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + dprintkdbg(DBG_0, "srb_going_remove: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list) if (i == srb) { @@ -821,8 +821,8 @@ static void srb_waiting_remove(struct DeviceCtlBlk *dcb, { struct ScsiReqBlk *i; struct ScsiReqBlk *tmp; - dprintkdbg(DBG_0, "srb_waiting_remove: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + dprintkdbg(DBG_0, "srb_waiting_remove: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list) if (i == srb) { @@ -836,8 +836,8 @@ static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { dprintkdbg(DBG_0, - "srb_going_to_waiting_move: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + "srb_going_to_waiting_move: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_move(&srb->list, &dcb->srb_waiting_list); } @@ -846,8 +846,8 @@ static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { dprintkdbg(DBG_0, - "srb_waiting_to_going_move: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + "srb_waiting_to_going_move: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_move(&srb->list, &dcb->srb_going_list); } @@ -982,8 +982,8 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, { int nseg; enum dma_data_direction dir = cmd->sc_data_direction; - dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n", - cmd->serial_number, dcb->target_id, dcb->target_lun); + dprintkdbg(DBG_0, "build_srb: (0x%p) <%02i-%i>\n", + cmd, dcb->target_id, dcb->target_lun); srb->dcb = dcb; srb->cmd = cmd; @@ -1086,8 +1086,8 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct s struct ScsiReqBlk *srb; struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)cmd->device->host->hostdata; - dprintkdbg(DBG_0, "queue_command: (pid#%li) <%02i-%i> cmnd=0x%02x\n", - cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + dprintkdbg(DBG_0, "queue_command: (0x%p) <%02i-%i> cmnd=0x%02x\n", + cmd, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); /* Assume BAD_TARGET; will be cleared later */ cmd->result = DID_BAD_TARGET << 16; @@ -1140,7 +1140,7 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct s /* process immediately */ send_srb(acb, srb); } - dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->serial_number); + dprintkdbg(DBG_1, "queue_command: (0x%p) done\n", cmd); return 0; complete: @@ -1203,9 +1203,9 @@ static void dump_register_info(struct AdapterCtlBlk *acb, dprintkl(KERN_INFO, "dump: srb=%p cmd=%p OOOPS!\n", srb, srb->cmd); else - dprintkl(KERN_INFO, "dump: srb=%p cmd=%p (pid#%li) " + dprintkl(KERN_INFO, "dump: srb=%p cmd=%p " "cmnd=0x%02x <%02i-%i>\n", - srb, srb->cmd, srb->cmd->serial_number, + srb, srb->cmd, srb->cmd->cmnd[0], srb->cmd->device->id, srb->cmd->device->lun); printk(" sglist=%p cnt=%i idx=%i len=%zu\n", @@ -1301,8 +1301,8 @@ static int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd) struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)cmd->device->host->hostdata; dprintkl(KERN_INFO, - "eh_bus_reset: (pid#%li) target=<%02i-%i> cmd=%p\n", - cmd->serial_number, cmd->device->id, cmd->device->lun, cmd); + "eh_bus_reset: (0%p) target=<%02i-%i> cmd=%p\n", + cmd, cmd->device->id, cmd->device->lun, cmd); if (timer_pending(&acb->waiting_timer)) del_timer(&acb->waiting_timer); @@ -1368,8 +1368,8 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd) (struct AdapterCtlBlk *)cmd->device->host->hostdata; struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; - dprintkl(KERN_INFO, "eh_abort: (pid#%li) target=<%02i-%i> cmd=%p\n", - cmd->serial_number, cmd->device->id, cmd->device->lun, cmd); + dprintkl(KERN_INFO, "eh_abort: (0x%p) target=<%02i-%i> cmd=%p\n", + cmd, cmd->device->id, cmd->device->lun, cmd); dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); if (!dcb) { @@ -1495,8 +1495,8 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, u16 s_stat2, return_code; u8 s_stat, scsicommand, i, identify_message; u8 *ptr; - dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> srb=%p\n", + dcb->target_id, dcb->target_lun, srb); srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */ @@ -1505,8 +1505,8 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS); #if 1 if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) { - dprintkdbg(DBG_KG, "start_scsi: (pid#%li) BUSY %02x %04x\n", - srb->cmd->serial_number, s_stat, s_stat2); + dprintkdbg(DBG_KG, "start_scsi: (0x%p) BUSY %02x %04x\n", + s_stat, s_stat2); /* * Try anyway? * @@ -1522,16 +1522,15 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, } #endif if (acb->active_dcb) { - dprintkl(KERN_DEBUG, "start_scsi: (pid#%li) Attempt to start a" - "command while another command (pid#%li) is active.", - srb->cmd->serial_number, + dprintkl(KERN_DEBUG, "start_scsi: (0x%p) Attempt to start a" + "command while another command (0x%p) is active.", + srb->cmd, acb->active_dcb->active_srb ? - acb->active_dcb->active_srb->cmd->serial_number : 0); + acb->active_dcb->active_srb->cmd : 0); return 1; } if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { - dprintkdbg(DBG_KG, "start_scsi: (pid#%li) Failed (busy)\n", - srb->cmd->serial_number); + dprintkdbg(DBG_KG, "start_scsi: (0x%p) Failed (busy)\n", srb->cmd); return 1; } /* Allow starting of SCSI commands half a second before we allow the mid-level @@ -1603,9 +1602,9 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, tag_number++; } if (tag_number >= dcb->max_command) { - dprintkl(KERN_WARNING, "start_scsi: (pid#%li) " + dprintkl(KERN_WARNING, "start_scsi: (0x%p) " "Out of tags target=<%02i-%i>)\n", - srb->cmd->serial_number, srb->cmd->device->id, + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); srb->state = SRB_READY; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, @@ -1623,8 +1622,8 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, #endif /*polling:*/ /* Send CDB ..command block ......... */ - dprintkdbg(DBG_KG, "start_scsi: (pid#%li) <%02i-%i> cmnd=0x%02x tag=%i\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun, + dprintkdbg(DBG_KG, "start_scsi: (0x%p) <%02i-%i> cmnd=0x%02x tag=%i\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun, srb->cmd->cmnd[0], srb->tag_number); if (srb->flag & AUTO_REQSENSE) { DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE); @@ -1647,8 +1646,8 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, * we caught an interrupt (must be reset or reselection ... ) * : Let's process it first! */ - dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> Failed - busy\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun); + dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> Failed - busy\n", + srb->cmd, dcb->target_id, dcb->target_lun); srb->state = SRB_READY; free_tag(dcb, srb); srb->msg_count = 0; @@ -1843,7 +1842,7 @@ static irqreturn_t dc395x_interrupt(int irq, void *dev_id) static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "msgout_phase0: (0x%p)\n", srb->cmd); if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) *pscsi_status = PH_BUS_FREE; /*.. initial phase */ @@ -1857,18 +1856,18 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, { u16 i; u8 *ptr; - dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "msgout_phase1: (0x%p)\n", srb->cmd); clear_fifo(acb, "msgout_phase1"); if (!(srb->state & SRB_MSGOUT)) { srb->state |= SRB_MSGOUT; dprintkl(KERN_DEBUG, - "msgout_phase1: (pid#%li) Phase unexpected\n", - srb->cmd->serial_number); /* So what ? */ + "msgout_phase1: (0x%p) Phase unexpected\n", + srb->cmd); /* So what ? */ } if (!srb->msg_count) { - dprintkdbg(DBG_0, "msgout_phase1: (pid#%li) NOP msg\n", - srb->cmd->serial_number); + dprintkdbg(DBG_0, "msgout_phase1: (0x%p) NOP msg\n", + srb->cmd); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); @@ -1888,7 +1887,7 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "command_phase0: (0x%p)\n", srb->cmd); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); } @@ -1899,7 +1898,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, struct DeviceCtlBlk *dcb; u8 *ptr; u16 i; - dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "command_phase1: (0x%p)\n", srb->cmd); clear_fifo(acb, "command_phase1"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN); @@ -2041,8 +2040,8 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, struct DeviceCtlBlk *dcb = srb->dcb; u16 scsi_status = *pscsi_status; u32 d_left_counter = 0; - dprintkdbg(DBG_0, "data_out_phase0: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_0, "data_out_phase0: (0x%p) <%02i-%i>\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); /* * KG: We need to drain the buffers before we draw any conclusions! @@ -2171,8 +2170,8 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "data_out_phase1: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_0, "data_out_phase1: (0x%p) <%02i-%i>\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); clear_fifo(acb, "data_out_phase1"); /* do prepare before transfer when data out phase */ data_io_transfer(acb, srb, XFERDATAOUT); @@ -2183,8 +2182,8 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, { u16 scsi_status = *pscsi_status; - dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_0, "data_in_phase0: (0x%p) <%02i-%i>\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); /* * KG: DataIn is much more tricky than DataOut. When the device is finished @@ -2204,8 +2203,8 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, unsigned int sc, fc; if (scsi_status & PARITYERROR) { - dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) " - "Parity Error\n", srb->cmd->serial_number); + dprintkl(KERN_INFO, "data_in_phase0: (0x%p) " + "Parity Error\n", srb->cmd); srb->status |= PARITY_ERROR; } /* @@ -2394,8 +2393,8 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "data_in_phase1: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_0, "data_in_phase1: (0x%p) <%02i-%i>\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); data_io_transfer(acb, srb, XFERDATAIN); } @@ -2406,8 +2405,8 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb = srb->dcb; u8 bval; dprintkdbg(DBG_0, - "data_io_transfer: (pid#%li) <%02i-%i> %c len=%i, sg=(%i/%i)\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun, + "data_io_transfer: (0x%p) <%02i-%i> %c len=%i, sg=(%i/%i)\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun, ((io_dir & DMACMD_DIR) ? 'r' : 'w'), srb->total_xfer_length, srb->sg_index, srb->sg_count); if (srb == acb->tmp_srb) @@ -2579,8 +2578,8 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "status_phase0: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_0, "status_phase0: (0x%p) <%02i-%i>\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); /* get message */ srb->state = SRB_COMPLETED; @@ -2593,8 +2592,8 @@ static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "status_phase1: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_0, "status_phase1: (0x%p) <%02i-%i>\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); srb->state = SRB_STATUS; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP); @@ -2635,8 +2634,8 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, { struct ScsiReqBlk *srb = NULL; struct ScsiReqBlk *i; - dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) tag=%i srb=%p\n", - srb->cmd->serial_number, tag, srb); + dprintkdbg(DBG_0, "msgin_qtag: (0x%p) tag=%i srb=%p\n", + srb->cmd, tag, srb); if (!(dcb->tag_mask & (1 << tag))) dprintkl(KERN_DEBUG, @@ -2654,8 +2653,8 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, if (!srb) goto mingx0; - dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->dcb->target_id, srb->dcb->target_lun); + dprintkdbg(DBG_0, "msgin_qtag: (0x%p) <%02i-%i>\n", + srb->cmd, srb->dcb->target_id, srb->dcb->target_lun); if (dcb->flag & ABORT_DEV_) { /*srb->state = SRB_ABORT_SENT; */ enable_msgout_abort(acb, srb); @@ -2865,7 +2864,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { struct DeviceCtlBlk *dcb = acb->active_dcb; - dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "msgin_phase0: (0x%p)\n", srb->cmd); srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); if (msgin_completed(srb->msgin_buf, acb->msg_len)) { @@ -2931,9 +2930,9 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, * SAVE POINTER may be ignored as we have the struct * ScsiReqBlk* associated with the scsi command. */ - dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) " + dprintkdbg(DBG_0, "msgin_phase0: (0x%p) " "SAVE POINTER rem=%i Ignore\n", - srb->cmd->serial_number, srb->total_xfer_length); + srb->cmd, srb->total_xfer_length); break; case RESTORE_POINTERS: @@ -2941,9 +2940,9 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, break; case ABORT: - dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) " + dprintkdbg(DBG_0, "msgin_phase0: (0x%p) " "<%02i-%i> ABORT msg\n", - srb->cmd->serial_number, dcb->target_id, + srb->cmd, dcb->target_id, dcb->target_lun); dcb->flag |= ABORT_DEV_; enable_msgout_abort(acb, srb); @@ -2975,7 +2974,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "msgin_phase1: (0x%p)\n", srb->cmd); clear_fifo(acb, "msgin_phase1"); DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); if (!(srb->state & SRB_MSGIN)) { @@ -3041,7 +3040,7 @@ static void disconnect(struct AdapterCtlBlk *acb) } srb = dcb->active_srb; acb->active_dcb = NULL; - dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "disconnect: (0x%p)\n", srb->cmd); srb->scsi_phase = PH_BUS_FREE; /* initial phase */ clear_fifo(acb, "disconnect"); @@ -3071,14 +3070,14 @@ static void disconnect(struct AdapterCtlBlk *acb) && srb->state != SRB_MSGOUT) { srb->state = SRB_READY; dprintkl(KERN_DEBUG, - "disconnect: (pid#%li) Unexpected\n", - srb->cmd->serial_number); + "disconnect: (0x%p) Unexpected\n", + srb->cmd); srb->target_status = SCSI_STAT_SEL_TIMEOUT; goto disc1; } else { /* Normal selection timeout */ - dprintkdbg(DBG_KG, "disconnect: (pid#%li) " - "<%02i-%i> SelTO\n", srb->cmd->serial_number, + dprintkdbg(DBG_KG, "disconnect: (0x%p) " + "<%02i-%i> SelTO\n", srb->cmd, dcb->target_id, dcb->target_lun); if (srb->retry_count++ > DC395x_MAX_RETRIES || acb->scan_devices) { @@ -3089,8 +3088,8 @@ static void disconnect(struct AdapterCtlBlk *acb) free_tag(dcb, srb); srb_going_to_waiting_move(dcb, srb); dprintkdbg(DBG_KG, - "disconnect: (pid#%li) Retry\n", - srb->cmd->serial_number); + "disconnect: (0x%p) Retry\n", + srb->cmd); waiting_set_timer(acb, HZ / 20); } } else if (srb->state & SRB_DISCONNECT) { @@ -3142,9 +3141,9 @@ static void reselect(struct AdapterCtlBlk *acb) } /* Why the if ? */ if (!acb->scan_devices) { - dprintkdbg(DBG_KG, "reselect: (pid#%li) <%02i-%i> " + dprintkdbg(DBG_KG, "reselect: (0x%p) <%02i-%i> " "Arb lost but Resel win rsel=%i stat=0x%04x\n", - srb->cmd->serial_number, dcb->target_id, + srb->cmd, dcb->target_id, dcb->target_lun, rsel_tar_lun_id, DC395x_read16(acb, TRM_S1040_SCSI_STATUS)); arblostflag = 1; @@ -3318,7 +3317,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, enum dma_data_direction dir = cmd->sc_data_direction; int ckc_only = 1; - dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->serial_number, + dprintkdbg(DBG_1, "srb_done: (0x%p) <%02i-%i>\n", srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n", srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count, @@ -3497,9 +3496,9 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, cmd->SCp.buffers_residual = 0; if (debug_enabled(DBG_KG)) { if (srb->total_xfer_length) - dprintkdbg(DBG_KG, "srb_done: (pid#%li) <%02i-%i> " + dprintkdbg(DBG_KG, "srb_done: (0x%p) <%02i-%i> " "cmnd=0x%02x Missed %i bytes\n", - cmd->serial_number, cmd->device->id, cmd->device->lun, + cmd, cmd->device->id, cmd->device->lun, cmd->cmnd[0], srb->total_xfer_length); } @@ -3508,8 +3507,8 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, if (srb == acb->tmp_srb) dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n"); else { - dprintkdbg(DBG_0, "srb_done: (pid#%li) done result=0x%08x\n", - cmd->serial_number, cmd->result); + dprintkdbg(DBG_0, "srb_done: (0x%p) done result=0x%08x\n", + cmd, cmd->result); srb_free_insert(acb, srb); } pci_unmap_srb(acb, srb); @@ -3538,7 +3537,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, p = srb->cmd; dir = p->sc_data_direction; result = MK_RES(0, did_flag, 0, 0); - printk("G:%li(%02i-%i) ", p->serial_number, + printk("G:%p(%02i-%i) ", p, p->device->id, p->device->lun); srb_going_remove(dcb, srb); free_tag(dcb, srb); @@ -3568,7 +3567,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, p = srb->cmd; result = MK_RES(0, did_flag, 0, 0); - printk("W:%li<%02i-%i>", p->serial_number, p->device->id, + printk("W:%p<%02i-%i>", p, p->device->id, p->device->lun); srb_waiting_remove(dcb, srb); srb_free_insert(acb, srb); @@ -3677,8 +3676,8 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { struct scsi_cmnd *cmd = srb->cmd; - dprintkdbg(DBG_1, "request_sense: (pid#%li) <%02i-%i>\n", - cmd->serial_number, cmd->device->id, cmd->device->lun); + dprintkdbg(DBG_1, "request_sense: (0x%p) <%02i-%i>\n", + cmd, cmd->device->id, cmd->device->lun); srb->flag |= AUTO_REQSENSE; srb->adapter_status = 0; @@ -3708,8 +3707,8 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, if (start_scsi(acb, dcb, srb)) { /* Should only happen, if sb. else grabs the bus */ dprintkl(KERN_DEBUG, - "request_sense: (pid#%li) failed <%02i-%i>\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun); + "request_sense: (0x%p) failed <%02i-%i>\n", + srb->cmd, dcb->target_id, dcb->target_lun); srb_going_to_waiting_move(dcb, srb); waiting_set_timer(acb, HZ / 100); } @@ -4717,13 +4716,13 @@ static int dc395x_proc_info(struct Scsi_Host *host, char *buffer, dcb->target_id, dcb->target_lun, list_size(&dcb->srb_waiting_list)); list_for_each_entry(srb, &dcb->srb_waiting_list, list) - SPRINTF(" %li", srb->cmd->serial_number); + SPRINTF(" %p", srb->cmd); if (!list_empty(&dcb->srb_going_list)) SPRINTF("\nDCB (%02i-%i): Going : %i:", dcb->target_id, dcb->target_lun, list_size(&dcb->srb_going_list)); list_for_each_entry(srb, &dcb->srb_going_list, list) - SPRINTF(" %li", srb->cmd->serial_number); + SPRINTF(" %p", srb->cmd); if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list)) SPRINTF("\n"); } diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 564e6ecd17c2..0119b8147797 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -394,12 +394,14 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) unsigned long flags; struct scsi_device *sdev; struct scsi_device_handler *scsi_dh = NULL; + struct device *dev = NULL; spin_lock_irqsave(q->queue_lock, flags); sdev = q->queuedata; if (sdev && sdev->scsi_dh_data) scsi_dh = sdev->scsi_dh_data->scsi_dh; - if (!scsi_dh || !get_device(&sdev->sdev_gendev) || + dev = get_device(&sdev->sdev_gendev); + if (!scsi_dh || !dev || sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL) err = SCSI_DH_NOSYS; @@ -410,12 +412,13 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) if (err) { if (fn) fn(data, err); - return err; + goto out; } if (scsi_dh->activate) err = scsi_dh->activate(sdev, fn, data); - put_device(&sdev->sdev_gendev); +out: + put_device(dev); return err; } EXPORT_SYMBOL_GPL(scsi_dh_activate); diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 42fe52902add..6fec9fe5dc39 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -782,7 +782,7 @@ static int alua_bus_attach(struct scsi_device *sdev) h->sdev = sdev; err = alua_initialize(sdev, h); - if (err != SCSI_DH_OK) + if ((err != SCSI_DH_OK) && (err != SCSI_DH_DEV_OFFLINED)) goto failed; if (!try_module_get(THIS_MODULE)) diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 293c183dfe6d..e7fc70d6b478 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -182,14 +182,24 @@ struct rdac_dh_data { struct rdac_controller *ctlr; #define UNINITIALIZED_LUN (1 << 8) unsigned lun; + +#define RDAC_MODE 0 +#define RDAC_MODE_AVT 1 +#define RDAC_MODE_IOSHIP 2 + unsigned char mode; + #define RDAC_STATE_ACTIVE 0 #define RDAC_STATE_PASSIVE 1 unsigned char state; #define RDAC_LUN_UNOWNED 0 #define RDAC_LUN_OWNED 1 -#define RDAC_LUN_AVT 2 char lun_state; + +#define RDAC_PREFERRED 0 +#define RDAC_NON_PREFERRED 1 + char preferred; + unsigned char sense[SCSI_SENSE_BUFFERSIZE]; union { struct c2_inquiry c2; @@ -199,11 +209,15 @@ struct rdac_dh_data { } inq; }; +static const char *mode[] = { + "RDAC", + "AVT", + "IOSHIP", +}; static const char *lun_state[] = { "unowned", "owned", - "owned (AVT mode)", }; struct rdac_queue_data { @@ -458,25 +472,33 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h) int err; struct c9_inquiry *inqp; - h->lun_state = RDAC_LUN_UNOWNED; h->state = RDAC_STATE_ACTIVE; err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h); if (err == SCSI_DH_OK) { inqp = &h->inq.c9; - if ((inqp->avte_cvp >> 7) == 0x1) { - /* LUN in AVT mode */ - sdev_printk(KERN_NOTICE, sdev, - "%s: AVT mode detected\n", - RDAC_NAME); - h->lun_state = RDAC_LUN_AVT; - } else if ((inqp->avte_cvp & 0x1) != 0) { - /* LUN was owned by the controller */ - h->lun_state = RDAC_LUN_OWNED; - } - } + /* detect the operating mode */ + if ((inqp->avte_cvp >> 5) & 0x1) + h->mode = RDAC_MODE_IOSHIP; /* LUN in IOSHIP mode */ + else if (inqp->avte_cvp >> 7) + h->mode = RDAC_MODE_AVT; /* LUN in AVT mode */ + else + h->mode = RDAC_MODE; /* LUN in RDAC mode */ - if (h->lun_state == RDAC_LUN_UNOWNED) - h->state = RDAC_STATE_PASSIVE; + /* Update ownership */ + if (inqp->avte_cvp & 0x1) + h->lun_state = RDAC_LUN_OWNED; + else { + h->lun_state = RDAC_LUN_UNOWNED; + if (h->mode == RDAC_MODE) + h->state = RDAC_STATE_PASSIVE; + } + + /* Update path prio*/ + if (inqp->path_prio & 0x1) + h->preferred = RDAC_PREFERRED; + else + h->preferred = RDAC_NON_PREFERRED; + } return err; } @@ -648,12 +670,27 @@ static int rdac_activate(struct scsi_device *sdev, { struct rdac_dh_data *h = get_rdac_data(sdev); int err = SCSI_DH_OK; + int act = 0; err = check_ownership(sdev, h); if (err != SCSI_DH_OK) goto done; - if (h->lun_state == RDAC_LUN_UNOWNED) { + switch (h->mode) { + case RDAC_MODE: + if (h->lun_state == RDAC_LUN_UNOWNED) + act = 1; + break; + case RDAC_MODE_IOSHIP: + if ((h->lun_state == RDAC_LUN_UNOWNED) && + (h->preferred == RDAC_PREFERRED)) + act = 1; + break; + default: + break; + } + + if (act) { err = queue_mode_select(sdev, fn, data); if (err == SCSI_DH_OK) return 0; @@ -836,8 +873,9 @@ static int rdac_bus_attach(struct scsi_device *sdev) spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); sdev_printk(KERN_NOTICE, sdev, - "%s: LUN %d (%s)\n", - RDAC_NAME, h->lun, lun_state[(int)h->lun_state]); + "%s: LUN %d (%s) (%s)\n", + RDAC_NAME, h->lun, mode[(int)h->mode], + lun_state[(int)h->lun_state]); return 0; diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index cffcb108ac96..b4f6c9a84e71 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -780,7 +780,7 @@ static int adpt_abort(struct scsi_cmnd * cmd) return FAILED; } pHba = (adpt_hba*) cmd->device->host->hostdata[0]; - printk(KERN_INFO"%s: Trying to Abort cmd=%ld\n",pHba->name, cmd->serial_number); + printk(KERN_INFO"%s: Trying to Abort\n",pHba->name); if ((dptdevice = (void*) (cmd->device->hostdata)) == NULL) { printk(KERN_ERR "%s: Unable to abort: No device in cmnd\n",pHba->name); return FAILED; @@ -802,10 +802,10 @@ static int adpt_abort(struct scsi_cmnd * cmd) printk(KERN_INFO"%s: Abort cmd not supported\n",pHba->name); return FAILED; } - printk(KERN_INFO"%s: Abort cmd=%ld failed.\n",pHba->name, cmd->serial_number); + printk(KERN_INFO"%s: Abort failed.\n",pHba->name); return FAILED; } - printk(KERN_INFO"%s: Abort cmd=%ld complete.\n",pHba->name, cmd->serial_number); + printk(KERN_INFO"%s: Abort complete.\n",pHba->name); return SUCCESS; } diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index 0eb4fe6a4c8a..94de88955a99 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1766,8 +1766,8 @@ static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt, struct mscp *cpp; if (SCpnt->host_scribble) - panic("%s: qcomm, pid %ld, SCpnt %p already active.\n", - ha->board_name, SCpnt->serial_number, SCpnt); + panic("%s: qcomm, SCpnt %p already active.\n", + ha->board_name, SCpnt); /* i is the mailbox number, look for the first free mailbox starting from last_cp_used */ @@ -1801,7 +1801,7 @@ static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt, if (do_trace) scmd_printk(KERN_INFO, SCpnt, - "qcomm, mbox %d, pid %ld.\n", i, SCpnt->serial_number); + "qcomm, mbox %d.\n", i); cpp->reqsen = 1; cpp->dispri = 1; @@ -1833,8 +1833,7 @@ static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt, if (do_dma(shost->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { unmap_dma(i, ha); SCpnt->host_scribble = NULL; - scmd_printk(KERN_INFO, SCpnt, - "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number); + scmd_printk(KERN_INFO, SCpnt, "qcomm, adapter busy.\n"); return 1; } @@ -1851,14 +1850,12 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg) unsigned int i; if (SCarg->host_scribble == NULL) { - scmd_printk(KERN_INFO, SCarg, - "abort, pid %ld inactive.\n", SCarg->serial_number); + scmd_printk(KERN_INFO, SCarg, "abort, cmd inactive.\n"); return SUCCESS; } i = *(unsigned int *)SCarg->host_scribble; - scmd_printk(KERN_WARNING, SCarg, - "abort, mbox %d, pid %ld.\n", i, SCarg->serial_number); + scmd_printk(KERN_WARNING, SCarg, "abort, mbox %d.\n", i); if (i >= shost->can_queue) panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name); @@ -1902,8 +1899,8 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg) SCarg->result = DID_ABORT << 16; SCarg->host_scribble = NULL; ha->cp_stat[i] = FREE; - printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n", - ha->board_name, i, SCarg->serial_number); + printk("%s, abort, mbox %d ready, DID_ABORT, done.\n", + ha->board_name, i); SCarg->scsi_done(SCarg); return SUCCESS; } @@ -1919,13 +1916,12 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) struct Scsi_Host *shost = SCarg->device->host; struct hostdata *ha = (struct hostdata *)shost->hostdata; - scmd_printk(KERN_INFO, SCarg, - "reset, enter, pid %ld.\n", SCarg->serial_number); + scmd_printk(KERN_INFO, SCarg, "reset, enter.\n"); spin_lock_irq(shost->host_lock); if (SCarg->host_scribble == NULL) - printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->serial_number); + printk("%s: reset, inactive.\n", ha->board_name); if (ha->in_reset) { printk("%s: reset, exit, already in reset.\n", ha->board_name); @@ -1964,14 +1960,14 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) { ha->cp_stat[i] = ABORTING; - printk("%s: reset, mbox %d aborting, pid %ld.\n", - ha->board_name, i, SCpnt->serial_number); + printk("%s: reset, mbox %d aborting.\n", + ha->board_name, i); } else { ha->cp_stat[i] = IN_RESET; - printk("%s: reset, mbox %d in reset, pid %ld.\n", - ha->board_name, i, SCpnt->serial_number); + printk("%s: reset, mbox %d in reset.\n", + ha->board_name, i); } if (SCpnt->host_scribble == NULL) @@ -2025,8 +2021,8 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) ha->cp_stat[i] = LOCKED; printk - ("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n", - ha->board_name, i, SCpnt->serial_number); + ("%s, reset, mbox %d locked, DID_RESET, done.\n", + ha->board_name, i); } else if (ha->cp_stat[i] == ABORTING) { @@ -2039,8 +2035,8 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) ha->cp_stat[i] = FREE; printk - ("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n", - ha->board_name, i, SCpnt->serial_number); + ("%s, reset, mbox %d aborting, DID_RESET, done.\n", + ha->board_name, i); } else @@ -2054,7 +2050,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) do_trace = 0; if (arg_done) - printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->serial_number); + printk("%s: reset, exit, done.\n", ha->board_name); else printk("%s: reset, exit.\n", ha->board_name); @@ -2238,10 +2234,10 @@ static int reorder(struct hostdata *ha, unsigned long cursec, cpp = &ha->cp[k]; SCpnt = cpp->SCpnt; scmd_printk(KERN_INFO, SCpnt, - "%s pid %ld mb %d fc %d nr %d sec %ld ns %u" + "%s mb %d fc %d nr %d sec %ld ns %u" " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", (ihdlr ? "ihdlr" : "qcomm"), - SCpnt->serial_number, k, flushcount, + k, flushcount, n_ready, blk_rq_pos(SCpnt->request), blk_rq_sectors(SCpnt->request), cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), @@ -2285,10 +2281,10 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec, if (do_dma(dev->host->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { scmd_printk(KERN_INFO, SCpnt, - "%s, pid %ld, mbox %d, adapter" + "%s, mbox %d, adapter" " busy, will abort.\n", (ihdlr ? "ihdlr" : "qcomm"), - SCpnt->serial_number, k); + k); ha->cp_stat[k] = ABORTING; continue; } @@ -2398,12 +2394,12 @@ static irqreturn_t ihdlr(struct Scsi_Host *shost) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", ha->board_name, i); if (SCpnt->host_scribble == NULL) - panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", ha->board_name, - i, SCpnt->serial_number, SCpnt); + panic("%s: ihdlr, mbox %d, SCpnt %p garbled.\n", ha->board_name, + i, SCpnt); if (*(unsigned int *)SCpnt->host_scribble != i) - panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", - ha->board_name, i, SCpnt->serial_number, + panic("%s: ihdlr, mbox %d, index mismatch %d.\n", + ha->board_name, i, *(unsigned int *)SCpnt->host_scribble); sync_dma(i, ha); @@ -2449,11 +2445,11 @@ static irqreturn_t ihdlr(struct Scsi_Host *shost) if (spp->target_status && SCpnt->device->type == TYPE_DISK && (!(tstatus == CHECK_CONDITION && ha->iocount <= 1000 && (SCpnt->sense_buffer[2] & 0xf) == NOT_READY))) - printk("%s: ihdlr, target %d.%d:%d, pid %ld, " + printk("%s: ihdlr, target %d.%d:%d, " "target_status 0x%x, sense key 0x%x.\n", ha->board_name, SCpnt->device->channel, SCpnt->device->id, - SCpnt->device->lun, SCpnt->serial_number, + SCpnt->device->lun, spp->target_status, SCpnt->sense_buffer[2]); ha->target_to[SCpnt->device->id][SCpnt->device->channel] = 0; @@ -2522,9 +2518,9 @@ static irqreturn_t ihdlr(struct Scsi_Host *shost) do_trace || msg_byte(spp->target_status)) #endif scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x," - " pid %ld, reg 0x%x, count %d.\n", + " reg 0x%x, count %d.\n", i, spp->adapter_status, spp->target_status, - SCpnt->serial_number, reg, ha->iocount); + reg, ha->iocount); unmap_dma(i, ha); diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index 4a9641e69f54..d5f8362335d3 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -372,8 +372,7 @@ static int eata_pio_queue_lck(struct scsi_cmnd *cmd, cp->status = USED; /* claim free slot */ DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd, - "eata_pio_queue pid %ld, y %d\n", - cmd->serial_number, y)); + "eata_pio_queue 0x%p, y %d\n", cmd, y)); cmd->scsi_done = (void *) done; @@ -417,8 +416,8 @@ static int eata_pio_queue_lck(struct scsi_cmnd *cmd, if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) { cmd->result = DID_BUS_BUSY << 16; scmd_printk(KERN_NOTICE, cmd, - "eata_pio_queue pid %ld, HBA busy, " - "returning DID_BUS_BUSY, done.\n", cmd->serial_number); + "eata_pio_queue pid 0x%p, HBA busy, " + "returning DID_BUS_BUSY, done.\n", cmd); done(cmd); cp->status = FREE; return 0; @@ -432,8 +431,8 @@ static int eata_pio_queue_lck(struct scsi_cmnd *cmd, outw(0, base + HA_RDATA); DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd, - "Queued base %#.4lx pid: %ld " - "slot %d irq %d\n", sh->base, cmd->serial_number, y, sh->irq)); + "Queued base %#.4lx cmd: 0x%p " + "slot %d irq %d\n", sh->base, cmd, y, sh->irq)); return 0; } @@ -445,8 +444,7 @@ static int eata_pio_abort(struct scsi_cmnd *cmd) unsigned int loop = 100; DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd, - "eata_pio_abort called pid: %ld\n", - cmd->serial_number)); + "eata_pio_abort called pid: 0x%p\n", cmd)); while (inb(cmd->device->host->base + HA_RAUXSTAT) & HA_ABUSY) if (--loop == 0) { @@ -481,8 +479,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd) struct Scsi_Host *host = cmd->device->host; DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd, - "eata_pio_reset called pid:%ld\n", - cmd->serial_number)); + "eata_pio_reset called\n")); spin_lock_irq(host->host_lock); @@ -501,7 +498,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd) sp = HD(cmd)->ccb[x].cmd; HD(cmd)->ccb[x].status = RESET; - printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->serial_number); + printk(KERN_WARNING "eata_pio_reset: slot %d in reset.\n", x); if (sp == NULL) panic("eata_pio_reset: slot %d, sp==NULL.\n", x); diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 57558523c1b8..9a1af1d6071a 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -708,8 +708,7 @@ static void esp_maybe_execute_command(struct esp *esp) tp = &esp->target[tgt]; lp = dev->hostdata; - list_del(&ent->list); - list_add(&ent->list, &esp->active_cmds); + list_move(&ent->list, &esp->active_cmds); esp->active_cmd = ent; @@ -1244,8 +1243,7 @@ static int esp_finish_select(struct esp *esp) /* Now that the state is unwound properly, put back onto * the issue queue. This command is no longer active. */ - list_del(&ent->list); - list_add(&ent->list, &esp->queued_cmds); + list_move(&ent->list, &esp->queued_cmds); esp->active_cmd = NULL; /* Return value ignored by caller, it directly invokes diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index bde6ee5333eb..cc23bd9480b2 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -380,49 +380,6 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, return fcoe; } -/** - * fcoe_interface_cleanup() - Clean up a FCoE interface - * @fcoe: The FCoE interface to be cleaned up - * - * Caller must be holding the RTNL mutex - */ -void fcoe_interface_cleanup(struct fcoe_interface *fcoe) -{ - struct net_device *netdev = fcoe->netdev; - struct fcoe_ctlr *fip = &fcoe->ctlr; - u8 flogi_maddr[ETH_ALEN]; - const struct net_device_ops *ops; - - /* - * Don't listen for Ethernet packets anymore. - * synchronize_net() ensures that the packet handlers are not running - * on another CPU. dev_remove_pack() would do that, this calls the - * unsyncronized version __dev_remove_pack() to avoid multiple delays. - */ - __dev_remove_pack(&fcoe->fcoe_packet_type); - __dev_remove_pack(&fcoe->fip_packet_type); - synchronize_net(); - - /* Delete secondary MAC addresses */ - memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_uc_del(netdev, flogi_maddr); - if (fip->spma) - dev_uc_del(netdev, fip->ctl_src_addr); - if (fip->mode == FIP_MODE_VN2VN) { - dev_mc_del(netdev, FIP_ALL_VN2VN_MACS); - dev_mc_del(netdev, FIP_ALL_P2P_MACS); - } else - dev_mc_del(netdev, FIP_ALL_ENODE_MACS); - - /* Tell the LLD we are done w/ FCoE */ - ops = netdev->netdev_ops; - if (ops->ndo_fcoe_disable) { - if (ops->ndo_fcoe_disable(netdev)) - FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE" - " specific feature for LLD.\n"); - } -} - /** * fcoe_interface_release() - fcoe_port kref release function * @kref: Embedded reference count in an fcoe_interface struct @@ -459,6 +416,68 @@ static inline void fcoe_interface_put(struct fcoe_interface *fcoe) kref_put(&fcoe->kref, fcoe_interface_release); } +/** + * fcoe_interface_cleanup() - Clean up a FCoE interface + * @fcoe: The FCoE interface to be cleaned up + * + * Caller must be holding the RTNL mutex + */ +void fcoe_interface_cleanup(struct fcoe_interface *fcoe) +{ + struct net_device *netdev = fcoe->netdev; + struct fcoe_ctlr *fip = &fcoe->ctlr; + u8 flogi_maddr[ETH_ALEN]; + const struct net_device_ops *ops; + struct fcoe_port *port = lport_priv(fcoe->ctlr.lp); + + FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); + + /* Logout of the fabric */ + fc_fabric_logoff(fcoe->ctlr.lp); + + /* Cleanup the fc_lport */ + fc_lport_destroy(fcoe->ctlr.lp); + + /* Stop the transmit retry timer */ + del_timer_sync(&port->timer); + + /* Free existing transmit skbs */ + fcoe_clean_pending_queue(fcoe->ctlr.lp); + + /* + * Don't listen for Ethernet packets anymore. + * synchronize_net() ensures that the packet handlers are not running + * on another CPU. dev_remove_pack() would do that, this calls the + * unsyncronized version __dev_remove_pack() to avoid multiple delays. + */ + __dev_remove_pack(&fcoe->fcoe_packet_type); + __dev_remove_pack(&fcoe->fip_packet_type); + synchronize_net(); + + /* Delete secondary MAC addresses */ + memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); + dev_uc_del(netdev, flogi_maddr); + if (fip->spma) + dev_uc_del(netdev, fip->ctl_src_addr); + if (fip->mode == FIP_MODE_VN2VN) { + dev_mc_del(netdev, FIP_ALL_VN2VN_MACS); + dev_mc_del(netdev, FIP_ALL_P2P_MACS); + } else + dev_mc_del(netdev, FIP_ALL_ENODE_MACS); + + if (!is_zero_ether_addr(port->data_src_addr)) + dev_uc_del(netdev, port->data_src_addr); + + /* Tell the LLD we are done w/ FCoE */ + ops = netdev->netdev_ops; + if (ops->ndo_fcoe_disable) { + if (ops->ndo_fcoe_disable(netdev)) + FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE" + " specific feature for LLD.\n"); + } + fcoe_interface_put(fcoe); +} + /** * fcoe_fip_recv() - Handler for received FIP frames * @skb: The receive skb @@ -821,39 +840,9 @@ static inline int fcoe_em_config(struct fc_lport *lport) * fcoe_if_destroy() - Tear down a SW FCoE instance * @lport: The local port to be destroyed * - * Locking: must be called with the RTNL mutex held and RTNL mutex - * needed to be dropped by this function since not dropping RTNL - * would cause circular locking warning on synchronous fip worker - * cancelling thru fcoe_interface_put invoked by this function. - * */ static void fcoe_if_destroy(struct fc_lport *lport) { - struct fcoe_port *port = lport_priv(lport); - struct fcoe_interface *fcoe = port->priv; - struct net_device *netdev = fcoe->netdev; - - FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); - - /* Logout of the fabric */ - fc_fabric_logoff(lport); - - /* Cleanup the fc_lport */ - fc_lport_destroy(lport); - - /* Stop the transmit retry timer */ - del_timer_sync(&port->timer); - - /* Free existing transmit skbs */ - fcoe_clean_pending_queue(lport); - - if (!is_zero_ether_addr(port->data_src_addr)) - dev_uc_del(netdev, port->data_src_addr); - rtnl_unlock(); - - /* receives may not be stopped until after this */ - fcoe_interface_put(fcoe); - /* Free queued packets for the per-CPU receive threads */ fcoe_percpu_clean(lport); @@ -1783,23 +1772,8 @@ static int fcoe_disable(struct net_device *netdev) int rc = 0; mutex_lock(&fcoe_config_mutex); -#ifdef CONFIG_FCOE_MODULE - /* - * Make sure the module has been initialized, and is not about to be - * removed. Module paramter sysfs files are writable before the - * module_init function is called and after module_exit. - */ - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto out_nodev; - } -#endif - - if (!rtnl_trylock()) { - mutex_unlock(&fcoe_config_mutex); - return -ERESTARTSYS; - } + rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock(); @@ -1809,7 +1783,6 @@ static int fcoe_disable(struct net_device *netdev) } else rc = -ENODEV; -out_nodev: mutex_unlock(&fcoe_config_mutex); return rc; } @@ -1828,22 +1801,7 @@ static int fcoe_enable(struct net_device *netdev) int rc = 0; mutex_lock(&fcoe_config_mutex); -#ifdef CONFIG_FCOE_MODULE - /* - * Make sure the module has been initialized, and is not about to be - * removed. Module paramter sysfs files are writable before the - * module_init function is called and after module_exit. - */ - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto out_nodev; - } -#endif - if (!rtnl_trylock()) { - mutex_unlock(&fcoe_config_mutex); - return -ERESTARTSYS; - } - + rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock(); @@ -1852,7 +1810,6 @@ static int fcoe_enable(struct net_device *netdev) else if (!fcoe_link_ok(fcoe->ctlr.lp)) fcoe_ctlr_link_up(&fcoe->ctlr); -out_nodev: mutex_unlock(&fcoe_config_mutex); return rc; } @@ -1868,35 +1825,22 @@ static int fcoe_enable(struct net_device *netdev) static int fcoe_destroy(struct net_device *netdev) { struct fcoe_interface *fcoe; + struct fc_lport *lport; int rc = 0; mutex_lock(&fcoe_config_mutex); -#ifdef CONFIG_FCOE_MODULE - /* - * Make sure the module has been initialized, and is not about to be - * removed. Module paramter sysfs files are writable before the - * module_init function is called and after module_exit. - */ - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto out_nodev; - } -#endif - if (!rtnl_trylock()) { - mutex_unlock(&fcoe_config_mutex); - return -ERESTARTSYS; - } - + rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); if (!fcoe) { rtnl_unlock(); rc = -ENODEV; goto out_nodev; } - fcoe_interface_cleanup(fcoe); + lport = fcoe->ctlr.lp; list_del(&fcoe->list); - /* RTNL mutex is dropped by fcoe_if_destroy */ - fcoe_if_destroy(fcoe->ctlr.lp); + fcoe_interface_cleanup(fcoe); + rtnl_unlock(); + fcoe_if_destroy(lport); out_nodev: mutex_unlock(&fcoe_config_mutex); return rc; @@ -1912,8 +1856,6 @@ static void fcoe_destroy_work(struct work_struct *work) port = container_of(work, struct fcoe_port, destroy_work); mutex_lock(&fcoe_config_mutex); - rtnl_lock(); - /* RTNL mutex is dropped by fcoe_if_destroy */ fcoe_if_destroy(port->lport); mutex_unlock(&fcoe_config_mutex); } @@ -1948,23 +1890,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) struct fc_lport *lport; mutex_lock(&fcoe_config_mutex); - - if (!rtnl_trylock()) { - mutex_unlock(&fcoe_config_mutex); - return -ERESTARTSYS; - } - -#ifdef CONFIG_FCOE_MODULE - /* - * Make sure the module has been initialized, and is not about to be - * removed. Module paramter sysfs files are writable before the - * module_init function is called and after module_exit. - */ - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto out_nodev; - } -#endif + rtnl_lock(); /* look for existing lport */ if (fcoe_hostlist_lookup(netdev)) { @@ -2026,7 +1952,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) int fcoe_link_speed_update(struct fc_lport *lport) { struct net_device *netdev = fcoe_netdev(lport); - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; + struct ethtool_cmd ecmd; if (!dev_ethtool_get_settings(netdev, &ecmd)) { lport->link_supported_speeds &= @@ -2037,11 +1963,14 @@ int fcoe_link_speed_update(struct fc_lport *lport) if (ecmd.supported & SUPPORTED_10000baseT_Full) lport->link_supported_speeds |= FC_PORTSPEED_10GBIT; - if (ecmd.speed == SPEED_1000) + switch (ethtool_cmd_speed(&ecmd)) { + case SPEED_1000: lport->link_speed = FC_PORTSPEED_1GBIT; - if (ecmd.speed == SPEED_10000) + break; + case SPEED_10000: lport->link_speed = FC_PORTSPEED_10GBIT; - + break; + } return 0; } return -1; diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 9d38be2a41f9..229e4af5508a 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -978,10 +978,8 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) * the FCF that answers multicast solicitations, not the others that * are sending periodic multicast advertisements. */ - if (mtu_valid) { - list_del(&fcf->list); - list_add(&fcf->list, &fip->fcfs); - } + if (mtu_valid) + list_move(&fcf->list, &fip->fcfs); /* * If this is the first validated FCF, note the time and diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index 258684101bfd..f81f77c8569e 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -335,7 +335,7 @@ int fcoe_transport_attach(struct fcoe_transport *ft) EXPORT_SYMBOL(fcoe_transport_attach); /** - * fcoe_transport_attach - Detaches an FCoE transport + * fcoe_transport_detach - Detaches an FCoE transport * @ft: The fcoe transport to be attached * * Returns : 0 for success @@ -343,6 +343,7 @@ EXPORT_SYMBOL(fcoe_transport_attach); int fcoe_transport_detach(struct fcoe_transport *ft) { int rc = 0; + struct fcoe_netdev_mapping *nm = NULL, *tmp; mutex_lock(&ft_mutex); if (!ft->attached) { @@ -352,6 +353,19 @@ int fcoe_transport_detach(struct fcoe_transport *ft) goto out_attach; } + /* remove netdev mapping for this transport as it is going away */ + mutex_lock(&fn_mutex); + list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { + if (nm->ft == ft) { + LIBFCOE_TRANSPORT_DBG("transport %s going away, " + "remove its netdev mapping for %s\n", + ft->name, nm->netdev->name); + list_del(&nm->list); + kfree(nm); + } + } + mutex_unlock(&fn_mutex); + list_del(&ft->list); ft->attached = false; LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name); @@ -371,9 +385,9 @@ static int fcoe_transport_show(char *buffer, const struct kernel_param *kp) i = j = sprintf(buffer, "Attached FCoE transports:"); mutex_lock(&ft_mutex); list_for_each_entry(ft, &fcoe_transports, list) { - i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name); - if (i >= PAGE_SIZE) + if (i >= PAGE_SIZE - IFNAMSIZ) break; + i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name); } mutex_unlock(&ft_mutex); if (i == j) @@ -530,9 +544,6 @@ static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) struct fcoe_transport *ft = NULL; enum fip_state fip_mode = (enum fip_state)(long)kp->arg; - if (!mutex_trylock(&ft_mutex)) - return restart_syscall(); - #ifdef CONFIG_LIBFCOE_MODULE /* * Make sure the module has been initialized, and is not about to be @@ -543,6 +554,8 @@ static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) goto out_nodev; #endif + mutex_lock(&ft_mutex); + netdev = fcoe_if_to_netdev(buffer); if (!netdev) { LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buffer); @@ -586,10 +599,7 @@ static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) dev_put(netdev); out_nodev: mutex_unlock(&ft_mutex); - if (rc == -ERESTARTSYS) - return restart_syscall(); - else - return rc; + return rc; } /** @@ -608,9 +618,6 @@ static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) struct net_device *netdev = NULL; struct fcoe_transport *ft = NULL; - if (!mutex_trylock(&ft_mutex)) - return restart_syscall(); - #ifdef CONFIG_LIBFCOE_MODULE /* * Make sure the module has been initialized, and is not about to be @@ -621,6 +628,8 @@ static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) goto out_nodev; #endif + mutex_lock(&ft_mutex); + netdev = fcoe_if_to_netdev(buffer); if (!netdev) { LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buffer); @@ -645,11 +654,7 @@ static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) dev_put(netdev); out_nodev: mutex_unlock(&ft_mutex); - - if (rc == -ERESTARTSYS) - return restart_syscall(); - else - return rc; + return rc; } /** @@ -667,9 +672,6 @@ static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) struct net_device *netdev = NULL; struct fcoe_transport *ft = NULL; - if (!mutex_trylock(&ft_mutex)) - return restart_syscall(); - #ifdef CONFIG_LIBFCOE_MODULE /* * Make sure the module has been initialized, and is not about to be @@ -680,6 +682,8 @@ static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) goto out_nodev; #endif + mutex_lock(&ft_mutex); + netdev = fcoe_if_to_netdev(buffer); if (!netdev) goto out_nodev; @@ -716,9 +720,6 @@ static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp) struct net_device *netdev = NULL; struct fcoe_transport *ft = NULL; - if (!mutex_trylock(&ft_mutex)) - return restart_syscall(); - #ifdef CONFIG_LIBFCOE_MODULE /* * Make sure the module has been initialized, and is not about to be @@ -729,6 +730,8 @@ static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp) goto out_nodev; #endif + mutex_lock(&ft_mutex); + netdev = fcoe_if_to_netdev(buffer); if (!netdev) goto out_nodev; @@ -743,10 +746,7 @@ static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp) dev_put(netdev); out_nodev: mutex_unlock(&ft_mutex); - if (rc == -ERESTARTSYS) - return restart_syscall(); - else - return rc; + return rc; } /** diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 415ad4fb50d4..c6c0434d8034 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -273,7 +273,7 @@ static ssize_t host_show_transport_mode(struct device *dev, "performant" : "simple"); } -/* List of controllers which cannot be reset on kexec with reset_devices */ +/* List of controllers which cannot be hard reset on kexec with reset_devices */ static u32 unresettable_controller[] = { 0x324a103C, /* Smart Array P712m */ 0x324b103C, /* SmartArray P711m */ @@ -291,16 +291,45 @@ static u32 unresettable_controller[] = { 0x409D0E11, /* Smart Array 6400 EM */ }; -static int ctlr_is_resettable(struct ctlr_info *h) +/* List of controllers which cannot even be soft reset */ +static u32 soft_unresettable_controller[] = { + /* Exclude 640x boards. These are two pci devices in one slot + * which share a battery backed cache module. One controls the + * cache, the other accesses the cache through the one that controls + * it. If we reset the one controlling the cache, the other will + * likely not be happy. Just forbid resetting this conjoined mess. + * The 640x isn't really supported by hpsa anyway. + */ + 0x409C0E11, /* Smart Array 6400 */ + 0x409D0E11, /* Smart Array 6400 EM */ +}; + +static int ctlr_is_hard_resettable(u32 board_id) { int i; for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++) - if (unresettable_controller[i] == h->board_id) + if (unresettable_controller[i] == board_id) return 0; return 1; } +static int ctlr_is_soft_resettable(u32 board_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(soft_unresettable_controller); i++) + if (soft_unresettable_controller[i] == board_id) + return 0; + return 1; +} + +static int ctlr_is_resettable(u32 board_id) +{ + return ctlr_is_hard_resettable(board_id) || + ctlr_is_soft_resettable(board_id); +} + static ssize_t host_show_resettable(struct device *dev, struct device_attribute *attr, char *buf) { @@ -308,7 +337,7 @@ static ssize_t host_show_resettable(struct device *dev, struct Scsi_Host *shost = class_to_shost(dev); h = shost_to_hba(shost); - return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h)); + return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h->board_id)); } static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[]) @@ -929,13 +958,6 @@ static void hpsa_slave_destroy(struct scsi_device *sdev) /* nothing to do. */ } -static void hpsa_scsi_setup(struct ctlr_info *h) -{ - h->ndevices = 0; - h->scsi_host = NULL; - spin_lock_init(&h->devlock); -} - static void hpsa_free_sg_chain_blocks(struct ctlr_info *h) { int i; @@ -1006,8 +1028,7 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h, pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE); } -static void complete_scsi_command(struct CommandList *cp, - int timeout, u32 tag) +static void complete_scsi_command(struct CommandList *cp) { struct scsi_cmnd *cmd; struct ctlr_info *h; @@ -1308,7 +1329,7 @@ static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, int retry_count = 0; do { - memset(c->err_info, 0, sizeof(c->err_info)); + 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); @@ -1570,6 +1591,7 @@ static unsigned char *msa2xxx_model[] = { "MSA2024", "MSA2312", "MSA2324", + "P2000 G3 SAS", NULL, }; @@ -2751,6 +2773,26 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg) } } +static int __devinit hpsa_send_host_reset(struct ctlr_info *h, + unsigned char *scsi3addr, u8 reset_type) +{ + struct CommandList *c; + + c = cmd_alloc(h); + if (!c) + return -ENOMEM; + fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, + RAID_CTLR_LUNID, TYPE_MSG); + c->Request.CDB[1] = reset_type; /* fill_cmd defaults to target reset */ + c->waiting = NULL; + enqueue_cmd_and_start_io(h, c); + /* Don't wait for completion, the reset won't complete. Don't free + * the command either. This is the last command we will send before + * re-initializing everything, so it doesn't matter and won't leak. + */ + return 0; +} + static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, void *buff, size_t size, u8 page_code, unsigned char *scsi3addr, int cmd_type) @@ -2828,7 +2870,8 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_NONE; c->Request.Timeout = 0; /* Don't time out */ - c->Request.CDB[0] = 0x01; /* RESET_MSG is 0x01 */ + memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB)); + c->Request.CDB[0] = cmd; c->Request.CDB[1] = 0x03; /* Reset target above */ /* If bytes 4-7 are zero, it means reset the */ /* LunID device */ @@ -2936,7 +2979,7 @@ static inline void finish_cmd(struct CommandList *c, u32 raw_tag) { removeQ(c); if (likely(c->cmd_type == CMD_SCSI)) - complete_scsi_command(c, 0, raw_tag); + complete_scsi_command(c); else if (c->cmd_type == CMD_IOCTL_PEND) complete(c->waiting); } @@ -2994,6 +3037,63 @@ static inline u32 process_nonindexed_cmd(struct ctlr_info *h, return next_command(h); } +/* Some controllers, like p400, will give us one interrupt + * after a soft reset, even if we turned interrupts off. + * Only need to check for this in the hpsa_xxx_discard_completions + * functions. + */ +static int ignore_bogus_interrupt(struct ctlr_info *h) +{ + if (likely(!reset_devices)) + return 0; + + if (likely(h->interrupts_enabled)) + return 0; + + dev_info(&h->pdev->dev, "Received interrupt while interrupts disabled " + "(known firmware bug.) Ignoring.\n"); + + return 1; +} + +static irqreturn_t hpsa_intx_discard_completions(int irq, void *dev_id) +{ + struct ctlr_info *h = dev_id; + unsigned long flags; + u32 raw_tag; + + if (ignore_bogus_interrupt(h)) + return IRQ_NONE; + + if (interrupt_not_for_us(h)) + return IRQ_NONE; + spin_lock_irqsave(&h->lock, flags); + while (interrupt_pending(h)) { + raw_tag = get_next_completion(h); + while (raw_tag != FIFO_EMPTY) + raw_tag = next_command(h); + } + spin_unlock_irqrestore(&h->lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t hpsa_msix_discard_completions(int irq, void *dev_id) +{ + struct ctlr_info *h = dev_id; + unsigned long flags; + u32 raw_tag; + + if (ignore_bogus_interrupt(h)) + return IRQ_NONE; + + spin_lock_irqsave(&h->lock, flags); + raw_tag = get_next_completion(h); + while (raw_tag != FIFO_EMPTY) + raw_tag = next_command(h); + spin_unlock_irqrestore(&h->lock, flags); + return IRQ_HANDLED; +} + static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id) { struct ctlr_info *h = dev_id; @@ -3132,11 +3232,10 @@ static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode, return 0; } -#define hpsa_soft_reset_controller(p) hpsa_message(p, 1, 0) #define hpsa_noop(p) hpsa_message(p, 3, 0) static int hpsa_controller_hard_reset(struct pci_dev *pdev, - void * __iomem vaddr, bool use_doorbell) + void * __iomem vaddr, u32 use_doorbell) { u16 pmcsr; int pos; @@ -3147,8 +3246,7 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev, * other way using the doorbell register. */ dev_info(&pdev->dev, "using doorbell to reset controller\n"); - writel(DOORBELL_CTLR_RESET, vaddr + SA5_DOORBELL); - msleep(1000); + writel(use_doorbell, vaddr + SA5_DOORBELL); } else { /* Try to do it the PCI power state way */ /* Quoting from the Open CISS Specification: "The Power @@ -3179,12 +3277,63 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev, pmcsr &= ~PCI_PM_CTRL_STATE_MASK; pmcsr |= PCI_D0; pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); - - msleep(500); } return 0; } +static __devinit void init_driver_version(char *driver_version, int len) +{ + memset(driver_version, 0, len); + strncpy(driver_version, "hpsa " HPSA_DRIVER_VERSION, len - 1); +} + +static __devinit int write_driver_ver_to_cfgtable( + struct CfgTable __iomem *cfgtable) +{ + char *driver_version; + int i, size = sizeof(cfgtable->driver_version); + + driver_version = kmalloc(size, GFP_KERNEL); + if (!driver_version) + return -ENOMEM; + + init_driver_version(driver_version, size); + for (i = 0; i < size; i++) + writeb(driver_version[i], &cfgtable->driver_version[i]); + kfree(driver_version); + return 0; +} + +static __devinit void read_driver_ver_from_cfgtable( + struct CfgTable __iomem *cfgtable, unsigned char *driver_ver) +{ + int i; + + for (i = 0; i < sizeof(cfgtable->driver_version); i++) + driver_ver[i] = readb(&cfgtable->driver_version[i]); +} + +static __devinit int controller_reset_failed( + struct CfgTable __iomem *cfgtable) +{ + + char *driver_ver, *old_driver_ver; + int rc, size = sizeof(cfgtable->driver_version); + + old_driver_ver = kmalloc(2 * size, GFP_KERNEL); + if (!old_driver_ver) + return -ENOMEM; + driver_ver = old_driver_ver + size; + + /* After a reset, the 32 bytes of "driver version" in the cfgtable + * should have been changed, otherwise we know the reset failed. + */ + init_driver_version(old_driver_ver, size); + read_driver_ver_from_cfgtable(cfgtable, driver_ver); + rc = !memcmp(driver_ver, old_driver_ver, size); + kfree(old_driver_ver); + return rc; +} /* This does a hard reset of the controller using PCI power management * states or the using the doorbell register. */ @@ -3195,10 +3344,10 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) u64 cfg_base_addr_index; void __iomem *vaddr; unsigned long paddr; - u32 misc_fw_support, active_transport; + u32 misc_fw_support; int rc; struct CfgTable __iomem *cfgtable; - bool use_doorbell; + u32 use_doorbell; u32 board_id; u16 command_register; @@ -3215,20 +3364,15 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) * using the doorbell register. */ - /* Exclude 640x boards. These are two pci devices in one slot - * which share a battery backed cache module. One controls the - * cache, the other accesses the cache through the one that controls - * it. If we reset the one controlling the cache, the other will - * likely not be happy. Just forbid resetting this conjoined mess. - * The 640x isn't really supported by hpsa anyway. - */ rc = hpsa_lookup_board_id(pdev, &board_id); - if (rc < 0) { + if (rc < 0 || !ctlr_is_resettable(board_id)) { dev_warn(&pdev->dev, "Not resetting device.\n"); return -ENODEV; } - if (board_id == 0x409C0E11 || board_id == 0x409D0E11) - return -ENOTSUPP; + + /* if controller is soft- but not hard resettable... */ + if (!ctlr_is_hard_resettable(board_id)) + return -ENOTSUPP; /* try soft reset later. */ /* Save the PCI command register */ pci_read_config_word(pdev, 4, &command_register); @@ -3257,10 +3401,28 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) rc = -ENOMEM; goto unmap_vaddr; } + rc = write_driver_ver_to_cfgtable(cfgtable); + if (rc) + goto unmap_vaddr; - /* If reset via doorbell register is supported, use that. */ + /* If reset via doorbell register is supported, use that. + * There are two such methods. Favor the newest method. + */ misc_fw_support = readl(&cfgtable->misc_fw_support); - use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET; + use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET2; + if (use_doorbell) { + use_doorbell = DOORBELL_CTLR_RESET2; + } else { + use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET; + if (use_doorbell) { + dev_warn(&pdev->dev, "Controller claims that " + "'Bit 2 doorbell reset' is " + "supported, but not 'bit 5 doorbell reset'. " + "Firmware update is recommended.\n"); + rc = -ENOTSUPP; /* try soft reset */ + goto unmap_cfgtable; + } + } rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell); if (rc) @@ -3279,30 +3441,32 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) msleep(HPSA_POST_RESET_PAUSE_MSECS); /* Wait for board to become not ready, then ready. */ - dev_info(&pdev->dev, "Waiting for board to become ready.\n"); + dev_info(&pdev->dev, "Waiting for board to reset.\n"); rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY); - if (rc) + if (rc) { dev_warn(&pdev->dev, - "failed waiting for board to become not ready\n"); + "failed waiting for board to reset." + " Will try soft reset.\n"); + rc = -ENOTSUPP; /* Not expected, but try soft reset later */ + goto unmap_cfgtable; + } rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY); if (rc) { dev_warn(&pdev->dev, - "failed waiting for board to become ready\n"); + "failed waiting for board to become ready " + "after hard reset\n"); goto unmap_cfgtable; } - dev_info(&pdev->dev, "board ready.\n"); - /* Controller should be in simple mode at this point. If it's not, - * It means we're on one of those controllers which doesn't support - * the doorbell reset method and on which the PCI power management reset - * method doesn't work (P800, for example.) - * In those cases, don't try to proceed, as it generally doesn't work. - */ - active_transport = readl(&cfgtable->TransportActive); - if (active_transport & PERFORMANT_MODE) { - dev_warn(&pdev->dev, "Unable to successfully reset controller," - " Ignoring controller.\n"); - rc = -ENODEV; + rc = controller_reset_failed(vaddr); + if (rc < 0) + goto unmap_cfgtable; + if (rc) { + dev_warn(&pdev->dev, "Unable to successfully reset " + "controller. Will try soft reset.\n"); + rc = -ENOTSUPP; + } else { + dev_info(&pdev->dev, "board ready after hard reset.\n"); } unmap_cfgtable: @@ -3543,6 +3707,9 @@ static int __devinit hpsa_find_cfgtables(struct ctlr_info *h) cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable)); if (!h->cfgtable) return -ENOMEM; + rc = write_driver_ver_to_cfgtable(h->cfgtable); + if (rc) + return rc; /* Find performant mode table. */ trans_offset = readl(&h->cfgtable->TransMethodOffset); h->transtable = remap_pci_mem(pci_resource_start(h->pdev, @@ -3777,11 +3944,12 @@ static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev) * due to concerns about shared bbwc between 6402/6404 pair. */ if (rc == -ENOTSUPP) - return 0; /* just try to do the kdump anyhow. */ + return rc; /* just try to do the kdump anyhow. */ if (rc) return -ENODEV; /* Now try to get the controller to respond to a no-op */ + dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n"); for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) { if (hpsa_noop(pdev) == 0) break; @@ -3792,18 +3960,133 @@ static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev) return 0; } +static __devinit int hpsa_allocate_cmd_pool(struct ctlr_info *h) +{ + h->cmd_pool_bits = kzalloc( + DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG) * + sizeof(unsigned long), GFP_KERNEL); + h->cmd_pool = pci_alloc_consistent(h->pdev, + h->nr_cmds * sizeof(*h->cmd_pool), + &(h->cmd_pool_dhandle)); + h->errinfo_pool = pci_alloc_consistent(h->pdev, + h->nr_cmds * sizeof(*h->errinfo_pool), + &(h->errinfo_pool_dhandle)); + if ((h->cmd_pool_bits == NULL) + || (h->cmd_pool == NULL) + || (h->errinfo_pool == NULL)) { + dev_err(&h->pdev->dev, "out of memory in %s", __func__); + return -ENOMEM; + } + return 0; +} + +static void hpsa_free_cmd_pool(struct ctlr_info *h) +{ + kfree(h->cmd_pool_bits); + if (h->cmd_pool) + pci_free_consistent(h->pdev, + h->nr_cmds * sizeof(struct CommandList), + h->cmd_pool, h->cmd_pool_dhandle); + if (h->errinfo_pool) + pci_free_consistent(h->pdev, + h->nr_cmds * sizeof(struct ErrorInfo), + h->errinfo_pool, + h->errinfo_pool_dhandle); +} + +static int hpsa_request_irq(struct ctlr_info *h, + irqreturn_t (*msixhandler)(int, void *), + irqreturn_t (*intxhandler)(int, void *)) +{ + int rc; + + if (h->msix_vector || h->msi_vector) + rc = request_irq(h->intr[h->intr_mode], msixhandler, + IRQF_DISABLED, h->devname, h); + else + rc = request_irq(h->intr[h->intr_mode], intxhandler, + IRQF_DISABLED, h->devname, h); + if (rc) { + dev_err(&h->pdev->dev, "unable to get irq %d for %s\n", + h->intr[h->intr_mode], h->devname); + return -ENODEV; + } + return 0; +} + +static int __devinit hpsa_kdump_soft_reset(struct ctlr_info *h) +{ + if (hpsa_send_host_reset(h, RAID_CTLR_LUNID, + HPSA_RESET_TYPE_CONTROLLER)) { + dev_warn(&h->pdev->dev, "Resetting array controller failed.\n"); + return -EIO; + } + + dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n"); + if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY)) { + dev_warn(&h->pdev->dev, "Soft reset had no effect.\n"); + return -1; + } + + dev_info(&h->pdev->dev, "Board reset, awaiting READY status.\n"); + if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY)) { + dev_warn(&h->pdev->dev, "Board failed to become ready " + "after soft reset.\n"); + return -1; + } + + return 0; +} + +static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) +{ + 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_sg_chain_blocks(h); + hpsa_free_cmd_pool(h); + kfree(h->blockFetchTable); + pci_free_consistent(h->pdev, h->reply_pool_size, + h->reply_pool, h->reply_pool_dhandle); + if (h->vaddr) + iounmap(h->vaddr); + if (h->transtable) + iounmap(h->transtable); + if (h->cfgtable) + iounmap(h->cfgtable); + pci_release_regions(h->pdev); + kfree(h); +} + static int __devinit hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int dac, rc; struct ctlr_info *h; + int try_soft_reset = 0; + unsigned long flags; if (number_of_controllers == 0) printk(KERN_INFO DRIVER_NAME "\n"); rc = hpsa_init_reset_devices(pdev); - if (rc) - return rc; + if (rc) { + if (rc != -ENOTSUPP) + return rc; + /* If the reset fails in a particular way (it has no way to do + * a proper hard reset, so returns -ENOTSUPP) we can try to do + * a soft reset once we get the controller configured up to the + * point that it can accept a command. + */ + try_soft_reset = 1; + rc = 0; + } + +reinit_after_soft_reset: /* Command structures must be aligned on a 32-byte boundary because * the 5 lower bits of the address are used by the hardware. and by @@ -3847,54 +4130,82 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, /* make sure the board interrupts are off */ h->access.set_intr_mask(h, HPSA_INTR_OFF); - if (h->msix_vector || h->msi_vector) - rc = request_irq(h->intr[h->intr_mode], do_hpsa_intr_msi, - IRQF_DISABLED, h->devname, h); - else - rc = request_irq(h->intr[h->intr_mode], do_hpsa_intr_intx, - IRQF_DISABLED, h->devname, h); - if (rc) { - dev_err(&pdev->dev, "unable to get irq %d for %s\n", - h->intr[h->intr_mode], h->devname); + if (hpsa_request_irq(h, do_hpsa_intr_msi, do_hpsa_intr_intx)) goto clean2; - } - dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, h->intr[h->intr_mode], dac ? "" : " not"); - - h->cmd_pool_bits = - kmalloc(((h->nr_cmds + BITS_PER_LONG - - 1) / BITS_PER_LONG) * sizeof(unsigned long), GFP_KERNEL); - h->cmd_pool = pci_alloc_consistent(h->pdev, - h->nr_cmds * sizeof(*h->cmd_pool), - &(h->cmd_pool_dhandle)); - h->errinfo_pool = pci_alloc_consistent(h->pdev, - h->nr_cmds * sizeof(*h->errinfo_pool), - &(h->errinfo_pool_dhandle)); - if ((h->cmd_pool_bits == NULL) - || (h->cmd_pool == NULL) - || (h->errinfo_pool == NULL)) { - dev_err(&pdev->dev, "out of memory"); - rc = -ENOMEM; + if (hpsa_allocate_cmd_pool(h)) goto clean4; - } if (hpsa_allocate_sg_chain_blocks(h)) goto clean4; init_waitqueue_head(&h->scan_wait_queue); h->scan_finished = 1; /* no scan currently in progress */ pci_set_drvdata(pdev, h); - memset(h->cmd_pool_bits, 0, - ((h->nr_cmds + BITS_PER_LONG - - 1) / BITS_PER_LONG) * sizeof(unsigned long)); + h->ndevices = 0; + h->scsi_host = NULL; + spin_lock_init(&h->devlock); + hpsa_put_ctlr_into_performant_mode(h); - hpsa_scsi_setup(h); + /* At this point, the controller is ready to take commands. + * Now, if reset_devices and the hard reset didn't work, try + * the soft reset and see if that works. + */ + if (try_soft_reset) { + + /* This is kind of gross. We may or may not get a completion + * from the soft reset command, and if we do, then the value + * from the fifo may or may not be valid. So, we wait 10 secs + * after the reset throwing away any completions we get during + * that time. Unregister the interrupt handler and register + * fake ones to scoop up any residual completions. + */ + 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); + rc = hpsa_request_irq(h, hpsa_msix_discard_completions, + hpsa_intx_discard_completions); + if (rc) { + dev_warn(&h->pdev->dev, "Failed to request_irq after " + "soft reset.\n"); + goto clean4; + } + + rc = hpsa_kdump_soft_reset(h); + if (rc) + /* Neither hard nor soft reset worked, we're hosed. */ + goto clean4; + + dev_info(&h->pdev->dev, "Board READY.\n"); + dev_info(&h->pdev->dev, + "Waiting for stale completions to drain.\n"); + h->access.set_intr_mask(h, HPSA_INTR_ON); + msleep(10000); + h->access.set_intr_mask(h, HPSA_INTR_OFF); + + rc = controller_reset_failed(h->cfgtable); + if (rc) + dev_info(&h->pdev->dev, + "Soft reset appears to have failed.\n"); + + /* since the controller's reset, we have to go back and re-init + * everything. Easiest to just forget what we've done and do it + * all over again. + */ + hpsa_undo_allocations_after_kdump_soft_reset(h); + try_soft_reset = 0; + if (rc) + /* don't go to clean4, we already unallocated */ + return -ENODEV; + + goto reinit_after_soft_reset; + } /* Turn the interrupts on so we can service requests */ h->access.set_intr_mask(h, HPSA_INTR_ON); - hpsa_put_ctlr_into_performant_mode(h); hpsa_hba_inquiry(h); hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ h->busy_initializing = 0; @@ -3902,16 +4213,7 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, clean4: hpsa_free_sg_chain_blocks(h); - kfree(h->cmd_pool_bits); - if (h->cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct CommandList), - h->cmd_pool, h->cmd_pool_dhandle); - if (h->errinfo_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct ErrorInfo), - h->errinfo_pool, - h->errinfo_pool_dhandle); + hpsa_free_cmd_pool(h); free_irq(h->intr[h->intr_mode], h); clean2: clean1: diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 621a1530054a..6d8dcd4dd06b 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -127,10 +127,12 @@ struct ctlr_info { }; #define HPSA_ABORT_MSG 0 #define HPSA_DEVICE_RESET_MSG 1 -#define HPSA_BUS_RESET_MSG 2 -#define HPSA_HOST_RESET_MSG 3 +#define HPSA_RESET_TYPE_CONTROLLER 0x00 +#define HPSA_RESET_TYPE_BUS 0x01 +#define HPSA_RESET_TYPE_TARGET 0x03 +#define HPSA_RESET_TYPE_LUN 0x04 #define HPSA_MSG_SEND_RETRY_LIMIT 10 -#define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS 1000 +#define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS (10000) /* Maximum time in seconds driver will wait for command completions * when polling before giving up. @@ -155,7 +157,7 @@ struct ctlr_info { * HPSA_BOARD_READY_ITERATIONS are derived from those. */ #define HPSA_BOARD_READY_WAIT_SECS (120) -#define HPSA_BOARD_NOT_READY_WAIT_SECS (10) +#define HPSA_BOARD_NOT_READY_WAIT_SECS (100) #define HPSA_BOARD_READY_POLL_INTERVAL_MSECS (100) #define HPSA_BOARD_READY_POLL_INTERVAL \ ((HPSA_BOARD_READY_POLL_INTERVAL_MSECS * HZ) / 1000) @@ -212,6 +214,7 @@ static void SA5_submit_command(struct ctlr_info *h, dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr, c->Header.Tag.lower); writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); + (void) readl(h->vaddr + SA5_REQUEST_PORT_OFFSET); h->commands_outstanding++; if (h->commands_outstanding > h->max_outstanding) h->max_outstanding = h->commands_outstanding; @@ -227,10 +230,12 @@ static void SA5_intr_mask(struct ctlr_info *h, unsigned long val) if (val) { /* Turn interrupts on */ h->interrupts_enabled = 1; writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); + (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); } else { /* Turn them off */ h->interrupts_enabled = 0; writel(SA5_INTR_OFF, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); + (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); } } @@ -239,10 +244,12 @@ static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val) if (val) { /* turn on interrupts */ h->interrupts_enabled = 1; writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); + (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); } else { h->interrupts_enabled = 0; writel(SA5_PERF_INTR_OFF, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); + (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); } } diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 18464900e761..55d741b019db 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -101,6 +101,7 @@ #define CFGTBL_ChangeReq 0x00000001l #define CFGTBL_AccCmds 0x00000001l #define DOORBELL_CTLR_RESET 0x00000004l +#define DOORBELL_CTLR_RESET2 0x00000020l #define CFGTBL_Trans_Simple 0x00000002l #define CFGTBL_Trans_Performant 0x00000004l @@ -256,14 +257,6 @@ struct ErrorInfo { #define CMD_IOCTL_PEND 0x01 #define CMD_SCSI 0x03 -/* This structure needs to be divisible by 32 for new - * indexing method and performant mode. - */ -#define PAD32 32 -#define PAD64DIFF 0 -#define USEEXTRA ((sizeof(void *) - 4)/4) -#define PADSIZE (PAD32 + PAD64DIFF * USEEXTRA) - #define DIRECT_LOOKUP_SHIFT 5 #define DIRECT_LOOKUP_BIT 0x10 #define DIRECT_LOOKUP_MASK (~((1 << DIRECT_LOOKUP_SHIFT) - 1)) @@ -345,6 +338,8 @@ struct CfgTable { u8 reserved[0x78 - 0x58]; 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 diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 041958453e2a..3d391dc3f11f 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -1849,8 +1849,7 @@ static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata) rc = ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata); if (!rc) rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0); - if (!rc) - rc = vio_enable_interrupts(to_vio_dev(hostdata->dev)); + vio_enable_interrupts(to_vio_dev(hostdata->dev)); } else if (hostdata->reenable_crq) { smp_rmb(); action = "enable"; diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c index 6568aab745a0..92109b126391 100644 --- a/drivers/scsi/in2000.c +++ b/drivers/scsi/in2000.c @@ -343,7 +343,7 @@ static int in2000_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) instance = cmd->device->host; hostdata = (struct IN2000_hostdata *) instance->hostdata; - DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x-%ld(", cmd->cmnd[0], cmd->serial_number)) + DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x(", cmd->cmnd[0])) /* Set up a few fields in the Scsi_Cmnd structure for our own use: * - host_scribble is the pointer to the next cmd in the input queue @@ -427,7 +427,7 @@ static int in2000_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) in2000_execute(cmd->device->host); - DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number)) + DB(DB_QUEUE_COMMAND, printk(")Q ")) return 0; } @@ -705,7 +705,7 @@ static void in2000_execute(struct Scsi_Host *instance) * to search the input_Q again... */ - DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number)) + DB(DB_EXECUTE, printk("%s)EX-2 ", (cmd->SCp.phase) ? "d:" : "")) } @@ -1149,7 +1149,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) case CSR_XFER_DONE | PHS_COMMAND: case CSR_UNEXP | PHS_COMMAND: case CSR_SRV_REQ | PHS_COMMAND: - DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number)) + DB(DB_INTR, printk("CMND-%02x", cmd->cmnd[0])) transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata); hostdata->state = S_CONNECTED; break; @@ -1191,7 +1191,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) switch (msg) { case COMMAND_COMPLETE: - DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number)) + DB(DB_INTR, printk("CCMP")) write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); hostdata->state = S_PRE_CMP_DISC; break; @@ -1329,7 +1329,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) write_3393(hostdata, WD_SOURCE_ID, SRCID_ER); if (phs == 0x60) { - DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number)) + DB(DB_INTR, printk("SX-DONE")) cmd->SCp.Message = COMMAND_COMPLETE; lun = read_3393(hostdata, WD_TARGET_LUN); DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun)) @@ -1350,7 +1350,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) in2000_execute(instance); } else { - printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->serial_number); + printk("%02x:%02x:%02x: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs); } break; @@ -1417,7 +1417,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) spin_unlock_irqrestore(instance->host_lock, flags); return IRQ_HANDLED; } - DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number)) + DB(DB_INTR, printk("UNEXP_DISC")) hostdata->connected = NULL; hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); hostdata->state = S_UNCONNECTED; @@ -1442,7 +1442,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) */ write_3393(hostdata, WD_SOURCE_ID, SRCID_ER); - DB(DB_INTR, printk("DISC-%ld", cmd->serial_number)) + DB(DB_INTR, printk("DISC")) if (cmd == NULL) { printk(" - Already disconnected! "); hostdata->state = S_UNCONNECTED; @@ -1575,7 +1575,6 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) } else hostdata->state = S_CONNECTED; - DB(DB_INTR, printk("-%ld", cmd->serial_number)) break; default: @@ -1704,7 +1703,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd) prev->host_scribble = cmd->host_scribble; cmd->host_scribble = NULL; cmd->result = DID_ABORT << 16; - printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->serial_number); + printk(KERN_WARNING "scsi%d: Abort - removing command from input_Q. ", instance->host_no); cmd->scsi_done(cmd); return SUCCESS; } @@ -1725,7 +1724,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd) if (hostdata->connected == cmd) { - printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->serial_number); + printk(KERN_WARNING "scsi%d: Aborting connected command - ", instance->host_no); printk("sending wd33c93 ABORT command - "); write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); @@ -2270,7 +2269,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, strcat(bp, "\nconnected: "); if (hd->connected) { cmd = (Scsi_Cmnd *) hd->connected; - sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); } } @@ -2278,7 +2277,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, strcat(bp, "\ninput_Q: "); cmd = (Scsi_Cmnd *) hd->input_Q; while (cmd) { - sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); cmd = (Scsi_Cmnd *) cmd->host_scribble; } @@ -2287,7 +2286,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, strcat(bp, "\ndisconnected_Q:"); cmd = (Scsi_Cmnd *) hd->disconnected_Q; while (cmd) { - sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); cmd = (Scsi_Cmnd *) cmd->host_scribble; } diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 0621238fac4a..12868ca46110 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -2717,13 +2718,18 @@ static int ipr_sdt_copy(struct ipr_ioa_cfg *ioa_cfg, unsigned long pci_address, u32 length) { int bytes_copied = 0; - int cur_len, rc, rem_len, rem_page_len; + int cur_len, rc, rem_len, rem_page_len, max_dump_size; __be32 *page; unsigned long lock_flags = 0; struct ipr_ioa_dump *ioa_dump = &ioa_cfg->dump->ioa_dump; + if (ioa_cfg->sis64) + max_dump_size = IPR_FMT3_MAX_IOA_DUMP_SIZE; + else + max_dump_size = IPR_FMT2_MAX_IOA_DUMP_SIZE; + while (bytes_copied < length && - (ioa_dump->hdr.len + bytes_copied) < IPR_MAX_IOA_DUMP_SIZE) { + (ioa_dump->hdr.len + bytes_copied) < max_dump_size) { if (ioa_dump->page_offset >= PAGE_SIZE || ioa_dump->page_offset == 0) { page = (__be32 *)__get_free_page(GFP_ATOMIC); @@ -2885,8 +2891,8 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) unsigned long lock_flags = 0; struct ipr_driver_dump *driver_dump = &dump->driver_dump; struct ipr_ioa_dump *ioa_dump = &dump->ioa_dump; - u32 num_entries, start_off, end_off; - u32 bytes_to_copy, bytes_copied, rc; + u32 num_entries, max_num_entries, start_off, end_off; + u32 max_dump_size, bytes_to_copy, bytes_copied, rc; struct ipr_sdt *sdt; int valid = 1; int i; @@ -2947,8 +2953,18 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) on entries in this table */ sdt = &ioa_dump->sdt; + if (ioa_cfg->sis64) { + max_num_entries = IPR_FMT3_NUM_SDT_ENTRIES; + max_dump_size = IPR_FMT3_MAX_IOA_DUMP_SIZE; + } else { + max_num_entries = IPR_FMT2_NUM_SDT_ENTRIES; + max_dump_size = IPR_FMT2_MAX_IOA_DUMP_SIZE; + } + + bytes_to_copy = offsetof(struct ipr_sdt, entry) + + (max_num_entries * sizeof(struct ipr_sdt_entry)); rc = ipr_get_ldump_data_section(ioa_cfg, start_addr, (__be32 *)sdt, - sizeof(struct ipr_sdt) / sizeof(__be32)); + bytes_to_copy / sizeof(__be32)); /* Smart Dump table is ready to use and the first entry is valid */ if (rc || ((be32_to_cpu(sdt->hdr.state) != IPR_FMT3_SDT_READY_TO_USE) && @@ -2964,13 +2980,20 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) num_entries = be32_to_cpu(sdt->hdr.num_entries_used); - if (num_entries > IPR_NUM_SDT_ENTRIES) - num_entries = IPR_NUM_SDT_ENTRIES; + if (num_entries > max_num_entries) + num_entries = max_num_entries; + + /* Update dump length to the actual data to be copied */ + dump->driver_dump.hdr.len += sizeof(struct ipr_sdt_header); + if (ioa_cfg->sis64) + dump->driver_dump.hdr.len += num_entries * sizeof(struct ipr_sdt_entry); + else + dump->driver_dump.hdr.len += max_num_entries * sizeof(struct ipr_sdt_entry); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); for (i = 0; i < num_entries; i++) { - if (ioa_dump->hdr.len > IPR_MAX_IOA_DUMP_SIZE) { + if (ioa_dump->hdr.len > max_dump_size) { driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS; break; } @@ -2989,7 +3012,7 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) valid = 0; } if (valid) { - if (bytes_to_copy > IPR_MAX_IOA_DUMP_SIZE) { + if (bytes_to_copy > max_dump_size) { sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY; continue; } @@ -3044,6 +3067,7 @@ static void ipr_release_dump(struct kref *kref) for (i = 0; i < dump->ioa_dump.next_page_index; i++) free_page((unsigned long) dump->ioa_dump.ioa_data[i]); + vfree(dump->ioa_dump.ioa_data); kfree(dump); LEAVE; } @@ -3835,7 +3859,7 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj, struct ipr_dump *dump; unsigned long lock_flags = 0; char *src; - int len; + int len, sdt_end; size_t rc = count; if (!capable(CAP_SYS_ADMIN)) @@ -3875,9 +3899,17 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj, off -= sizeof(dump->driver_dump); - if (count && off < offsetof(struct ipr_ioa_dump, ioa_data)) { - if (off + count > offsetof(struct ipr_ioa_dump, ioa_data)) - len = offsetof(struct ipr_ioa_dump, ioa_data) - off; + if (ioa_cfg->sis64) + sdt_end = offsetof(struct ipr_ioa_dump, sdt.entry) + + (be32_to_cpu(dump->ioa_dump.sdt.hdr.num_entries_used) * + sizeof(struct ipr_sdt_entry)); + else + sdt_end = offsetof(struct ipr_ioa_dump, sdt.entry) + + (IPR_FMT2_NUM_SDT_ENTRIES * sizeof(struct ipr_sdt_entry)); + + if (count && off < sdt_end) { + if (off + count > sdt_end) + len = sdt_end - off; else len = count; src = (u8 *)&dump->ioa_dump + off; @@ -3887,7 +3919,7 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj, count -= len; } - off -= offsetof(struct ipr_ioa_dump, ioa_data); + off -= sdt_end; while (count) { if ((off & PAGE_MASK) != ((off + count) & PAGE_MASK)) @@ -3916,6 +3948,7 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj, static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) { struct ipr_dump *dump; + __be32 **ioa_data; unsigned long lock_flags = 0; dump = kzalloc(sizeof(struct ipr_dump), GFP_KERNEL); @@ -3925,6 +3958,19 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) return -ENOMEM; } + if (ioa_cfg->sis64) + ioa_data = vmalloc(IPR_FMT3_MAX_NUM_DUMP_PAGES * sizeof(__be32 *)); + else + ioa_data = vmalloc(IPR_FMT2_MAX_NUM_DUMP_PAGES * sizeof(__be32 *)); + + if (!ioa_data) { + ipr_err("Dump memory allocation failed\n"); + kfree(dump); + return -ENOMEM; + } + + dump->ioa_dump.ioa_data = ioa_data; + kref_init(&dump->kref); dump->ioa_cfg = ioa_cfg; @@ -3932,6 +3978,7 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) if (INACTIVE != ioa_cfg->sdt_state) { spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + vfree(dump->ioa_dump.ioa_data); kfree(dump); return 0; } @@ -4953,9 +5000,35 @@ static int ipr_eh_abort(struct scsi_cmnd * scsi_cmd) * IRQ_NONE / IRQ_HANDLED **/ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, - volatile u32 int_reg) + u32 int_reg) { irqreturn_t rc = IRQ_HANDLED; + u32 int_mask_reg; + + int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32); + int_reg &= ~int_mask_reg; + + /* If an interrupt on the adapter did not occur, ignore it. + * Or in the case of SIS 64, check for a stage change interrupt. + */ + if ((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0) { + if (ioa_cfg->sis64) { + int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; + if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) { + + /* clear stage change */ + writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; + list_del(&ioa_cfg->reset_cmd->queue); + del_timer(&ioa_cfg->reset_cmd->timer); + ipr_reset_ioa_job(ioa_cfg->reset_cmd); + return IRQ_HANDLED; + } + } + + return IRQ_NONE; + } if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { /* Mask the interrupt */ @@ -4968,6 +5041,13 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, list_del(&ioa_cfg->reset_cmd->queue); del_timer(&ioa_cfg->reset_cmd->timer); ipr_reset_ioa_job(ioa_cfg->reset_cmd); + } else if ((int_reg & IPR_PCII_HRRQ_UPDATED) == int_reg) { + if (ipr_debug && printk_ratelimit()) + dev_err(&ioa_cfg->pdev->dev, + "Spurious interrupt detected. 0x%08X\n", int_reg); + writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); + return IRQ_NONE; } else { if (int_reg & IPR_PCII_IOA_UNIT_CHECKED) ioa_cfg->ioa_unit_checked = 1; @@ -5016,10 +5096,11 @@ static irqreturn_t ipr_isr(int irq, void *devp) { struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; unsigned long lock_flags = 0; - volatile u32 int_reg, int_mask_reg; + u32 int_reg = 0; u32 ioasc; u16 cmd_index; int num_hrrq = 0; + int irq_none = 0; struct ipr_cmnd *ipr_cmd; irqreturn_t rc = IRQ_NONE; @@ -5031,33 +5112,6 @@ static irqreturn_t ipr_isr(int irq, void *devp) return IRQ_NONE; } - int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg; - - /* If an interrupt on the adapter did not occur, ignore it. - * Or in the case of SIS 64, check for a stage change interrupt. - */ - if (unlikely((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0)) { - if (ioa_cfg->sis64) { - int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; - if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) { - - /* clear stage change */ - writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; - list_del(&ioa_cfg->reset_cmd->queue); - del_timer(&ioa_cfg->reset_cmd->timer); - ipr_reset_ioa_job(ioa_cfg->reset_cmd); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return IRQ_HANDLED; - } - } - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return IRQ_NONE; - } - while (1) { ipr_cmd = NULL; @@ -5097,7 +5151,7 @@ static irqreturn_t ipr_isr(int irq, void *devp) /* Clear the PCI interrupt */ do { writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg; + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); } while (int_reg & IPR_PCII_HRRQ_UPDATED && num_hrrq++ < IPR_MAX_HRRQ_RETRIES); @@ -5107,6 +5161,9 @@ static irqreturn_t ipr_isr(int irq, void *devp) return IRQ_HANDLED; } + } else if (rc == IRQ_NONE && irq_none == 0) { + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); + irq_none++; } else break; } @@ -5143,7 +5200,8 @@ static int ipr_build_ioadl64(struct ipr_ioa_cfg *ioa_cfg, nseg = scsi_dma_map(scsi_cmd); if (nseg < 0) { - dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n"); + if (printk_ratelimit()) + dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n"); return -1; } @@ -5773,7 +5831,8 @@ static int ipr_queuecommand_lck(struct scsi_cmnd *scsi_cmd, } ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; - ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST; + if (ipr_is_gscsi(res)) + ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST; ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR; ioarcb->cmd_pkt.flags_lo |= ipr_get_task_attributes(scsi_cmd); } @@ -7516,7 +7575,7 @@ static int ipr_reset_get_unit_check_job(struct ipr_cmnd *ipr_cmd) static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) { struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - volatile u32 int_reg; + u32 int_reg; ENTER; ioa_cfg->pdev->state_saved = true; @@ -7555,7 +7614,10 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) ipr_cmd->job_step = ipr_reset_enable_ioa; if (GET_DUMP == ioa_cfg->sdt_state) { - ipr_reset_start_timer(ipr_cmd, IPR_DUMP_TIMEOUT); + if (ioa_cfg->sis64) + ipr_reset_start_timer(ipr_cmd, IPR_SIS64_DUMP_TIMEOUT); + else + ipr_reset_start_timer(ipr_cmd, IPR_SIS32_DUMP_TIMEOUT); ipr_cmd->job_step = ipr_reset_wait_for_dump; schedule_work(&ioa_cfg->work_q); return IPR_RC_JOB_RETURN; diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 13f425fb8851..f93f8637c5a1 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -38,8 +38,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.5.1" -#define IPR_DRIVER_DATE "(August 10, 2010)" +#define IPR_DRIVER_VERSION "2.5.2" +#define IPR_DRIVER_DATE "(April 27, 2011)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding @@ -217,7 +217,8 @@ #define IPR_CHECK_FOR_RESET_TIMEOUT (HZ / 10) #define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ) #define IPR_PCI_RESET_TIMEOUT (HZ / 2) -#define IPR_DUMP_TIMEOUT (15 * HZ) +#define IPR_SIS32_DUMP_TIMEOUT (15 * HZ) +#define IPR_SIS64_DUMP_TIMEOUT (40 * HZ) #define IPR_DUMP_DELAY_SECONDS 4 #define IPR_DUMP_DELAY_TIMEOUT (IPR_DUMP_DELAY_SECONDS * HZ) @@ -285,9 +286,12 @@ IPR_PCII_NO_HOST_RRQ | IPR_PCII_IOARRIN_LOST | IPR_PCII_MMIO_ERROR) /* * Dump literals */ -#define IPR_MAX_IOA_DUMP_SIZE (4 * 1024 * 1024) -#define IPR_NUM_SDT_ENTRIES 511 -#define IPR_MAX_NUM_DUMP_PAGES ((IPR_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1) +#define IPR_FMT2_MAX_IOA_DUMP_SIZE (4 * 1024 * 1024) +#define IPR_FMT3_MAX_IOA_DUMP_SIZE (32 * 1024 * 1024) +#define IPR_FMT2_NUM_SDT_ENTRIES 511 +#define IPR_FMT3_NUM_SDT_ENTRIES 0xFFF +#define IPR_FMT2_MAX_NUM_DUMP_PAGES ((IPR_FMT2_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1) +#define IPR_FMT3_MAX_NUM_DUMP_PAGES ((IPR_FMT3_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1) /* * Misc literals @@ -474,7 +478,7 @@ struct ipr_cmd_pkt { u8 flags_lo; #define IPR_FLAGS_LO_ALIGNED_BFR 0x20 -#define IPR_FLAGS_LO_DELAY_AFTER_RST 0x10 +#define IPR_FLAGS_LO_DELAY_AFTER_RST 0x10 #define IPR_FLAGS_LO_UNTAGGED_TASK 0x00 #define IPR_FLAGS_LO_SIMPLE_TASK 0x02 #define IPR_FLAGS_LO_ORDERED_TASK 0x04 @@ -1164,7 +1168,7 @@ struct ipr_sdt_header { struct ipr_sdt { struct ipr_sdt_header hdr; - struct ipr_sdt_entry entry[IPR_NUM_SDT_ENTRIES]; + struct ipr_sdt_entry entry[IPR_FMT3_NUM_SDT_ENTRIES]; }__attribute__((packed, aligned (4))); struct ipr_uc_sdt { @@ -1608,7 +1612,7 @@ struct ipr_driver_dump { struct ipr_ioa_dump { struct ipr_dump_entry_header hdr; struct ipr_sdt sdt; - __be32 *ioa_data[IPR_MAX_NUM_DUMP_PAGES]; + __be32 **ioa_data; u32 reserved; u32 next_page_index; u32 page_offset; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 5b799a37ad09..2a3a4720a771 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -57,9 +57,6 @@ static struct kmem_cache *scsi_pkt_cachep; #define FC_SRB_READ (1 << 1) #define FC_SRB_WRITE (1 << 0) -/* constant added to e_d_tov timeout to get rec_tov value */ -#define REC_TOV_CONST 1 - /* * The SCp.ptr should be tested and set under the scsi_pkt_queue lock */ @@ -248,7 +245,7 @@ static inline void fc_fcp_unlock_pkt(struct fc_fcp_pkt *fsp) /** * fc_fcp_timer_set() - Start a timer for a fcp_pkt * @fsp: The FCP packet to start a timer for - * @delay: The timeout period for the timer + * @delay: The timeout period in jiffies */ static void fc_fcp_timer_set(struct fc_fcp_pkt *fsp, unsigned long delay) { @@ -335,22 +332,23 @@ static void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp) /** * fc_fcp_can_queue_ramp_up() - increases can_queue * @lport: lport to ramp up can_queue - * - * Locking notes: Called with Scsi_Host lock held */ static void fc_fcp_can_queue_ramp_up(struct fc_lport *lport) { struct fc_fcp_internal *si = fc_get_scsi_internal(lport); + unsigned long flags; int can_queue; + spin_lock_irqsave(lport->host->host_lock, flags); + if (si->last_can_queue_ramp_up_time && (time_before(jiffies, si->last_can_queue_ramp_up_time + FC_CAN_QUEUE_PERIOD))) - return; + goto unlock; if (time_before(jiffies, si->last_can_queue_ramp_down_time + FC_CAN_QUEUE_PERIOD)) - return; + goto unlock; si->last_can_queue_ramp_up_time = jiffies; @@ -362,6 +360,9 @@ static void fc_fcp_can_queue_ramp_up(struct fc_lport *lport) lport->host->can_queue = can_queue; shost_printk(KERN_ERR, lport->host, "libfc: increased " "can_queue to %d.\n", can_queue); + +unlock: + spin_unlock_irqrestore(lport->host->host_lock, flags); } /** @@ -373,18 +374,19 @@ static void fc_fcp_can_queue_ramp_up(struct fc_lport *lport) * commands complete or timeout, then try again with a reduced * can_queue. Eventually we will hit the point where we run * on all reserved structs. - * - * Locking notes: Called with Scsi_Host lock held */ static void fc_fcp_can_queue_ramp_down(struct fc_lport *lport) { struct fc_fcp_internal *si = fc_get_scsi_internal(lport); + unsigned long flags; int can_queue; + spin_lock_irqsave(lport->host->host_lock, flags); + if (si->last_can_queue_ramp_down_time && (time_before(jiffies, si->last_can_queue_ramp_down_time + FC_CAN_QUEUE_PERIOD))) - return; + goto unlock; si->last_can_queue_ramp_down_time = jiffies; @@ -395,6 +397,9 @@ static void fc_fcp_can_queue_ramp_down(struct fc_lport *lport) lport->host->can_queue = can_queue; shost_printk(KERN_ERR, lport->host, "libfc: Could not allocate frame.\n" "Reducing can_queue to %d.\n", can_queue); + +unlock: + spin_unlock_irqrestore(lport->host->host_lock, flags); } /* @@ -409,16 +414,13 @@ static inline struct fc_frame *fc_fcp_frame_alloc(struct fc_lport *lport, size_t len) { struct fc_frame *fp; - unsigned long flags; fp = fc_frame_alloc(lport, len); if (likely(fp)) return fp; /* error case */ - spin_lock_irqsave(lport->host->host_lock, flags); fc_fcp_can_queue_ramp_down(lport); - spin_unlock_irqrestore(lport->host->host_lock, flags); return NULL; } @@ -1093,16 +1095,14 @@ static int fc_fcp_pkt_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp) /** * get_fsp_rec_tov() - Helper function to get REC_TOV * @fsp: the FCP packet + * + * Returns rec tov in jiffies as rpriv->e_d_tov + 1 second */ static inline unsigned int get_fsp_rec_tov(struct fc_fcp_pkt *fsp) { - struct fc_rport *rport; - struct fc_rport_libfc_priv *rpriv; + struct fc_rport_libfc_priv *rpriv = fsp->rport->dd_data; - rport = fsp->rport; - rpriv = rport->dd_data; - - return rpriv->e_d_tov + REC_TOV_CONST; + return msecs_to_jiffies(rpriv->e_d_tov) + HZ; } /** @@ -1122,7 +1122,6 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp, struct fc_rport_libfc_priv *rpriv; const size_t len = sizeof(fsp->cdb_cmd); int rc = 0; - unsigned int rec_tov; if (fc_fcp_lock_pkt(fsp)) return 0; @@ -1153,12 +1152,9 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp, fsp->seq_ptr = seq; fc_fcp_pkt_hold(fsp); /* hold for fc_fcp_pkt_destroy */ - rec_tov = get_fsp_rec_tov(fsp); - setup_timer(&fsp->timer, fc_fcp_timeout, (unsigned long)fsp); - if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED) - fc_fcp_timer_set(fsp, rec_tov); + fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); unlock: fc_fcp_unlock_pkt(fsp); @@ -1235,16 +1231,14 @@ static void fc_lun_reset_send(unsigned long data) { struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data; struct fc_lport *lport = fsp->lp; - unsigned int rec_tov; if (lport->tt.fcp_cmd_send(lport, fsp, fc_tm_done)) { if (fsp->recov_retry++ >= FC_MAX_RECOV_RETRY) return; if (fc_fcp_lock_pkt(fsp)) return; - rec_tov = get_fsp_rec_tov(fsp); setup_timer(&fsp->timer, fc_lun_reset_send, (unsigned long)fsp); - fc_fcp_timer_set(fsp, rec_tov); + fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); fc_fcp_unlock_pkt(fsp); } } @@ -1536,12 +1530,11 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) } fc_fcp_srr(fsp, r_ctl, offset); } else if (e_stat & ESB_ST_SEQ_INIT) { - unsigned int rec_tov = get_fsp_rec_tov(fsp); /* * The remote port has the initiative, so just * keep waiting for it to complete. */ - fc_fcp_timer_set(fsp, rec_tov); + fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); } else { /* @@ -1705,7 +1698,6 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) { struct fc_fcp_pkt *fsp = arg; struct fc_frame_header *fh; - unsigned int rec_tov; if (IS_ERR(fp)) { fc_fcp_srr_error(fsp, fp); @@ -1732,8 +1724,7 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) switch (fc_frame_payload_op(fp)) { case ELS_LS_ACC: fsp->recov_retry = 0; - rec_tov = get_fsp_rec_tov(fsp); - fc_fcp_timer_set(fsp, rec_tov); + fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); break; case ELS_LS_RJT: default: diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 906bbcad0e2d..389ab80aef0a 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1590,7 +1590,6 @@ void fc_lport_enter_flogi(struct fc_lport *lport) */ int fc_lport_config(struct fc_lport *lport) { - INIT_LIST_HEAD(&lport->ema_list); INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout); mutex_init(&lport->lp_mutex); diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 60e98a62f308..02d53d89534f 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -805,6 +805,8 @@ struct lpfc_hba { struct dentry *idiag_root; struct dentry *idiag_pci_cfg; struct dentry *idiag_que_info; + struct dentry *idiag_que_acc; + struct dentry *idiag_drb_acc; #endif /* Used for deferred freeing of ELS data buffers */ diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 77b2871d96b7..37e2a1272f86 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -2426,6 +2426,7 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) { struct bsg_job_data *dd_data; struct fc_bsg_job *job; + struct lpfc_mbx_nembed_cmd *nembed_sge; uint32_t size; unsigned long flags; uint8_t *to; @@ -2469,9 +2470,8 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) memcpy(to, from, size); } else if ((phba->sli_rev == LPFC_SLI_REV4) && (pmboxq->u.mb.mbxCommand == MBX_SLI4_CONFIG)) { - struct lpfc_mbx_nembed_cmd *nembed_sge = - (struct lpfc_mbx_nembed_cmd *) - &pmboxq->u.mb.un.varWords[0]; + nembed_sge = (struct lpfc_mbx_nembed_cmd *) + &pmboxq->u.mb.un.varWords[0]; from = (uint8_t *)dd_data->context_un.mbox.dmp->dma. virt; @@ -2496,16 +2496,18 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) job->reply_payload.sg_cnt, from, size); job->reply->result = 0; - + /* need to hold the lock until we set job->dd_data to NULL + * to hold off the timeout handler returning to the mid-layer + * while we are still processing the job. + */ job->dd_data = NULL; + dd_data->context_un.mbox.set_job = NULL; + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); job->job_done(job); + } else { + dd_data->context_un.mbox.set_job = NULL; + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); } - dd_data->context_un.mbox.set_job = NULL; - /* need to hold the lock until we call job done to hold off - * the timeout handler returning to the midlayer while - * we are stillprocessing the job - */ - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); kfree(dd_data->context_un.mbox.mb); mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); @@ -2644,6 +2646,11 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, struct ulp_bde64 *rxbpl = NULL; struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *) job->request->rqst_data.h_vendor.vendor_cmd; + struct READ_EVENT_LOG_VAR *rdEventLog; + uint32_t transmit_length, receive_length, mode; + struct lpfc_mbx_nembed_cmd *nembed_sge; + struct mbox_header *header; + struct ulp_bde64 *bde; uint8_t *ext = NULL; int rc = 0; uint8_t *from; @@ -2651,9 +2658,16 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, /* in case no data is transferred */ job->reply->reply_payload_rcv_len = 0; + /* sanity check to protect driver */ + if (job->reply_payload.payload_len > BSG_MBOX_SIZE || + job->request_payload.payload_len > BSG_MBOX_SIZE) { + rc = -ERANGE; + goto job_done; + } + /* check if requested extended data lengths are valid */ - if ((mbox_req->inExtWLen > MAILBOX_EXT_SIZE) || - (mbox_req->outExtWLen > MAILBOX_EXT_SIZE)) { + if ((mbox_req->inExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t)) || + (mbox_req->outExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t))) { rc = -ERANGE; goto job_done; } @@ -2744,8 +2758,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, * use ours */ if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { - uint32_t transmit_length = pmb->un.varWords[1]; - uint32_t receive_length = pmb->un.varWords[4]; + transmit_length = pmb->un.varWords[1]; + receive_length = pmb->un.varWords[4]; /* transmit length cannot be greater than receive length or * mailbox extension size */ @@ -2795,10 +2809,9 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, from += sizeof(MAILBOX_t); memcpy((uint8_t *)dmp->dma.virt, from, transmit_length); } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) { - struct READ_EVENT_LOG_VAR *rdEventLog = - &pmb->un.varRdEventLog ; - uint32_t receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; - uint32_t mode = bf_get(lpfc_event_log, rdEventLog); + rdEventLog = &pmb->un.varRdEventLog; + receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; + mode = bf_get(lpfc_event_log, rdEventLog); /* receive length cannot be greater than mailbox * extension size @@ -2843,7 +2856,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, /* rebuild the command for sli4 using our own buffers * like we do for biu diags */ - uint32_t receive_length = pmb->un.varWords[2]; + receive_length = pmb->un.varWords[2]; /* receive length cannot be greater than mailbox * extension size */ @@ -2879,8 +2892,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys); } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) && pmb->un.varUpdateCfg.co) { - struct ulp_bde64 *bde = - (struct ulp_bde64 *)&pmb->un.varWords[4]; + bde = (struct ulp_bde64 *)&pmb->un.varWords[4]; /* bde size cannot be greater than mailbox ext size */ if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) { @@ -2921,10 +2933,6 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, memcpy((uint8_t *)dmp->dma.virt, from, bde->tus.f.bdeSize); } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) { - struct lpfc_mbx_nembed_cmd *nembed_sge; - struct mbox_header *header; - uint32_t receive_length; - /* rebuild the command for sli4 using our own buffers * like we do for biu diags */ @@ -3386,6 +3394,7 @@ lpfc_menlo_cmd(struct fc_bsg_job *job) job->dd_data = NULL; return rc; } + /** * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job * @job: fc_bsg_job to handle diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index a2c33e7c9152..b542aca6f5ae 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -109,3 +109,133 @@ struct menlo_response { uint32_t xri; /* return the xri of the iocb exchange */ }; +/* + * macros and data structures for handling sli-config mailbox command + * pass-through support, this header file is shared between user and + * kernel spaces, note the set of macros are duplicates from lpfc_hw4.h, + * with macro names prefixed with bsg_, as the macros defined in + * lpfc_hw4.h are not accessible from user space. + */ + +/* Macros to deal with bit fields. Each bit field must have 3 #defines + * associated with it (_SHIFT, _MASK, and _WORD). + * EG. For a bit field that is in the 7th bit of the "field4" field of a + * structure and is 2 bits in size the following #defines must exist: + * struct temp { + * uint32_t field1; + * uint32_t field2; + * uint32_t field3; + * uint32_t field4; + * #define example_bit_field_SHIFT 7 + * #define example_bit_field_MASK 0x03 + * #define example_bit_field_WORD field4 + * uint32_t field5; + * }; + * Then the macros below may be used to get or set the value of that field. + * EG. To get the value of the bit field from the above example: + * struct temp t1; + * value = bsg_bf_get(example_bit_field, &t1); + * And then to set that bit field: + * bsg_bf_set(example_bit_field, &t1, 2); + * Or clear that bit field: + * bsg_bf_set(example_bit_field, &t1, 0); + */ +#define bsg_bf_get_le32(name, ptr) \ + ((le32_to_cpu((ptr)->name##_WORD) >> name##_SHIFT) & name##_MASK) +#define bsg_bf_get(name, ptr) \ + (((ptr)->name##_WORD >> name##_SHIFT) & name##_MASK) +#define bsg_bf_set_le32(name, ptr, value) \ + ((ptr)->name##_WORD = cpu_to_le32(((((value) & \ + name##_MASK) << name##_SHIFT) | (le32_to_cpu((ptr)->name##_WORD) & \ + ~(name##_MASK << name##_SHIFT))))) +#define bsg_bf_set(name, ptr, value) \ + ((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \ + ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT)))) + +/* + * The sli_config structure specified here is based on the following + * restriction: + * + * -- SLI_CONFIG EMB=0, carrying MSEs, will carry subcommands without + * carrying HBD. + * -- SLI_CONFIG EMB=1, not carrying MSE, will carry subcommands with or + * without carrying HBDs. + */ + +struct lpfc_sli_config_mse { + uint32_t pa_lo; + uint32_t pa_hi; + uint32_t buf_len; +#define lpfc_mbox_sli_config_mse_len_SHIFT 0 +#define lpfc_mbox_sli_config_mse_len_MASK 0xffffff +#define lpfc_mbox_sli_config_mse_len_WORD buf_len +}; + +struct lpfc_sli_config_subcmd_hbd { + uint32_t buf_len; +#define lpfc_mbox_sli_config_ecmn_hbd_len_SHIFT 0 +#define lpfc_mbox_sli_config_ecmn_hbd_len_MASK 0xffffff +#define lpfc_mbox_sli_config_ecmn_hbd_len_WORD buf_len + uint32_t pa_lo; + uint32_t pa_hi; +}; + +struct lpfc_sli_config_hdr { + uint32_t word1; +#define lpfc_mbox_hdr_emb_SHIFT 0 +#define lpfc_mbox_hdr_emb_MASK 0x00000001 +#define lpfc_mbox_hdr_emb_WORD word1 +#define lpfc_mbox_hdr_mse_cnt_SHIFT 3 +#define lpfc_mbox_hdr_mse_cnt_MASK 0x0000001f +#define lpfc_mbox_hdr_mse_cnt_WORD word1 + uint32_t payload_length; + uint32_t tag_lo; + uint32_t tag_hi; + uint32_t reserved5; +}; + +struct lpfc_sli_config_generic { + struct lpfc_sli_config_hdr sli_config_hdr; +#define LPFC_MBX_SLI_CONFIG_MAX_MSE 19 + struct lpfc_sli_config_mse mse[LPFC_MBX_SLI_CONFIG_MAX_MSE]; +}; + +struct lpfc_sli_config_subcmnd { + struct lpfc_sli_config_hdr sli_config_hdr; + uint32_t word6; +#define lpfc_subcmnd_opcode_SHIFT 0 +#define lpfc_subcmnd_opcode_MASK 0xff +#define lpfc_subcmnd_opcode_WORD word6 +#define lpfc_subcmnd_subsys_SHIFT 8 +#define lpfc_subcmnd_subsys_MASK 0xff +#define lpfc_subcmnd_subsys_WORD word6 + uint32_t timeout; + uint32_t request_length; + uint32_t word9; +#define lpfc_subcmnd_version_SHIFT 0 +#define lpfc_subcmnd_version_MASK 0xff +#define lpfc_subcmnd_version_WORD word9 + uint32_t word10; +#define lpfc_subcmnd_ask_rd_len_SHIFT 0 +#define lpfc_subcmnd_ask_rd_len_MASK 0xffffff +#define lpfc_subcmnd_ask_rd_len_WORD word10 + uint32_t rd_offset; + uint32_t obj_name[26]; + uint32_t hbd_count; +#define LPFC_MBX_SLI_CONFIG_MAX_HBD 10 + struct lpfc_sli_config_subcmd_hbd hbd[LPFC_MBX_SLI_CONFIG_MAX_HBD]; +}; + +struct lpfc_sli_config_mbox { + uint32_t word0; +#define lpfc_mqe_status_SHIFT 16 +#define lpfc_mqe_status_MASK 0x0000FFFF +#define lpfc_mqe_status_WORD word0 +#define lpfc_mqe_command_SHIFT 8 +#define lpfc_mqe_command_MASK 0x000000FF +#define lpfc_mqe_command_WORD word0 + union { + struct lpfc_sli_config_generic sli_config_generic; + struct lpfc_sli_config_subcmnd sli_config_subcmnd; + } un; +}; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 3d967741c708..c93fca058603 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1119,172 +1119,14 @@ lpfc_debugfs_dumpDataDif_release(struct inode *inode, struct file *file) } /* + * --------------------------------- * iDiag debugfs file access methods - */ - -/* - * iDiag PCI config space register access methods: + * --------------------------------- * - * The PCI config space register accessees of read, write, read-modify-write - * for set bits, and read-modify-write for clear bits to SLI4 PCI functions - * are provided. In the proper SLI4 PCI function's debugfs iDiag directory, + * All access methods are through the proper SLI4 PCI function's debugfs + * iDiag directory: * - * /sys/kernel/debug/lpfc/fn<#>/iDiag - * - * the access is through the debugfs entry pciCfg: - * - * 1. For PCI config space register read access, there are two read methods: - * A) read a single PCI config space register in the size of a byte - * (8 bits), a word (16 bits), or a dword (32 bits); or B) browse through - * the 4K extended PCI config space. - * - * A) Read a single PCI config space register consists of two steps: - * - * Step-1: Set up PCI config space register read command, the command - * syntax is, - * - * echo 1 > pciCfg - * - * where, 1 is the iDiag command for PCI config space read, is the - * offset from the beginning of the device's PCI config space to read from, - * and is the size of PCI config space register data to read back, - * it will be 1 for reading a byte (8 bits), 2 for reading a word (16 bits - * or 2 bytes), or 4 for reading a dword (32 bits or 4 bytes). - * - * Setp-2: Perform the debugfs read operation to execute the idiag command - * set up in Step-1, - * - * cat pciCfg - * - * Examples: - * To read PCI device's vendor-id and device-id from PCI config space, - * - * echo 1 0 4 > pciCfg - * cat pciCfg - * - * To read PCI device's currnt command from config space, - * - * echo 1 4 2 > pciCfg - * cat pciCfg - * - * B) Browse through the entire 4K extended PCI config space also consists - * of two steps: - * - * Step-1: Set up PCI config space register browsing command, the command - * syntax is, - * - * echo 1 0 4096 > pciCfg - * - * where, 1 is the iDiag command for PCI config space read, 0 must be used - * as the offset for PCI config space register browse, and 4096 must be - * used as the count for PCI config space register browse. - * - * Step-2: Repeately issue the debugfs read operation to browse through - * the entire PCI config space registers: - * - * cat pciCfg - * cat pciCfg - * cat pciCfg - * ... - * - * When browsing to the end of the 4K PCI config space, the browse method - * shall wrap around to start reading from beginning again, and again... - * - * 2. For PCI config space register write access, it supports a single PCI - * config space register write in the size of a byte (8 bits), a word - * (16 bits), or a dword (32 bits). The command syntax is, - * - * echo 2 > pciCfg - * - * where, 2 is the iDiag command for PCI config space write, is - * the offset from the beginning of the device's PCI config space to write - * into, is the size of data to write into the PCI config space, - * it will be 1 for writing a byte (8 bits), 2 for writing a word (16 bits - * or 2 bytes), or 4 for writing a dword (32 bits or 4 bytes), and - * is the data to be written into the PCI config space register at the - * offset. - * - * Examples: - * To disable PCI device's interrupt assertion, - * - * 1) Read in device's PCI config space register command field : - * - * echo 1 4 2 > pciCfg - * cat pciCfg - * - * 2) Set bit 10 (Interrupt Disable bit) in the : - * - * = | (1 < 10) - * - * 3) Write the modified command back: - * - * echo 2 4 2 > pciCfg - * - * 3. For PCI config space register set bits access, it supports a single PCI - * config space register set bits in the size of a byte (8 bits), a word - * (16 bits), or a dword (32 bits). The command syntax is, - * - * echo 3 > pciCfg - * - * where, 3 is the iDiag command for PCI config space set bits, is - * the offset from the beginning of the device's PCI config space to set - * bits into, is the size of the bitmask to set into the PCI config - * space, it will be 1 for setting a byte (8 bits), 2 for setting a word - * (16 bits or 2 bytes), or 4 for setting a dword (32 bits or 4 bytes), and - * is the bitmask, indicating the bits to be set into the PCI - * config space register at the offset. The logic performed to the content - * of the PCI config space register, regval, is, - * - * regval |= - * - * 4. For PCI config space register clear bits access, it supports a single - * PCI config space register clear bits in the size of a byte (8 bits), - * a word (16 bits), or a dword (32 bits). The command syntax is, - * - * echo 4 > pciCfg - * - * where, 4 is the iDiag command for PCI config space clear bits, - * is the offset from the beginning of the device's PCI config space to - * clear bits from, is the size of the bitmask to set into the PCI - * config space, it will be 1 for setting a byte (8 bits), 2 for setting - * a word(16 bits or 2 bytes), or 4 for setting a dword (32 bits or 4 - * bytes), and is the bitmask, indicating the bits to be cleared - * from the PCI config space register at the offset. the logic performed - * to the content of the PCI config space register, regval, is, - * - * regval &= ~ - * - * Note, for all single register read, write, set bits, or clear bits access, - * the offset () must be aligned with the size of the data: - * - * For data size of byte (8 bits), the offset must be aligned to the byte - * boundary; for data size of word (16 bits), the offset must be aligned - * to the word boundary; while for data size of dword (32 bits), the offset - * must be aligned to the dword boundary. Otherwise, the interface will - * return the error: - * - * "-bash: echo: write error: Invalid argument". - * - * For example: - * - * echo 1 2 4 > pciCfg - * -bash: echo: write error: Invalid argument - * - * Note also, all of the numbers in the command fields for all read, write, - * set bits, and clear bits PCI config space register command fields can be - * either decimal or hex. - * - * For example, - * echo 1 0 4096 > pciCfg - * - * will be the same as - * echo 1 0 0x1000 > pciCfg - * - * And, - * echo 2 155 1 10 > pciCfg - * - * will be - * echo 2 0x9b 1 0xa > pciCfg + * /sys/kernel/debug/lpfc/fn<#>/iDiag */ /** @@ -1331,10 +1173,10 @@ static int lpfc_idiag_cmd_get(const char __user *buf, size_t nbytes, for (i = 0; i < LPFC_IDIAG_CMD_DATA_SIZE; i++) { step_str = strsep(&pbuf, "\t "); if (!step_str) - return 0; + return i; idiag_cmd->data[i] = simple_strtol(step_str, NULL, 0); } - return 0; + return i; } /** @@ -1403,7 +1245,7 @@ lpfc_idiag_release(struct inode *inode, struct file *file) * Description: * This routine frees the buffer that was allocated when the debugfs file * was opened. It also reset the fields in the idiag command struct in the - * case the command is not continuous browsing of the data structure. + * case of command for write operation. * * Returns: * This function returns zero. @@ -1413,18 +1255,20 @@ lpfc_idiag_cmd_release(struct inode *inode, struct file *file) { struct lpfc_debug *debug = file->private_data; - /* Read PCI config register, if not read all, clear command fields */ - if ((debug->op == LPFC_IDIAG_OP_RD) && - (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD)) - if ((idiag.cmd.data[1] == sizeof(uint8_t)) || - (idiag.cmd.data[1] == sizeof(uint16_t)) || - (idiag.cmd.data[1] == sizeof(uint32_t))) + if (debug->op == LPFC_IDIAG_OP_WR) { + switch (idiag.cmd.opcode) { + case LPFC_IDIAG_CMD_PCICFG_WR: + case LPFC_IDIAG_CMD_PCICFG_ST: + case LPFC_IDIAG_CMD_PCICFG_CL: + case LPFC_IDIAG_CMD_QUEACC_WR: + case LPFC_IDIAG_CMD_QUEACC_ST: + case LPFC_IDIAG_CMD_QUEACC_CL: memset(&idiag, 0, sizeof(idiag)); - - /* Write PCI config register, clear command fields */ - if ((debug->op == LPFC_IDIAG_OP_WR) && - (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)) - memset(&idiag, 0, sizeof(idiag)); + break; + default: + break; + } + } /* Free the buffers to the file operation */ kfree(debug->buffer); @@ -1504,7 +1348,7 @@ lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes, len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, "%03x: %08x\n", where, u32val); break; - case LPFC_PCI_CFG_SIZE: /* browse all */ + case LPFC_PCI_CFG_BROWSE: /* browse all */ goto pcicfg_browse; break; default: @@ -1586,16 +1430,21 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf, debug->op = LPFC_IDIAG_OP_WR; rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); - if (rc) + if (rc < 0) return rc; if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) { + /* Sanity check on PCI config read command line arguments */ + if (rc != LPFC_PCI_CFG_RD_CMD_ARG) + goto error_out; /* Read command from PCI config space, set up command fields */ where = idiag.cmd.data[0]; count = idiag.cmd.data[1]; - if (count == LPFC_PCI_CFG_SIZE) { - if (where != 0) + if (count == LPFC_PCI_CFG_BROWSE) { + if (where % sizeof(uint32_t)) goto error_out; + /* Starting offset to browse */ + idiag.offset.last_rd = where; } else if ((count != sizeof(uint8_t)) && (count != sizeof(uint16_t)) && (count != sizeof(uint32_t))) @@ -1621,6 +1470,9 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf, } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR || idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST || idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) { + /* Sanity check on PCI config write command line arguments */ + if (rc != LPFC_PCI_CFG_WR_CMD_ARG) + goto error_out; /* Write command to PCI config space, read-modify-write */ where = idiag.cmd.data[0]; count = idiag.cmd.data[1]; @@ -1753,10 +1605,12 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path EQ information:\n"); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], EQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", + "\tEQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", phba->sli4_hba.sp_eq->queue_id, phba->sli4_hba.sp_eq->entry_count, + phba->sli4_hba.sp_eq->entry_size, phba->sli4_hba.sp_eq->host_index, phba->sli4_hba.sp_eq->hba_index); @@ -1765,10 +1619,12 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, "Fast-path EQ information:\n"); for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) { len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], EQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", + "\tEQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", phba->sli4_hba.fp_eq[fcp_qidx]->queue_id, phba->sli4_hba.fp_eq[fcp_qidx]->entry_count, + phba->sli4_hba.fp_eq[fcp_qidx]->entry_size, phba->sli4_hba.fp_eq[fcp_qidx]->host_index, phba->sli4_hba.fp_eq[fcp_qidx]->hba_index); } @@ -1776,89 +1632,101 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, /* Get mailbox complete queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Mailbox CQ information:\n"); + "Slow-path MBX CQ information:\n"); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated EQ-ID [%02d]:\n", + "Associated EQID[%02d]:\n", phba->sli4_hba.mbx_cq->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], CQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", + "\tCQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", phba->sli4_hba.mbx_cq->queue_id, phba->sli4_hba.mbx_cq->entry_count, + phba->sli4_hba.mbx_cq->entry_size, phba->sli4_hba.mbx_cq->host_index, phba->sli4_hba.mbx_cq->hba_index); /* Get slow-path complete queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path CQ information:\n"); + "Slow-path ELS CQ information:\n"); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated EQ-ID [%02d]:\n", + "Associated EQID[%02d]:\n", phba->sli4_hba.els_cq->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], CQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", + "\tCQID [%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", phba->sli4_hba.els_cq->queue_id, phba->sli4_hba.els_cq->entry_count, + phba->sli4_hba.els_cq->entry_size, phba->sli4_hba.els_cq->host_index, phba->sli4_hba.els_cq->hba_index); /* Get fast-path complete queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Fast-path CQ information:\n"); + "Fast-path FCP CQ information:\n"); for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) { len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated EQ-ID [%02d]:\n", + "Associated EQID[%02d]:\n", phba->sli4_hba.fcp_cq[fcp_qidx]->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], EQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", - phba->sli4_hba.fcp_cq[fcp_qidx]->queue_id, - phba->sli4_hba.fcp_cq[fcp_qidx]->entry_count, - phba->sli4_hba.fcp_cq[fcp_qidx]->host_index, - phba->sli4_hba.fcp_cq[fcp_qidx]->hba_index); + "\tCQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", + phba->sli4_hba.fcp_cq[fcp_qidx]->queue_id, + phba->sli4_hba.fcp_cq[fcp_qidx]->entry_count, + phba->sli4_hba.fcp_cq[fcp_qidx]->entry_size, + phba->sli4_hba.fcp_cq[fcp_qidx]->host_index, + phba->sli4_hba.fcp_cq[fcp_qidx]->hba_index); } len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); /* Get mailbox queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Mailbox MQ information:\n"); + "Slow-path MBX MQ information:\n"); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated CQ-ID [%02d]:\n", + "Associated CQID[%02d]:\n", phba->sli4_hba.mbx_wq->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], MQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", + "\tWQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", phba->sli4_hba.mbx_wq->queue_id, phba->sli4_hba.mbx_wq->entry_count, + phba->sli4_hba.mbx_wq->entry_size, phba->sli4_hba.mbx_wq->host_index, phba->sli4_hba.mbx_wq->hba_index); /* Get slow-path work queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path WQ information:\n"); + "Slow-path ELS WQ information:\n"); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated CQ-ID [%02d]:\n", + "Associated CQID[%02d]:\n", phba->sli4_hba.els_wq->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], WQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", + "\tWQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", phba->sli4_hba.els_wq->queue_id, phba->sli4_hba.els_wq->entry_count, + phba->sli4_hba.els_wq->entry_size, phba->sli4_hba.els_wq->host_index, phba->sli4_hba.els_wq->hba_index); /* Get fast-path work queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Fast-path WQ information:\n"); + "Fast-path FCP WQ information:\n"); for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) { len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated CQ-ID [%02d]:\n", + "Associated CQID[%02d]:\n", phba->sli4_hba.fcp_wq[fcp_qidx]->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], WQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", + "\tWQID[%02d], " + "QE-COUNT[%04d], WQE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", phba->sli4_hba.fcp_wq[fcp_qidx]->queue_id, phba->sli4_hba.fcp_wq[fcp_qidx]->entry_count, + phba->sli4_hba.fcp_wq[fcp_qidx]->entry_size, phba->sli4_hba.fcp_wq[fcp_qidx]->host_index, phba->sli4_hba.fcp_wq[fcp_qidx]->hba_index); } @@ -1868,26 +1736,597 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path RQ information:\n"); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated CQ-ID [%02d]:\n", + "Associated CQID[%02d]:\n", phba->sli4_hba.hdr_rq->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], RHQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", + "\tHQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", phba->sli4_hba.hdr_rq->queue_id, phba->sli4_hba.hdr_rq->entry_count, + phba->sli4_hba.hdr_rq->entry_size, phba->sli4_hba.hdr_rq->host_index, phba->sli4_hba.hdr_rq->hba_index); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], RDQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", + "\tDQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", phba->sli4_hba.dat_rq->queue_id, phba->sli4_hba.dat_rq->entry_count, + phba->sli4_hba.dat_rq->entry_size, phba->sli4_hba.dat_rq->host_index, phba->sli4_hba.dat_rq->hba_index); return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); } +/** + * lpfc_idiag_que_param_check - queue access command parameter sanity check + * @q: The pointer to queue structure. + * @index: The index into a queue entry. + * @count: The number of queue entries to access. + * + * Description: + * The routine performs sanity check on device queue access method commands. + * + * Returns: + * This function returns -EINVAL when fails the sanity check, otherwise, it + * returns 0. + **/ +static int +lpfc_idiag_que_param_check(struct lpfc_queue *q, int index, int count) +{ + /* Only support single entry read or browsing */ + if ((count != 1) && (count != LPFC_QUE_ACC_BROWSE)) + return -EINVAL; + if (index > q->entry_count - 1) + return -EINVAL; + return 0; +} + +/** + * lpfc_idiag_queacc_read_qe - read a single entry from the given queue index + * @pbuffer: The pointer to buffer to copy the read data into. + * @pque: The pointer to the queue to be read. + * @index: The index into the queue entry. + * + * Description: + * This routine reads out a single entry from the given queue's index location + * and copies it into the buffer provided. + * + * Returns: + * This function returns 0 when it fails, otherwise, it returns the length of + * the data read into the buffer provided. + **/ +static int +lpfc_idiag_queacc_read_qe(char *pbuffer, int len, struct lpfc_queue *pque, + uint32_t index) +{ + int offset, esize; + uint32_t *pentry; + + if (!pbuffer || !pque) + return 0; + + esize = pque->entry_size; + len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, + "QE-INDEX[%04d]:\n", index); + + offset = 0; + pentry = pque->qe[index].address; + while (esize > 0) { + len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, + "%08x ", *pentry); + pentry++; + offset += sizeof(uint32_t); + esize -= sizeof(uint32_t); + if (esize > 0 && !(offset % (4 * sizeof(uint32_t)))) + len += snprintf(pbuffer+len, + LPFC_QUE_ACC_BUF_SIZE-len, "\n"); + } + len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n"); + + return len; +} + +/** + * lpfc_idiag_queacc_read - idiag debugfs read port queue + * @file: The file pointer to read from. + * @buf: The buffer to copy the data to. + * @nbytes: The number of bytes to read. + * @ppos: The position in the file to start reading from. + * + * Description: + * This routine reads data from the @phba device queue memory according to the + * idiag command, and copies to user @buf. Depending on the queue dump read + * command setup, it does either a single queue entry read or browing through + * all entries of the queue. + * + * Returns: + * This function returns the amount of data that was read (this could be less + * than @nbytes if the end of the file was reached) or a negative error value. + **/ +static ssize_t +lpfc_idiag_queacc_read(struct file *file, char __user *buf, size_t nbytes, + loff_t *ppos) +{ + struct lpfc_debug *debug = file->private_data; + uint32_t last_index, index, count; + struct lpfc_queue *pque = NULL; + char *pbuffer; + int len = 0; + + /* This is a user read operation */ + debug->op = LPFC_IDIAG_OP_RD; + + if (!debug->buffer) + debug->buffer = kmalloc(LPFC_QUE_ACC_BUF_SIZE, GFP_KERNEL); + if (!debug->buffer) + return 0; + pbuffer = debug->buffer; + + if (*ppos) + return 0; + + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { + index = idiag.cmd.data[2]; + count = idiag.cmd.data[3]; + pque = (struct lpfc_queue *)idiag.ptr_private; + } else + return 0; + + /* Browse the queue starting from index */ + if (count == LPFC_QUE_ACC_BROWSE) + goto que_browse; + + /* Read a single entry from the queue */ + len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index); + + return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); + +que_browse: + + /* Browse all entries from the queue */ + last_index = idiag.offset.last_rd; + index = last_index; + + while (len < LPFC_QUE_ACC_SIZE - pque->entry_size) { + len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index); + index++; + if (index > pque->entry_count - 1) + break; + } + + /* Set up the offset for next portion of pci cfg read */ + if (index > pque->entry_count - 1) + index = 0; + idiag.offset.last_rd = index; + + return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); +} + +/** + * lpfc_idiag_queacc_write - Syntax check and set up idiag queacc commands + * @file: The file pointer to read from. + * @buf: The buffer to copy the user data from. + * @nbytes: The number of bytes to get. + * @ppos: The position in the file to start reading from. + * + * This routine get the debugfs idiag command struct from user space and then + * perform the syntax check for port queue read (dump) or write (set) command + * accordingly. In the case of port queue read command, it sets up the command + * in the idiag command struct for the following debugfs read operation. In + * the case of port queue write operation, it executes the write operation + * into the port queue entry accordingly. + * + * It returns the @nbytges passing in from debugfs user space when successful. + * In case of error conditions, it returns proper error code back to the user + * space. + **/ +static ssize_t +lpfc_idiag_queacc_write(struct file *file, const char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct lpfc_debug *debug = file->private_data; + struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; + uint32_t qidx, quetp, queid, index, count, offset, value; + uint32_t *pentry; + struct lpfc_queue *pque; + int rc; + + /* This is a user write operation */ + debug->op = LPFC_IDIAG_OP_WR; + + rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); + if (rc < 0) + return rc; + + /* Get and sanity check on command feilds */ + quetp = idiag.cmd.data[0]; + queid = idiag.cmd.data[1]; + index = idiag.cmd.data[2]; + count = idiag.cmd.data[3]; + offset = idiag.cmd.data[4]; + value = idiag.cmd.data[5]; + + /* Sanity check on command line arguments */ + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || + idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST || + idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) { + if (rc != LPFC_QUE_ACC_WR_CMD_ARG) + goto error_out; + if (count != 1) + goto error_out; + } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { + if (rc != LPFC_QUE_ACC_RD_CMD_ARG) + goto error_out; + } else + goto error_out; + + switch (quetp) { + case LPFC_IDIAG_EQ: + /* Slow-path event queue */ + if (phba->sli4_hba.sp_eq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.sp_eq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.sp_eq; + goto pass_check; + } + /* Fast-path event queue */ + for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) { + if (phba->sli4_hba.fp_eq[qidx]->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.fp_eq[qidx], + index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.fp_eq[qidx]; + goto pass_check; + } + } + goto error_out; + break; + case LPFC_IDIAG_CQ: + /* MBX complete queue */ + if (phba->sli4_hba.mbx_cq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.mbx_cq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.mbx_cq; + goto pass_check; + } + /* ELS complete queue */ + if (phba->sli4_hba.els_cq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.els_cq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.els_cq; + goto pass_check; + } + /* FCP complete queue */ + for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) { + if (phba->sli4_hba.fcp_cq[qidx]->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.fcp_cq[qidx], + index, count); + if (rc) + goto error_out; + idiag.ptr_private = + phba->sli4_hba.fcp_cq[qidx]; + goto pass_check; + } + } + goto error_out; + break; + case LPFC_IDIAG_MQ: + /* MBX work queue */ + if (phba->sli4_hba.mbx_wq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.mbx_wq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.mbx_wq; + goto pass_check; + } + break; + case LPFC_IDIAG_WQ: + /* ELS work queue */ + if (phba->sli4_hba.els_wq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.els_wq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.els_wq; + goto pass_check; + } + /* FCP work queue */ + for (qidx = 0; qidx < phba->cfg_fcp_wq_count; qidx++) { + if (phba->sli4_hba.fcp_wq[qidx]->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.fcp_wq[qidx], + index, count); + if (rc) + goto error_out; + idiag.ptr_private = + phba->sli4_hba.fcp_wq[qidx]; + goto pass_check; + } + } + goto error_out; + break; + case LPFC_IDIAG_RQ: + /* HDR queue */ + if (phba->sli4_hba.hdr_rq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.hdr_rq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.hdr_rq; + goto pass_check; + } + /* DAT queue */ + if (phba->sli4_hba.dat_rq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.dat_rq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.dat_rq; + goto pass_check; + } + goto error_out; + break; + default: + goto error_out; + break; + } + +pass_check: + + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { + if (count == LPFC_QUE_ACC_BROWSE) + idiag.offset.last_rd = index; + } + + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || + idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST || + idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) { + /* Additional sanity checks on write operation */ + pque = (struct lpfc_queue *)idiag.ptr_private; + if (offset > pque->entry_size/sizeof(uint32_t) - 1) + goto error_out; + pentry = pque->qe[index].address; + pentry += offset; + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR) + *pentry = value; + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST) + *pentry |= value; + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) + *pentry &= ~value; + } + return nbytes; + +error_out: + /* Clean out command structure on command error out */ + memset(&idiag, 0, sizeof(idiag)); + return -EINVAL; +} + +/** + * lpfc_idiag_drbacc_read_reg - idiag debugfs read a doorbell register + * @phba: The pointer to hba structure. + * @pbuffer: The pointer to the buffer to copy the data to. + * @len: The lenght of bytes to copied. + * @drbregid: The id to doorbell registers. + * + * Description: + * This routine reads a doorbell register and copies its content to the + * user buffer pointed to by @pbuffer. + * + * Returns: + * This function returns the amount of data that was copied into @pbuffer. + **/ +static int +lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer, + int len, uint32_t drbregid) +{ + + if (!pbuffer) + return 0; + + switch (drbregid) { + case LPFC_DRB_EQCQ: + len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + "EQCQ-DRB-REG: 0x%08x\n", + readl(phba->sli4_hba.EQCQDBregaddr)); + break; + case LPFC_DRB_MQ: + len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + "MQ-DRB-REG: 0x%08x\n", + readl(phba->sli4_hba.MQDBregaddr)); + break; + case LPFC_DRB_WQ: + len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + "WQ-DRB-REG: 0x%08x\n", + readl(phba->sli4_hba.WQDBregaddr)); + break; + case LPFC_DRB_RQ: + len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + "RQ-DRB-REG: 0x%08x\n", + readl(phba->sli4_hba.RQDBregaddr)); + break; + default: + break; + } + + return len; +} + +/** + * lpfc_idiag_drbacc_read - idiag debugfs read port doorbell + * @file: The file pointer to read from. + * @buf: The buffer to copy the data to. + * @nbytes: The number of bytes to read. + * @ppos: The position in the file to start reading from. + * + * Description: + * This routine reads data from the @phba device doorbell register according + * to the idiag command, and copies to user @buf. Depending on the doorbell + * register read command setup, it does either a single doorbell register + * read or dump all doorbell registers. + * + * Returns: + * This function returns the amount of data that was read (this could be less + * than @nbytes if the end of the file was reached) or a negative error value. + **/ +static ssize_t +lpfc_idiag_drbacc_read(struct file *file, char __user *buf, size_t nbytes, + loff_t *ppos) +{ + struct lpfc_debug *debug = file->private_data; + struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; + uint32_t drb_reg_id, i; + char *pbuffer; + int len = 0; + + /* This is a user read operation */ + debug->op = LPFC_IDIAG_OP_RD; + + if (!debug->buffer) + debug->buffer = kmalloc(LPFC_DRB_ACC_BUF_SIZE, GFP_KERNEL); + if (!debug->buffer) + return 0; + pbuffer = debug->buffer; + + if (*ppos) + return 0; + + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) + drb_reg_id = idiag.cmd.data[0]; + else + return 0; + + if (drb_reg_id == LPFC_DRB_ACC_ALL) + for (i = 1; i <= LPFC_DRB_MAX; i++) + len = lpfc_idiag_drbacc_read_reg(phba, + pbuffer, len, i); + else + len = lpfc_idiag_drbacc_read_reg(phba, + pbuffer, len, drb_reg_id); + + return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); +} + +/** + * lpfc_idiag_drbacc_write - Syntax check and set up idiag drbacc commands + * @file: The file pointer to read from. + * @buf: The buffer to copy the user data from. + * @nbytes: The number of bytes to get. + * @ppos: The position in the file to start reading from. + * + * This routine get the debugfs idiag command struct from user space and then + * perform the syntax check for port doorbell register read (dump) or write + * (set) command accordingly. In the case of port queue read command, it sets + * up the command in the idiag command struct for the following debugfs read + * operation. In the case of port doorbell register write operation, it + * executes the write operation into the port doorbell register accordingly. + * + * It returns the @nbytges passing in from debugfs user space when successful. + * In case of error conditions, it returns proper error code back to the user + * space. + **/ +static ssize_t +lpfc_idiag_drbacc_write(struct file *file, const char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct lpfc_debug *debug = file->private_data; + struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; + uint32_t drb_reg_id, value, reg_val; + void __iomem *drb_reg; + int rc; + + /* This is a user write operation */ + debug->op = LPFC_IDIAG_OP_WR; + + rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); + if (rc < 0) + return rc; + + /* Sanity check on command line arguments */ + drb_reg_id = idiag.cmd.data[0]; + value = idiag.cmd.data[1]; + + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR || + idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || + idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { + if (rc != LPFC_DRB_ACC_WR_CMD_ARG) + goto error_out; + if (drb_reg_id > LPFC_DRB_MAX) + goto error_out; + } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) { + if (rc != LPFC_DRB_ACC_RD_CMD_ARG) + goto error_out; + if ((drb_reg_id > LPFC_DRB_MAX) && + (drb_reg_id != LPFC_DRB_ACC_ALL)) + goto error_out; + } else + goto error_out; + + /* Perform the write access operation */ + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR || + idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || + idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { + switch (drb_reg_id) { + case LPFC_DRB_EQCQ: + drb_reg = phba->sli4_hba.EQCQDBregaddr; + break; + case LPFC_DRB_MQ: + drb_reg = phba->sli4_hba.MQDBregaddr; + break; + case LPFC_DRB_WQ: + drb_reg = phba->sli4_hba.WQDBregaddr; + break; + case LPFC_DRB_RQ: + drb_reg = phba->sli4_hba.RQDBregaddr; + break; + default: + goto error_out; + } + + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR) + reg_val = value; + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST) { + reg_val = readl(drb_reg); + reg_val |= value; + } + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { + reg_val = readl(drb_reg); + reg_val &= ~value; + } + writel(reg_val, drb_reg); + readl(drb_reg); /* flush */ + } + return nbytes; + +error_out: + /* Clean out command structure on command error out */ + memset(&idiag, 0, sizeof(idiag)); + return -EINVAL; +} + #undef lpfc_debugfs_op_disc_trc static const struct file_operations lpfc_debugfs_op_disc_trc = { .owner = THIS_MODULE, @@ -1986,6 +2425,26 @@ static const struct file_operations lpfc_idiag_op_queInfo = { .release = lpfc_idiag_release, }; +#undef lpfc_idiag_op_queacc +static const struct file_operations lpfc_idiag_op_queAcc = { + .owner = THIS_MODULE, + .open = lpfc_idiag_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_idiag_queacc_read, + .write = lpfc_idiag_queacc_write, + .release = lpfc_idiag_cmd_release, +}; + +#undef lpfc_idiag_op_drbacc +static const struct file_operations lpfc_idiag_op_drbAcc = { + .owner = THIS_MODULE, + .open = lpfc_idiag_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_idiag_drbacc_read, + .write = lpfc_idiag_drbacc_write, + .release = lpfc_idiag_cmd_release, +}; + #endif /** @@ -2261,6 +2720,32 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) } } + /* iDiag access PCI function queue */ + snprintf(name, sizeof(name), "queAcc"); + if (!phba->idiag_que_acc) { + phba->idiag_que_acc = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->idiag_root, phba, &lpfc_idiag_op_queAcc); + if (!phba->idiag_que_acc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2926 Can't create idiag debugfs\n"); + goto debug_failed; + } + } + + /* iDiag access PCI function doorbell registers */ + snprintf(name, sizeof(name), "drbAcc"); + if (!phba->idiag_drb_acc) { + phba->idiag_drb_acc = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->idiag_root, phba, &lpfc_idiag_op_drbAcc); + if (!phba->idiag_drb_acc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2927 Can't create idiag debugfs\n"); + goto debug_failed; + } + } + debug_failed: return; #endif @@ -2339,6 +2824,16 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) * iDiag release */ if (phba->sli_rev == LPFC_SLI_REV4) { + if (phba->idiag_drb_acc) { + /* iDiag drbAcc */ + debugfs_remove(phba->idiag_drb_acc); + phba->idiag_drb_acc = NULL; + } + if (phba->idiag_que_acc) { + /* iDiag queAcc */ + debugfs_remove(phba->idiag_que_acc); + phba->idiag_que_acc = NULL; + } if (phba->idiag_que_info) { /* iDiag queInfo */ debugfs_remove(phba->idiag_que_info); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index 91b9a9427cda..6525a5e62d27 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -39,13 +39,42 @@ /* hbqinfo output buffer size */ #define LPFC_HBQINFO_SIZE 8192 -/* rdPciConf output buffer size */ +/* pciConf */ +#define LPFC_PCI_CFG_BROWSE 0xffff +#define LPFC_PCI_CFG_RD_CMD_ARG 2 +#define LPFC_PCI_CFG_WR_CMD_ARG 3 #define LPFC_PCI_CFG_SIZE 4096 #define LPFC_PCI_CFG_RD_BUF_SIZE (LPFC_PCI_CFG_SIZE/2) #define LPFC_PCI_CFG_RD_SIZE (LPFC_PCI_CFG_SIZE/4) -/* queue info output buffer size */ -#define LPFC_QUE_INFO_GET_BUF_SIZE 2048 +/* queue info */ +#define LPFC_QUE_INFO_GET_BUF_SIZE 4096 + +/* queue acc */ +#define LPFC_QUE_ACC_BROWSE 0xffff +#define LPFC_QUE_ACC_RD_CMD_ARG 4 +#define LPFC_QUE_ACC_WR_CMD_ARG 6 +#define LPFC_QUE_ACC_BUF_SIZE 4096 +#define LPFC_QUE_ACC_SIZE (LPFC_QUE_ACC_BUF_SIZE/2) + +#define LPFC_IDIAG_EQ 1 +#define LPFC_IDIAG_CQ 2 +#define LPFC_IDIAG_MQ 3 +#define LPFC_IDIAG_WQ 4 +#define LPFC_IDIAG_RQ 5 + +/* doorbell acc */ +#define LPFC_DRB_ACC_ALL 0xffff +#define LPFC_DRB_ACC_RD_CMD_ARG 1 +#define LPFC_DRB_ACC_WR_CMD_ARG 2 +#define LPFC_DRB_ACC_BUF_SIZE 256 + +#define LPFC_DRB_EQCQ 1 +#define LPFC_DRB_MQ 2 +#define LPFC_DRB_WQ 3 +#define LPFC_DRB_RQ 4 + +#define LPFC_DRB_MAX 4 #define SIZE_U8 sizeof(uint8_t) #define SIZE_U16 sizeof(uint16_t) @@ -73,13 +102,23 @@ struct lpfc_idiag_offset { uint32_t last_rd; }; -#define LPFC_IDIAG_CMD_DATA_SIZE 4 +#define LPFC_IDIAG_CMD_DATA_SIZE 8 struct lpfc_idiag_cmd { uint32_t opcode; #define LPFC_IDIAG_CMD_PCICFG_RD 0x00000001 #define LPFC_IDIAG_CMD_PCICFG_WR 0x00000002 #define LPFC_IDIAG_CMD_PCICFG_ST 0x00000003 #define LPFC_IDIAG_CMD_PCICFG_CL 0x00000004 + +#define LPFC_IDIAG_CMD_QUEACC_RD 0x00000011 +#define LPFC_IDIAG_CMD_QUEACC_WR 0x00000012 +#define LPFC_IDIAG_CMD_QUEACC_ST 0x00000013 +#define LPFC_IDIAG_CMD_QUEACC_CL 0x00000014 + +#define LPFC_IDIAG_CMD_DRBACC_RD 0x00000021 +#define LPFC_IDIAG_CMD_DRBACC_WR 0x00000022 +#define LPFC_IDIAG_CMD_DRBACC_ST 0x00000023 +#define LPFC_IDIAG_CMD_DRBACC_CL 0x00000024 uint32_t data[LPFC_IDIAG_CMD_DATA_SIZE]; }; @@ -87,6 +126,7 @@ struct lpfc_idiag { uint32_t active; struct lpfc_idiag_cmd cmd; struct lpfc_idiag_offset offset; + void *ptr_private; }; #endif diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index d34b69f9cdb1..e2c452467c8b 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -670,6 +670,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * Driver needs to re-reg VPI in order for f/w * to update the MAC address. */ + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_register_new_vport(phba, vport, ndlp); return 0; } @@ -869,8 +870,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ if ((phba->hba_flag & HBA_FIP_SUPPORT) && (phba->fcf.fcf_flag & FCF_DISCOVERY) && - (irsp->ulpStatus != IOSTAT_LOCAL_REJECT) && - (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) { + !((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && + (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) { lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS, "2611 FLOGI failed on FCF (x%x), " "status:x%x/x%x, tmo:x%x, perform " @@ -1085,14 +1086,15 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (sp->cmn.fcphHigh < FC_PH3) sp->cmn.fcphHigh = FC_PH3; - if ((phba->sli_rev == LPFC_SLI_REV4) && - (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == - LPFC_SLI_INTF_IF_TYPE_0)) { - elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1); - elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1); - /* FLOGI needs to be 3 for WQE FCFI */ - /* Set the fcfi to the fcfi we registered with */ - elsiocb->iocb.ulpContext = phba->fcf.fcfi; + if (phba->sli_rev == LPFC_SLI_REV4) { + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_0) { + elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1); + elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1); + /* FLOGI needs to be 3 for WQE FCFI */ + /* Set the fcfi to the fcfi we registered with */ + elsiocb->iocb.ulpContext = phba->fcf.fcfi; + } } else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { sp->cmn.request_multiple_Nport = 1; /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */ @@ -4107,13 +4109,13 @@ lpfc_els_clear_rrq(struct lpfc_vport *vport, pcmd += sizeof(uint32_t); rrq = (struct RRQ *)pcmd; rrq->rrq_exchg = be32_to_cpu(rrq->rrq_exchg); - rxid = be16_to_cpu(bf_get(rrq_rxid, rrq)); + rxid = bf_get(rrq_rxid, rrq); lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "2883 Clear RRQ for SID:x%x OXID:x%x RXID:x%x" " x%x x%x\n", be32_to_cpu(bf_get(rrq_did, rrq)), - be16_to_cpu(bf_get(rrq_oxid, rrq)), + bf_get(rrq_oxid, rrq), rxid, iocb->iotag, iocb->iocb.ulpContext); @@ -4121,7 +4123,7 @@ lpfc_els_clear_rrq(struct lpfc_vport *vport, "Clear RRQ: did:x%x flg:x%x exchg:x%.08x", ndlp->nlp_DID, ndlp->nlp_flag, rrq->rrq_exchg); if (vport->fc_myDID == be32_to_cpu(bf_get(rrq_did, rrq))) - xri = be16_to_cpu(bf_get(rrq_oxid, rrq)); + xri = bf_get(rrq_oxid, rrq); else xri = rxid; prrq = lpfc_get_active_rrq(vport, xri, ndlp->nlp_DID); @@ -7290,8 +7292,9 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = cmdiocb->vport; IOCB_t *irsp; struct lpfc_nodelist *ndlp; - ndlp = (struct lpfc_nodelist *)cmdiocb->context1; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + ndlp = (struct lpfc_nodelist *)cmdiocb->context1; irsp = &rspiocb->iocb; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "LOGO npiv cmpl: status:x%x/x%x did:x%x", @@ -7302,6 +7305,19 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Trigger the release of the ndlp after logo */ lpfc_nlp_put(ndlp); + + /* NPIV LOGO completes to NPort */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "2928 NPIV LOGO completes to NPort x%x " + "Data: x%x x%x x%x x%x\n", + ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], + irsp->ulpTimeout, vport->num_disc_nodes); + + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_FABRIC; + spin_unlock_irq(shost->host_lock); + } } /** diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 301498301a8f..7a35df5e2038 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -3569,6 +3569,10 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) "rport add: did:x%x flg:x%x type x%x", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); + /* Don't add the remote port if unloading. */ + if (vport->load_flag & FC_UNLOADING) + return; + ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids); if (!rport || !get_device(&rport->dev)) { dev_printk(KERN_WARNING, &phba->pcidev->dev, diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 8433ac0d9fb4..4dff668ebdad 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1059,6 +1059,11 @@ struct rq_context { #define lpfc_rq_context_rqe_size_SHIFT 8 /* Version 1 Only */ #define lpfc_rq_context_rqe_size_MASK 0x0000000F #define lpfc_rq_context_rqe_size_WORD word0 +#define LPFC_RQE_SIZE_8 2 +#define LPFC_RQE_SIZE_16 3 +#define LPFC_RQE_SIZE_32 4 +#define LPFC_RQE_SIZE_64 5 +#define LPFC_RQE_SIZE_128 6 #define lpfc_rq_context_page_size_SHIFT 0 /* Version 1 Only */ #define lpfc_rq_context_page_size_MASK 0x000000FF #define lpfc_rq_context_page_size_WORD word0 @@ -2108,6 +2113,8 @@ struct lpfc_mbx_pc_sli4_params { #define sgl_pp_align_WORD word12 uint32_t rsvd_13_63[51]; }; +#define SLI4_PAGE_ALIGN(addr) (((addr)+((SLI4_PAGE_SIZE)-1)) \ + &(~((SLI4_PAGE_SIZE)-1))) struct lpfc_sli4_parameters { uint32_t word0; @@ -2491,6 +2498,9 @@ struct wqe_common { #define wqe_reqtag_SHIFT 0 #define wqe_reqtag_MASK 0x0000FFFF #define wqe_reqtag_WORD word9 +#define wqe_temp_rpi_SHIFT 16 +#define wqe_temp_rpi_MASK 0x0000FFFF +#define wqe_temp_rpi_WORD word9 #define wqe_rcvoxid_SHIFT 16 #define wqe_rcvoxid_MASK 0x0000FFFF #define wqe_rcvoxid_WORD word9 @@ -2524,7 +2534,7 @@ struct wqe_common { #define wqe_wqes_WORD word10 /* Note that this field overlaps above fields */ #define wqe_wqid_SHIFT 1 -#define wqe_wqid_MASK 0x0000007f +#define wqe_wqid_MASK 0x00007fff #define wqe_wqid_WORD word10 #define wqe_pri_SHIFT 16 #define wqe_pri_MASK 0x00000007 @@ -2621,7 +2631,11 @@ struct xmit_els_rsp64_wqe { uint32_t rsvd4; struct wqe_did wqe_dest; struct wqe_common wqe_com; /* words 6-11 */ - uint32_t rsvd_12_15[4]; + uint32_t word12; +#define wqe_rsp_temp_rpi_SHIFT 0 +#define wqe_rsp_temp_rpi_MASK 0x0000FFFF +#define wqe_rsp_temp_rpi_WORD word12 + uint32_t rsvd_13_15[3]; }; struct xmit_bls_rsp64_wqe { diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 505f88443b5c..7dda036a1af3 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -3209,9 +3209,9 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, phba->sli4_hba.link_state.logical_speed = bf_get(lpfc_acqe_logical_link_speed, acqe_link); lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2900 Async FCoE Link event - Speed:%dGBit duplex:x%x " - "LA Type:x%x Port Type:%d Port Number:%d Logical " - "speed:%dMbps Fault:%d\n", + "2900 Async FC/FCoE Link event - Speed:%dGBit " + "duplex:x%x LA Type:x%x Port Type:%d Port Number:%d " + "Logical speed:%dMbps Fault:%d\n", phba->sli4_hba.link_state.speed, phba->sli4_hba.link_state.topology, phba->sli4_hba.link_state.status, @@ -4906,6 +4906,7 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba) uint16_t rpi_limit, curr_rpi_range; struct lpfc_dmabuf *dmabuf; struct lpfc_rpi_hdr *rpi_hdr; + uint32_t rpi_count; rpi_limit = phba->sli4_hba.max_cfg_param.rpi_base + phba->sli4_hba.max_cfg_param.max_rpi - 1; @@ -4920,7 +4921,9 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba) * and to allow the full max_rpi range per port. */ if ((curr_rpi_range + (LPFC_RPI_HDR_COUNT - 1)) > rpi_limit) - return NULL; + rpi_count = rpi_limit - curr_rpi_range; + else + rpi_count = LPFC_RPI_HDR_COUNT; /* * First allocate the protocol header region for the port. The @@ -4961,7 +4964,7 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba) * The next_rpi stores the next module-64 rpi value to post * in any subsequent rpi memory region postings. */ - phba->sli4_hba.next_rpi += LPFC_RPI_HDR_COUNT; + phba->sli4_hba.next_rpi += rpi_count; spin_unlock_irq(&phba->hbalock); return rpi_hdr; @@ -7004,7 +7007,8 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) lpfc_sli4_bar0_register_memmap(phba, if_type); } - if (pci_resource_start(pdev, 2)) { + if ((if_type == LPFC_SLI_INTF_IF_TYPE_0) && + (pci_resource_start(pdev, 2))) { /* * Map SLI4 if type 0 HBA Control Register base to a kernel * virtual address and setup the registers. @@ -7021,7 +7025,8 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) lpfc_sli4_bar1_register_memmap(phba); } - if (pci_resource_start(pdev, 4)) { + if ((if_type == LPFC_SLI_INTF_IF_TYPE_0) && + (pci_resource_start(pdev, 4))) { /* * Map SLI4 if type 0 HBA Doorbell Register base to a kernel * virtual address and setup the registers. diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index fbab9734e9b4..e6ce9033f85e 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1736,7 +1736,7 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox, } /* Setup for the none-embedded mbox command */ - pcount = (PAGE_ALIGN(length))/SLI4_PAGE_SIZE; + pcount = (SLI4_PAGE_ALIGN(length))/SLI4_PAGE_SIZE; pcount = (pcount > LPFC_SLI4_MBX_SGE_MAX_PAGES) ? LPFC_SLI4_MBX_SGE_MAX_PAGES : pcount; /* Allocate record for keeping SGE virtual addresses */ diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index fe7cc84e773b..84e4481b2406 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -3238,9 +3238,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) if (!lpfc_cmd) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "2873 SCSI Layer I/O Abort Request IO CMPL Status " - "x%x ID %d " - "LUN %d snum %#lx\n", ret, cmnd->device->id, - cmnd->device->lun, cmnd->serial_number); + "x%x ID %d LUN %d\n", + ret, cmnd->device->id, cmnd->device->lun); return SUCCESS; } @@ -3318,16 +3317,15 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, "0748 abort handler timed out waiting " "for abort to complete: ret %#x, ID %d, " - "LUN %d, snum %#lx\n", - ret, cmnd->device->id, cmnd->device->lun, - cmnd->serial_number); + "LUN %d\n", + ret, cmnd->device->id, cmnd->device->lun); } out: lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "0749 SCSI Layer I/O Abort Request Status x%x ID %d " - "LUN %d snum %#lx\n", ret, cmnd->device->id, - cmnd->device->lun, cmnd->serial_number); + "LUN %d\n", ret, cmnd->device->id, + cmnd->device->lun); return ret; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index dacabbe0a586..837d272cb2d6 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4769,8 +4769,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) else phba->hba_flag &= ~HBA_FIP_SUPPORT; - if (phba->sli_rev != LPFC_SLI_REV4 || - !(phba->hba_flag & HBA_FCOE_MODE)) { + if (phba->sli_rev != LPFC_SLI_REV4) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "0376 READ_REV Error. SLI Level %d " "FCoE enabled %d\n", @@ -5018,10 +5017,11 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) lpfc_reg_fcfi(phba, mboxq); mboxq->vport = phba->pport; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (rc == MBX_SUCCESS) - rc = 0; - else + if (rc != MBX_SUCCESS) goto out_unset_queue; + rc = 0; + phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, + &mboxq->u.mqe.un.reg_fcfi); } /* * The port is ready, set the host's link state to LINK_DOWN @@ -6402,6 +6402,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, uint32_t els_id = LPFC_ELS_ID_DEFAULT; int numBdes, i; struct ulp_bde64 bde; + struct lpfc_nodelist *ndlp; fip = phba->hba_flag & HBA_FIP_SUPPORT; /* The fcp commands will set command type */ @@ -6447,6 +6448,7 @@ 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.ulpLe) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2007 Only Limited Edition cmd Format" @@ -6472,6 +6474,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, els_id = ((iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK) >> LPFC_FIP_ELS_ID_SHIFT); } + bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com, ndlp->nlp_rpi); bf_set(wqe_els_id, &wqe->els_req.wqe_com, els_id); bf_set(wqe_dbde, &wqe->els_req.wqe_com, 1); bf_set(wqe_iod, &wqe->els_req.wqe_com, LPFC_WQE_IOD_READ); @@ -6604,6 +6607,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, command_type = OTHER_COMMAND; break; case CMD_XMIT_ELS_RSP64_CX: + ndlp = (struct lpfc_nodelist *)iocbq->context1; /* words0-2 BDE memcpy */ /* word3 iocb=iotag32 wqe=response_payload_len */ wqe->xmit_els_rsp.response_payload_len = xmit_len; @@ -6626,6 +6630,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_lenloc, &wqe->xmit_els_rsp.wqe_com, LPFC_WQE_LENLOC_WORD3); bf_set(wqe_ebde_cnt, &wqe->xmit_els_rsp.wqe_com, 0); + bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp, ndlp->nlp_rpi); command_type = OTHER_COMMAND; break; case CMD_CLOSE_XRI_CN: @@ -10522,8 +10527,8 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, bf_set(lpfc_mbox_hdr_version, &shdr->request, phba->sli4_hba.pc_sli4_params.cqv); if (phba->sli4_hba.pc_sli4_params.cqv == LPFC_Q_CREATE_VERSION_2) { - bf_set(lpfc_mbx_cq_create_page_size, &cq_create->u.request, - (PAGE_SIZE/SLI4_PAGE_SIZE)); + /* FW only supports 1. Should be PAGE_SIZE/SLI4_PAGE_SIZE */ + bf_set(lpfc_mbx_cq_create_page_size, &cq_create->u.request, 1); bf_set(lpfc_cq_eq_id_2, &cq_create->u.request.context, eq->queue_id); } else { @@ -10967,6 +10972,12 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, &rq_create->u.request.context, hrq->entry_count); rq_create->u.request.context.buffer_size = LPFC_HDR_BUF_SIZE; + bf_set(lpfc_rq_context_rqe_size, + &rq_create->u.request.context, + LPFC_RQE_SIZE_8); + bf_set(lpfc_rq_context_page_size, + &rq_create->u.request.context, + (PAGE_SIZE/SLI4_PAGE_SIZE)); } else { switch (hrq->entry_count) { default: @@ -11042,9 +11053,12 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, phba->sli4_hba.pc_sli4_params.rqv); if (phba->sli4_hba.pc_sli4_params.rqv == LPFC_Q_CREATE_VERSION_1) { bf_set(lpfc_rq_context_rqe_count_1, - &rq_create->u.request.context, - hrq->entry_count); + &rq_create->u.request.context, hrq->entry_count); rq_create->u.request.context.buffer_size = LPFC_DATA_BUF_SIZE; + bf_set(lpfc_rq_context_rqe_size, &rq_create->u.request.context, + LPFC_RQE_SIZE_8); + bf_set(lpfc_rq_context_page_size, &rq_create->u.request.context, + (PAGE_SIZE/SLI4_PAGE_SIZE)); } else { switch (drq->entry_count) { default: diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 2404d1d65563..c03921b1232c 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.22" +#define LPFC_DRIVER_VERSION "8.3.23" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index f2684dd09ed0..5c1776406c96 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -1469,8 +1469,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) if( scb->state & SCB_ABORT ) { printk(KERN_WARNING - "megaraid: aborted cmd %lx[%x] complete.\n", - scb->cmd->serial_number, scb->idx); + "megaraid: aborted cmd [%x] complete.\n", + scb->idx); scb->cmd->result = (DID_ABORT << 16); @@ -1488,8 +1488,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) if( scb->state & SCB_RESET ) { printk(KERN_WARNING - "megaraid: reset cmd %lx[%x] complete.\n", - scb->cmd->serial_number, scb->idx); + "megaraid: reset cmd [%x] complete.\n", + scb->idx); scb->cmd->result = (DID_RESET << 16); @@ -1958,8 +1958,8 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor) struct list_head *pos, *next; scb_t *scb; - printk(KERN_WARNING "megaraid: %s-%lx cmd=%x \n", - (aor == SCB_ABORT)? "ABORTING":"RESET", cmd->serial_number, + printk(KERN_WARNING "megaraid: %s cmd=%x \n", + (aor == SCB_ABORT)? "ABORTING":"RESET", cmd->cmnd[0], cmd->device->channel, cmd->device->id, cmd->device->lun); @@ -1983,9 +1983,9 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor) if( scb->state & SCB_ISSUED ) { printk(KERN_WARNING - "megaraid: %s-%lx[%x], fw owner.\n", + "megaraid: %s[%x], fw owner.\n", (aor==SCB_ABORT) ? "ABORTING":"RESET", - cmd->serial_number, scb->idx); + scb->idx); return FALSE; } @@ -1996,9 +1996,9 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor) * list */ printk(KERN_WARNING - "megaraid: %s-%lx[%x], driver owner.\n", + "megaraid: %s-[%x], driver owner.\n", (aor==SCB_ABORT) ? "ABORTING":"RESET", - cmd->serial_number, scb->idx); + scb->idx); mega_free_scb(adapter, scb); diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 1dba32870b4c..2e6619eff3ea 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -2315,8 +2315,8 @@ megaraid_mbox_dpc(unsigned long devp) // Was an abort issued for this command earlier if (scb->state & SCB_ABORT) { con_log(CL_ANN, (KERN_NOTICE - "megaraid: aborted cmd %lx[%x] completed\n", - scp->serial_number, scb->sno)); + "megaraid: aborted cmd [%x] completed\n", + scb->sno)); } /* @@ -2472,8 +2472,8 @@ megaraid_abort_handler(struct scsi_cmnd *scp) raid_dev = ADAP2RAIDDEV(adapter); con_log(CL_ANN, (KERN_WARNING - "megaraid: aborting-%ld cmd=%x \n", - scp->serial_number, scp->cmnd[0], SCP2CHANNEL(scp), + "megaraid: aborting cmd=%x \n", + scp->cmnd[0], SCP2CHANNEL(scp), SCP2TARGET(scp), SCP2LUN(scp))); // If FW has stopped responding, simply return failure @@ -2496,9 +2496,8 @@ megaraid_abort_handler(struct scsi_cmnd *scp) list_del_init(&scb->list); // from completed list con_log(CL_ANN, (KERN_WARNING - "megaraid: %ld:%d[%d:%d], abort from completed list\n", - scp->serial_number, scb->sno, - scb->dev_channel, scb->dev_target)); + "megaraid: %d[%d:%d], abort from completed list\n", + scb->sno, scb->dev_channel, scb->dev_target)); scp->result = (DID_ABORT << 16); scp->scsi_done(scp); @@ -2527,9 +2526,8 @@ megaraid_abort_handler(struct scsi_cmnd *scp) ASSERT(!(scb->state & SCB_ISSUED)); con_log(CL_ANN, (KERN_WARNING - "megaraid abort: %ld[%d:%d], driver owner\n", - scp->serial_number, scb->dev_channel, - scb->dev_target)); + "megaraid abort: [%d:%d], driver owner\n", + scb->dev_channel, scb->dev_target)); scp->result = (DID_ABORT << 16); scp->scsi_done(scp); @@ -2560,25 +2558,21 @@ megaraid_abort_handler(struct scsi_cmnd *scp) if (!(scb->state & SCB_ISSUED)) { con_log(CL_ANN, (KERN_WARNING - "megaraid abort: %ld%d[%d:%d], invalid state\n", - scp->serial_number, scb->sno, scb->dev_channel, - scb->dev_target)); + "megaraid abort: %d[%d:%d], invalid state\n", + scb->sno, scb->dev_channel, scb->dev_target)); BUG(); } else { con_log(CL_ANN, (KERN_WARNING - "megaraid abort: %ld:%d[%d:%d], fw owner\n", - scp->serial_number, scb->sno, scb->dev_channel, - scb->dev_target)); + "megaraid abort: %d[%d:%d], fw owner\n", + scb->sno, scb->dev_channel, scb->dev_target)); } } } spin_unlock_irq(&adapter->lock); if (!found) { - con_log(CL_ANN, (KERN_WARNING - "megaraid abort: scsi cmd:%ld, do now own\n", - scp->serial_number)); + con_log(CL_ANN, (KERN_WARNING "megaraid abort: do now own\n")); // FIXME: Should there be a callback for this command? return SUCCESS; @@ -2649,9 +2643,8 @@ megaraid_reset_handler(struct scsi_cmnd *scp) } else { if (scb->scp == scp) { // Found command con_log(CL_ANN, (KERN_WARNING - "megaraid: %ld:%d[%d:%d], reset from pending list\n", - scp->serial_number, scb->sno, - scb->dev_channel, scb->dev_target)); + "megaraid: %d[%d:%d], reset from pending list\n", + scb->sno, scb->dev_channel, scb->dev_target)); } else { con_log(CL_ANN, (KERN_WARNING "megaraid: IO packet with %d[%d:%d] being reset\n", diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 66d4cea4df98..89c623ebadbc 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1751,10 +1751,9 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) list_del_init(&reset_cmd->list); if (reset_cmd->scmd) { reset_cmd->scmd->result = DID_RESET << 16; - printk(KERN_NOTICE "%d:%p reset [%02x], %#lx\n", + printk(KERN_NOTICE "%d:%p reset [%02x]\n", reset_index, reset_cmd, - reset_cmd->scmd->cmnd[0], - reset_cmd->scmd->serial_number); + reset_cmd->scmd->cmnd[0]); reset_cmd->scmd->scsi_done(reset_cmd->scmd); megasas_return_cmd(instance, reset_cmd); @@ -1879,8 +1878,8 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) instance = (struct megasas_instance *)scmd->device->host->hostdata; - scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n", - scmd->serial_number, scmd->cmnd[0], scmd->retries); + scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x retries=%x\n", + scmd->cmnd[0], scmd->retries); if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { printk(KERN_ERR "megasas: cannot recover from previous reset " @@ -2349,9 +2348,9 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance) cmd->frame_phys_addr , 0, instance->reg_set); } else if (cmd->scmd) { - printk(KERN_NOTICE "megasas: %p scsi cmd [%02x],%#lx" + printk(KERN_NOTICE "megasas: %p scsi cmd [%02x]" "detected on the internal queue, issue again.\n", - cmd, cmd->scmd->cmnd[0], cmd->scmd->serial_number); + cmd, cmd->scmd->cmnd[0]); atomic_inc(&instance->fw_outstanding); instance->instancet->fire_cmd(instance, diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 197aa1b3f0f3..494474779532 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -415,8 +415,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd) #if 1 if (DEBUG_TARGET(cmd)) { int i; - printk(KERN_DEBUG "mesh_start: %p ser=%lu tgt=%d cmd=", - cmd, cmd->serial_number, id); + printk(KERN_DEBUG "mesh_start: %p tgt=%d cmd=", cmd, id); for (i = 0; i < cmd->cmd_len; ++i) printk(" %x", cmd->cmnd[i]); printk(" use_sg=%d buffer=%p bufflen=%u\n", diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 3346357031e9..efa0255491c2 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -522,7 +522,8 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc, desc = "Device Status Change"; break; case MPI2_EVENT_IR_OPERATION_STATUS: - desc = "IR Operation Status"; + if (!ioc->hide_ir_msg) + desc = "IR Operation Status"; break; case MPI2_EVENT_SAS_DISCOVERY: { @@ -553,16 +554,20 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc, desc = "SAS Enclosure Device Status Change"; break; case MPI2_EVENT_IR_VOLUME: - desc = "IR Volume"; + if (!ioc->hide_ir_msg) + desc = "IR Volume"; break; case MPI2_EVENT_IR_PHYSICAL_DISK: - desc = "IR Physical Disk"; + if (!ioc->hide_ir_msg) + desc = "IR Physical Disk"; break; case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - desc = "IR Configuration Change List"; + if (!ioc->hide_ir_msg) + desc = "IR Configuration Change List"; break; case MPI2_EVENT_LOG_ENTRY_ADDED: - desc = "Log Entry Added"; + if (!ioc->hide_ir_msg) + desc = "Log Entry Added"; break; } @@ -616,7 +621,10 @@ _base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info) originator_str = "PL"; break; case 2: - originator_str = "IR"; + if (!ioc->hide_ir_msg) + originator_str = "IR"; + else + originator_str = "WarpDrive"; break; } @@ -1508,6 +1516,7 @@ mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid) } ioc->scsi_lookup[i].cb_idx = 0xFF; ioc->scsi_lookup[i].scmd = NULL; + ioc->scsi_lookup[i].direct_io = 0; list_add_tail(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); @@ -1844,10 +1853,12 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) printk("), "); printk("Capabilities=("); - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { - printk("Raid"); - i++; + if (!ioc->hide_ir_msg) { + if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { + printk("Raid"); + i++; + } } if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) { @@ -3680,6 +3691,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) u32 reply_address; u16 smid; struct _tr_list *delayed_tr, *delayed_tr_next; + u8 hide_flag; dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); @@ -3706,6 +3718,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) ioc->scsi_lookup[i].cb_idx = 0xFF; ioc->scsi_lookup[i].smid = smid; ioc->scsi_lookup[i].scmd = NULL; + ioc->scsi_lookup[i].direct_io = 0; list_add_tail(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); } @@ -3766,6 +3779,15 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) if (sleep_flag == CAN_SLEEP) _base_static_config_pages(ioc); + if (ioc->wait_for_port_enable_to_complete && ioc->is_warpdrive) { + if (ioc->manu_pg10.OEMIdentifier == 0x80) { + hide_flag = (u8) (ioc->manu_pg10.OEMSpecificFlags0 & + MFG_PAGE10_HIDE_SSDS_MASK); + if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) + ioc->mfg_pg10_hide_flag = hide_flag; + } + } + if (ioc->wait_for_port_enable_to_complete) { if (diag_buffer_enable != 0) mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 500328245f61..2a3c05f6db8b 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,11 +69,11 @@ #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 "08.100.00.00" +#define MPT2SAS_DRIVER_VERSION "08.100.00.01" #define MPT2SAS_MAJOR_VERSION 08 #define MPT2SAS_MINOR_VERSION 100 #define MPT2SAS_BUILD_VERSION 00 -#define MPT2SAS_RELEASE_VERSION 00 +#define MPT2SAS_RELEASE_VERSION 01 /* * Set MPT2SAS_SG_DEPTH value based on user input. @@ -188,6 +188,16 @@ #define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044 #define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046 +/* + * WarpDrive Specific Log codes + */ + +#define MPT2_WARPDRIVE_LOGENTRY (0x8002) +#define MPT2_WARPDRIVE_LC_SSDT (0x41) +#define MPT2_WARPDRIVE_LC_SSDLW (0x43) +#define MPT2_WARPDRIVE_LC_SSDLF (0x44) +#define MPT2_WARPDRIVE_LC_BRMF (0x4D) + /* * per target private data */ @@ -199,6 +209,7 @@ * struct MPT2SAS_TARGET - starget private hostdata * @starget: starget object * @sas_address: target sas address + * @raid_device: raid_device pointer to access volume data * @handle: device handle * @num_luns: number luns * @flags: MPT_TARGET_FLAGS_XXX flags @@ -208,6 +219,7 @@ struct MPT2SAS_TARGET { struct scsi_target *starget; u64 sas_address; + struct _raid_device *raid_device; u16 handle; int num_luns; u32 flags; @@ -215,6 +227,7 @@ struct MPT2SAS_TARGET { u8 tm_busy; }; + /* * per device private data */ @@ -262,6 +275,12 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_10 { MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_10, Mpi2ManufacturingPage10_t, MPI2_POINTER pMpi2ManufacturingPage10_t; +#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003) +#define MFG_PAGE10_HIDE_ALL_DISKS (0x00) +#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01) +#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02) + + struct MPT2SAS_DEVICE { struct MPT2SAS_TARGET *sas_target; unsigned int lun; @@ -341,6 +360,7 @@ struct _sas_device { * @sdev: scsi device struct (volumes are single lun) * @wwid: unique identifier for the volume * @handle: device handle + * @block_size: Block size of the volume * @id: target id * @channel: target channel * @volume_type: the raid level @@ -348,20 +368,33 @@ struct _sas_device { * @num_pds: number of hidden raid components * @responding: used in _scsih_raid_device_mark_responding * @percent_complete: resync percent complete + * @direct_io_enabled: Whether direct io to PDs are allowed or not + * @stripe_exponent: X where 2powX is the stripe sz in blocks + * @max_lba: Maximum number of LBA in the volume + * @stripe_sz: Stripe Size of the volume + * @device_info: Device info of the volume member disk + * @pd_handle: Array of handles of the physical drives for direct I/O in le16 */ +#define MPT_MAX_WARPDRIVE_PDS 8 struct _raid_device { struct list_head list; struct scsi_target *starget; struct scsi_device *sdev; u64 wwid; u16 handle; + u16 block_sz; int id; int channel; u8 volume_type; - u32 device_info; u8 num_pds; u8 responding; u8 percent_complete; + u8 direct_io_enabled; + u8 stripe_exponent; + u64 max_lba; + u32 stripe_sz; + u32 device_info; + u16 pd_handle[MPT_MAX_WARPDRIVE_PDS]; }; /** @@ -470,6 +503,7 @@ struct chain_tracker { * @smid: system message id * @scmd: scsi request pointer * @cb_idx: callback index + * @direct_io: To indicate whether I/O is direct (WARPDRIVE) * @chain_list: list of chains associated to this IO * @tracker_list: list of free request (ioc->free_list) */ @@ -477,14 +511,14 @@ struct scsiio_tracker { u16 smid; struct scsi_cmnd *scmd; u8 cb_idx; + u8 direct_io; struct list_head chain_list; struct list_head tracker_list; }; /** - * struct request_tracker - misc mf request tracker + * struct request_tracker - firmware request tracker * @smid: system message id - * @scmd: scsi request pointer * @cb_idx: callback index * @tracker_list: list of free request (ioc->free_list) */ @@ -832,6 +866,11 @@ struct MPT2SAS_ADAPTER { u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; u32 ring_buffer_offset; u32 ring_buffer_sz; + u8 is_warpdrive; + u8 hide_ir_msg; + u8 mfg_pg10_hide_flag; + u8 hide_drives; + }; typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 1c6d2b405eef..437c2d94c45a 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -688,6 +688,13 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, goto out; } + /* Check for overflow and wraparound */ + if (karg.data_sge_offset * 4 > ioc->request_sz || + karg.data_sge_offset > (UINT_MAX / 4)) { + ret = -EINVAL; + goto out; + } + /* copy in request message frame from user */ if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, @@ -1034,7 +1041,10 @@ _ctl_getiocinfo(void __user *arg) __func__)); memset(&karg, 0 , sizeof(karg)); - karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; + if (ioc->is_warpdrive) + karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200; + else + karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; if (ioc->pfacts) karg.port_number = ioc->pfacts[0].PortNumber; pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision); @@ -1963,7 +1973,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) Mpi2DiagBufferPostReply_t *mpi_reply; int rc, i; u8 buffer_type; - unsigned long timeleft; + unsigned long timeleft, request_size, copy_size; u16 smid; u16 ioc_status; u8 issue_reset = 0; @@ -1999,6 +2009,8 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) return -ENOMEM; } + request_size = ioc->diag_buffer_sz[buffer_type]; + if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) { printk(MPT2SAS_ERR_FMT "%s: either the starting_offset " "or bytes_to_read are not 4 byte aligned\n", ioc->name, @@ -2006,13 +2018,23 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) return -EINVAL; } + if (karg.starting_offset > request_size) + return -EINVAL; + diag_data = (void *)(request_data + karg.starting_offset); dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), " "offset(%d), sz(%d)\n", ioc->name, __func__, diag_data, karg.starting_offset, karg.bytes_to_read)); + /* Truncate data on requests that are too large */ + if ((diag_data + karg.bytes_to_read < diag_data) || + (diag_data + karg.bytes_to_read > request_data + request_size)) + copy_size = request_size - karg.starting_offset; + else + copy_size = karg.bytes_to_read; + if (copy_to_user((void __user *)uarg->diagnostic_data, - diag_data, karg.bytes_to_read)) { + diag_data, copy_size)) { printk(MPT2SAS_ERR_FMT "%s: Unable to write " "mpt_diag_read_buffer_t data @ %p\n", ioc->name, __func__, diag_data); diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h index 69916e46e04f..11ff1d5fb8f0 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h @@ -133,6 +133,7 @@ struct mpt2_ioctl_pci_info { #define MPT2_IOCTL_INTERFACE_FC_IP (0x02) #define MPT2_IOCTL_INTERFACE_SAS (0x03) #define MPT2_IOCTL_INTERFACE_SAS2 (0x04) +#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200 (0x05) #define MPT2_IOCTL_VERSION_LENGTH (32) /** diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index d2064a0533ae..f12e02358d6d 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -233,6 +233,9 @@ static struct pci_device_id scsih_pci_table[] = { PCI_ANY_ID, PCI_ANY_ID }, { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, PCI_ANY_ID, PCI_ANY_ID }, + /* SSS6200 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, + PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, scsih_pci_table); @@ -1256,6 +1259,7 @@ _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; raid_device->starget = starget; } spin_unlock_irqrestore(&ioc->raid_device_lock, flags); @@ -1455,7 +1459,10 @@ static int _scsih_is_raid(struct device *dev) { struct scsi_device *sdev = to_scsi_device(dev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); + if (ioc->is_warpdrive) + return 0; return (sdev->channel == RAID_CHANNEL) ? 1 : 0; } @@ -1480,7 +1487,7 @@ _scsih_get_resync(struct device *dev) sdev->channel); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (!raid_device) + if (!raid_device || ioc->is_warpdrive) goto out; if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, @@ -1640,6 +1647,212 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, kfree(vol_pg0); } +/** + * _scsih_disable_ddio - Disable direct I/O for all the volumes + * @ioc: per adapter object + */ +static void +_scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc) +{ + Mpi2RaidVolPage1_t vol_pg1; + Mpi2ConfigReply_t mpi_reply; + struct _raid_device *raid_device; + u16 handle; + u16 ioc_status; + + handle = 0xFFFF; + while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, + &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + handle = le16_to_cpu(vol_pg1.DevHandle); + raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + if (raid_device) + raid_device->direct_io_enabled = 0; + } + return; +} + + +/** + * _scsih_get_num_volumes - Get number of volumes in the ioc + * @ioc: per adapter object + */ +static u8 +_scsih_get_num_volumes(struct MPT2SAS_ADAPTER *ioc) +{ + Mpi2RaidVolPage1_t vol_pg1; + Mpi2ConfigReply_t mpi_reply; + u16 handle; + u8 vol_cnt = 0; + u16 ioc_status; + + handle = 0xFFFF; + while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, + &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + vol_cnt++; + handle = le16_to_cpu(vol_pg1.DevHandle); + } + return vol_cnt; +} + + +/** + * _scsih_init_warpdrive_properties - Set properties for warpdrive direct I/O. + * @ioc: per adapter object + * @raid_device: the raid_device object + */ +static void +_scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc, + struct _raid_device *raid_device) +{ + Mpi2RaidVolPage0_t *vol_pg0; + Mpi2RaidPhysDiskPage0_t pd_pg0; + Mpi2ConfigReply_t mpi_reply; + u16 sz; + u8 num_pds, count; + u64 mb = 1024 * 1024; + u64 tb_2 = 2 * mb * mb; + u64 capacity; + u32 stripe_sz; + u8 i, stripe_exp; + + if (!ioc->is_warpdrive) + return; + + if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "globally as drives are exposed\n", ioc->name); + return; + } + if (_scsih_get_num_volumes(ioc) > 1) { + _scsih_disable_ddio(ioc); + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "globally as number of drives > 1\n", ioc->name); + return; + } + if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, + &num_pds)) || !num_pds) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "Failure in computing number of drives\n", ioc->name); + return; + } + + sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * + sizeof(Mpi2RaidVol0PhysDisk_t)); + vol_pg0 = kzalloc(sz, GFP_KERNEL); + if (!vol_pg0) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "Memory allocation failure for RVPG0\n", ioc->name); + return; + } + + if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "Failure in retrieving RVPG0\n", ioc->name); + kfree(vol_pg0); + return; + } + + /* + * WARPDRIVE:If number of physical disks in a volume exceeds the max pds + * assumed for WARPDRIVE, disable direct I/O + */ + if (num_pds > MPT_MAX_WARPDRIVE_PDS) { + printk(MPT2SAS_WARN_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x): num_mem=%d, " + "max_mem_allowed=%d\n", ioc->name, raid_device->handle, + num_pds, MPT_MAX_WARPDRIVE_PDS); + kfree(vol_pg0); + return; + } + for (count = 0; count < num_pds; count++) { + 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) { + 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", + ioc->name, raid_device->handle, + vol_pg0->PhysDisk[count].PhysDiskNum); + goto out_error; + } + raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle); + } + + /* + * Assumption for WD: Direct I/O is not supported if the volume is + * not RAID0, if the stripe size is not 64KB, if the block size is + * not 512 and if the volume size is >2TB + */ + if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0 || + le16_to_cpu(vol_pg0->BlockSize) != 512) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x): type=%d, " + "s_sz=%uK, blk_size=%u\n", ioc->name, + raid_device->handle, raid_device->volume_type, + le32_to_cpu(vol_pg0->StripeSize)/2, + le16_to_cpu(vol_pg0->BlockSize)); + goto out_error; + } + + capacity = (u64) le16_to_cpu(vol_pg0->BlockSize) * + (le64_to_cpu(vol_pg0->MaxLBA) + 1); + + if (capacity > tb_2) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x) since drive sz > 2TB\n", + ioc->name, raid_device->handle); + goto out_error; + } + + stripe_sz = le32_to_cpu(vol_pg0->StripeSize); + stripe_exp = 0; + for (i = 0; i < 32; i++) { + if (stripe_sz & 1) + break; + stripe_exp++; + stripe_sz >>= 1; + } + if (i == 32) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x) invalid stripe sz %uK\n", + ioc->name, raid_device->handle, + le32_to_cpu(vol_pg0->StripeSize)/2); + goto out_error; + } + raid_device->stripe_exponent = stripe_exp; + raid_device->direct_io_enabled = 1; + + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive" + " with handle(0x%04x)\n", ioc->name, raid_device->handle); + /* + * WARPDRIVE: Though the following fields are not used for direct IO, + * stored for future purpose: + */ + raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA); + raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize); + raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize); + + + kfree(vol_pg0); + return; + +out_error: + raid_device->direct_io_enabled = 0; + for (count = 0; count < num_pds; count++) + raid_device->pd_handle[count] = 0; + kfree(vol_pg0); + return; +} /** * _scsih_enable_tlr - setting TLR flags @@ -1710,6 +1923,11 @@ _scsih_slave_configure(struct scsi_device *sdev) _scsih_get_volume_capabilities(ioc, raid_device); + /* + * WARPDRIVE: Initialize the required data for Direct IO + */ + _scsih_init_warpdrive_properties(ioc, raid_device); + /* RAID Queue Depth Support * IS volume = underlying qdepth of drive type, either * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH @@ -1757,14 +1975,16 @@ _scsih_slave_configure(struct scsi_device *sdev) break; } - sdev_printk(KERN_INFO, sdev, "%s: " - "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n", - r_level, raid_device->handle, - (unsigned long long)raid_device->wwid, - raid_device->num_pds, ds); + if (!ioc->hide_ir_msg) + sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " + "wwid(0x%016llx), pd_count(%d), type(%s)\n", + r_level, raid_device->handle, + (unsigned long long)raid_device->wwid, + raid_device->num_pds, ds); _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); /* raid transport support */ - _scsih_set_level(sdev, raid_device); + if (!ioc->is_warpdrive) + _scsih_set_level(sdev, raid_device); return 0; } @@ -2133,8 +2353,7 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, switch (type) { case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: scmd_lookup = _scsih_scsi_lookup_get(ioc, smid_task); - if (scmd_lookup && (scmd_lookup->serial_number == - scmd->serial_number)) + if (scmd_lookup) rc = FAILED; else rc = SUCCESS; @@ -2182,16 +2401,20 @@ _scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) struct MPT2SAS_TARGET *priv_target = starget->hostdata; struct _sas_device *sas_device = NULL; unsigned long flags; + char *device_str = NULL; if (!priv_target) return; + if (ioc->hide_ir_msg) + device_str = "WarpDrive"; + else + device_str = "volume"; scsi_print_command(scmd); if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { - starget_printk(KERN_INFO, starget, "volume handle(0x%04x), " - "volume wwid(0x%016llx)\n", - priv_target->handle, - (unsigned long long)priv_target->sas_address); + starget_printk(KERN_INFO, starget, "%s handle(0x%04x), " + "%s wwid(0x%016llx)\n", device_str, priv_target->handle, + device_str, (unsigned long long)priv_target->sas_address); } else { spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, @@ -3130,6 +3353,9 @@ _scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc, a = 0; b = 0; + if (ioc->is_warpdrive) + return; + /* Volume Resets for Deleted or Removed */ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; for (i = 0; i < event_data->NumElements; i++, element++) { @@ -3346,6 +3572,105 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) SAM_STAT_CHECK_CONDITION; } +/** + * _scsih_scsi_direct_io_get - returns direct io flag + * @ioc: per adapter object + * @smid: system request message index + * + * Returns the smid stored scmd pointer. + */ +static inline u8 +_scsih_scsi_direct_io_get(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + return ioc->scsi_lookup[smid - 1].direct_io; +} + +/** + * _scsih_scsi_direct_io_set - sets direct io flag + * @ioc: per adapter object + * @smid: system request message index + * @direct_io: Zero or non-zero value to set in the direct_io flag + * + * Returns Nothing. + */ +static inline void +_scsih_scsi_direct_io_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 direct_io) +{ + ioc->scsi_lookup[smid - 1].direct_io = direct_io; +} + + +/** + * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O + * @ioc: per adapter object + * @scmd: pointer to scsi command object + * @raid_device: pointer to raid device data structure + * @mpi_request: pointer to the SCSI_IO reqest message frame + * @smid: system request message index + * + * Returns nothing + */ +static void +_scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, + struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, + u16 smid) +{ + u32 v_lba, p_lba, stripe_off, stripe_unit, column, io_size; + u32 stripe_sz, stripe_exp; + u8 num_pds, *cdb_ptr, *tmp_ptr, *lba_ptr1, *lba_ptr2; + u8 cdb0 = scmd->cmnd[0]; + + /* + * Try Direct I/O to RAID memeber disks + */ + if (cdb0 == READ_16 || cdb0 == READ_10 || + cdb0 == WRITE_16 || cdb0 == WRITE_10) { + cdb_ptr = mpi_request->CDB.CDB32; + + if ((cdb0 < READ_16) || !(cdb_ptr[2] | cdb_ptr[3] | cdb_ptr[4] + | cdb_ptr[5])) { + io_size = scsi_bufflen(scmd) >> 9; + /* get virtual lba */ + lba_ptr1 = lba_ptr2 = (cdb0 < READ_16) ? &cdb_ptr[2] : + &cdb_ptr[6]; + tmp_ptr = (u8 *)&v_lba + 3; + *tmp_ptr-- = *lba_ptr1++; + *tmp_ptr-- = *lba_ptr1++; + *tmp_ptr-- = *lba_ptr1++; + *tmp_ptr = *lba_ptr1; + + if (((u64)v_lba + (u64)io_size - 1) <= + (u32)raid_device->max_lba) { + stripe_sz = raid_device->stripe_sz; + stripe_exp = raid_device->stripe_exponent; + stripe_off = v_lba & (stripe_sz - 1); + + /* Check whether IO falls within a stripe */ + if ((stripe_off + io_size) <= stripe_sz) { + num_pds = raid_device->num_pds; + p_lba = v_lba >> stripe_exp; + stripe_unit = p_lba / num_pds; + column = p_lba % num_pds; + p_lba = (stripe_unit << stripe_exp) + + stripe_off; + mpi_request->DevHandle = + cpu_to_le16(raid_device-> + pd_handle[column]); + tmp_ptr = (u8 *)&p_lba + 3; + *lba_ptr2++ = *tmp_ptr--; + *lba_ptr2++ = *tmp_ptr--; + *lba_ptr2++ = *tmp_ptr--; + *lba_ptr2 = *tmp_ptr; + /* + * WD: To indicate this I/O is directI/O + */ + _scsih_scsi_direct_io_set(ioc, smid, 1); + } + } + } + } +} + /** * _scsih_qcmd - main scsi request entry point * @scmd: pointer to scsi command object @@ -3363,6 +3688,7 @@ _scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT2SAS_DEVICE *sas_device_priv_data; struct MPT2SAS_TARGET *sas_target_priv_data; + struct _raid_device *raid_device; Mpi2SCSIIORequest_t *mpi_request; u32 mpi_control; u16 smid; @@ -3424,8 +3750,10 @@ _scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) } else mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; - /* Make sure Device is not raid volume */ - if (!_scsih_is_raid(&scmd->device->sdev_gendev) && + /* Make sure Device is not raid volume. + * We do not expose raid functionality to upper layer for warpdrive. + */ + if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) && sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; @@ -3473,9 +3801,14 @@ _scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) } } + raid_device = sas_target_priv_data->raid_device; + if (raid_device && raid_device->direct_io_enabled) + _scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request, + smid); + if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) mpt2sas_base_put_smid_scsi_io(ioc, smid, - sas_device_priv_data->sas_target->handle); + le16_to_cpu(mpi_request->DevHandle)); else mpt2sas_base_put_smid_default(ioc, smid); return 0; @@ -3540,10 +3873,16 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, unsigned long flags; struct scsi_target *starget = scmd->device->sdev_target; struct MPT2SAS_TARGET *priv_target = starget->hostdata; + char *device_str = NULL; if (!priv_target) return; + if (ioc->hide_ir_msg) + device_str = "WarpDrive"; + else + device_str = "volume"; + if (log_info == 0x31170000) return; @@ -3660,8 +3999,8 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, scsi_print_command(scmd); if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { - printk(MPT2SAS_WARN_FMT "\tvolume wwid(0x%016llx)\n", ioc->name, - (unsigned long long)priv_target->sas_address); + printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name, + device_str, (unsigned long long)priv_target->sas_address); } else { spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, @@ -3840,6 +4179,20 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) scmd->result = DID_NO_CONNECT << 16; goto out; } + /* + * WARPDRIVE: If direct_io is set then it is directIO, + * the failed direct I/O should be redirected to volume + */ + if (_scsih_scsi_direct_io_get(ioc, smid)) { + _scsih_scsi_direct_io_set(ioc, smid, 0); + memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); + mpi_request->DevHandle = + cpu_to_le16(sas_device_priv_data->sas_target->handle); + mpt2sas_base_put_smid_scsi_io(ioc, smid, + sas_device_priv_data->sas_target->handle); + return 0; + } + /* turning off TLR */ scsi_state = mpi_reply->SCSIState; @@ -3848,7 +4201,10 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; if (!sas_device_priv_data->tlr_snoop_check) { sas_device_priv_data->tlr_snoop_check++; - if (!_scsih_is_raid(&scmd->device->sdev_gendev) && + /* Make sure Device is not raid volume. + * We do not expose raid functionality to upper layer for warpdrive. + */ + if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) && sas_is_tlr_enabled(scmd->device) && response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { sas_disable_tlr(scmd->device); @@ -4681,8 +5037,10 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, _scsih_ublock_io_device(ioc, sas_device_backup.handle); - mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address, - sas_device_backup.sas_address_parent); + if (!ioc->hide_drives) + mpt2sas_transport_port_remove(ioc, + sas_device_backup.sas_address, + sas_device_backup.sas_address_parent); printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" "(0x%016llx)\n", ioc->name, sas_device_backup.handle, @@ -5413,6 +5771,7 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc, &sas_device->volume_wwid); set_bit(handle, ioc->pd_handles); _scsih_reprobe_target(sas_device->starget, 1); + } /** @@ -5591,7 +5950,8 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data; #ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + && !ioc->hide_ir_msg) _scsih_sas_ir_config_change_event_debug(ioc, event_data); #endif @@ -5614,16 +5974,20 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, le16_to_cpu(element->VolDevHandle)); break; case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: - _scsih_sas_pd_hide(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_hide(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: - _scsih_sas_pd_expose(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_expose(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_HIDE: - _scsih_sas_pd_add(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_add(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: - _scsih_sas_pd_delete(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_delete(ioc, element); break; } } @@ -5654,9 +6018,10 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, handle = le16_to_cpu(event_data->VolDevHandle); state = le32_to_cpu(event_data->NewValue); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " - "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); + if (!ioc->hide_ir_msg) + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " + "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, + le32_to_cpu(event_data->PreviousValue), state)); switch (state) { case MPI2_RAID_VOL_STATE_MISSING: @@ -5736,9 +6101,10 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, handle = le16_to_cpu(event_data->PhysDiskDevHandle); state = le32_to_cpu(event_data->NewValue); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " - "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); + if (!ioc->hide_ir_msg) + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " + "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, + le32_to_cpu(event_data->PreviousValue), state)); switch (state) { case MPI2_RAID_PD_STATE_ONLINE: @@ -5747,7 +6113,8 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, case MPI2_RAID_PD_STATE_OPTIMAL: case MPI2_RAID_PD_STATE_HOT_SPARE: - set_bit(handle, ioc->pd_handles); + if (!ioc->is_warpdrive) + set_bit(handle, ioc->pd_handles); spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = _scsih_sas_device_find_by_handle(ioc, handle); @@ -5851,7 +6218,8 @@ _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, u16 handle; #ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + && !ioc->hide_ir_msg) _scsih_sas_ir_operation_status_event_debug(ioc, event_data); #endif @@ -5910,7 +6278,7 @@ static void _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, u16 slot, u16 handle) { - struct MPT2SAS_TARGET *sas_target_priv_data; + struct MPT2SAS_TARGET *sas_target_priv_data = NULL; struct scsi_target *starget; struct _sas_device *sas_device; unsigned long flags; @@ -5918,7 +6286,7 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, spin_lock_irqsave(&ioc->sas_device_lock, flags); list_for_each_entry(sas_device, &ioc->sas_device_list, list) { if (sas_device->sas_address == sas_address && - sas_device->slot == slot && sas_device->starget) { + sas_device->slot == slot) { sas_device->responding = 1; starget = sas_device->starget; if (starget && starget->hostdata) { @@ -5927,13 +6295,15 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, sas_target_priv_data->deleted = 0; } else sas_target_priv_data = NULL; - starget_printk(KERN_INFO, sas_device->starget, - "handle(0x%04x), sas_addr(0x%016llx), enclosure " - "logical id(0x%016llx), slot(%d)\n", handle, - (unsigned long long)sas_device->sas_address, - (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot); + if (starget) + starget_printk(KERN_INFO, starget, + "handle(0x%04x), sas_addr(0x%016llx), " + "enclosure logical id(0x%016llx), " + "slot(%d)\n", handle, + (unsigned long long)sas_device->sas_address, + (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot); if (sas_device->handle == handle) goto out; printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", @@ -6025,6 +6395,12 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, starget_printk(KERN_INFO, raid_device->starget, "handle(0x%04x), wwid(0x%016llx)\n", handle, (unsigned long long)raid_device->wwid); + /* + * WARPDRIVE: The handles of the PDs might have changed + * across the host reset so re-initialize the + * required data for Direct IO + */ + _scsih_init_warpdrive_properties(ioc, raid_device); if (raid_device->handle == handle) goto out; printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", @@ -6086,18 +6462,20 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) } /* refresh the pd_handles */ - phys_disk_num = 0xFF; - memset(ioc->pd_handles, 0, ioc->pd_handles_sz); - while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, - phys_disk_num))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - phys_disk_num = pd_pg0.PhysDiskNum; - handle = le16_to_cpu(pd_pg0.DevHandle); - set_bit(handle, ioc->pd_handles); + if (!ioc->is_warpdrive) { + phys_disk_num = 0xFF; + memset(ioc->pd_handles, 0, ioc->pd_handles_sz); + while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, + &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, + phys_disk_num))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + phys_disk_num = pd_pg0.PhysDiskNum; + handle = le16_to_cpu(pd_pg0.DevHandle); + set_bit(handle, ioc->pd_handles); + } } } @@ -6242,6 +6620,50 @@ _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) } } +/** + * _scsih_hide_unhide_sas_devices - add/remove device to/from OS + * @ioc: per adapter object + * + * Return nothing. + */ +static void +_scsih_hide_unhide_sas_devices(struct MPT2SAS_ADAPTER *ioc) +{ + struct _sas_device *sas_device, *sas_device_next; + + if (!ioc->is_warpdrive || ioc->mfg_pg10_hide_flag != + MFG_PAGE10_HIDE_IF_VOL_PRESENT) + return; + + if (ioc->hide_drives) { + if (_scsih_get_num_volumes(ioc)) + return; + ioc->hide_drives = 0; + list_for_each_entry_safe(sas_device, sas_device_next, + &ioc->sas_device_list, list) { + if (!mpt2sas_transport_port_add(ioc, sas_device->handle, + sas_device->sas_address_parent)) { + _scsih_sas_device_remove(ioc, sas_device); + } else if (!sas_device->starget) { + mpt2sas_transport_port_remove(ioc, + sas_device->sas_address, + sas_device->sas_address_parent); + _scsih_sas_device_remove(ioc, sas_device); + } + } + } else { + if (!_scsih_get_num_volumes(ioc)) + return; + ioc->hide_drives = 1; + list_for_each_entry_safe(sas_device, sas_device_next, + &ioc->sas_device_list, list) { + mpt2sas_transport_port_remove(ioc, + sas_device->sas_address, + sas_device->sas_address_parent); + } + } +} + /** * mpt2sas_scsih_reset_handler - reset callback handler (for scsih) * @ioc: per adapter object @@ -6326,6 +6748,7 @@ _firmware_event_work(struct work_struct *work) spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); _scsih_remove_unresponding_sas_devices(ioc); + _scsih_hide_unhide_sas_devices(ioc); return; } @@ -6425,6 +6848,53 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, (Mpi2EventDataIrVolume_t *) mpi_reply->EventData); break; + case MPI2_EVENT_LOG_ENTRY_ADDED: + { + Mpi2EventDataLogEntryAdded_t *log_entry; + u32 *log_code; + + if (!ioc->is_warpdrive) + break; + + log_entry = (Mpi2EventDataLogEntryAdded_t *) + mpi_reply->EventData; + log_code = (u32 *)log_entry->LogData; + + if (le16_to_cpu(log_entry->LogEntryQualifier) + != MPT2_WARPDRIVE_LOGENTRY) + break; + + switch (le32_to_cpu(*log_code)) { + case MPT2_WARPDRIVE_LC_SSDT: + printk(MPT2SAS_WARN_FMT "WarpDrive Warning: " + "IO Throttling has occurred in the WarpDrive " + "subsystem. Check WarpDrive documentation for " + "additional details.\n", ioc->name); + break; + case MPT2_WARPDRIVE_LC_SSDLW: + printk(MPT2SAS_WARN_FMT "WarpDrive Warning: " + "Program/Erase Cycles for the WarpDrive subsystem " + "in degraded range. Check WarpDrive documentation " + "for additional details.\n", ioc->name); + break; + case MPT2_WARPDRIVE_LC_SSDLF: + printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: " + "There are no Program/Erase Cycles for the " + "WarpDrive subsystem. The storage device will be " + "in read-only mode. Check WarpDrive documentation " + "for additional details.\n", ioc->name); + break; + case MPT2_WARPDRIVE_LC_BRMF: + printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: " + "The Backup Rail Monitor has failed on the " + "WarpDrive subsystem. Check WarpDrive " + "documentation for additional details.\n", + ioc->name); + break; + } + + break; + } case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: case MPI2_EVENT_IR_OPERATION_STATUS: case MPI2_EVENT_SAS_DISCOVERY: @@ -6583,7 +7053,8 @@ _scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc) mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; - printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name); + if (!ioc->hide_ir_msg) + printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name); init_completion(&ioc->scsih_cmds.done); mpt2sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); @@ -6597,10 +7068,11 @@ _scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc) if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) { mpi_reply = ioc->scsih_cmds.reply; - printk(MPT2SAS_INFO_FMT "IR shutdown (complete): " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); + if (!ioc->hide_ir_msg) + printk(MPT2SAS_INFO_FMT "IR shutdown (complete): " + "ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc->name, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo)); } out: @@ -6759,6 +7231,9 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) 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); + + if (ioc->hide_drives) + return; if (!mpt2sas_transport_port_add(ioc, sas_device->handle, sas_device->sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); @@ -6812,6 +7287,9 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) list_move_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (ioc->hide_drives) + continue; + if (!mpt2sas_transport_port_add(ioc, sas_device->handle, sas_device->sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); @@ -6882,6 +7360,11 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->id = mpt_ids++; sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id); ioc->pdev = pdev; + if (id->device == MPI2_MFGPAGE_DEVID_SSS6200) { + ioc->is_warpdrive = 1; + ioc->hide_ir_msg = 1; + } else + ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS; ioc->scsi_io_cb_idx = scsi_io_cb_idx; ioc->tm_cb_idx = tm_cb_idx; ioc->ctl_cb_idx = ctl_cb_idx; @@ -6947,6 +7430,20 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) } ioc->wait_for_port_enable_to_complete = 0; + if (ioc->is_warpdrive) { + if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) + ioc->hide_drives = 0; + else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS) + ioc->hide_drives = 1; + else { + if (_scsih_get_num_volumes(ioc)) + ioc->hide_drives = 1; + else + ioc->hide_drives = 0; + } + } else + ioc->hide_drives = 0; + _scsih_probe_devices(ioc); return 0; diff --git a/drivers/scsi/mvsas/Kconfig b/drivers/scsi/mvsas/Kconfig index 6de7af27e507..c82b012aba37 100644 --- a/drivers/scsi/mvsas/Kconfig +++ b/drivers/scsi/mvsas/Kconfig @@ -3,6 +3,7 @@ # # Copyright 2007 Red Hat, Inc. # Copyright 2008 Marvell. +# Copyright 2009-20011 Marvell. # # This file is licensed under GPLv2. # diff --git a/drivers/scsi/mvsas/Makefile b/drivers/scsi/mvsas/Makefile index ffbf759e46f1..87b231a5bd5e 100644 --- a/drivers/scsi/mvsas/Makefile +++ b/drivers/scsi/mvsas/Makefile @@ -3,6 +3,7 @@ # # Copyright 2007 Red Hat, Inc. # Copyright 2008 Marvell. +# Copyright 2009-2011 Marvell. # # This file is licensed under GPLv2. # diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c index afc7f6f3a13e..13c960481391 100644 --- a/drivers/scsi/mvsas/mv_64xx.c +++ b/drivers/scsi/mvsas/mv_64xx.c @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * diff --git a/drivers/scsi/mvsas/mv_64xx.h b/drivers/scsi/mvsas/mv_64xx.h index 42e947d9795e..545889bd9753 100644 --- a/drivers/scsi/mvsas/mv_64xx.h +++ b/drivers/scsi/mvsas/mv_64xx.h @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c index eed4c5c72013..78162c3c36e6 100644 --- a/drivers/scsi/mvsas/mv_94xx.c +++ b/drivers/scsi/mvsas/mv_94xx.c @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h index 23ed9b164669..8835befe2c0e 100644 --- a/drivers/scsi/mvsas/mv_94xx.h +++ b/drivers/scsi/mvsas/mv_94xx.h @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * diff --git a/drivers/scsi/mvsas/mv_chips.h b/drivers/scsi/mvsas/mv_chips.h index a67e1c4172f9..1753a6fc42d0 100644 --- a/drivers/scsi/mvsas/mv_chips.h +++ b/drivers/scsi/mvsas/mv_chips.h @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h index 1849da1f030d..bc00c940743c 100644 --- a/drivers/scsi/mvsas/mv_defs.h +++ b/drivers/scsi/mvsas/mv_defs.h @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * @@ -34,6 +35,8 @@ enum chip_flavors { chip_6485, chip_9480, chip_9180, + chip_9445, + chip_9485, chip_1300, chip_1320 }; diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 938d045e4180..90b636611cde 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * @@ -25,13 +26,24 @@ #include "mv_sas.h" +static int lldd_max_execute_num = 1; +module_param_named(collector, lldd_max_execute_num, int, S_IRUGO); +MODULE_PARM_DESC(collector, "\n" + "\tIf greater than one, tells the SAS Layer to run in Task Collector\n" + "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n" + "\tThe mvsas SAS LLDD supports both modes.\n" + "\tDefault: 1 (Direct Mode).\n"); + static struct scsi_transport_template *mvs_stt; +struct kmem_cache *mvs_task_list_cache; static const struct mvs_chip_info mvs_chips[] = { [chip_6320] = { 1, 2, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, [chip_6440] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, [chip_6485] = { 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, }, [chip_9180] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, }, [chip_9480] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, }, + [chip_9445] = { 1, 4, 0x800, 17, 64, 11, &mvs_94xx_dispatch, }, + [chip_9485] = { 2, 4, 0x800, 17, 64, 11, &mvs_94xx_dispatch, }, [chip_1300] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, [chip_1320] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, }, }; @@ -107,7 +119,6 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id) static void mvs_free(struct mvs_info *mvi) { - int i; struct mvs_wq *mwq; int slot_nr; @@ -119,12 +130,8 @@ static void mvs_free(struct mvs_info *mvi) else slot_nr = MVS_SLOTS; - for (i = 0; i < mvi->tags_num; i++) { - struct mvs_slot_info *slot = &mvi->slot_info[i]; - if (slot->buf) - dma_free_coherent(mvi->dev, MVS_SLOT_BUF_SZ, - slot->buf, slot->buf_dma); - } + if (mvi->dma_pool) + pci_pool_destroy(mvi->dma_pool); if (mvi->tx) dma_free_coherent(mvi->dev, @@ -213,6 +220,7 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque) static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) { int i = 0, slot_nr; + char pool_name[32]; if (mvi->flags & MVF_FLAG_SOC) slot_nr = MVS_SOC_SLOTS; @@ -272,18 +280,14 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) if (!mvi->bulk_buffer) goto err_out; #endif - for (i = 0; i < slot_nr; i++) { - struct mvs_slot_info *slot = &mvi->slot_info[i]; - - slot->buf = dma_alloc_coherent(mvi->dev, MVS_SLOT_BUF_SZ, - &slot->buf_dma, GFP_KERNEL); - if (!slot->buf) { - printk(KERN_DEBUG"failed to allocate slot->buf.\n"); + sprintf(pool_name, "%s%d", "mvs_dma_pool", mvi->id); + mvi->dma_pool = pci_pool_create(pool_name, mvi->pdev, MVS_SLOT_BUF_SZ, 16, 0); + if (!mvi->dma_pool) { + printk(KERN_DEBUG "failed to create dma pool %s.\n", pool_name); goto err_out; - } - memset(slot->buf, 0, MVS_SLOT_BUF_SZ); - ++mvi->tags_num; } + mvi->tags_num = slot_nr; + /* Initialize tags */ mvs_tag_init(mvi); return 0; @@ -484,7 +488,7 @@ static void __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost, sha->num_phys = nr_core * chip_info->n_phy; - sha->lldd_max_execute_num = 1; + sha->lldd_max_execute_num = lldd_max_execute_num; if (mvi->flags & MVF_FLAG_SOC) can_queue = MVS_SOC_CAN_QUEUE; @@ -670,6 +674,24 @@ static struct pci_device_id __devinitdata mvs_pci_table[] = { { PCI_VDEVICE(TTI, 0x2740), chip_9480 }, { PCI_VDEVICE(TTI, 0x2744), chip_9480 }, { PCI_VDEVICE(TTI, 0x2760), chip_9480 }, + { + .vendor = 0x1b4b, + .device = 0x9445, + .subvendor = PCI_ANY_ID, + .subdevice = 0x9480, + .class = 0, + .class_mask = 0, + .driver_data = chip_9445, + }, + { + .vendor = 0x1b4b, + .device = 0x9485, + .subvendor = PCI_ANY_ID, + .subdevice = 0x9480, + .class = 0, + .class_mask = 0, + .driver_data = chip_9485, + }, { } /* terminate list */ }; @@ -690,6 +712,14 @@ static int __init mvs_init(void) if (!mvs_stt) return -ENOMEM; + mvs_task_list_cache = kmem_cache_create("mvs_task_list", sizeof(struct mvs_task_list), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!mvs_task_list_cache) { + rc = -ENOMEM; + mv_printk("%s: mvs_task_list_cache alloc failed! \n", __func__); + goto err_out; + } + rc = pci_register_driver(&mvs_pci_driver); if (rc) @@ -706,6 +736,7 @@ static void __exit mvs_exit(void) { pci_unregister_driver(&mvs_pci_driver); sas_release_transport(mvs_stt); + kmem_cache_destroy(mvs_task_list_cache); } module_init(mvs_init); diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index adedaa916ecb..0ef27425c447 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * @@ -862,178 +863,286 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi, } #define DEV_IS_GONE(mvi_dev) ((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE))) -static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, - struct completion *completion,int is_tmf, - struct mvs_tmf_task *tmf) +static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf, + struct mvs_tmf_task *tmf, int *pass) { struct domain_device *dev = task->dev; - struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; - struct mvs_info *mvi = mvi_dev->mvi_info; + struct mvs_device *mvi_dev = dev->lldd_dev; struct mvs_task_exec_info tei; - struct sas_task *t = task; struct mvs_slot_info *slot; - u32 tag = 0xdeadbeef, rc, n_elem = 0; - u32 n = num, pass = 0; - unsigned long flags = 0, flags_libsas = 0; + u32 tag = 0xdeadbeef, n_elem = 0; + int rc = 0; if (!dev->port) { - struct task_status_struct *tsm = &t->task_status; + struct task_status_struct *tsm = &task->task_status; tsm->resp = SAS_TASK_UNDELIVERED; tsm->stat = SAS_PHY_DOWN; + /* + * libsas will use dev->port, should + * not call task_done for sata + */ if (dev->dev_type != SATA_DEV) - t->task_done(t); - return 0; + task->task_done(task); + return rc; } - spin_lock_irqsave(&mvi->lock, flags); - do { - dev = t->dev; - mvi_dev = dev->lldd_dev; - if (DEV_IS_GONE(mvi_dev)) { - if (mvi_dev) - mv_dprintk("device %d not ready.\n", - mvi_dev->device_id); - else - mv_dprintk("device %016llx not ready.\n", - SAS_ADDR(dev->sas_addr)); + if (DEV_IS_GONE(mvi_dev)) { + if (mvi_dev) + mv_dprintk("device %d not ready.\n", + mvi_dev->device_id); + else + mv_dprintk("device %016llx not ready.\n", + SAS_ADDR(dev->sas_addr)); rc = SAS_PHY_DOWN; - goto out_done; - } + return rc; + } + tei.port = dev->port->lldd_port; + if (tei.port && !tei.port->port_attached && !tmf) { + if (sas_protocol_ata(task->task_proto)) { + struct task_status_struct *ts = &task->task_status; + mv_dprintk("SATA/STP port %d does not attach" + "device.\n", dev->port->id); + ts->resp = SAS_TASK_COMPLETE; + ts->stat = SAS_PHY_DOWN; - if (dev->port->id >= mvi->chip->n_phy) - tei.port = &mvi->port[dev->port->id - mvi->chip->n_phy]; - else - tei.port = &mvi->port[dev->port->id]; + task->task_done(task); - if (tei.port && !tei.port->port_attached) { - if (sas_protocol_ata(t->task_proto)) { - struct task_status_struct *ts = &t->task_status; - - mv_dprintk("port %d does not" - "attached device.\n", dev->port->id); - ts->stat = SAS_PROTO_RESPONSE; - ts->stat = SAS_PHY_DOWN; - spin_unlock_irqrestore(dev->sata_dev.ap->lock, - flags_libsas); - spin_unlock_irqrestore(&mvi->lock, flags); - t->task_done(t); - spin_lock_irqsave(&mvi->lock, flags); - spin_lock_irqsave(dev->sata_dev.ap->lock, - flags_libsas); - if (n > 1) - t = list_entry(t->list.next, - struct sas_task, list); - continue; - } else { - struct task_status_struct *ts = &t->task_status; - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_PHY_DOWN; - t->task_done(t); - if (n > 1) - t = list_entry(t->list.next, - struct sas_task, list); - continue; - } - } - - if (!sas_protocol_ata(t->task_proto)) { - if (t->num_scatter) { - n_elem = dma_map_sg(mvi->dev, - t->scatter, - t->num_scatter, - t->data_dir); - if (!n_elem) { - rc = -ENOMEM; - goto err_out; - } - } } else { - n_elem = t->num_scatter; + struct task_status_struct *ts = &task->task_status; + mv_dprintk("SAS port %d does not attach" + "device.\n", dev->port->id); + ts->resp = SAS_TASK_UNDELIVERED; + ts->stat = SAS_PHY_DOWN; + task->task_done(task); } + return rc; + } - rc = mvs_tag_alloc(mvi, &tag); - if (rc) - goto err_out; - - slot = &mvi->slot_info[tag]; - - - t->lldd_task = NULL; - slot->n_elem = n_elem; - slot->slot_tag = tag; - memset(slot->buf, 0, MVS_SLOT_BUF_SZ); - - tei.task = t; - tei.hdr = &mvi->slot[tag]; - tei.tag = tag; - tei.n_elem = n_elem; - switch (t->task_proto) { - case SAS_PROTOCOL_SMP: - rc = mvs_task_prep_smp(mvi, &tei); - break; - case SAS_PROTOCOL_SSP: - rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf); - break; - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: - rc = mvs_task_prep_ata(mvi, &tei); - break; - default: - dev_printk(KERN_ERR, mvi->dev, - "unknown sas_task proto: 0x%x\n", - t->task_proto); - rc = -EINVAL; - break; + if (!sas_protocol_ata(task->task_proto)) { + if (task->num_scatter) { + n_elem = dma_map_sg(mvi->dev, + task->scatter, + task->num_scatter, + task->data_dir); + if (!n_elem) { + rc = -ENOMEM; + goto prep_out; + } } + } else { + n_elem = task->num_scatter; + } - if (rc) { - mv_dprintk("rc is %x\n", rc); - goto err_out_tag; - } - slot->task = t; - slot->port = tei.port; - t->lldd_task = slot; - list_add_tail(&slot->entry, &tei.port->list); - /* TODO: select normal or high priority */ - spin_lock(&t->task_state_lock); - t->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock(&t->task_state_lock); + rc = mvs_tag_alloc(mvi, &tag); + if (rc) + goto err_out; - mvs_hba_memory_dump(mvi, tag, t->task_proto); - mvi_dev->running_req++; - ++pass; - mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); - if (n > 1) - t = list_entry(t->list.next, struct sas_task, list); - if (likely(pass)) - MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) & - (MVS_CHIP_SLOT_SZ - 1)); + slot = &mvi->slot_info[tag]; - } while (--n); - rc = 0; - goto out_done; + task->lldd_task = NULL; + slot->n_elem = n_elem; + slot->slot_tag = tag; + slot->buf = pci_pool_alloc(mvi->dma_pool, GFP_ATOMIC, &slot->buf_dma); + if (!slot->buf) + goto err_out_tag; + memset(slot->buf, 0, MVS_SLOT_BUF_SZ); + + tei.task = task; + tei.hdr = &mvi->slot[tag]; + tei.tag = tag; + tei.n_elem = n_elem; + switch (task->task_proto) { + case SAS_PROTOCOL_SMP: + rc = mvs_task_prep_smp(mvi, &tei); + break; + case SAS_PROTOCOL_SSP: + rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf); + break; + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + rc = mvs_task_prep_ata(mvi, &tei); + break; + default: + dev_printk(KERN_ERR, mvi->dev, + "unknown sas_task proto: 0x%x\n", + task->task_proto); + rc = -EINVAL; + break; + } + + if (rc) { + mv_dprintk("rc is %x\n", rc); + goto err_out_slot_buf; + } + slot->task = task; + slot->port = tei.port; + task->lldd_task = slot; + list_add_tail(&slot->entry, &tei.port->list); + spin_lock(&task->task_state_lock); + task->task_state_flags |= SAS_TASK_AT_INITIATOR; + spin_unlock(&task->task_state_lock); + + mvs_hba_memory_dump(mvi, tag, task->task_proto); + mvi_dev->running_req++; + ++(*pass); + mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); + + return rc; + +err_out_slot_buf: + pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma); err_out_tag: mvs_tag_free(mvi, tag); err_out: - dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); - if (!sas_protocol_ata(t->task_proto)) + dev_printk(KERN_ERR, mvi->dev, "mvsas prep failed[%d]!\n", rc); + if (!sas_protocol_ata(task->task_proto)) if (n_elem) - dma_unmap_sg(mvi->dev, t->scatter, n_elem, - t->data_dir); -out_done: + dma_unmap_sg(mvi->dev, task->scatter, n_elem, + task->data_dir); +prep_out: + return rc; +} + +static struct mvs_task_list *mvs_task_alloc_list(int *num, gfp_t gfp_flags) +{ + struct mvs_task_list *first = NULL; + + for (; *num > 0; --*num) { + struct mvs_task_list *mvs_list = kmem_cache_zalloc(mvs_task_list_cache, gfp_flags); + + if (!mvs_list) + break; + + INIT_LIST_HEAD(&mvs_list->list); + if (!first) + first = mvs_list; + else + list_add_tail(&mvs_list->list, &first->list); + + } + + return first; +} + +static inline void mvs_task_free_list(struct mvs_task_list *mvs_list) +{ + LIST_HEAD(list); + struct list_head *pos, *a; + struct mvs_task_list *mlist = NULL; + + __list_add(&list, mvs_list->list.prev, &mvs_list->list); + + list_for_each_safe(pos, a, &list) { + list_del_init(pos); + mlist = list_entry(pos, struct mvs_task_list, list); + kmem_cache_free(mvs_task_list_cache, mlist); + } +} + +static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, + struct completion *completion, int is_tmf, + struct mvs_tmf_task *tmf) +{ + struct domain_device *dev = task->dev; + struct mvs_info *mvi = NULL; + u32 rc = 0; + u32 pass = 0; + unsigned long flags = 0; + + mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info; + + if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL)) + spin_unlock_irq(dev->sata_dev.ap->lock); + + spin_lock_irqsave(&mvi->lock, flags); + rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass); + if (rc) + dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); + + if (likely(pass)) + MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) & + (MVS_CHIP_SLOT_SZ - 1)); spin_unlock_irqrestore(&mvi->lock, flags); + + if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL)) + spin_lock_irq(dev->sata_dev.ap->lock); + + return rc; +} + +static int mvs_collector_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, + struct completion *completion, int is_tmf, + struct mvs_tmf_task *tmf) +{ + struct domain_device *dev = task->dev; + struct mvs_prv_info *mpi = dev->port->ha->lldd_ha; + struct mvs_info *mvi = NULL; + struct sas_task *t = task; + struct mvs_task_list *mvs_list = NULL, *a; + LIST_HEAD(q); + int pass[2] = {0}; + u32 rc = 0; + u32 n = num; + unsigned long flags = 0; + + mvs_list = mvs_task_alloc_list(&n, gfp_flags); + if (n) { + printk(KERN_ERR "%s: mvs alloc list failed.\n", __func__); + rc = -ENOMEM; + goto free_list; + } + + __list_add(&q, mvs_list->list.prev, &mvs_list->list); + + list_for_each_entry(a, &q, list) { + a->task = t; + t = list_entry(t->list.next, struct sas_task, list); + } + + list_for_each_entry(a, &q , list) { + + t = a->task; + mvi = ((struct mvs_device *)t->dev->lldd_dev)->mvi_info; + + spin_lock_irqsave(&mvi->lock, flags); + rc = mvs_task_prep(t, mvi, is_tmf, tmf, &pass[mvi->id]); + if (rc) + dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); + spin_unlock_irqrestore(&mvi->lock, flags); + } + + if (likely(pass[0])) + MVS_CHIP_DISP->start_delivery(mpi->mvi[0], + (mpi->mvi[0]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); + + if (likely(pass[1])) + MVS_CHIP_DISP->start_delivery(mpi->mvi[1], + (mpi->mvi[1]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); + + list_del_init(&q); + +free_list: + if (mvs_list) + mvs_task_free_list(mvs_list); + return rc; } int mvs_queue_command(struct sas_task *task, const int num, gfp_t gfp_flags) { - return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL); + struct mvs_device *mvi_dev = task->dev->lldd_dev; + struct sas_ha_struct *sas = mvi_dev->mvi_info->sas; + + if (sas->lldd_max_execute_num < 2) + return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL); + else + return mvs_collector_task_exec(task, num, gfp_flags, NULL, 0, NULL); } static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) @@ -1067,6 +1176,11 @@ static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, /* do nothing */ break; } + + if (slot->buf) { + pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma); + slot->buf = NULL; + } list_del_init(&slot->entry); task->lldd_task = NULL; slot->task = NULL; @@ -1255,6 +1369,7 @@ static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock) spin_lock_irqsave(&mvi->lock, flags); port->port_attached = 1; phy->port = port; + sas_port->lldd_port = port; if (phy->phy_type & PORT_TYPE_SAS) { port->wide_port_phymap = sas_port->phy_mask; mv_printk("set wide port phy map %x\n", sas_port->phy_mask); diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index 77ddc7c1e5f2..1367d8b9350d 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * @@ -67,6 +68,7 @@ extern struct mvs_tgt_initiator mvs_tgt; extern struct mvs_info *tgt_mvi; extern const struct mvs_dispatch mvs_64xx_dispatch; extern const struct mvs_dispatch mvs_94xx_dispatch; +extern struct kmem_cache *mvs_task_list_cache; #define DEV_IS_EXPANDER(type) \ ((type == EDGE_DEV) || (type == FANOUT_DEV)) @@ -341,6 +343,7 @@ struct mvs_info { dma_addr_t bulk_buffer_dma; #define TRASH_BUCKET_SIZE 0x20000 #endif + void *dma_pool; struct mvs_slot_info slot_info[0]; }; @@ -367,6 +370,11 @@ struct mvs_task_exec_info { int n_elem; }; +struct mvs_task_list { + struct sas_task *task; + struct list_head list; +}; + /******************** function prototype *********************/ void mvs_get_sas_addr(void *buf, u32 buflen); diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 835d8d66e696..4b3b4755945c 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -8147,7 +8147,7 @@ static int ncr53c8xx_abort(struct scsi_cmnd *cmd) unsigned long flags; struct scsi_cmnd *done_list; - printk("ncr53c8xx_abort: command pid %lu\n", cmd->serial_number); + printk("ncr53c8xx_abort\n"); NCR_LOCK_NCB(np, flags); diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 96d5ad0c1e42..7f636b118287 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3814,6 +3814,9 @@ static long pmcraid_ioctl_passthrough( rc = -EFAULT; goto out_free_buffer; } + } else if (request_size < 0) { + rc = -EINVAL; + goto out_free_buffer; } /* check if we have any additional command parameters */ diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 8ba5744c267e..d838205ab169 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4066,7 +4066,7 @@ __qla1280_print_scsi_cmd(struct scsi_cmnd *cmd) } */ printk(" tag=%d, transfersize=0x%x \n", cmd->tag, cmd->transfersize); - printk(" Pid=%li, SP=0x%p\n", cmd->serial_number, CMD_SP(cmd)); + printk(" SP=0x%p\n", CMD_SP(cmd)); printk(" underflow size = 0x%x, direction=0x%x\n", cmd->underflow, cmd->sc_data_direction); } diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index d3e58d763b43..532313e0725e 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -496,8 +496,8 @@ qla2x00_sysfs_read_sfp(struct file *filp, struct kobject *kobj, offset = 0; } - rval = qla2x00_read_sfp(vha, ha->sfp_data_dma, addr, offset, - SFP_BLOCK_SIZE); + rval = qla2x00_read_sfp(vha, ha->sfp_data_dma, ha->sfp_data, + addr, offset, SFP_BLOCK_SIZE, 0); if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Unable to read SFP data (%x/%x/%x).\n", rval, @@ -628,12 +628,12 @@ qla2x00_sysfs_write_edc(struct file *filp, struct kobject *kobj, memcpy(ha->edc_data, &buf[8], len); - rval = qla2x00_write_edc(vha, dev, adr, ha->edc_data_dma, - ha->edc_data, len, opt); + rval = qla2x00_write_sfp(vha, ha->edc_data_dma, ha->edc_data, + dev, adr, len, opt); if (rval != QLA_SUCCESS) { DEBUG2(qla_printk(KERN_INFO, ha, "Unable to write EDC (%x) %02x:%02x:%04x:%02x:%02x.\n", - rval, dev, adr, opt, len, *buf)); + rval, dev, adr, opt, len, buf[8])); return 0; } @@ -685,8 +685,8 @@ qla2x00_sysfs_write_edc_status(struct file *filp, struct kobject *kobj, return -EINVAL; memset(ha->edc_data, 0, len); - rval = qla2x00_read_edc(vha, dev, adr, ha->edc_data_dma, - ha->edc_data, len, opt); + rval = qla2x00_read_sfp(vha, ha->edc_data_dma, ha->edc_data, + dev, adr, len, opt); if (rval != QLA_SUCCESS) { DEBUG2(qla_printk(KERN_INFO, ha, "Unable to write EDC status (%x) %02x:%02x:%04x:%02x.\n", @@ -1568,7 +1568,7 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport) /* Now that the rport has been deleted, set the fcport state to FCS_DEVICE_DEAD */ - atomic_set(&fcport->state, FCS_DEVICE_DEAD); + qla2x00_set_fcport_state(fcport, FCS_DEVICE_DEAD); /* * Transport has effectively 'deleted' the rport, clear @@ -1877,14 +1877,15 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) scsi_remove_host(vha->host); + /* Allow timer to run to drain queued items, when removing vp */ + qla24xx_deallocate_vp_id(vha); + if (vha->timer_active) { qla2x00_vp_stop_timer(vha); DEBUG15(printk(KERN_INFO "scsi(%ld): timer for the vport[%d]" " = %p has stopped\n", vha->host_no, vha->vp_idx, vha)); } - qla24xx_deallocate_vp_id(vha); - /* No pending activities shall be there on the vha now */ DEBUG(msleep(random32()%10)); /* Just to see if something falls on * the net we have placed below */ diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 903b0586ded3..8c10e2c4928e 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h index 074a999c7017..0f0f54e35f06 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.h +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 096141148257..c53719a9a747 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index b74e6b5743dc..930414541ec6 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index ee20353c8550..cc5a79259d33 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -1717,6 +1717,14 @@ typedef struct fc_port { #define FCS_DEVICE_LOST 3 #define FCS_ONLINE 4 +static const char * const port_state_str[] = { + "Unknown", + "UNCONFIGURED", + "DEAD", + "LOST", + "ONLINE" +}; + /* * FC port flags. */ diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 6271353e8c51..a5a4e1275bf2 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index f5ba09c8a663..691783abfb69 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -416,8 +416,7 @@ struct cmd_type_6 { uint8_t vp_index; uint32_t fcp_data_dseg_address[2]; /* Data segment address. */ - uint16_t fcp_data_dseg_len; /* Data segment length. */ - uint16_t reserved_1; /* MUST be set to 0. */ + uint32_t fcp_data_dseg_len; /* Data segment length. */ }; #define COMMAND_TYPE_7 0x18 /* Command Type 7 entry */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index d48326ee3f61..0b381224ae4b 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -39,6 +39,8 @@ extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *); extern int qla2x00_perform_loop_resync(scsi_qla_host_t *); extern int qla2x00_loop_resync(scsi_qla_host_t *); +extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *); + extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *); extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *); @@ -100,6 +102,8 @@ extern int ql2xgffidenable; extern int ql2xenabledif; extern int ql2xenablehba_err_chk; extern int ql2xtargetreset; +extern int ql2xdontresethba; +extern unsigned int ql2xmaxlun; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); @@ -319,15 +323,12 @@ extern int qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *); extern int -qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); +qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *, + uint16_t, uint16_t, uint16_t, uint16_t); extern int -qla2x00_read_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t, - uint8_t *, uint16_t, uint16_t); - -extern int -qla2x00_write_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t, - uint8_t *, uint16_t, uint16_t); +qla2x00_write_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *, + uint16_t, uint16_t, uint16_t, uint16_t); extern int qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); @@ -549,7 +550,6 @@ extern int qla82xx_wr_32(struct qla_hw_data *, ulong, u32); extern int qla82xx_rd_32(struct qla_hw_data *, ulong); extern int qla82xx_rdmem(struct qla_hw_data *, u64, void *, int); extern int qla82xx_wrmem(struct qla_hw_data *, u64, void *, int); -extern void qla82xx_rom_unlock(struct qla_hw_data *); /* ISP 8021 IDC */ extern void qla82xx_clear_drv_active(struct qla_hw_data *); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 74a91b6dfc68..8cd9066ad906 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 8575808dbae0..920b76bfbb93 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -35,8 +35,6 @@ static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *, static int qla2x00_restart_isp(scsi_qla_host_t *); -static int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *); - static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *); static int qla84xx_init_chip(scsi_qla_host_t *); static int qla25xx_init_queues(struct qla_hw_data *); @@ -385,8 +383,18 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, switch (data[0]) { case MBS_COMMAND_COMPLETE: + /* + * Driver must validate login state - If PRLI not complete, + * force a relogin attempt via implicit LOGO, PLOGI, and PRLI + * requests. + */ + rval = qla2x00_get_port_database(vha, fcport, 0); + if (rval != QLA_SUCCESS) { + qla2x00_post_async_logout_work(vha, fcport, NULL); + qla2x00_post_async_login_work(vha, fcport, NULL); + break; + } if (fcport->flags & FCF_FCP2_DEVICE) { - fcport->flags |= FCF_ASYNC_SENT; qla2x00_post_async_adisc_work(vha, fcport, data); break; } @@ -397,7 +405,7 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, if (data[1] & QLA_LOGIO_LOGIN_RETRIED) set_bit(RELOGIN_NEEDED, &vha->dpc_flags); else - qla2x00_mark_device_lost(vha, fcport, 1, 1); + qla2x00_mark_device_lost(vha, fcport, 1, 0); break; case MBS_PORT_ID_USED: fcport->loop_id = data[1]; @@ -409,7 +417,7 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, rval = qla2x00_find_new_loop_id(vha, fcport); if (rval != QLA_SUCCESS) { fcport->flags &= ~FCF_ASYNC_SENT; - qla2x00_mark_device_lost(vha, fcport, 1, 1); + qla2x00_mark_device_lost(vha, fcport, 1, 0); break; } qla2x00_post_async_login_work(vha, fcport, NULL); @@ -441,7 +449,7 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, if (data[1] & QLA_LOGIO_LOGIN_RETRIED) set_bit(RELOGIN_NEEDED, &vha->dpc_flags); else - qla2x00_mark_device_lost(vha, fcport, 1, 1); + qla2x00_mark_device_lost(vha, fcport, 1, 0); return; } @@ -2536,7 +2544,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) fcport->vp_idx = vha->vp_idx; fcport->port_type = FCT_UNKNOWN; fcport->loop_id = FC_NO_LOOP_ID; - atomic_set(&fcport->state, FCS_UNCONFIGURED); + qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED); fcport->supported_classes = FC_COS_UNSPECIFIED; return fcport; @@ -2722,7 +2730,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) "loop_id=0x%04x\n", vha->host_no, fcport->loop_id)); - atomic_set(&fcport->state, FCS_DEVICE_LOST); + qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); } } @@ -2934,7 +2942,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) qla2x00_iidma_fcport(vha, fcport); qla24xx_update_fcport_fcp_prio(vha, fcport); qla2x00_reg_remote_port(vha, fcport); - atomic_set(&fcport->state, FCS_ONLINE); + qla2x00_set_fcport_state(fcport, FCS_ONLINE); } /* @@ -3391,7 +3399,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, * Context: * Kernel context. */ -static int +int qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) { int rval; @@ -5202,7 +5210,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) } /* Reset Initialization control block */ - memset(icb, 0, sizeof(struct init_cb_81xx)); + memset(icb, 0, ha->init_cb_size); /* Copy 1st segment. */ dptr1 = (uint8_t *)icb; @@ -5427,6 +5435,13 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) ha->isp_abort_cnt = 0; clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); + /* Update the firmware version */ + qla2x00_get_fw_version(vha, &ha->fw_major_version, + &ha->fw_minor_version, &ha->fw_subminor_version, + &ha->fw_attributes, &ha->fw_memory_size, + ha->mpi_version, &ha->mpi_capabilities, + ha->phy_version); + if (ha->fce) { ha->flags.fce_enabled = 1; memset(ha->fce, 0, @@ -5508,26 +5523,26 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha) * * Return: * non-zero (if found) - * 0 (if not found) + * -1 (if not found) * * Context: * Kernel context */ -uint8_t +static int qla24xx_get_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport) { int i, entries; uint8_t pid_match, wwn_match; - uint8_t priority; + int priority; uint32_t pid1, pid2; uint64_t wwn1, wwn2; struct qla_fcp_prio_entry *pri_entry; struct qla_hw_data *ha = vha->hw; if (!ha->fcp_prio_cfg || !ha->flags.fcp_prio_enabled) - return 0; + return -1; - priority = 0; + priority = -1; entries = ha->fcp_prio_cfg->num_entries; pri_entry = &ha->fcp_prio_cfg->entry[0]; @@ -5610,7 +5625,7 @@ int qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport) { int ret; - uint8_t priority; + int priority; uint16_t mb[5]; if (fcport->port_type != FCT_TARGET || @@ -5618,6 +5633,9 @@ qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport) return QLA_FUNCTION_FAILED; priority = qla24xx_get_fcp_prio(vha, fcport); + if (priority < 0) + return QLA_FUNCTION_FAILED; + ret = qla24xx_set_fcp_prio(vha, fcport->loop_id, priority, mb); if (ret == QLA_SUCCESS) fcport->fcp_prio = priority; diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 48f97a92e33d..4c8167e11f69 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -83,3 +83,22 @@ qla2x00_clean_dsd_pool(struct qla_hw_data *ha, srb_t *sp) } INIT_LIST_HEAD(&((struct crc_context *)sp->ctx)->dsd_list); } + +static inline void +qla2x00_set_fcport_state(fc_port_t *fcport, int state) +{ + int old_state; + + old_state = atomic_read(&fcport->state); + atomic_set(&fcport->state, state); + + /* Don't print state transitions during initial allocation of fcport */ + if (old_state && old_state != state) { + DEBUG(qla_printk(KERN_WARNING, fcport->vha->hw, + "scsi(%ld): FCPort state transitioned from %s to %s - " + "portid=%02x%02x%02x.\n", fcport->vha->host_no, + port_state_str[old_state], port_state_str[state], + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); + } +} diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index d78d5896fc33..7bac3cd109d6 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 712518d05128..9c0f0e3389eb 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -843,7 +843,10 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, qla_printk(KERN_WARNING, ha, "Invalid SCSI completion handle %d.\n", index); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); return; } @@ -861,7 +864,10 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, qla_printk(KERN_WARNING, ha, "Invalid ISP SCSI completion handle\n"); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); } } @@ -878,7 +884,10 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, if (index >= MAX_OUTSTANDING_COMMANDS) { qla_printk(KERN_WARNING, ha, "%s: Invalid completion handle (%x).\n", func, index); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); goto done; } sp = req->outstanding_cmds[index]; @@ -1564,7 +1573,10 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) "scsi(%ld): Invalid status handle (0x%x).\n", vha->host_no, sts->handle); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); return; } @@ -1794,12 +1806,13 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) if (logit) DEBUG2(qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d) FCP command status: 0x%x-0x%x (0x%x) " - "oxid=0x%x cdb=%02x%02x%02x len=0x%x " + "portid=%02x%02x%02x oxid=0x%x cdb=%02x%02x%02x len=0x%x " "rsp_info=0x%x resid=0x%x fw_resid=0x%x\n", vha->host_no, cp->device->id, cp->device->lun, comp_status, scsi_status, - cp->result, ox_id, cp->cmnd[0], - cp->cmnd[1], cp->cmnd[2], scsi_bufflen(cp), rsp_info_len, - resid_len, fw_resid_len)); + cp->result, fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa, ox_id, cp->cmnd[0], cp->cmnd[1], + cp->cmnd[2], scsi_bufflen(cp), rsp_info_len, resid_len, + fw_resid_len)); if (rsp->status_srb == NULL) qla2x00_sp_compl(ha, sp); @@ -1908,13 +1921,17 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) qla2x00_sp_compl(ha, sp); } else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type == - COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7) { + COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7 + || pkt->entry_type == COMMAND_TYPE_6) { DEBUG2(printk("scsi(%ld): Error entry - invalid handle\n", - vha->host_no)); + vha->host_no)); qla_printk(KERN_WARNING, ha, - "Error entry - invalid handle\n"); + "Error entry - invalid handle\n"); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); } } diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 34893397ac84..c26f0acdfecc 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -1261,11 +1261,12 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) /* Check for logged in state. */ if (pd24->current_login_state != PDS_PRLI_COMPLETE && pd24->last_login_state != PDS_PRLI_COMPLETE) { - DEBUG2(printk("%s(%ld): Unable to verify " - "login-state (%x/%x) for loop_id %x\n", - __func__, vha->host_no, - pd24->current_login_state, - pd24->last_login_state, fcport->loop_id)); + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld): Unable to verify login-state (%x/%x) " + " - portid=%02x%02x%02x.\n", vha->host_no, + pd24->current_login_state, pd24->last_login_state, + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); rval = QLA_FUNCTION_FAILED; goto gpd_error_out; } @@ -1289,6 +1290,12 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) /* Check for logged in state. */ if (pd->master_state != PD_STATE_PORT_LOGGED_IN && pd->slave_state != PD_STATE_PORT_LOGGED_IN) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld): Unable to verify login-state (%x/%x) " + " - portid=%02x%02x%02x.\n", vha->host_no, + pd->master_state, pd->slave_state, + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); rval = QLA_FUNCTION_FAILED; goto gpd_error_out; } @@ -1883,7 +1890,8 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, lg->handle = MAKE_HANDLE(req->id, lg->handle); lg->nport_handle = cpu_to_le16(loop_id); lg->control_flags = - __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO); + __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO| + LCF_FREE_NPORT); lg->port_id[0] = al_pa; lg->port_id[1] = area; lg->port_id[2] = domain; @@ -2362,7 +2370,7 @@ qla24xx_abort_command(srb_t *sp) abt->entry_count = 1; abt->handle = MAKE_HANDLE(req->id, abt->handle); abt->nport_handle = cpu_to_le16(fcport->loop_id); - abt->handle_to_abort = handle; + abt->handle_to_abort = MAKE_HANDLE(req->id, handle); abt->port_id[0] = fcport->d_id.b.al_pa; abt->port_id[1] = fcport->d_id.b.area; abt->port_id[2] = fcport->d_id.b.domain; @@ -2778,44 +2786,6 @@ qla2x00_disable_fce_trace(scsi_qla_host_t *vha, uint64_t *wr, uint64_t *rd) return rval; } -int -qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint16_t addr, - uint16_t off, uint16_t count) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - if (!IS_FWI2_CAPABLE(vha->hw)) - return QLA_FUNCTION_FAILED; - - DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); - - mcp->mb[0] = MBC_READ_SFP; - mcp->mb[1] = addr; - mcp->mb[2] = MSW(sfp_dma); - mcp->mb[3] = LSW(sfp_dma); - mcp->mb[6] = MSW(MSD(sfp_dma)); - mcp->mb[7] = LSW(MSD(sfp_dma)); - mcp->mb[8] = count; - mcp->mb[9] = off; - mcp->mb[10] = 0; - mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, - vha->host_no, rval, mcp->mb[0])); - } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); - } - - return rval; -} - int qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t *port_speed, uint16_t *mb) @@ -3581,15 +3551,22 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha) } int -qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, - dma_addr_t sfp_dma, uint8_t *sfp, uint16_t len, uint16_t opt) +qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, + uint16_t dev, uint16_t off, uint16_t len, uint16_t opt) { int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; + struct qla_hw_data *ha = vha->hw; + + if (!IS_FWI2_CAPABLE(ha)) + return QLA_FUNCTION_FAILED; DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + if (len == 1) + opt |= BIT_0; + mcp->mb[0] = MBC_READ_SFP; mcp->mb[1] = dev; mcp->mb[2] = MSW(sfp_dma); @@ -3597,17 +3574,16 @@ qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, mcp->mb[6] = MSW(MSD(sfp_dma)); mcp->mb[7] = LSW(MSD(sfp_dma)); mcp->mb[8] = len; - mcp->mb[9] = adr; + mcp->mb[9] = off; mcp->mb[10] = opt; mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; + mcp->in_mb = MBX_1|MBX_0; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); if (opt & BIT_0) - if (sfp) - *sfp = mcp->mb[8]; + *sfp = mcp->mb[1]; if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, @@ -3620,18 +3596,24 @@ qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, } int -qla2x00_write_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, - dma_addr_t sfp_dma, uint8_t *sfp, uint16_t len, uint16_t opt) +qla2x00_write_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, + uint16_t dev, uint16_t off, uint16_t len, uint16_t opt) { int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; + struct qla_hw_data *ha = vha->hw; + + if (!IS_FWI2_CAPABLE(ha)) + return QLA_FUNCTION_FAILED; DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + if (len == 1) + opt |= BIT_0; + if (opt & BIT_0) - if (sfp) - len = *sfp; + len = *sfp; mcp->mb[0] = MBC_WRITE_SFP; mcp->mb[1] = dev; @@ -3640,10 +3622,10 @@ qla2x00_write_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, mcp->mb[6] = MSW(MSD(sfp_dma)); mcp->mb[7] = LSW(MSD(sfp_dma)); mcp->mb[8] = len; - mcp->mb[9] = adr; + mcp->mb[9] = off; mcp->mb[10] = opt; mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; + mcp->in_mb = MBX_1|MBX_0; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); @@ -4160,63 +4142,32 @@ int qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp, uint16_t *frac) { int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; + uint8_t byte; struct qla_hw_data *ha = vha->hw; - DEBUG11(printk(KERN_INFO "%s(%ld): entered.\n", __func__, ha->host_no)); + DEBUG11(printk(KERN_INFO "%s(%ld): entered.\n", __func__, vha->host_no)); - /* High bits. */ - mcp->mb[0] = MBC_READ_SFP; - mcp->mb[1] = 0x98; - mcp->mb[2] = 0; - mcp->mb[3] = 0; - mcp->mb[6] = 0; - mcp->mb[7] = 0; - mcp->mb[8] = 1; - mcp->mb[9] = 0x01; - mcp->mb[10] = BIT_13|BIT_0; - mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); + /* Integer part */ + rval = qla2x00_read_sfp(vha, 0, &byte, 0x98, 0x01, 1, BIT_13|BIT_0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk(KERN_WARNING - "%s(%ld): failed=%x (%x).\n", __func__, - vha->host_no, rval, mcp->mb[0])); + "%s(%ld): failed=%x.\n", __func__, vha->host_no, rval)); ha->flags.thermal_supported = 0; goto fail; } - *temp = mcp->mb[1] & 0xFF; + *temp = byte; - /* Low bits. */ - mcp->mb[0] = MBC_READ_SFP; - mcp->mb[1] = 0x98; - mcp->mb[2] = 0; - mcp->mb[3] = 0; - mcp->mb[6] = 0; - mcp->mb[7] = 0; - mcp->mb[8] = 1; - mcp->mb[9] = 0x10; - mcp->mb[10] = BIT_13|BIT_0; - mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); + /* Fraction part */ + rval = qla2x00_read_sfp(vha, 0, &byte, 0x98, 0x10, 1, BIT_13|BIT_0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk(KERN_WARNING - "%s(%ld): failed=%x (%x).\n", __func__, - vha->host_no, rval, mcp->mb[0])); + "%s(%ld): failed=%x.\n", __func__, vha->host_no, rval)); ha->flags.thermal_supported = 0; goto fail; } - *frac = ((mcp->mb[1] & 0xFF) >> 6) * 25; + *frac = (byte >> 6) * 25; - if (rval == QLA_SUCCESS) - DEBUG11(printk(KERN_INFO - "%s(%ld): done.\n", __func__, ha->host_no)); + DEBUG11(printk(KERN_INFO "%s(%ld): done.\n", __func__, vha->host_no)); fail: return rval; } diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 2b69392a71a1..5e343919acad 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -136,7 +136,7 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) vha->host_no, fcport->loop_id, fcport->vp_idx)); qla2x00_mark_device_lost(vha, fcport, 0, 0); - atomic_set(&fcport->state, FCS_UNCONFIGURED); + qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED); } } @@ -456,7 +456,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) else host->max_cmd_len = MAX_CMDSZ; host->max_channel = MAX_BUSES - 1; - host->max_lun = MAX_LUNS; + host->max_lun = ql2xmaxlun; host->unique_id = host->host_no; host->max_id = MAX_TARGETS_2200; host->transportt = qla2xxx_transport_vport_template; diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 455fe134d31d..e1138bcc834c 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -844,6 +844,12 @@ qla82xx_rom_lock(struct qla_hw_data *ha) return 0; } +static void +qla82xx_rom_unlock(struct qla_hw_data *ha) +{ + qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); +} + static int qla82xx_wait_rom_busy(struct qla_hw_data *ha) { @@ -924,7 +930,7 @@ qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) return -1; } ret = qla82xx_do_rom_fast_read(ha, addr, valp); - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); return ret; } @@ -1056,7 +1062,7 @@ qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr, ret = qla82xx_flash_wait_write_finish(ha); done_write: - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); return ret; } @@ -1081,12 +1087,26 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) /* Halt all the indiviual PEGs and other blocks of the ISP */ qla82xx_rom_lock(ha); - /* mask all niu interrupts */ + /* disable all I2Q */ + qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x10, 0x0); + qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x14, 0x0); + qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x18, 0x0); + qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x1c, 0x0); + qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x20, 0x0); + qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x24, 0x0); + + /* disable all niu interrupts */ qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x40, 0xff); /* disable xge rx/tx */ qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x70000, 0x00); /* disable xg1 rx/tx */ qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x80000, 0x00); + /* disable sideband mac */ + qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x90000, 0x00); + /* disable ap0 mac */ + qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0xa0000, 0x00); + /* disable ap1 mac */ + qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0xb0000, 0x00); /* halt sre */ val = qla82xx_rd_32(ha, QLA82XX_CRB_SRE + 0x1000); @@ -1101,6 +1121,7 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x10, 0x0); qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x18, 0x0); qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x100, 0x0); + qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x200, 0x0); /* halt pegs */ qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c, 1); @@ -1108,9 +1129,9 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c, 1); qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c, 1); qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c, 1); + msleep(20); /* big hammer */ - msleep(1000); if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) /* don't reset CAM block on reset */ qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff); @@ -1129,7 +1150,7 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) qla82xx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val); msleep(20); - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); /* Read the signature value from the flash. * Offset 0: Contain signature (0xcafecafe) @@ -2395,9 +2416,13 @@ qla82xx_load_fw(scsi_qla_host_t *vha) if (qla82xx_fw_load_from_flash(ha) == QLA_SUCCESS) { qla_printk(KERN_ERR, ha, - "Firmware loaded successfully from flash\n"); + "Firmware loaded successfully from flash\n"); return QLA_SUCCESS; + } else { + qla_printk(KERN_ERR, ha, + "Firmware load from flash failed\n"); } + try_blob_fw: qla_printk(KERN_INFO, ha, "Attempting to load firmware from blob\n"); @@ -2548,11 +2573,11 @@ qla2xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address; *dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); *dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - cmd_pkt->fcp_data_dseg_len = dsd_list_len; + *dsd_seg++ = cpu_to_le32(dsd_list_len); } else { *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = dsd_list_len; + *cur_dsd++ = cpu_to_le32(dsd_list_len); } cur_dsd = (uint32_t *)next_dsd; while (avail_dsds) { @@ -2991,7 +3016,7 @@ qla82xx_unprotect_flash(struct qla_hw_data *ha) qla_printk(KERN_WARNING, ha, "Write disable failed\n"); done_unprotect: - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); return ret; } @@ -3020,7 +3045,7 @@ qla82xx_protect_flash(struct qla_hw_data *ha) if (qla82xx_write_disable_flash(ha) != 0) qla_printk(KERN_WARNING, ha, "Write disable failed\n"); done_protect: - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); return ret; } @@ -3048,7 +3073,7 @@ qla82xx_erase_sector(struct qla_hw_data *ha, int addr) } ret = qla82xx_flash_wait_write_finish(ha); done: - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); return ret; } @@ -3228,7 +3253,7 @@ void qla82xx_rom_lock_recovery(struct qla_hw_data *ha) * else died while holding it. * In either case, unlock. */ - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); } /* @@ -3528,15 +3553,18 @@ int qla82xx_device_state_handler(scsi_qla_host_t *vha) { uint32_t dev_state; + uint32_t old_dev_state; int rval = QLA_SUCCESS; unsigned long dev_init_timeout; struct qla_hw_data *ha = vha->hw; + int loopcount = 0; qla82xx_idc_lock(ha); if (!vha->flags.init_done) qla82xx_set_drv_active(vha); dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + old_dev_state = dev_state; qla_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state, dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); @@ -3553,10 +3581,16 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) break; } dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - qla_printk(KERN_INFO, ha, - "2:Device state is 0x%x = %s\n", dev_state, - dev_state < MAX_STATES ? - qdev_state[dev_state] : "Unknown"); + if (old_dev_state != dev_state) { + loopcount = 0; + old_dev_state = dev_state; + } + if (loopcount < 5) { + qla_printk(KERN_INFO, ha, + "2:Device state is 0x%x = %s\n", dev_state, + dev_state < MAX_STATES ? + qdev_state[dev_state] : "Unknown"); + } switch (dev_state) { case QLA82XX_DEV_READY: @@ -3570,6 +3604,7 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) qla82xx_idc_lock(ha); break; case QLA82XX_DEV_NEED_RESET: + if (!ql2xdontresethba) qla82xx_need_reset_handler(vha); dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); @@ -3604,6 +3639,7 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) msleep(1000); qla82xx_idc_lock(ha); } + loopcount++; } exit: qla82xx_idc_unlock(ha); @@ -3621,7 +3657,8 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) if (dev_state == QLA82XX_DEV_NEED_RESET && !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) { qla_printk(KERN_WARNING, ha, - "%s(): Adapter reset needed!\n", __func__); + "scsi(%ld) %s: Adapter reset needed!\n", + vha->host_no, __func__); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && @@ -3632,10 +3669,27 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); } else { - qla82xx_check_fw_alive(vha); if (qla82xx_check_fw_alive(vha)) { halt_status = qla82xx_rd_32(ha, QLA82XX_PEG_HALT_STATUS1); + qla_printk(KERN_INFO, ha, + "scsi(%ld): %s, Dumping hw/fw registers:\n " + " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n " + " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n " + " PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n " + " PEG_NET_4_PC: 0x%x\n", + vha->host_no, __func__, halt_status, + qla82xx_rd_32(ha, QLA82XX_PEG_HALT_STATUS2), + qla82xx_rd_32(ha, + QLA82XX_CRB_PEG_NET_0 + 0x3c), + qla82xx_rd_32(ha, + QLA82XX_CRB_PEG_NET_1 + 0x3c), + qla82xx_rd_32(ha, + QLA82XX_CRB_PEG_NET_2 + 0x3c), + qla82xx_rd_32(ha, + QLA82XX_CRB_PEG_NET_3 + 0x3c), + qla82xx_rd_32(ha, + QLA82XX_CRB_PEG_NET_4 + 0x3c)); if (halt_status & HALT_STATUS_UNRECOVERABLE) { set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags); @@ -3651,8 +3705,9 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) if (ha->flags.mbox_busy) { ha->flags.mbox_int = 1; DEBUG2(qla_printk(KERN_ERR, ha, - "Due to fw hung, doing premature " - "completion of mbx command\n")); + "scsi(%ld) Due to fw hung, doing " + "premature completion of mbx " + "command\n", vha->host_no)); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags)) complete(&ha->mbx_intr_comp); diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index ed5883f1778a..8a21832c6693 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index aa7747529165..f461925a9dfc 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -164,6 +164,20 @@ module_param(ql2xasynctmfenable, int, S_IRUGO); MODULE_PARM_DESC(ql2xasynctmfenable, "Enables issue of TM IOCBs asynchronously via IOCB mechanism" "Default is 0 - Issue TM IOCBs via mailbox mechanism."); + +int ql2xdontresethba; +module_param(ql2xdontresethba, int, S_IRUGO); +MODULE_PARM_DESC(ql2xdontresethba, + "Option to specify reset behaviour\n" + " 0 (Default) -- Reset on failure.\n" + " 1 -- Do not reset on failure.\n"); + +uint ql2xmaxlun = MAX_LUNS; +module_param(ql2xmaxlun, uint, S_IRUGO); +MODULE_PARM_DESC(ql2xmaxlun, + "Defines the maximum LU number to register with the SCSI " + "midlayer. Default is 65535."); + /* * SCSI host template entry points */ @@ -528,7 +542,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport, static int qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) { - scsi_qla_host_t *vha = shost_priv(cmd->device->host); + scsi_qla_host_t *vha = shost_priv(host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); struct qla_hw_data *ha = vha->hw; @@ -2128,7 +2142,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) else host->max_cmd_len = MAX_CMDSZ; host->max_channel = MAX_BUSES - 1; - host->max_lun = MAX_LUNS; + host->max_lun = ql2xmaxlun; host->transportt = qla2xxx_transport_template; sht->vendor_id = (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC); @@ -2360,21 +2374,26 @@ qla2x00_remove_one(struct pci_dev *pdev) base_vha = pci_get_drvdata(pdev); ha = base_vha->hw; - spin_lock_irqsave(&ha->vport_slock, flags); - list_for_each_entry(vha, &ha->vp_list, list) { - atomic_inc(&vha->vref_count); + mutex_lock(&ha->vport_lock); + while (ha->cur_vport_count) { + struct Scsi_Host *scsi_host; - if (vha->fc_vport) { - spin_unlock_irqrestore(&ha->vport_slock, flags); + spin_lock_irqsave(&ha->vport_slock, flags); - fc_vport_terminate(vha->fc_vport); + BUG_ON(base_vha->list.next == &ha->vp_list); + /* This assumes first entry in ha->vp_list is always base vha */ + vha = list_first_entry(&base_vha->list, scsi_qla_host_t, list); + scsi_host = scsi_host_get(vha->host); - spin_lock_irqsave(&ha->vport_slock, flags); - } + spin_unlock_irqrestore(&ha->vport_slock, flags); + mutex_unlock(&ha->vport_lock); - atomic_dec(&vha->vref_count); + fc_vport_terminate(vha->fc_vport); + scsi_host_put(vha->host); + + mutex_lock(&ha->vport_lock); } - spin_unlock_irqrestore(&ha->vport_slock, flags); + mutex_unlock(&ha->vport_lock); set_bit(UNLOADING, &base_vha->dpc_flags); @@ -2544,7 +2563,7 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, { if (atomic_read(&fcport->state) == FCS_ONLINE && vha->vp_idx == fcport->vp_idx) { - atomic_set(&fcport->state, FCS_DEVICE_LOST); + qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); qla2x00_schedule_rport_del(vha, fcport, defer); } /* @@ -2552,7 +2571,7 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, * port but do the retries. */ if (atomic_read(&fcport->state) != FCS_DEVICE_DEAD) - atomic_set(&fcport->state, FCS_DEVICE_LOST); + qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); if (!do_login) return; @@ -2607,7 +2626,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) continue; if (atomic_read(&fcport->state) == FCS_ONLINE) { - atomic_set(&fcport->state, FCS_DEVICE_LOST); + qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); if (defer) qla2x00_schedule_rport_del(vha, fcport, defer); else if (vha->vp_idx == fcport->vp_idx) @@ -3214,6 +3233,17 @@ void qla2x00_relogin(struct scsi_qla_host *vha) fcport->d_id.b.area, fcport->d_id.b.al_pa); + if (fcport->loop_id == FC_NO_LOOP_ID) { + fcport->loop_id = next_loopid = + ha->min_external_loopid; + status = qla2x00_find_new_loop_id( + vha, fcport); + if (status != QLA_SUCCESS) { + /* Ran out of IDs to use */ + break; + } + } + if (IS_ALOGIO_CAPABLE(ha)) { fcport->flags |= FCF_ASYNC_SENT; data[0] = 0; @@ -3604,7 +3634,8 @@ qla2x00_timer(scsi_qla_host_t *vha) if (!pci_channel_offline(ha->pdev)) pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); - if (IS_QLA82XX(ha)) { + /* Make sure qla82xx_watchdog is run only for physical port */ + if (!vha->vp_idx && IS_QLA82XX(ha)) { if (test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) start_dpc++; qla82xx_watchdog(vha); @@ -3612,7 +3643,8 @@ qla2x00_timer(scsi_qla_host_t *vha) /* Loop down handler. */ if (atomic_read(&vha->loop_down_timer) > 0 && - !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) + !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) && + !(test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags)) && vha->flags.online) { if (atomic_read(&vha->loop_down_timer) == @@ -3648,7 +3680,11 @@ qla2x00_timer(scsi_qla_host_t *vha) if (!(sfcp->flags & FCF_FCP2_DEVICE)) continue; - set_bit(ISP_ABORT_NEEDED, + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, + &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); break; } @@ -3667,7 +3703,12 @@ qla2x00_timer(scsi_qla_host_t *vha) qla_printk(KERN_WARNING, ha, "Loop down - aborting ISP.\n"); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, + &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, + &vha->dpc_flags); } } DEBUG3(printk("scsi(%ld): Loop Down - seconds remaining %d\n", @@ -3675,8 +3716,8 @@ qla2x00_timer(scsi_qla_host_t *vha) atomic_read(&vha->loop_down_timer))); } - /* Check if beacon LED needs to be blinked */ - if (ha->beacon_blink_led == 1) { + /* Check if beacon LED needs to be blinked for physical host only */ + if (!vha->vp_idx && (ha->beacon_blink_led == 1)) { set_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags); start_dpc++; } diff --git a/drivers/scsi/qla2xxx/qla_settings.h b/drivers/scsi/qla2xxx/qla_settings.h index f0b2b9986a55..d70f03008981 100644 --- a/drivers/scsi/qla2xxx/qla_settings.h +++ b/drivers/scsi/qla2xxx/qla_settings.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 22070621206c..693647661ed1 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 3a260c3f055a..062c97bf62f5 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -1,15 +1,15 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.07.00" +#define QLA2XXX_VERSION "8.03.07.03-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 #define QLA_DRIVER_PATCH_VER 7 -#define QLA_DRIVER_BETA_VER 0 +#define QLA_DRIVER_BETA_VER 3 diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 230ba097d28c..c22f2a764d9d 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -2068,15 +2068,14 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) struct scsi_qla_host *ha = to_qla_host(cmd->device->host); unsigned int id = cmd->device->id; unsigned int lun = cmd->device->lun; - unsigned long serial = cmd->serial_number; unsigned long flags; struct srb *srb = NULL; int ret = SUCCESS; int wait = 0; ql4_printk(KERN_INFO, ha, - "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n", - ha->host_no, id, lun, cmd, serial); + "scsi%ld:%d:%d: Abort command issued cmd=%p\n", + ha->host_no, id, lun, cmd); spin_lock_irqsave(&ha->hardware_lock, flags); srb = (struct srb *) CMD_SP(cmd); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index e2d45c91b8e8..9689d41c7888 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1292,8 +1292,10 @@ static struct scsi_host_template qpti_template = { .use_clustering = ENABLE_CLUSTERING, }; +static const struct of_device_id qpti_match[]; static int __devinit qpti_sbus_probe(struct platform_device *op) { + const struct of_device_id *match; struct scsi_host_template *tpnt; struct device_node *dp = op->dev.of_node; struct Scsi_Host *host; @@ -1301,9 +1303,10 @@ static int __devinit qpti_sbus_probe(struct platform_device *op) static int nqptis; const char *fcode; - if (!op->dev.of_match) + match = of_match_device(qpti_match, &op->dev); + if (!match) return -EINVAL; - tpnt = op->dev.of_match->data; + tpnt = match->data; /* Sometimes Antares cards come up not completely * setup, and we get a report of a zero IRQ. diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 633c2395a92a..abea2cf05c2e 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -321,6 +321,12 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) "changed. The Linux SCSI layer does not " "automatically adjust these parameters.\n"); + if (sshdr.asc == 0x38 && sshdr.ascq == 0x07) + scmd_printk(KERN_WARNING, scmd, + "Warning! Received an indication that the " + "LUN reached a thin provisioning soft " + "threshold.\n"); + /* * Pass the UA upwards for a determination in the completion * functions. diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 6d5c7ff43f5b..ec1803a48723 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -74,8 +74,6 @@ struct kmem_cache *scsi_sdb_cache; */ #define SCSI_QUEUE_DELAY 3 -static void scsi_run_queue(struct request_queue *q); - /* * Function: scsi_unprep_request() * @@ -161,7 +159,7 @@ static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy) blk_requeue_request(q, cmd->request); spin_unlock_irqrestore(q->queue_lock, flags); - scsi_run_queue(q); + kblockd_schedule_work(q, &device->requeue_work); return 0; } @@ -400,10 +398,15 @@ static inline int scsi_host_is_busy(struct Scsi_Host *shost) static void scsi_run_queue(struct request_queue *q) { struct scsi_device *sdev = q->queuedata; - struct Scsi_Host *shost = sdev->host; + struct Scsi_Host *shost; LIST_HEAD(starved_list); unsigned long flags; + /* if the device is dead, sdev will be NULL, so no queue to run */ + if (!sdev) + return; + + shost = sdev->host; if (scsi_target(sdev)->single_lun) scsi_single_lun_run(sdev); @@ -411,8 +414,6 @@ static void scsi_run_queue(struct request_queue *q) list_splice_init(&shost->starved_list, &starved_list); while (!list_empty(&starved_list)) { - int flagset; - /* * As long as shost is accepting commands and we have * starved queues, call blk_run_queue. scsi_request_fn @@ -436,18 +437,9 @@ static void scsi_run_queue(struct request_queue *q) } spin_unlock(shost->host_lock); - spin_lock(sdev->request_queue->queue_lock); - flagset = test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) && - !test_bit(QUEUE_FLAG_REENTER, - &sdev->request_queue->queue_flags); - if (flagset) - queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue); - __blk_run_queue(sdev->request_queue, false); - if (flagset) - queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue); + __blk_run_queue(sdev->request_queue); spin_unlock(sdev->request_queue->queue_lock); - spin_lock(shost->host_lock); } /* put any unprocessed entries back */ @@ -457,6 +449,16 @@ static void scsi_run_queue(struct request_queue *q) blk_run_queue(q); } +void scsi_requeue_run_queue(struct work_struct *work) +{ + struct scsi_device *sdev; + struct request_queue *q; + + sdev = container_of(work, struct scsi_device, requeue_work); + q = sdev->request_queue; + scsi_run_queue(q); +} + /* * Function: scsi_requeue_command() * diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index c99da926fdac..f46855cd853d 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -386,13 +386,59 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, * @s: output goes here * @p: not used */ -static int proc_scsi_show(struct seq_file *s, void *p) +static int always_match(struct device *dev, void *data) { - seq_printf(s, "Attached devices:\n"); - bus_for_each_dev(&scsi_bus_type, NULL, s, proc_print_scsidevice); - return 0; + return 1; } +static inline struct device *next_scsi_device(struct device *start) +{ + struct device *next = bus_find_device(&scsi_bus_type, start, NULL, + always_match); + put_device(start); + return next; +} + +static void *scsi_seq_start(struct seq_file *sfile, loff_t *pos) +{ + struct device *dev = NULL; + loff_t n = *pos; + + while ((dev = next_scsi_device(dev))) { + if (!n--) + break; + sfile->private++; + } + return dev; +} + +static void *scsi_seq_next(struct seq_file *sfile, void *v, loff_t *pos) +{ + (*pos)++; + sfile->private++; + return next_scsi_device(v); +} + +static void scsi_seq_stop(struct seq_file *sfile, void *v) +{ + put_device(v); +} + +static int scsi_seq_show(struct seq_file *sfile, void *dev) +{ + if (!sfile->private) + seq_puts(sfile, "Attached devices:\n"); + + return proc_print_scsidevice(dev, sfile); +} + +static const struct seq_operations scsi_seq_ops = { + .start = scsi_seq_start, + .next = scsi_seq_next, + .stop = scsi_seq_stop, + .show = scsi_seq_show +}; + /** * proc_scsi_open - glue function * @inode: not used @@ -406,7 +452,7 @@ static int proc_scsi_open(struct inode *inode, struct file *file) * We don't really need this for the write case but it doesn't * harm either. */ - return single_open(file, proc_scsi_show, NULL); + return seq_open(file, &scsi_seq_ops); } static const struct file_operations proc_scsi_operations = { @@ -415,7 +461,7 @@ static const struct file_operations proc_scsi_operations = { .read = seq_read, .write = proc_scsi_write, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; /** diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 087821fac8fe..58584dc0724a 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -242,6 +242,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, int display_failure_msg = 1, ret; struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); extern void scsi_evt_thread(struct work_struct *work); + extern void scsi_requeue_run_queue(struct work_struct *work); sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size, GFP_ATOMIC); @@ -264,6 +265,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, INIT_LIST_HEAD(&sdev->event_list); spin_lock_init(&sdev->list_lock); INIT_WORK(&sdev->event_work, scsi_evt_thread); + INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue); sdev->sdev_gendev.parent = get_device(&starget->dev); sdev->sdev_target = starget; diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index e44ff64233fd..e63912510fb9 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -322,14 +322,8 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) kfree(evt); } - if (sdev->request_queue) { - sdev->request_queue->queuedata = NULL; - /* user context needed to free queue */ - scsi_free_queue(sdev->request_queue); - /* temporary expedient, try to catch use of queue lock - * after free of sdev */ - sdev->request_queue = NULL; - } + /* NULL queue means the device can't be used */ + sdev->request_queue = NULL; scsi_target_reap(scsi_target(sdev)); @@ -937,6 +931,12 @@ void __scsi_remove_device(struct scsi_device *sdev) if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(dev); + + /* cause the request function to reject all I/O requests */ + sdev->request_queue->queuedata = NULL; + + /* Freeing the queue signals to block that we're done */ + scsi_free_queue(sdev->request_queue); put_device(dev); } diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index 8bca8c25ba69..84a1fdf67864 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -275,10 +275,8 @@ void scsi_tgt_free_queue(struct Scsi_Host *shost) for (i = 0; i < ARRAY_SIZE(qdata->cmd_hash); i++) { list_for_each_entry_safe(tcmd, n, &qdata->cmd_hash[i], - hash_list) { - list_del(&tcmd->hash_list); - list_add(&tcmd->hash_list, &cmds); - } + hash_list) + list_move(&tcmd->hash_list, &cmds); } spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index fdf3fa639056..1b214910b714 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -422,8 +422,7 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, snprintf(fc_host->work_q_name, sizeof(fc_host->work_q_name), "fc_wq_%d", shost->host_no); - fc_host->work_q = create_singlethread_workqueue( - fc_host->work_q_name); + fc_host->work_q = alloc_workqueue(fc_host->work_q_name, 0, 0); if (!fc_host->work_q) return -ENOMEM; @@ -431,8 +430,8 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, snprintf(fc_host->devloss_work_q_name, sizeof(fc_host->devloss_work_q_name), "fc_dl_%d", shost->host_no); - fc_host->devloss_work_q = create_singlethread_workqueue( - fc_host->devloss_work_q_name); + fc_host->devloss_work_q = + alloc_workqueue(fc_host->devloss_work_q_name, 0, 0); if (!fc_host->devloss_work_q) { destroy_workqueue(fc_host->work_q); fc_host->work_q = NULL; @@ -2489,6 +2488,8 @@ fc_rport_final_delete(struct work_struct *work) unsigned long flags; int do_callback = 0; + fc_terminate_rport_io(rport); + /* * if a scan is pending, flush the SCSI Host work_q so that * that we can reclaim the rport scan work element. @@ -2496,8 +2497,6 @@ fc_rport_final_delete(struct work_struct *work) if (rport->flags & FC_RPORT_SCAN_PENDING) scsi_flush_work(shost); - fc_terminate_rport_io(rport); - /* * Cancel any outstanding timers. These should really exist * only when rmmod'ing the LLDD and we're asking for @@ -3816,28 +3815,17 @@ fc_bsg_host_dispatch(struct request_queue *q, struct Scsi_Host *shost, static void fc_bsg_goose_queue(struct fc_rport *rport) { - int flagset; - unsigned long flags; - if (!rport->rqst_q) return; + /* + * This get/put dance makes no sense + */ get_device(&rport->dev); - - spin_lock_irqsave(rport->rqst_q->queue_lock, flags); - flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) && - !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags); - if (flagset) - queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q); - __blk_run_queue(rport->rqst_q, false); - if (flagset) - queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q); - spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags); - + blk_run_queue_async(rport->rqst_q); put_device(&rport->dev); } - /** * fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD * @q: rport request queue diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index a124a28f2ccb..a1baccce05f0 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -565,12 +565,12 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr pDCB->TagMask |= 1 << tag[1]; pSRB->TagNumber = tag[1]; DC390_write8(ScsiFifo, tag[1]); - DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for Cmd %li (SRB %p), block tag %02x\n", scmd->serial_number, pSRB, tag[1])); + DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for SRB %p, block tag %02x\n", pSRB, tag[1])); cmd = SEL_W_ATN3; } else { /* No TagQ */ //no_tag: - DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", disc_allowed ? "" : "o", scmd->serial_number, pSRB)); + DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for SRB %p, No TagQ\n", disc_allowed ? "" : "o", pSRB)); } pSRB->SRBState = SRB_START_; @@ -620,8 +620,8 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr if (DC390_read8 (Scsi_Status) & INTERRUPT) { dc390_freetag (pDCB, pSRB); - DEBUG0(printk ("DC390: Interrupt during Start SCSI (pid %li, target %02i-%02i)\n", - scmd->serial_number, scmd->device->id, scmd->device->lun)); + DEBUG0(printk ("DC390: Interrupt during Start SCSI (target %02i-%02i)\n", + scmd->device->id, scmd->device->lun)); pSRB->SRBState = SRB_READY; //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); pACB->SelLost++; @@ -1705,8 +1705,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* status = pSRB->TargetStatus; - DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\ - pSRB, pcmd->serial_number)); + DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p\n", status, pcmd->result, pSRB)); if(pSRB->SRBFlag & AUTO_REQSENSE) { /* Last command was a Request Sense */ pSRB->SRBFlag &= ~AUTO_REQSENSE; @@ -1727,7 +1726,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* } else { SET_RES_DRV(pcmd->result, DRIVER_SENSE); //pSRB->ScsiCmdLen = (u8) (pSRB->Segment1[0] >> 8); - DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->serial_number, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); + DEBUG0 (printk ("DC390: RETRY (%02x), target %02i-%02i\n", pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); pSRB->TotalXferredLen = 0; SET_RES_DID(pcmd->result, DID_SOFT_ERROR); } @@ -1747,7 +1746,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* else if (status == SAM_STAT_TASK_SET_FULL) { scsi_track_queue_full(pcmd->device, pDCB->GoingSRBCnt - 1); - DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->serial_number, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); + DEBUG0 (printk ("DC390: RETRY (%02x), target %02i-%02i\n", pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); pSRB->TotalXferredLen = 0; SET_RES_DID(pcmd->result, DID_SOFT_ERROR); } @@ -1801,7 +1800,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* /* Add to free list */ dc390_Free_insert (pACB, pSRB); - DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->serial_number)); + DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done\n")); pcmd->scsi_done (pcmd); return; @@ -1997,8 +1996,7 @@ static int DC390_abort(struct scsi_cmnd *cmd) struct dc390_acb *pACB = (struct dc390_acb*) cmd->device->host->hostdata; struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata; - scmd_printk(KERN_WARNING, cmd, - "DC390: Abort command (pid %li)\n", cmd->serial_number); + scmd_printk(KERN_WARNING, cmd, "DC390: Abort command\n"); /* abort() is too stupid for already sent commands at the moment. * If it's called we are in trouble anyway, so let's dump some info @@ -2006,7 +2004,7 @@ static int DC390_abort(struct scsi_cmnd *cmd) dc390_dumpinfo(pACB, pDCB, NULL); pDCB->DCBFlag |= ABORT_DEV_; - printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->serial_number); + printk(KERN_INFO "DC390: Aborted.\n"); return FAILED; } diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index edfc5da8be4c..90e104d6b558 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1256,8 +1256,8 @@ static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct j = ((struct hostdata *) SCpnt->device->host->hostdata)->board_number; if (SCpnt->host_scribble) - panic("%s: qcomm, pid %ld, SCpnt %p already active.\n", - BN(j), SCpnt->serial_number, SCpnt); + panic("%s: qcomm, SCpnt %p already active.\n", + BN(j), SCpnt); /* i is the mailbox number, look for the first free mailbox starting from last_cp_used */ @@ -1286,9 +1286,9 @@ static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct cpp->cpp_index = i; SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index; - if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n", + if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d.\n", BN(j), i, SCpnt->device->channel, SCpnt->device->id, - SCpnt->device->lun, SCpnt->serial_number); + SCpnt->device->lun); cpp->opcode = OP_SCSI; cpp->channel = SCpnt->device->channel; @@ -1315,7 +1315,7 @@ static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct unmap_dma(i, j); SCpnt->host_scribble = NULL; scmd_printk(KERN_INFO, SCpnt, - "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number); + "qcomm, adapter busy.\n"); return 1; } @@ -1337,14 +1337,12 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) { j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number; if (SCarg->host_scribble == NULL) { - scmd_printk(KERN_INFO, SCarg, "abort, pid %ld inactive.\n", - SCarg->serial_number); + scmd_printk(KERN_INFO, SCarg, "abort, command inactive.\n"); return SUCCESS; } i = *(unsigned int *)SCarg->host_scribble; - scmd_printk(KERN_INFO, SCarg, "abort, mbox %d, pid %ld.\n", - i, SCarg->serial_number); + scmd_printk(KERN_INFO, SCarg, "abort, mbox %d.\n", i); if (i >= sh[j]->can_queue) panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j)); @@ -1387,8 +1385,7 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) { SCarg->result = DID_ABORT << 16; SCarg->host_scribble = NULL; HD(j)->cp_stat[i] = FREE; - printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n", - BN(j), i, SCarg->serial_number); + printk("%s, abort, mbox %d ready, DID_ABORT, done.\n", BN(j), i); SCarg->scsi_done(SCarg); return SUCCESS; } @@ -1403,12 +1400,12 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { struct scsi_cmnd *SCpnt; j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number; - scmd_printk(KERN_INFO, SCarg, "reset, enter, pid %ld.\n", SCarg->serial_number); + scmd_printk(KERN_INFO, SCarg, "reset, enter.\n"); spin_lock_irq(sh[j]->host_lock); if (SCarg->host_scribble == NULL) - printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->serial_number); + printk("%s: reset, inactive.\n", BN(j)); if (HD(j)->in_reset) { printk("%s: reset, exit, already in reset.\n", BN(j)); @@ -1445,14 +1442,12 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) { HD(j)->cp_stat[i] = ABORTING; - printk("%s: reset, mbox %d aborting, pid %ld.\n", - BN(j), i, SCpnt->serial_number); + printk("%s: reset, mbox %d aborting.\n", BN(j), i); } else { HD(j)->cp_stat[i] = IN_RESET; - printk("%s: reset, mbox %d in reset, pid %ld.\n", - BN(j), i, SCpnt->serial_number); + printk("%s: reset, mbox %d in reset.\n", BN(j), i); } if (SCpnt->host_scribble == NULL) @@ -1500,8 +1495,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { /* This mailbox is still waiting for its interrupt */ HD(j)->cp_stat[i] = LOCKED; - printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n", - BN(j), i, SCpnt->serial_number); + printk("%s, reset, mbox %d locked, DID_RESET, done.\n", BN(j), i); } else if (HD(j)->cp_stat[i] == ABORTING) { @@ -1513,8 +1507,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { /* This mailbox was never queued to the adapter */ HD(j)->cp_stat[i] = FREE; - printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n", - BN(j), i, SCpnt->serial_number); + printk("%s, reset, mbox %d aborting, DID_RESET, done.\n", BN(j), i); } else @@ -1528,7 +1521,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { HD(j)->in_reset = FALSE; do_trace = FALSE; - if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->serial_number); + if (arg_done) printk("%s: reset, exit, done.\n", BN(j)); else printk("%s: reset, exit.\n", BN(j)); spin_unlock_irq(sh[j]->host_lock); @@ -1671,10 +1664,10 @@ static int reorder(unsigned int j, unsigned long cursec, if (link_statistics && (overlap || !(flushcount % link_statistics))) for (n = 0; n < n_ready; n++) { k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %u"\ + printk("%s %d.%d:%d mb %d fc %d nr %d sec %ld ns %u"\ " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, - SCpnt->lun, SCpnt->serial_number, k, flushcount, n_ready, + SCpnt->lun, k, flushcount, n_ready, blk_rq_pos(SCpnt->request), blk_rq_sectors(SCpnt->request), cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), YESNO(overlap), cpp->xdir); @@ -1709,9 +1702,9 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec, unsigned in if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { scmd_printk(KERN_INFO, SCpnt, - "%s, pid %ld, mbox %d, adapter" + "%s, mbox %d, adapter" " busy, will abort.\n", (ihdlr ? "ihdlr" : "qcomm"), - SCpnt->serial_number, k); + k); HD(j)->cp_stat[k] = ABORTING; continue; } @@ -1793,12 +1786,12 @@ static irqreturn_t ihdlr(unsigned int j) if (SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i); if (SCpnt->host_scribble == NULL) - panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i, - SCpnt->serial_number, SCpnt); + panic("%s: ihdlr, mbox %d, SCpnt %p garbled.\n", BN(j), i, + SCpnt); if (*(unsigned int *)SCpnt->host_scribble != i) - panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", - BN(j), i, SCpnt->serial_number, *(unsigned int *)SCpnt->host_scribble); + panic("%s: ihdlr, mbox %d, index mismatch %d.\n", + BN(j), i, *(unsigned int *)SCpnt->host_scribble); sync_dma(i, j); @@ -1841,8 +1834,8 @@ static irqreturn_t ihdlr(unsigned int j) (!(tstatus == CHECK_CONDITION && HD(j)->iocount <= 1000 && (SCpnt->sense_buffer[2] & 0xf) == NOT_READY))) scmd_printk(KERN_INFO, SCpnt, - "ihdlr, pid %ld, target_status 0x%x, sense key 0x%x.\n", - SCpnt->serial_number, spp->target_status, + "ihdlr, target_status 0x%x, sense key 0x%x.\n", + spp->target_status, SCpnt->sense_buffer[2]); HD(j)->target_to[scmd_id(SCpnt)][scmd_channel(SCpnt)] = 0; @@ -1913,8 +1906,8 @@ static irqreturn_t ihdlr(unsigned int j) do_trace || msg_byte(spp->target_status)) #endif scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"\ - " pid %ld, reg 0x%x, count %d.\n", - i, spp->adapter_status, spp->target_status, SCpnt->serial_number, + " reg 0x%x, count %d.\n", + i, spp->adapter_status, spp->target_status, reg, HD(j)->iocount); unmap_dma(i, j); diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 4468ae3610f7..97ae716134d0 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -381,7 +381,7 @@ wd33c93_queuecommand_lck(struct scsi_cmnd *cmd, hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata; DB(DB_QUEUE_COMMAND, - printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->serial_number)) + printk("Q-%d-%02x( ", cmd->device->id, cmd->cmnd[0])) /* Set up a few fields in the scsi_cmnd structure for our own use: * - host_scribble is the pointer to the next cmd in the input queue @@ -462,7 +462,7 @@ wd33c93_queuecommand_lck(struct scsi_cmnd *cmd, wd33c93_execute(cmd->device->host); - DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number)) + DB(DB_QUEUE_COMMAND, printk(")Q ")) spin_unlock_irq(&hostdata->lock); return 0; @@ -687,7 +687,7 @@ wd33c93_execute(struct Scsi_Host *instance) */ DB(DB_EXECUTE, - printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number)) + printk("%s)EX-2 ", (cmd->SCp.phase) ? "d:" : "")) } static void @@ -963,7 +963,7 @@ wd33c93_intr(struct Scsi_Host *instance) case CSR_XFER_DONE | PHS_COMMAND: case CSR_UNEXP | PHS_COMMAND: case CSR_SRV_REQ | PHS_COMMAND: - DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number)) + DB(DB_INTR, printk("CMND-%02x", cmd->cmnd[0])) transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata); hostdata->state = S_CONNECTED; @@ -1007,7 +1007,7 @@ wd33c93_intr(struct Scsi_Host *instance) switch (msg) { case COMMAND_COMPLETE: - DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number)) + DB(DB_INTR, printk("CCMP")) write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_PRE_CMP_DISC; break; @@ -1174,7 +1174,7 @@ wd33c93_intr(struct Scsi_Host *instance) write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); if (phs == 0x60) { - DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number)) + DB(DB_INTR, printk("SX-DONE")) cmd->SCp.Message = COMMAND_COMPLETE; lun = read_wd33c93(regs, WD_TARGET_LUN); DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun)) @@ -1200,8 +1200,8 @@ wd33c93_intr(struct Scsi_Host *instance) wd33c93_execute(instance); } else { printk - ("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", - asr, sr, phs, cmd->serial_number); + ("%02x:%02x:%02x: Unknown SEL_XFER_DONE phase!!---", + asr, sr, phs); spin_unlock_irqrestore(&hostdata->lock, flags); } break; @@ -1266,7 +1266,7 @@ wd33c93_intr(struct Scsi_Host *instance) spin_unlock_irqrestore(&hostdata->lock, flags); return; } - DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number)) + DB(DB_INTR, printk("UNEXP_DISC")) hostdata->connected = NULL; hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); hostdata->state = S_UNCONNECTED; @@ -1292,7 +1292,7 @@ wd33c93_intr(struct Scsi_Host *instance) */ write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); - DB(DB_INTR, printk("DISC-%ld", cmd->serial_number)) + DB(DB_INTR, printk("DISC")) if (cmd == NULL) { printk(" - Already disconnected! "); hostdata->state = S_UNCONNECTED; @@ -1491,7 +1491,6 @@ wd33c93_intr(struct Scsi_Host *instance) } else hostdata->state = S_CONNECTED; - DB(DB_INTR, printk("-%ld", cmd->serial_number)) spin_unlock_irqrestore(&hostdata->lock, flags); break; @@ -1637,8 +1636,8 @@ wd33c93_abort(struct scsi_cmnd * cmd) cmd->host_scribble = NULL; cmd->result = DID_ABORT << 16; printk - ("scsi%d: Abort - removing command %ld from input_Q. ", - instance->host_no, cmd->serial_number); + ("scsi%d: Abort - removing command from input_Q. ", + instance->host_no); enable_irq(cmd->device->host->irq); cmd->scsi_done(cmd); return SUCCESS; @@ -1662,8 +1661,8 @@ wd33c93_abort(struct scsi_cmnd * cmd) uchar sr, asr; unsigned long timeout; - printk("scsi%d: Aborting connected command %ld - ", - instance->host_no, cmd->serial_number); + printk("scsi%d: Aborting connected command - ", + instance->host_no); printk("stopping DMA - "); if (hostdata->dma == D_DMA_RUNNING) { @@ -1729,8 +1728,8 @@ wd33c93_abort(struct scsi_cmnd * cmd) while (tmp) { if (tmp == cmd) { printk - ("scsi%d: Abort - command %ld found on disconnected_Q - ", - instance->host_no, cmd->serial_number); + ("scsi%d: Abort - command found on disconnected_Q - ", + instance->host_no); printk("Abort SNOOZE. "); enable_irq(cmd->device->host->irq); return FAILED; @@ -2180,8 +2179,8 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off strcat(bp, "\nconnected: "); if (hd->connected) { cmd = (struct scsi_cmnd *) hd->connected; - sprintf(tbuf, " %ld-%d:%d(%02x)", - cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %d:%d(%02x)", + cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); } } @@ -2189,8 +2188,8 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off strcat(bp, "\ninput_Q: "); cmd = (struct scsi_cmnd *) hd->input_Q; while (cmd) { - sprintf(tbuf, " %ld-%d:%d(%02x)", - cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %d:%d(%02x)", + cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); cmd = (struct scsi_cmnd *) cmd->host_scribble; } @@ -2199,8 +2198,8 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off strcat(bp, "\ndisconnected_Q:"); cmd = (struct scsi_cmnd *) hd->disconnected_Q; while (cmd) { - sprintf(tbuf, " %ld-%d:%d(%02x)", - cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %d:%d(%02x)", + cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); cmd = (struct scsi_cmnd *) cmd->host_scribble; } diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 7c031fdc8205..06d15b6f2215 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, if (!ccdev) return; bus = ccdev->bus; + + /* We support SLOW only on 6..9 */ + if (ccdev->id.revision >= 10 && mode == SSB_CLKMODE_SLOW) + mode = SSB_CLKMODE_DYNAMIC; + + if (cc->capabilities & SSB_CHIPCO_CAP_PMU) + return; /* PMU controls clockmode, separated function needed */ + SSB_WARN_ON(ccdev->id.revision >= 20); + /* chipcommon cores prior to rev6 don't support dynamic clock control */ if (ccdev->id.revision < 6) return; - /* chipcommon cores rev10 are a whole new ball game */ + + /* ChipCommon cores rev10+ need testing */ if (ccdev->id.revision >= 10) return; + if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) return; switch (mode) { - case SSB_CLKMODE_SLOW: + case SSB_CLKMODE_SLOW: /* For revs 6..9 only */ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW; chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); break; case SSB_CLKMODE_FAST: - ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */ - tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); - tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; - tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; - chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + if (ccdev->id.revision < 10) { + ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */ + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; + tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + } else { + chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, + (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) | + SSB_CHIPCO_SYSCLKCTL_FORCEHT)); + /* udelay(150); TODO: not available in early init */ + } break; case SSB_CLKMODE_DYNAMIC: - tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); - tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; - tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; - tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; - if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) - tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; - chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + if (ccdev->id.revision < 10) { + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; + if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != + SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) + tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); - /* for dynamic control, we have to release our xtal_pu "force on" */ - if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) - ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0); + /* For dynamic control, we have to release our xtal_pu + * "force on" */ + if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) + ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0); + } else { + chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, + (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) & + ~SSB_CHIPCO_SYSCLKCTL_FORCEHT)); + } break; default: SSB_WARN_ON(1); @@ -260,6 +286,12 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) if (cc->dev->id.revision >= 11) cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status); + + if (cc->dev->id.revision >= 20) { + chipco_write32(cc, SSB_CHIPCO_GPIOPULLUP, 0); + chipco_write32(cc, SSB_CHIPCO_GPIOPULLDOWN, 0); + } + ssb_pmu_init(cc); chipco_powercontrol_init(cc); ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c index 5732bb2c3578..305ade7825f7 100644 --- a/drivers/ssb/driver_chipcommon_pmu.c +++ b/drivers/ssb/driver_chipcommon_pmu.c @@ -423,6 +423,8 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc) switch (bus->chip_id) { case 0x4312: + min_msk = 0xCBB; + break; case 0x4322: /* We keep the default settings: * min_msk = 0xCBB diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 0e8d35224614..82feb348c8bb 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -15,6 +15,11 @@ #include "ssb_private.h" +static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address); +static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data); +static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address); +static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, + u8 address, u16 data); static inline u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset) @@ -403,6 +408,107 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc) } #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ +/************************************************** + * Workarounds. + **************************************************/ + +static void ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc) +{ + u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0)); + if (((tmp & 0xF000) >> 12) != pc->dev->core_index) { + tmp &= ~0xF000; + tmp |= (pc->dev->core_index << 12); + pcicore_write16(pc, SSB_PCICORE_SPROM(0), tmp); + } +} + +static u8 ssb_pcicore_polarity_workaround(struct ssb_pcicore *pc) +{ + return (ssb_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80; +} + +static void ssb_pcicore_serdes_workaround(struct ssb_pcicore *pc) +{ + const u8 serdes_pll_device = 0x1D; + const u8 serdes_rx_device = 0x1F; + u16 tmp; + + ssb_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */, + ssb_pcicore_polarity_workaround(pc)); + tmp = ssb_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */); + if (tmp & 0x4000) + ssb_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000); +} + +static void ssb_pcicore_pci_setup_workarounds(struct ssb_pcicore *pc) +{ + struct ssb_device *pdev = pc->dev; + struct ssb_bus *bus = pdev->bus; + u32 tmp; + + tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); + tmp |= SSB_PCICORE_SBTOPCI_PREF; + tmp |= SSB_PCICORE_SBTOPCI_BURST; + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); + + if (pdev->id.revision < 5) { + tmp = ssb_read32(pdev, SSB_IMCFGLO); + tmp &= ~SSB_IMCFGLO_SERTO; + tmp |= 2; + tmp &= ~SSB_IMCFGLO_REQTO; + tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; + ssb_write32(pdev, SSB_IMCFGLO, tmp); + ssb_commit_settings(bus); + } else if (pdev->id.revision >= 11) { + tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); + tmp |= SSB_PCICORE_SBTOPCI_MRM; + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); + } +} + +static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) +{ + u32 tmp; + u8 rev = pc->dev->id.revision; + + if (rev == 0 || rev == 1) { + /* TLP Workaround register. */ + tmp = ssb_pcie_read(pc, 0x4); + tmp |= 0x8; + ssb_pcie_write(pc, 0x4, tmp); + } + if (rev == 1) { + /* DLLP Link Control register. */ + tmp = ssb_pcie_read(pc, 0x100); + tmp |= 0x40; + ssb_pcie_write(pc, 0x100, tmp); + } + + if (rev == 0) { + const u8 serdes_rx_device = 0x1F; + + ssb_pcie_mdio_write(pc, serdes_rx_device, + 2 /* Timer */, 0x8128); + ssb_pcie_mdio_write(pc, serdes_rx_device, + 6 /* CDR */, 0x0100); + ssb_pcie_mdio_write(pc, serdes_rx_device, + 7 /* CDR BW */, 0x1466); + } else if (rev == 3 || rev == 4 || rev == 5) { + /* TODO: DLLP Power Management Threshold */ + ssb_pcicore_serdes_workaround(pc); + /* TODO: ASPM */ + } else if (rev == 7) { + /* TODO: No PLL down */ + } + + if (rev >= 6) { + /* Miscellaneous Configuration Fixup */ + tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(5)); + if (!(tmp & 0x8000)) + pcicore_write16(pc, SSB_PCICORE_SPROM(5), + tmp | 0x8000); + } +} /************************************************** * Generic and Clientmode operation code. @@ -417,14 +523,14 @@ static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) void ssb_pcicore_init(struct ssb_pcicore *pc) { struct ssb_device *dev = pc->dev; - struct ssb_bus *bus; if (!dev) return; - bus = dev->bus; if (!ssb_device_is_enabled(dev)) ssb_device_enable(dev, 0); + ssb_pcicore_fix_sprom_core_index(pc); + #ifdef CONFIG_SSB_PCICORE_HOSTMODE pc->hostmode = pcicore_is_in_hostmode(pc); if (pc->hostmode) @@ -432,6 +538,11 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ if (!pc->hostmode) ssb_pcicore_init_clientmode(pc); + + /* Additional always once-executed workarounds */ + ssb_pcicore_serdes_workaround(pc); + /* TODO: ASPM */ + /* TODO: Clock Request Update */ } static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) @@ -446,28 +557,98 @@ static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data) pcicore_write32(pc, 0x134, data); } -static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, - u8 address, u16 data) +static void ssb_pcie_mdio_set_phy(struct ssb_pcicore *pc, u8 phy) { const u16 mdio_control = 0x128; const u16 mdio_data = 0x12C; u32 v; int i; + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 28); /* Write Transaction */ + v |= (1 << 17); /* Turnaround */ + v |= (0x1F << 18); + v |= (phy << 4); + pcicore_write32(pc, mdio_data, v); + + udelay(10); + for (i = 0; i < 200; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) + break; + msleep(1); + } +} + +static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address) +{ + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; + int max_retries = 10; + u16 ret = 0; + u32 v; + int i; + v = 0x80; /* Enable Preamble Sequence */ v |= 0x2; /* MDIO Clock Divisor */ pcicore_write32(pc, mdio_control, v); + if (pc->dev->id.revision >= 10) { + max_retries = 200; + ssb_pcie_mdio_set_phy(pc, device); + } + + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 29); /* Read Transaction */ + v |= (1 << 17); /* Turnaround */ + if (pc->dev->id.revision < 10) + v |= (u32)device << 22; + v |= (u32)address << 18; + pcicore_write32(pc, mdio_data, v); + /* Wait for the device to complete the transaction */ + udelay(10); + for (i = 0; i < max_retries; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) { + udelay(10); + ret = pcicore_read32(pc, mdio_data); + break; + } + msleep(1); + } + pcicore_write32(pc, mdio_control, 0); + return ret; +} + +static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, + u8 address, u16 data) +{ + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; + int max_retries = 10; + u32 v; + int i; + + v = 0x80; /* Enable Preamble Sequence */ + v |= 0x2; /* MDIO Clock Divisor */ + pcicore_write32(pc, mdio_control, v); + + if (pc->dev->id.revision >= 10) { + max_retries = 200; + ssb_pcie_mdio_set_phy(pc, device); + } + v = (1 << 30); /* Start of Transaction */ v |= (1 << 28); /* Write Transaction */ v |= (1 << 17); /* Turnaround */ - v |= (u32)device << 22; + if (pc->dev->id.revision < 10) + v |= (u32)device << 22; v |= (u32)address << 18; v |= data; pcicore_write32(pc, mdio_data, v); /* Wait for the device to complete the transaction */ udelay(10); - for (i = 0; i < 10; i++) { + for (i = 0; i < max_retries; i++) { v = pcicore_read32(pc, mdio_control); if (v & 0x100 /* Trans complete */) break; @@ -476,30 +657,6 @@ static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, pcicore_write32(pc, mdio_control, 0); } -static void ssb_broadcast_value(struct ssb_device *dev, - u32 address, u32 data) -{ - /* This is used for both, PCI and ChipCommon core, so be careful. */ - BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR); - BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA); - - ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address); - ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */ - ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data); - ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */ -} - -static void ssb_commit_settings(struct ssb_bus *bus) -{ - struct ssb_device *dev; - - dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev; - if (WARN_ON(!dev)) - return; - /* This forces an update of the cached registers. */ - ssb_broadcast_value(dev, 0xFD8, 0); -} - int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, struct ssb_device *dev) { @@ -550,48 +707,10 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, if (pc->setup_done) goto out; if (pdev->id.coreid == SSB_DEV_PCI) { - tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); - tmp |= SSB_PCICORE_SBTOPCI_PREF; - tmp |= SSB_PCICORE_SBTOPCI_BURST; - pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); - - if (pdev->id.revision < 5) { - tmp = ssb_read32(pdev, SSB_IMCFGLO); - tmp &= ~SSB_IMCFGLO_SERTO; - tmp |= 2; - tmp &= ~SSB_IMCFGLO_REQTO; - tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; - ssb_write32(pdev, SSB_IMCFGLO, tmp); - ssb_commit_settings(bus); - } else if (pdev->id.revision >= 11) { - tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); - tmp |= SSB_PCICORE_SBTOPCI_MRM; - pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); - } + ssb_pcicore_pci_setup_workarounds(pc); } else { WARN_ON(pdev->id.coreid != SSB_DEV_PCIE); - //TODO: Better make defines for all these magic PCIE values. - if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) { - /* TLP Workaround register. */ - tmp = ssb_pcie_read(pc, 0x4); - tmp |= 0x8; - ssb_pcie_write(pc, 0x4, tmp); - } - if (pdev->id.revision == 0) { - const u8 serdes_rx_device = 0x1F; - - ssb_pcie_mdio_write(pc, serdes_rx_device, - 2 /* Timer */, 0x8128); - ssb_pcie_mdio_write(pc, serdes_rx_device, - 6 /* CDR */, 0x0100); - ssb_pcie_mdio_write(pc, serdes_rx_device, - 7 /* CDR BW */, 0x1466); - } else if (pdev->id.revision == 1) { - /* DLLP Link Control register. */ - tmp = ssb_pcie_read(pc, 0x100); - tmp |= 0x40; - ssb_pcie_write(pc, 0x100, tmp); - } + ssb_pcicore_pcie_setup_workarounds(pc); } pc->setup_done = 1; out: diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index e05ba6eefc7e..f8a13f863217 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -1117,23 +1117,22 @@ static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev) { u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV; - /* The REJECT bit changed position in TMSLOW between - * Backplane revisions. */ + /* The REJECT bit seems to be different for Backplane rev 2.3 */ switch (rev) { case SSB_IDLOW_SSBREV_22: - return SSB_TMSLOW_REJECT_22; + case SSB_IDLOW_SSBREV_24: + case SSB_IDLOW_SSBREV_26: + return SSB_TMSLOW_REJECT; case SSB_IDLOW_SSBREV_23: return SSB_TMSLOW_REJECT_23; - case SSB_IDLOW_SSBREV_24: /* TODO - find the proper REJECT bits */ - case SSB_IDLOW_SSBREV_25: /* same here */ - case SSB_IDLOW_SSBREV_26: /* same here */ + case SSB_IDLOW_SSBREV_25: /* TODO - find the proper REJECT bit */ case SSB_IDLOW_SSBREV_27: /* same here */ - return SSB_TMSLOW_REJECT_23; /* this is a guess */ + return SSB_TMSLOW_REJECT; /* this is a guess */ default: printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev); WARN_ON(1); } - return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23); + return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23); } int ssb_device_is_enabled(struct ssb_device *dev) @@ -1309,20 +1308,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown); int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl) { - struct ssb_chipcommon *cc; int err; enum ssb_clkmode mode; err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); if (err) goto error; - cc = &bus->chipco; - mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; - ssb_chipco_set_clockmode(cc, mode); #ifdef CONFIG_SSB_DEBUG bus->powered_up = 1; #endif + + mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; + ssb_chipco_set_clockmode(&bus->chipco, mode); + return 0; error: ssb_printk(KERN_ERR PFX "Bus powerup failed\n"); @@ -1330,6 +1329,37 @@ int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl) } EXPORT_SYMBOL(ssb_bus_powerup); +static void ssb_broadcast_value(struct ssb_device *dev, + u32 address, u32 data) +{ +#ifdef CONFIG_SSB_DRIVER_PCICORE + /* This is used for both, PCI and ChipCommon core, so be careful. */ + BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR); + BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA); +#endif + + ssb_write32(dev, SSB_CHIPCO_BCAST_ADDR, address); + ssb_read32(dev, SSB_CHIPCO_BCAST_ADDR); /* flush */ + ssb_write32(dev, SSB_CHIPCO_BCAST_DATA, data); + ssb_read32(dev, SSB_CHIPCO_BCAST_DATA); /* flush */ +} + +void ssb_commit_settings(struct ssb_bus *bus) +{ + struct ssb_device *dev; + +#ifdef CONFIG_SSB_DRIVER_PCICORE + dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev; +#else + dev = bus->chipco.dev; +#endif + if (WARN_ON(!dev)) + return; + /* This forces an update of the cached registers. */ + ssb_broadcast_value(dev, 0xFD8, 0); +} +EXPORT_SYMBOL(ssb_commit_settings); + u32 ssb_admatch_base(u32 adm) { u32 base = 0; diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 6f34963b3c64..7ad48585c5e6 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -662,7 +662,6 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, static int ssb_pci_sprom_get(struct ssb_bus *bus, struct ssb_sprom *sprom) { - const struct ssb_sprom *fallback; int err; u16 *buf; @@ -707,10 +706,17 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, if (err) { /* All CRC attempts failed. * Maybe there is no SPROM on the device? - * If we have a fallback, use that. */ - fallback = ssb_get_fallback_sprom(); - if (fallback) { - memcpy(sprom, fallback, sizeof(*sprom)); + * Now we ask the arch code if there is some sprom + * available for this device in some other storage */ + err = ssb_fill_sprom_with_fallback(bus, sprom); + if (err) { + ssb_printk(KERN_WARNING PFX "WARNING: Using" + " fallback SPROM failed (err %d)\n", + err); + } else { + ssb_dprintk(KERN_DEBUG PFX "Using SPROM" + " revision %d provided by" + " platform.\n", sprom->revision); err = 0; goto out_free; } diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c index 29884c00c4d5..45e5babd3961 100644 --- a/drivers/ssb/scan.c +++ b/drivers/ssb/scan.c @@ -258,7 +258,10 @@ static int we_support_multiple_80211_cores(struct ssb_bus *bus) #ifdef CONFIG_SSB_PCIHOST if (bus->bustype == SSB_BUSTYPE_PCI) { if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM && - bus->host_pci->device == 0x4324) + ((bus->host_pci->device == 0x4313) || + (bus->host_pci->device == 0x431A) || + (bus->host_pci->device == 0x4321) || + (bus->host_pci->device == 0x4324))) return 1; } #endif /* CONFIG_SSB_PCIHOST */ @@ -307,7 +310,7 @@ int ssb_bus_scan(struct ssb_bus *bus, } else { if (bus->bustype == SSB_BUSTYPE_PCI) { bus->chip_id = pcidev_to_chipid(bus->host_pci); - pci_read_config_word(bus->host_pci, PCI_REVISION_ID, + pci_read_config_byte(bus->host_pci, PCI_REVISION_ID, &bus->chip_rev); bus->chip_package = 0; } else { diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c index 5f34d7a3e3a5..45ff0e3a3828 100644 --- a/drivers/ssb/sprom.c +++ b/drivers/ssb/sprom.c @@ -17,7 +17,7 @@ #include -static const struct ssb_sprom *fallback_sprom; +static int(*get_fallback_sprom)(struct ssb_bus *dev, struct ssb_sprom *out); static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, @@ -145,36 +145,43 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus, } /** - * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found. + * ssb_arch_register_fallback_sprom - Registers a method providing a + * fallback SPROM if no SPROM is found. * - * @sprom: The SPROM data structure to register. + * @sprom_callback: The callback function. * - * With this function the architecture implementation may register a fallback - * SPROM data structure. The fallback is only used for PCI based SSB devices, - * where no valid SPROM can be found in the shadow registers. + * With this function the architecture implementation may register a + * callback handler which fills the SPROM data structure. The fallback is + * only used for PCI based SSB devices, where no valid SPROM can be found + * in the shadow registers. * - * This function is useful for weird architectures that have a half-assed SSB device - * hardwired to their PCI bus. + * This function is useful for weird architectures that have a half-assed + * SSB device hardwired to their PCI bus. * - * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently - * don't use this fallback. - * Architectures must provide the SPROM for native SSB devices anyway, - * so the fallback also isn't used for native devices. + * Note that it does only work with PCI attached SSB devices. PCMCIA + * devices currently don't use this fallback. + * Architectures must provide the SPROM for native SSB devices anyway, so + * the fallback also isn't used for native devices. * - * This function is available for architecture code, only. So it is not exported. + * This function is available for architecture code, only. So it is not + * exported. */ -int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom) +int ssb_arch_register_fallback_sprom(int (*sprom_callback)(struct ssb_bus *bus, + struct ssb_sprom *out)) { - if (fallback_sprom) + if (get_fallback_sprom) return -EEXIST; - fallback_sprom = sprom; + get_fallback_sprom = sprom_callback; return 0; } -const struct ssb_sprom *ssb_get_fallback_sprom(void) +int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out) { - return fallback_sprom; + if (!get_fallback_sprom) + return -ENOENT; + + return get_fallback_sprom(bus, out); } /* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */ diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 0331139a726f..77653014db0b 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -171,7 +171,8 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus, const char *buf, size_t count, int (*sprom_check_crc)(const u16 *sprom, size_t size), int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom)); -extern const struct ssb_sprom *ssb_get_fallback_sprom(void); +extern int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, + struct ssb_sprom *out); /* core.c */ diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c index eeb7dd43f9a8..830822f86e41 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c @@ -2288,7 +2288,3 @@ struct net_device *init_ft1000_card(struct pcmcia_device *link, free_netdev(dev); return NULL; } - -EXPORT_SYMBOL(init_ft1000_card); -EXPORT_SYMBOL(stop_ft1000_card); -EXPORT_SYMBOL(flarion_ft1000_cnt); diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c index 935608e72007..bdfb1aec58df 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c @@ -214,6 +214,3 @@ void ft1000CleanupProc(struct net_device *dev) remove_proc_entry(FT1000_PROC, init_net.proc_net); unregister_netdevice_notifier(&ft1000_netdev_notifier); } - -EXPORT_SYMBOL(ft1000InitProc); -EXPORT_SYMBOL(ft1000CleanupProc); diff --git a/drivers/staging/gma500/Kconfig b/drivers/staging/gma500/Kconfig index 5501eb9b3355..ce8bedaeaac2 100644 --- a/drivers/staging/gma500/Kconfig +++ b/drivers/staging/gma500/Kconfig @@ -1,6 +1,6 @@ config DRM_PSB tristate "Intel GMA500 KMS Framebuffer" - depends on DRM && PCI + depends on DRM && PCI && X86 select FB_CFB_COPYAREA select FB_CFB_FILLRECT select FB_CFB_IMAGEBLIT diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index 33973568214f..aaa81883f0ad 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/staging/hv/netvsc_drv.c @@ -317,8 +317,6 @@ static void netvsc_get_drvinfo(struct net_device *net, static const struct ethtool_ops ethtool_ops = { .get_drvinfo = netvsc_get_drvinfo, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, }; @@ -406,6 +404,7 @@ static int netvsc_probe(struct device *device) net->netdev_ops = &device_ops; /* TODO: Add GSO and Checksum offload */ + net->hw_features = NETIF_F_SG; net->features = NETIF_F_SG; SET_ETHTOOL_OPS(net, ðtool_ops); diff --git a/drivers/staging/intel_sst/intelmid_v1_control.c b/drivers/staging/intel_sst/intelmid_v1_control.c index 9cc15c1c18d4..1ea814218059 100644 --- a/drivers/staging/intel_sst/intelmid_v1_control.c +++ b/drivers/staging/intel_sst/intelmid_v1_control.c @@ -28,6 +28,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include diff --git a/drivers/staging/intel_sst/intelmid_v2_control.c b/drivers/staging/intel_sst/intelmid_v2_control.c index 26d815a67eb8..3c6b3abff3c3 100644 --- a/drivers/staging/intel_sst/intelmid_v2_control.c +++ b/drivers/staging/intel_sst/intelmid_v2_control.c @@ -29,6 +29,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include "intel_sst.h" #include "intelmid_snd_control.h" diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c index b5d21f6497f9..22c04eabed41 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c @@ -12,6 +12,7 @@ */ #include #include +#include #include #include "olpc_dcon.h" diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index c93ef207b0b4..c0f0ac7c1cdb 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "netfs.h" diff --git a/drivers/staging/rt2860/common/cmm_data_pci.c b/drivers/staging/rt2860/common/cmm_data_pci.c index bef0bbd8cef7..f01a51c381f1 100644 --- a/drivers/staging/rt2860/common/cmm_data_pci.c +++ b/drivers/staging/rt2860/common/cmm_data_pci.c @@ -444,7 +444,7 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, return (NDIS_STATUS_FAILURE); } } - /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */ + /* Drop not U2M frames, can't drop here because we will drop beacon in this case */ /* I am kind of doubting the U2M bit operation */ /* if (pRxD->U2M == 0) */ /* return(NDIS_STATUS_FAILURE); */ diff --git a/drivers/staging/rt2860/common/cmm_data_usb.c b/drivers/staging/rt2860/common/cmm_data_usb.c index 5637857ae9eb..83a62faa7e57 100644 --- a/drivers/staging/rt2860/common/cmm_data_usb.c +++ b/drivers/staging/rt2860/common/cmm_data_usb.c @@ -860,7 +860,7 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, DBGPRINT_RAW(RT_DEBUG_ERROR, ("received packet too long\n")); return NDIS_STATUS_FAILURE; } - /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */ + /* Drop not U2M frames, can't drop here because we will drop beacon in this case */ /* I am kind of doubting the U2M bit operation */ /* if (pRxD->U2M == 0) */ /* return(NDIS_STATUS_FAILURE); */ diff --git a/drivers/staging/rts_pstor/debug.h b/drivers/staging/rts_pstor/debug.h index e1408b0e7ae4..ab305be96fb5 100644 --- a/drivers/staging/rts_pstor/debug.h +++ b/drivers/staging/rts_pstor/debug.h @@ -28,7 +28,7 @@ #define RTSX_STOR "rts_pstor: " -#if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG #define RTSX_DEBUGP(x...) printk(KERN_DEBUG RTSX_STOR x) #define RTSX_DEBUGPN(x...) printk(KERN_DEBUG x) #define RTSX_DEBUGPX(x...) printk(x) diff --git a/drivers/staging/rts_pstor/ms.c b/drivers/staging/rts_pstor/ms.c index 810e170894f5..d89795c6a3ac 100644 --- a/drivers/staging/rts_pstor/ms.c +++ b/drivers/staging/rts_pstor/ms.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "rtsx.h" #include "rtsx_transport.h" diff --git a/drivers/staging/rts_pstor/rtsx_chip.c b/drivers/staging/rts_pstor/rtsx_chip.c index d2f1c715a684..4e60780ea804 100644 --- a/drivers/staging/rts_pstor/rtsx_chip.c +++ b/drivers/staging/rts_pstor/rtsx_chip.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "rtsx.h" #include "rtsx_transport.h" @@ -1311,11 +1312,11 @@ void rtsx_polling_func(struct rtsx_chip *chip) #ifdef SUPPORT_OCP if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { - #if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER | MS_OC_NOW | MS_OC_EVER)) { RTSX_DEBUGP("Over current, OCPSTAT is 0x%x\n", chip->ocp_stat); } - #endif +#endif if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) { if (chip->card_exist & SD_CARD) { diff --git a/drivers/staging/rts_pstor/rtsx_scsi.c b/drivers/staging/rts_pstor/rtsx_scsi.c index 20c2464a20f9..7de1fae443fc 100644 --- a/drivers/staging/rts_pstor/rtsx_scsi.c +++ b/drivers/staging/rts_pstor/rtsx_scsi.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "rtsx.h" #include "rtsx_transport.h" diff --git a/drivers/staging/rts_pstor/sd.c b/drivers/staging/rts_pstor/sd.c index 8d066bd428c4..b1277a6c7a8b 100644 --- a/drivers/staging/rts_pstor/sd.c +++ b/drivers/staging/rts_pstor/sd.c @@ -909,7 +909,7 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir) RTSX_WRITE_REG(chip, SD_VPCLK0_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET); RTSX_WRITE_REG(chip, CLK_CTL, CHANGE_CLK, 0); } else { -#if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG rtsx_read_register(chip, SD_VP_CTL, &val); RTSX_DEBUGP("SD_VP_CTL: 0x%x\n", val); rtsx_read_register(chip, SD_DCMPS_CTL, &val); @@ -958,7 +958,7 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir) return STATUS_SUCCESS; Fail: -#if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG rtsx_read_register(chip, SD_VP_CTL, &val); RTSX_DEBUGP("SD_VP_CTL: 0x%x\n", val); rtsx_read_register(chip, SD_DCMPS_CTL, &val); diff --git a/drivers/staging/rts_pstor/trace.h b/drivers/staging/rts_pstor/trace.h index 2c668bae6ff4..bc83b49a4eb4 100644 --- a/drivers/staging/rts_pstor/trace.h +++ b/drivers/staging/rts_pstor/trace.h @@ -82,7 +82,7 @@ do { \ #define TRACE_GOTO(chip, label) goto label #endif -#if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG static inline void rtsx_dump(u8 *buf, int buf_len) { int i; diff --git a/drivers/staging/rts_pstor/xd.c b/drivers/staging/rts_pstor/xd.c index 7bcd468b8f2c..9f3add1e8f59 100644 --- a/drivers/staging/rts_pstor/xd.c +++ b/drivers/staging/rts_pstor/xd.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "rtsx.h" #include "rtsx_transport.h" diff --git a/drivers/staging/solo6x10/Kconfig b/drivers/staging/solo6x10/Kconfig index 2cf77c940860..03dcac4ea4d0 100644 --- a/drivers/staging/solo6x10/Kconfig +++ b/drivers/staging/solo6x10/Kconfig @@ -2,6 +2,7 @@ config SOLO6X10 tristate "Softlogic 6x10 MPEG codec cards" depends on PCI && VIDEO_DEV && SND && I2C select VIDEOBUF_DMA_SG + select SND_PCM ---help--- This driver supports the Softlogic based MPEG-4 and h.264 codec codec cards. diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index 20dae73d3b78..506547b603e1 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -653,7 +653,7 @@ static int SBD_setup_device(struct spectra_nand_dev *dev, int which) } dev->queue->queuedata = dev; - /* As Linux block layer does't support >4KB hardware sector, */ + /* As Linux block layer doesn't support >4KB hardware sector, */ /* Here we force report 512 byte hardware sector size to Kernel */ blk_queue_logical_block_size(dev->queue, 512); diff --git a/drivers/staging/tidspbridge/dynload/cload.c b/drivers/staging/tidspbridge/dynload/cload.c index 5cecd237e3f6..fe1ef0addb09 100644 --- a/drivers/staging/tidspbridge/dynload/cload.c +++ b/drivers/staging/tidspbridge/dynload/cload.c @@ -718,7 +718,7 @@ static void dload_symbols(struct dload_state *dlthis) * as a temporary for .dllview record construction. * Allocate storage for the whole table. Add 1 to the section count * in case a trampoline section is auto-generated as well as the - * size of the trampoline section name so DLLView does't get lost. + * size of the trampoline section name so DLLView doesn't get lost. */ siz = sym_count * sizeof(struct local_symbol); diff --git a/drivers/staging/tty/specialix.c b/drivers/staging/tty/specialix.c index cb24c6d999db..5c3598ec7456 100644 --- a/drivers/staging/tty/specialix.c +++ b/drivers/staging/tty/specialix.c @@ -978,7 +978,7 @@ static void sx_change_speed(struct specialix_board *bp, spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_CAR, port_No(port)); - /* The Specialix board does't implement the RTS lines. + /* The Specialix board doesn't implement the RTS lines. They are used to set the IRQ level. Don't touch them. */ if (sx_crtscts(tty)) port->MSVR = MSVR_DTR | (sx_in(bp, CD186x_MSVR) & MSVR_RTS); diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c index 0f02a4b12ae4..4f4f13321f40 100644 --- a/drivers/staging/usbip/vhci_hcd.c +++ b/drivers/staging/usbip/vhci_hcd.c @@ -876,8 +876,10 @@ static void vhci_shutdown_connection(struct usbip_device *ud) } /* kill threads related to this sdev, if v.c. exists */ - kthread_stop(vdev->ud.tcp_rx); - kthread_stop(vdev->ud.tcp_tx); + if (vdev->ud.tcp_rx) + kthread_stop(vdev->ud.tcp_rx); + if (vdev->ud.tcp_tx) + kthread_stop(vdev->ud.tcp_tx); usbip_uinfo("stop threads\n"); @@ -949,9 +951,6 @@ static void vhci_device_init(struct vhci_device *vdev) { memset(vdev, 0, sizeof(*vdev)); - vdev->ud.tcp_rx = kthread_create(vhci_rx_loop, &vdev->ud, "vhci_rx"); - vdev->ud.tcp_tx = kthread_create(vhci_tx_loop, &vdev->ud, "vhci_tx"); - vdev->ud.side = USBIP_VHCI; vdev->ud.status = VDEV_ST_NULL; /* vdev->ud.lock = SPIN_LOCK_UNLOCKED; */ @@ -1139,7 +1138,7 @@ static int vhci_hcd_probe(struct platform_device *pdev) usbip_uerr("create hcd failed\n"); return -ENOMEM; } - + hcd->has_tt = 1; /* this is private data for vhci_hcd */ the_controller = hcd_to_vhci(hcd); diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c index 3f2459f30415..e2dadbd5ef1e 100644 --- a/drivers/staging/usbip/vhci_sysfs.c +++ b/drivers/staging/usbip/vhci_sysfs.c @@ -21,6 +21,7 @@ #include "vhci.h" #include +#include /* TODO: refine locking ?*/ @@ -220,13 +221,13 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, vdev->ud.tcp_socket = socket; vdev->ud.status = VDEV_ST_NOTASSIGNED; - wake_up_process(vdev->ud.tcp_rx); - wake_up_process(vdev->ud.tcp_tx); - spin_unlock(&vdev->ud.lock); 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"); + rh_port_connect(rhport, speed); return count; diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 6a71f52c59b1..76378397b763 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c @@ -273,7 +273,7 @@ int prism2_del_key(struct wiphy *wiphy, struct net_device *dev, } int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_index) + u8 key_index, bool unicast, bool multicast) { wlandevice_t *wlandev = dev->ml_priv; diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig index 9ef2dbbfa62b..5cb0f0ef6af0 100644 --- a/drivers/target/Kconfig +++ b/drivers/target/Kconfig @@ -30,5 +30,6 @@ config TCM_PSCSI passthrough access to Linux/SCSI device source "drivers/target/loopback/Kconfig" +source "drivers/target/tcm_fc/Kconfig" endif diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 1178bbfc68fe..21df808a992c 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -24,3 +24,5 @@ obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o # Fabric modules obj-$(CONFIG_LOOPBACK_TARGET) += loopback/ + +obj-$(CONFIG_TCM_FC) += tcm_fc/ diff --git a/drivers/target/tcm_fc/Kconfig b/drivers/target/tcm_fc/Kconfig new file mode 100644 index 000000000000..40caf458e89e --- /dev/null +++ b/drivers/target/tcm_fc/Kconfig @@ -0,0 +1,5 @@ +config TCM_FC + tristate "TCM_FC fabric Plugin" + depends on LIBFC + help + Say Y here to enable the TCM FC plugin for accessing FC fabrics in TCM diff --git a/drivers/target/tcm_fc/Makefile b/drivers/target/tcm_fc/Makefile new file mode 100644 index 000000000000..7a5c2b64cf65 --- /dev/null +++ b/drivers/target/tcm_fc/Makefile @@ -0,0 +1,15 @@ +EXTRA_CFLAGS += -I$(srctree)/drivers/target/ \ + -I$(srctree)/drivers/scsi/ \ + -I$(srctree)/include/scsi/ \ + -I$(srctree)/drivers/target/tcm_fc/ + +tcm_fc-y += tfc_cmd.o \ + tfc_conf.o \ + tfc_io.o \ + tfc_sess.o + +obj-$(CONFIG_TCM_FC) += tcm_fc.o + +ifdef CONFIGFS_TCM_FC_DEBUG +EXTRA_CFLAGS += -DTCM_FC_DEBUG +endif diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h new file mode 100644 index 000000000000..defff32b7880 --- /dev/null +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2010 Cisco Systems, Inc. + * + * 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. + */ +#ifndef __TCM_FC_H__ +#define __TCM_FC_H__ + +#define FT_VERSION "0.3" + +#define FT_NAMELEN 32 /* length of ASCII WWPNs including pad */ +#define FT_TPG_NAMELEN 32 /* max length of TPG name */ +#define FT_LUN_NAMELEN 32 /* max length of LUN name */ + +/* + * Debug options. + */ +#define FT_DEBUG_CONF 0x01 /* configuration messages */ +#define FT_DEBUG_SESS 0x02 /* session messages */ +#define FT_DEBUG_TM 0x04 /* TM operations */ +#define FT_DEBUG_IO 0x08 /* I/O commands */ +#define FT_DEBUG_DATA 0x10 /* Data transfer */ + +extern unsigned int ft_debug_logging; /* debug options */ + +#define FT_DEBUG(mask, fmt, args...) \ + do { \ + if (ft_debug_logging & (mask)) \ + printk(KERN_INFO "tcm_fc: %s: " fmt, \ + __func__, ##args); \ + } while (0) + +#define FT_CONF_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_CONF, fmt, ##args) +#define FT_SESS_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_SESS, fmt, ##args) +#define FT_TM_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_TM, fmt, ##args) +#define FT_IO_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_IO, fmt, ##args) +#define FT_DATA_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_DATA, fmt, ##args) + +struct ft_transport_id { + __u8 format; + __u8 __resvd1[7]; + __u8 wwpn[8]; + __u8 __resvd2[8]; +} __attribute__((__packed__)); + +/* + * Session (remote port). + */ +struct ft_sess { + u32 port_id; /* for hash lookup use only */ + u32 params; + u16 max_frame; /* maximum frame size */ + u64 port_name; /* port name for transport ID */ + struct ft_tport *tport; + struct se_session *se_sess; + struct hlist_node hash; /* linkage in ft_sess_hash table */ + struct rcu_head rcu; + struct kref kref; /* ref for hash and outstanding I/Os */ +}; + +/* + * Hash table of sessions per local port. + * Hash lookup by remote port FC_ID. + */ +#define FT_SESS_HASH_BITS 6 +#define FT_SESS_HASH_SIZE (1 << FT_SESS_HASH_BITS) + +/* + * Per local port data. + * This is created only after a TPG exists that allows target function + * for the local port. If the TPG exists, this is allocated when + * we're notified that the local port has been created, or when + * the first PRLI provider callback is received. + */ +struct ft_tport { + struct fc_lport *lport; + struct ft_tpg *tpg; /* NULL if TPG deleted before tport */ + u32 sess_count; /* number of sessions in hash */ + struct rcu_head rcu; + struct hlist_head hash[FT_SESS_HASH_SIZE]; /* list of sessions */ +}; + +/* + * Node ID and authentication. + */ +struct ft_node_auth { + u64 port_name; + u64 node_name; +}; + +/* + * Node ACL for FC remote port session. + */ +struct ft_node_acl { + struct ft_node_auth node_auth; + struct se_node_acl se_node_acl; +}; + +struct ft_lun { + u32 index; + char name[FT_LUN_NAMELEN]; +}; + +/* + * Target portal group (local port). + */ +struct ft_tpg { + u32 index; + struct ft_lport_acl *lport_acl; + struct ft_tport *tport; /* active tport or NULL */ + struct list_head list; /* linkage in ft_lport_acl tpg_list */ + struct list_head lun_list; /* head of LUNs */ + struct se_portal_group se_tpg; + struct task_struct *thread; /* processing thread */ + struct se_queue_obj qobj; /* queue for processing thread */ +}; + +struct ft_lport_acl { + u64 wwpn; + char name[FT_NAMELEN]; + struct list_head list; + struct list_head tpg_list; + struct se_wwn fc_lport_wwn; +}; + +enum ft_cmd_state { + FC_CMD_ST_NEW = 0, + FC_CMD_ST_REJ +}; + +/* + * Commands + */ +struct ft_cmd { + enum ft_cmd_state state; + u16 lun; /* LUN from request */ + struct ft_sess *sess; /* session held for cmd */ + struct fc_seq *seq; /* sequence in exchange mgr */ + struct se_cmd se_cmd; /* Local TCM I/O descriptor */ + struct fc_frame *req_frame; + unsigned char *cdb; /* pointer to CDB inside frame */ + u32 write_data_len; /* data received on writes */ + struct se_queue_req se_req; + /* Local sense buffer */ + unsigned char ft_sense_buffer[TRANSPORT_SENSE_BUFFER]; + u32 was_ddp_setup:1; /* Set only if ddp is setup */ + struct scatterlist *sg; /* Set only if DDP is setup */ + u32 sg_cnt; /* No. of item in scatterlist */ +}; + +extern struct list_head ft_lport_list; +extern struct mutex ft_lport_lock; +extern struct fc4_prov ft_prov; +extern struct target_fabric_configfs *ft_configfs; + +/* + * Fabric methods. + */ + +/* + * Session ops. + */ +void ft_sess_put(struct ft_sess *); +int ft_sess_shutdown(struct se_session *); +void ft_sess_close(struct se_session *); +void ft_sess_stop(struct se_session *, int, int); +int ft_sess_logged_in(struct se_session *); +u32 ft_sess_get_index(struct se_session *); +u32 ft_sess_get_port_name(struct se_session *, unsigned char *, u32); +void ft_sess_set_erl0(struct se_session *); + +void ft_lport_add(struct fc_lport *, void *); +void ft_lport_del(struct fc_lport *, void *); +int ft_lport_notify(struct notifier_block *, unsigned long, void *); + +/* + * IO methods. + */ +void ft_check_stop_free(struct se_cmd *); +void ft_release_cmd(struct se_cmd *); +int ft_queue_status(struct se_cmd *); +int ft_queue_data_in(struct se_cmd *); +int ft_write_pending(struct se_cmd *); +int ft_write_pending_status(struct se_cmd *); +u32 ft_get_task_tag(struct se_cmd *); +int ft_get_cmd_state(struct se_cmd *); +void ft_new_cmd_failure(struct se_cmd *); +int ft_queue_tm_resp(struct se_cmd *); +int ft_is_state_remove(struct se_cmd *); + +/* + * other internal functions. + */ +int ft_thread(void *); +void ft_recv_req(struct ft_sess *, struct fc_frame *); +struct ft_tpg *ft_lport_find_tpg(struct fc_lport *); +struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *); + +void ft_recv_write_data(struct ft_cmd *, struct fc_frame *); +void ft_dump_cmd(struct ft_cmd *, const char *caller); + +ssize_t ft_format_wwn(char *, size_t, u64); + +#endif /* __TCM_FC_H__ */ diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c new file mode 100644 index 000000000000..49e51778f733 --- /dev/null +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -0,0 +1,696 @@ +/* + * Copyright (c) 2010 Cisco Systems, Inc. + * + * 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. + */ + +/* XXX TBD some includes may be extraneous */ + +#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 "tcm_fc.h" + +/* + * Dump cmd state for debugging. + */ +void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) +{ + struct fc_exch *ep; + struct fc_seq *sp; + struct se_cmd *se_cmd; + struct se_mem *mem; + struct se_transport_task *task; + + if (!(ft_debug_logging & FT_DEBUG_IO)) + return; + + se_cmd = &cmd->se_cmd; + printk(KERN_INFO "%s: cmd %p state %d sess %p seq %p se_cmd %p\n", + caller, cmd, cmd->state, cmd->sess, cmd->seq, se_cmd); + printk(KERN_INFO "%s: cmd %p cdb %p\n", + caller, cmd, cmd->cdb); + printk(KERN_INFO "%s: cmd %p lun %d\n", caller, cmd, cmd->lun); + + task = T_TASK(se_cmd); + printk(KERN_INFO "%s: cmd %p task %p se_num %u buf %p len %u se_cmd_flags <0x%x>\n", + caller, cmd, task, task->t_tasks_se_num, + task->t_task_buf, se_cmd->data_length, se_cmd->se_cmd_flags); + if (task->t_mem_list) + list_for_each_entry(mem, task->t_mem_list, se_list) + printk(KERN_INFO "%s: cmd %p mem %p page %p " + "len 0x%x off 0x%x\n", + caller, cmd, mem, + mem->se_page, mem->se_len, mem->se_off); + sp = cmd->seq; + if (sp) { + ep = fc_seq_exch(sp); + printk(KERN_INFO "%s: cmd %p sid %x did %x " + "ox_id %x rx_id %x seq_id %x e_stat %x\n", + caller, cmd, ep->sid, ep->did, ep->oxid, ep->rxid, + sp->id, ep->esb_stat); + } + print_hex_dump(KERN_INFO, "ft_dump_cmd ", DUMP_PREFIX_NONE, + 16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0); +} + +/* + * Get LUN from CDB. + */ +static int ft_get_lun_for_cmd(struct ft_cmd *cmd, u8 *lunp) +{ + u64 lun; + + lun = lunp[1]; + switch (lunp[0] >> 6) { + case 0: + break; + case 1: + lun |= (lunp[0] & 0x3f) << 8; + break; + default: + return -1; + } + if (lun >= TRANSPORT_MAX_LUNS_PER_TPG) + return -1; + cmd->lun = lun; + return transport_get_lun_for_cmd(&cmd->se_cmd, NULL, lun); +} + +static void ft_queue_cmd(struct ft_sess *sess, struct ft_cmd *cmd) +{ + struct se_queue_obj *qobj; + unsigned long flags; + + qobj = &sess->tport->tpg->qobj; + spin_lock_irqsave(&qobj->cmd_queue_lock, flags); + list_add_tail(&cmd->se_req.qr_list, &qobj->qobj_list); + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + atomic_inc(&qobj->queue_cnt); + wake_up_interruptible(&qobj->thread_wq); +} + +static struct ft_cmd *ft_dequeue_cmd(struct se_queue_obj *qobj) +{ + unsigned long flags; + struct se_queue_req *qr; + + spin_lock_irqsave(&qobj->cmd_queue_lock, flags); + if (list_empty(&qobj->qobj_list)) { + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + return NULL; + } + qr = list_first_entry(&qobj->qobj_list, struct se_queue_req, qr_list); + list_del(&qr->qr_list); + atomic_dec(&qobj->queue_cnt); + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + return container_of(qr, struct ft_cmd, se_req); +} + +static void ft_free_cmd(struct ft_cmd *cmd) +{ + struct fc_frame *fp; + struct fc_lport *lport; + + if (!cmd) + return; + fp = cmd->req_frame; + lport = fr_dev(fp); + if (fr_seq(fp)) + lport->tt.seq_release(fr_seq(fp)); + fc_frame_free(fp); + ft_sess_put(cmd->sess); /* undo get from lookup at recv */ + kfree(cmd); +} + +void ft_release_cmd(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + + ft_free_cmd(cmd); +} + +void ft_check_stop_free(struct se_cmd *se_cmd) +{ + transport_generic_free_cmd(se_cmd, 0, 1, 0); +} + +/* + * Send response. + */ +int ft_queue_status(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + struct fc_frame *fp; + struct fcp_resp_with_ext *fcp; + struct fc_lport *lport; + struct fc_exch *ep; + size_t len; + + ft_dump_cmd(cmd, __func__); + ep = fc_seq_exch(cmd->seq); + lport = ep->lp; + len = sizeof(*fcp) + se_cmd->scsi_sense_length; + fp = fc_frame_alloc(lport, len); + if (!fp) { + /* XXX shouldn't just drop it - requeue and retry? */ + return 0; + } + fcp = fc_frame_payload_get(fp, len); + memset(fcp, 0, len); + fcp->resp.fr_status = se_cmd->scsi_status; + + len = se_cmd->scsi_sense_length; + if (len) { + fcp->resp.fr_flags |= FCP_SNS_LEN_VAL; + fcp->ext.fr_sns_len = htonl(len); + memcpy((fcp + 1), se_cmd->sense_buffer, len); + } + + /* + * Test underflow and overflow with one mask. Usually both are off. + * Bidirectional commands are not handled yet. + */ + if (se_cmd->se_cmd_flags & (SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT)) { + if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) + fcp->resp.fr_flags |= FCP_RESID_OVER; + else + fcp->resp.fr_flags |= FCP_RESID_UNDER; + fcp->ext.fr_resid = cpu_to_be32(se_cmd->residual_count); + } + + /* + * Send response. + */ + cmd->seq = lport->tt.seq_start_next(cmd->seq); + fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP, + FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0); + + lport->tt.seq_send(lport, cmd->seq, fp); + lport->tt.exch_done(cmd->seq); + return 0; +} + +int ft_write_pending_status(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + + return cmd->write_data_len != se_cmd->data_length; +} + +/* + * Send TX_RDY (transfer ready). + */ +int ft_write_pending(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + struct fc_frame *fp; + struct fcp_txrdy *txrdy; + struct fc_lport *lport; + struct fc_exch *ep; + struct fc_frame_header *fh; + u32 f_ctl; + + ft_dump_cmd(cmd, __func__); + + ep = fc_seq_exch(cmd->seq); + lport = ep->lp; + fp = fc_frame_alloc(lport, sizeof(*txrdy)); + if (!fp) + return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + + txrdy = fc_frame_payload_get(fp, sizeof(*txrdy)); + memset(txrdy, 0, sizeof(*txrdy)); + txrdy->ft_burst_len = htonl(se_cmd->data_length); + + cmd->seq = lport->tt.seq_start_next(cmd->seq); + fc_fill_fc_hdr(fp, FC_RCTL_DD_DATA_DESC, ep->did, ep->sid, FC_TYPE_FCP, + FC_FC_EX_CTX | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); + + fh = fc_frame_header_get(fp); + f_ctl = ntoh24(fh->fh_f_ctl); + + /* Only if it is 'Exchange Responder' */ + if (f_ctl & FC_FC_EX_CTX) { + /* Target is 'exchange responder' and sending XFER_READY + * to 'exchange initiator (initiator)' + */ + 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) { + /* + * Map se_mem list to scatterlist, so that + * DDP can be setup. DDP setup function require + * scatterlist. se_mem_list is internal to + * TCM/LIO target + */ + transport_do_task_sg_chain(se_cmd); + cmd->sg = T_TASK(se_cmd)->t_tasks_sg_chained; + cmd->sg_cnt = + T_TASK(se_cmd)->t_tasks_sg_chained_no; + } + if (cmd->sg && lport->tt.ddp_setup(lport, ep->xid, + cmd->sg, cmd->sg_cnt)) + cmd->was_ddp_setup = 1; + } + } + lport->tt.seq_send(lport, cmd->seq, fp); + return 0; +} + +u32 ft_get_task_tag(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + + return fc_seq_exch(cmd->seq)->rxid; +} + +int ft_get_cmd_state(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + + return cmd->state; +} + +int ft_is_state_remove(struct se_cmd *se_cmd) +{ + return 0; /* XXX TBD */ +} + +void ft_new_cmd_failure(struct se_cmd *se_cmd) +{ + /* XXX TBD */ + printk(KERN_INFO "%s: se_cmd %p\n", __func__, se_cmd); +} + +/* + * FC sequence response handler for follow-on sequences (data) and aborts. + */ +static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) +{ + struct ft_cmd *cmd = arg; + struct fc_frame_header *fh; + + if (IS_ERR(fp)) { + /* XXX need to find cmd if queued */ + cmd->se_cmd.t_state = TRANSPORT_REMOVE; + cmd->seq = NULL; + transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0); + return; + } + + fh = fc_frame_header_get(fp); + + switch (fh->fh_r_ctl) { + case FC_RCTL_DD_SOL_DATA: /* write data */ + ft_recv_write_data(cmd, fp); + break; + case FC_RCTL_DD_UNSOL_CTL: /* command */ + case FC_RCTL_DD_SOL_CTL: /* transfer ready */ + case FC_RCTL_DD_DATA_DESC: /* transfer ready */ + default: + printk(KERN_INFO "%s: unhandled frame r_ctl %x\n", + __func__, fh->fh_r_ctl); + fc_frame_free(fp); + transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0); + break; + } +} + +/* + * Send a FCP response including SCSI status and optional FCP rsp_code. + * status is SAM_STAT_GOOD (zero) iff code is valid. + * This is used in error cases, such as allocation failures. + */ +static void ft_send_resp_status(struct fc_lport *lport, + const struct fc_frame *rx_fp, + u32 status, enum fcp_resp_rsp_codes code) +{ + struct fc_frame *fp; + struct fc_seq *sp; + const struct fc_frame_header *fh; + size_t len; + struct fcp_resp_with_ext *fcp; + struct fcp_resp_rsp_info *info; + + fh = fc_frame_header_get(rx_fp); + FT_IO_DBG("FCP error response: did %x oxid %x status %x code %x\n", + ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), status, code); + len = sizeof(*fcp); + if (status == SAM_STAT_GOOD) + len += sizeof(*info); + fp = fc_frame_alloc(lport, len); + if (!fp) + return; + fcp = fc_frame_payload_get(fp, len); + memset(fcp, 0, len); + fcp->resp.fr_status = status; + if (status == SAM_STAT_GOOD) { + fcp->ext.fr_rsp_len = htonl(sizeof(*info)); + fcp->resp.fr_flags |= FCP_RSP_LEN_VAL; + info = (struct fcp_resp_rsp_info *)(fcp + 1); + info->rsp_code = code; + } + + fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0); + sp = fr_seq(fp); + if (sp) + lport->tt.seq_send(lport, sp, fp); + else + lport->tt.frame_send(lport, fp); +} + +/* + * Send error or task management response. + * Always frees the cmd and associated state. + */ +static void ft_send_resp_code(struct ft_cmd *cmd, enum fcp_resp_rsp_codes code) +{ + ft_send_resp_status(cmd->sess->tport->lport, + cmd->req_frame, SAM_STAT_GOOD, code); + ft_free_cmd(cmd); +} + +/* + * Handle Task Management Request. + */ +static void ft_send_tm(struct ft_cmd *cmd) +{ + struct se_tmr_req *tmr; + struct fcp_cmnd *fcp; + u8 tm_func; + + fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); + + switch (fcp->fc_tm_flags) { + case FCP_TMF_LUN_RESET: + tm_func = TMR_LUN_RESET; + if (ft_get_lun_for_cmd(cmd, fcp->fc_lun) < 0) { + ft_dump_cmd(cmd, __func__); + transport_send_check_condition_and_sense(&cmd->se_cmd, + cmd->se_cmd.scsi_sense_reason, 0); + ft_sess_put(cmd->sess); + return; + } + break; + case FCP_TMF_TGT_RESET: + tm_func = TMR_TARGET_WARM_RESET; + break; + case FCP_TMF_CLR_TASK_SET: + tm_func = TMR_CLEAR_TASK_SET; + break; + case FCP_TMF_ABT_TASK_SET: + tm_func = TMR_ABORT_TASK_SET; + break; + case FCP_TMF_CLR_ACA: + tm_func = TMR_CLEAR_ACA; + break; + default: + /* + * FCP4r01 indicates having a combination of + * tm_flags set is invalid. + */ + FT_TM_DBG("invalid FCP tm_flags %x\n", fcp->fc_tm_flags); + ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); + return; + } + + FT_TM_DBG("alloc tm cmd fn %d\n", tm_func); + tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func); + if (!tmr) { + FT_TM_DBG("alloc failed\n"); + ft_send_resp_code(cmd, FCP_TMF_FAILED); + return; + } + cmd->se_cmd.se_tmr_req = tmr; + transport_generic_handle_tmr(&cmd->se_cmd); +} + +/* + * Send status from completed task management request. + */ +int ft_queue_tm_resp(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + struct se_tmr_req *tmr = se_cmd->se_tmr_req; + enum fcp_resp_rsp_codes code; + + switch (tmr->response) { + case TMR_FUNCTION_COMPLETE: + code = FCP_TMF_CMPL; + break; + case TMR_LUN_DOES_NOT_EXIST: + code = FCP_TMF_INVALID_LUN; + break; + case TMR_FUNCTION_REJECTED: + code = FCP_TMF_REJECTED; + break; + case TMR_TASK_DOES_NOT_EXIST: + case TMR_TASK_STILL_ALLEGIANT: + case TMR_TASK_FAILOVER_NOT_SUPPORTED: + case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED: + case TMR_FUNCTION_AUTHORIZATION_FAILED: + default: + code = FCP_TMF_FAILED; + break; + } + FT_TM_DBG("tmr fn %d resp %d fcp code %d\n", + tmr->function, tmr->response, code); + ft_send_resp_code(cmd, code); + return 0; +} + +/* + * Handle incoming FCP command. + */ +static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) +{ + struct ft_cmd *cmd; + struct fc_lport *lport = sess->tport->lport; + + cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); + if (!cmd) + goto busy; + cmd->sess = sess; + cmd->seq = lport->tt.seq_assign(lport, fp); + if (!cmd->seq) { + kfree(cmd); + goto busy; + } + cmd->req_frame = fp; /* hold frame during cmd */ + ft_queue_cmd(sess, cmd); + return; + +busy: + FT_IO_DBG("cmd or seq allocation failure - sending BUSY\n"); + ft_send_resp_status(lport, fp, SAM_STAT_BUSY, 0); + fc_frame_free(fp); + ft_sess_put(sess); /* undo get from lookup */ +} + + +/* + * Handle incoming FCP frame. + * Caller has verified that the frame is type FCP. + */ +void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp) +{ + struct fc_frame_header *fh = fc_frame_header_get(fp); + + switch (fh->fh_r_ctl) { + case FC_RCTL_DD_UNSOL_CMD: /* command */ + ft_recv_cmd(sess, fp); + break; + case FC_RCTL_DD_SOL_DATA: /* write data */ + case FC_RCTL_DD_UNSOL_CTL: + case FC_RCTL_DD_SOL_CTL: + case FC_RCTL_DD_DATA_DESC: /* transfer ready */ + case FC_RCTL_ELS4_REQ: /* SRR, perhaps */ + default: + printk(KERN_INFO "%s: unhandled frame r_ctl %x\n", + __func__, fh->fh_r_ctl); + fc_frame_free(fp); + ft_sess_put(sess); /* undo get from lookup */ + break; + } +} + +/* + * Send new command to target. + */ +static void ft_send_cmd(struct ft_cmd *cmd) +{ + struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); + struct se_cmd *se_cmd; + struct fcp_cmnd *fcp; + int data_dir; + u32 data_len; + int task_attr; + int ret; + + fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); + if (!fcp) + goto err; + + if (fcp->fc_flags & FCP_CFL_LEN_MASK) + goto err; /* not handling longer CDBs yet */ + + if (fcp->fc_tm_flags) { + task_attr = FCP_PTA_SIMPLE; + data_dir = DMA_NONE; + data_len = 0; + } else { + switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) { + case 0: + data_dir = DMA_NONE; + break; + case FCP_CFL_RDDATA: + data_dir = DMA_FROM_DEVICE; + break; + case FCP_CFL_WRDATA: + data_dir = DMA_TO_DEVICE; + break; + case FCP_CFL_WRDATA | FCP_CFL_RDDATA: + goto err; /* TBD not supported by tcm_fc yet */ + } + + /* FCP_PTA_ maps 1:1 to TASK_ATTR_ */ + task_attr = fcp->fc_pri_ta & FCP_PTA_MASK; + data_len = ntohl(fcp->fc_dl); + cmd->cdb = fcp->fc_cdb; + } + + se_cmd = &cmd->se_cmd; + /* + * Initialize struct se_cmd descriptor from target_core_mod + * infrastructure + */ + transport_init_se_cmd(se_cmd, &ft_configfs->tf_ops, cmd->sess->se_sess, + data_len, data_dir, task_attr, + &cmd->ft_sense_buffer[0]); + /* + * Check for FCP task management flags + */ + if (fcp->fc_tm_flags) { + ft_send_tm(cmd); + return; + } + + fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); + + ret = ft_get_lun_for_cmd(cmd, fcp->fc_lun); + if (ret < 0) { + ft_dump_cmd(cmd, __func__); + transport_send_check_condition_and_sense(&cmd->se_cmd, + cmd->se_cmd.scsi_sense_reason, 0); + return; + } + + ret = transport_generic_allocate_tasks(se_cmd, cmd->cdb); + + FT_IO_DBG("r_ctl %x alloc task ret %d\n", fh->fh_r_ctl, ret); + ft_dump_cmd(cmd, __func__); + + if (ret == -1) { + transport_send_check_condition_and_sense(se_cmd, + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); + transport_generic_free_cmd(se_cmd, 0, 1, 0); + return; + } + if (ret == -2) { + if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) + ft_queue_status(se_cmd); + else + transport_send_check_condition_and_sense(se_cmd, + se_cmd->scsi_sense_reason, 0); + transport_generic_free_cmd(se_cmd, 0, 1, 0); + return; + } + transport_generic_handle_cdb(se_cmd); + return; + +err: + ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); + return; +} + +/* + * Handle request in the command thread. + */ +static void ft_exec_req(struct ft_cmd *cmd) +{ + FT_IO_DBG("cmd state %x\n", cmd->state); + switch (cmd->state) { + case FC_CMD_ST_NEW: + ft_send_cmd(cmd); + break; + default: + break; + } +} + +/* + * Processing thread. + * Currently one thread per tpg. + */ +int ft_thread(void *arg) +{ + struct ft_tpg *tpg = arg; + struct se_queue_obj *qobj = &tpg->qobj; + struct ft_cmd *cmd; + int ret; + + set_user_nice(current, -20); + + while (!kthread_should_stop()) { + ret = wait_event_interruptible(qobj->thread_wq, + atomic_read(&qobj->queue_cnt) || kthread_should_stop()); + if (ret < 0 || kthread_should_stop()) + goto out; + cmd = ft_dequeue_cmd(qobj); + if (cmd) + ft_exec_req(cmd); + } + +out: + return 0; +} diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c new file mode 100644 index 000000000000..fcdbbffe88cc --- /dev/null +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -0,0 +1,677 @@ +/******************************************************************************* + * Filename: tcm_fc.c + * + * This file contains the configfs implementation for TCM_fc fabric node. + * Based on tcm_loop_configfs.c + * + * Copyright (c) 2010 Cisco Systems, Inc. + * Copyright (c) 2009,2010 Rising Tide, Inc. + * Copyright (c) 2009,2010 Linux-iSCSI.org + * + * Copyright (c) 2009,2010 Nicholas A. Bellinger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tcm_fc.h" + +struct target_fabric_configfs *ft_configfs; + +LIST_HEAD(ft_lport_list); +DEFINE_MUTEX(ft_lport_lock); + +unsigned int ft_debug_logging; +module_param_named(debug_logging, ft_debug_logging, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); + +/* + * Parse WWN. + * If strict, we require lower-case hex and colon separators to be sure + * the name is the same as what would be generated by ft_format_wwn() + * so the name and wwn are mapped one-to-one. + */ +static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict) +{ + const char *cp; + char c; + u32 nibble; + u32 byte = 0; + u32 pos = 0; + u32 err; + + *wwn = 0; + for (cp = name; cp < &name[FT_NAMELEN - 1]; cp++) { + c = *cp; + if (c == '\n' && cp[1] == '\0') + continue; + if (strict && pos++ == 2 && byte++ < 7) { + pos = 0; + if (c == ':') + continue; + err = 1; + goto fail; + } + if (c == '\0') { + err = 2; + if (strict && byte != 8) + goto fail; + return cp - name; + } + err = 3; + if (isdigit(c)) + nibble = c - '0'; + else if (isxdigit(c) && (islower(c) || !strict)) + nibble = tolower(c) - 'a' + 10; + else + goto fail; + *wwn = (*wwn << 4) | nibble; + } + err = 4; +fail: + FT_CONF_DBG("err %u len %zu pos %u byte %u\n", + err, cp - name, pos, byte); + return -1; +} + +ssize_t ft_format_wwn(char *buf, size_t len, u64 wwn) +{ + u8 b[8]; + + put_unaligned_be64(wwn, b); + return snprintf(buf, len, + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", + b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); +} + +static ssize_t ft_wwn_show(void *arg, char *buf) +{ + u64 *wwn = arg; + ssize_t len; + + len = ft_format_wwn(buf, PAGE_SIZE - 2, *wwn); + buf[len++] = '\n'; + return len; +} + +static ssize_t ft_wwn_store(void *arg, const char *buf, size_t len) +{ + ssize_t ret; + u64 wwn; + + ret = ft_parse_wwn(buf, &wwn, 0); + if (ret > 0) + *(u64 *)arg = wwn; + return ret; +} + +/* + * ACL auth ops. + */ + +static ssize_t ft_nacl_show_port_name( + struct se_node_acl *se_nacl, + char *page) +{ + struct ft_node_acl *acl = container_of(se_nacl, + struct ft_node_acl, se_node_acl); + + return ft_wwn_show(&acl->node_auth.port_name, page); +} + +static ssize_t ft_nacl_store_port_name( + struct se_node_acl *se_nacl, + const char *page, + size_t count) +{ + struct ft_node_acl *acl = container_of(se_nacl, + struct ft_node_acl, se_node_acl); + + return ft_wwn_store(&acl->node_auth.port_name, page, count); +} + +TF_NACL_BASE_ATTR(ft, port_name, S_IRUGO | S_IWUSR); + +static ssize_t ft_nacl_show_node_name( + struct se_node_acl *se_nacl, + char *page) +{ + struct ft_node_acl *acl = container_of(se_nacl, + struct ft_node_acl, se_node_acl); + + return ft_wwn_show(&acl->node_auth.node_name, page); +} + +static ssize_t ft_nacl_store_node_name( + struct se_node_acl *se_nacl, + const char *page, + size_t count) +{ + struct ft_node_acl *acl = container_of(se_nacl, + struct ft_node_acl, se_node_acl); + + return ft_wwn_store(&acl->node_auth.node_name, page, count); +} + +TF_NACL_BASE_ATTR(ft, node_name, S_IRUGO | S_IWUSR); + +static struct configfs_attribute *ft_nacl_base_attrs[] = { + &ft_nacl_port_name.attr, + &ft_nacl_node_name.attr, + NULL, +}; + +/* + * ACL ops. + */ + +/* + * Add ACL for an initiator. The ACL is named arbitrarily. + * The port_name and/or node_name are attributes. + */ +static struct se_node_acl *ft_add_acl( + struct se_portal_group *se_tpg, + struct config_group *group, + const char *name) +{ + struct ft_node_acl *acl; + struct ft_tpg *tpg; + u64 wwpn; + u32 q_depth; + + FT_CONF_DBG("add acl %s\n", name); + tpg = container_of(se_tpg, struct ft_tpg, se_tpg); + + if (ft_parse_wwn(name, &wwpn, 1) < 0) + return ERR_PTR(-EINVAL); + + acl = kzalloc(sizeof(struct ft_node_acl), GFP_KERNEL); + if (!(acl)) + return ERR_PTR(-ENOMEM); + acl->node_auth.port_name = wwpn; + + q_depth = 32; /* XXX bogus default - get from tpg? */ + return core_tpg_add_initiator_node_acl(&tpg->se_tpg, + &acl->se_node_acl, name, q_depth); +} + +static void ft_del_acl(struct se_node_acl *se_acl) +{ + struct se_portal_group *se_tpg = se_acl->se_tpg; + struct ft_tpg *tpg; + struct ft_node_acl *acl = container_of(se_acl, + struct ft_node_acl, se_node_acl); + + FT_CONF_DBG("del acl %s\n", + config_item_name(&se_acl->acl_group.cg_item)); + + tpg = container_of(se_tpg, struct ft_tpg, se_tpg); + FT_CONF_DBG("del acl %p se_acl %p tpg %p se_tpg %p\n", + acl, se_acl, tpg, &tpg->se_tpg); + + core_tpg_del_initiator_node_acl(&tpg->se_tpg, se_acl, 1); + kfree(acl); +} + +struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) +{ + struct ft_node_acl *found = NULL; + struct ft_node_acl *acl; + struct se_portal_group *se_tpg = &tpg->se_tpg; + struct se_node_acl *se_acl; + + spin_lock_bh(&se_tpg->acl_node_lock); + list_for_each_entry(se_acl, &se_tpg->acl_node_list, acl_list) { + acl = container_of(se_acl, struct ft_node_acl, se_node_acl); + FT_CONF_DBG("acl %p port_name %llx\n", + acl, (unsigned long long)acl->node_auth.port_name); + if (acl->node_auth.port_name == rdata->ids.port_name || + acl->node_auth.node_name == rdata->ids.node_name) { + FT_CONF_DBG("acl %p port_name %llx matched\n", acl, + (unsigned long long)rdata->ids.port_name); + found = acl; + /* XXX need to hold onto ACL */ + break; + } + } + spin_unlock_bh(&se_tpg->acl_node_lock); + return found; +} + +struct se_node_acl *ft_tpg_alloc_fabric_acl(struct se_portal_group *se_tpg) +{ + struct ft_node_acl *acl; + + acl = kzalloc(sizeof(*acl), GFP_KERNEL); + if (!(acl)) { + printk(KERN_ERR "Unable to allocate struct ft_node_acl\n"); + return NULL; + } + FT_CONF_DBG("acl %p\n", acl); + return &acl->se_node_acl; +} + +static void ft_tpg_release_fabric_acl(struct se_portal_group *se_tpg, + struct se_node_acl *se_acl) +{ + struct ft_node_acl *acl = container_of(se_acl, + struct ft_node_acl, se_node_acl); + + FT_CONF_DBG(KERN_INFO "acl %p\n", acl); + kfree(acl); +} + +/* + * local_port port_group (tpg) ops. + */ +static struct se_portal_group *ft_add_tpg( + struct se_wwn *wwn, + struct config_group *group, + const char *name) +{ + struct ft_lport_acl *lacl; + struct ft_tpg *tpg; + unsigned long index; + int ret; + + FT_CONF_DBG("tcm_fc: add tpg %s\n", name); + + /* + * Name must be "tpgt_" followed by the index. + */ + if (strstr(name, "tpgt_") != name) + return NULL; + if (strict_strtoul(name + 5, 10, &index) || index > UINT_MAX) + return NULL; + + lacl = container_of(wwn, struct ft_lport_acl, fc_lport_wwn); + tpg = kzalloc(sizeof(*tpg), GFP_KERNEL); + if (!tpg) + return NULL; + tpg->index = index; + tpg->lport_acl = lacl; + INIT_LIST_HEAD(&tpg->lun_list); + transport_init_queue_obj(&tpg->qobj); + + ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, + (void *)tpg, TRANSPORT_TPG_TYPE_NORMAL); + if (ret < 0) { + kfree(tpg); + return NULL; + } + + tpg->thread = kthread_run(ft_thread, tpg, "ft_tpg%lu", index); + if (IS_ERR(tpg->thread)) { + kfree(tpg); + return NULL; + } + + mutex_lock(&ft_lport_lock); + list_add_tail(&tpg->list, &lacl->tpg_list); + mutex_unlock(&ft_lport_lock); + + return &tpg->se_tpg; +} + +static void ft_del_tpg(struct se_portal_group *se_tpg) +{ + struct ft_tpg *tpg = container_of(se_tpg, struct ft_tpg, se_tpg); + + FT_CONF_DBG("del tpg %s\n", + config_item_name(&tpg->se_tpg.tpg_group.cg_item)); + + kthread_stop(tpg->thread); + + /* Wait for sessions to be freed thru RCU, for BUG_ON below */ + synchronize_rcu(); + + mutex_lock(&ft_lport_lock); + list_del(&tpg->list); + if (tpg->tport) { + tpg->tport->tpg = NULL; + tpg->tport = NULL; + } + mutex_unlock(&ft_lport_lock); + + core_tpg_deregister(se_tpg); + kfree(tpg); +} + +/* + * Verify that an lport is configured to use the tcm_fc module, and return + * the target port group that should be used. + * + * The caller holds ft_lport_lock. + */ +struct ft_tpg *ft_lport_find_tpg(struct fc_lport *lport) +{ + struct ft_lport_acl *lacl; + struct ft_tpg *tpg; + + list_for_each_entry(lacl, &ft_lport_list, list) { + if (lacl->wwpn == lport->wwpn) { + list_for_each_entry(tpg, &lacl->tpg_list, list) + return tpg; /* XXX for now return first entry */ + return NULL; + } + } + return NULL; +} + +/* + * target config instance ops. + */ + +/* + * Add lport to allowed config. + * The name is the WWPN in lower-case ASCII, colon-separated bytes. + */ +static struct se_wwn *ft_add_lport( + struct target_fabric_configfs *tf, + struct config_group *group, + const char *name) +{ + struct ft_lport_acl *lacl; + struct ft_lport_acl *old_lacl; + u64 wwpn; + + FT_CONF_DBG("add lport %s\n", name); + if (ft_parse_wwn(name, &wwpn, 1) < 0) + return NULL; + lacl = kzalloc(sizeof(*lacl), GFP_KERNEL); + if (!lacl) + return NULL; + lacl->wwpn = wwpn; + INIT_LIST_HEAD(&lacl->tpg_list); + + mutex_lock(&ft_lport_lock); + list_for_each_entry(old_lacl, &ft_lport_list, list) { + if (old_lacl->wwpn == wwpn) { + mutex_unlock(&ft_lport_lock); + kfree(lacl); + return NULL; + } + } + list_add_tail(&lacl->list, &ft_lport_list); + ft_format_wwn(lacl->name, sizeof(lacl->name), wwpn); + mutex_unlock(&ft_lport_lock); + + return &lacl->fc_lport_wwn; +} + +static void ft_del_lport(struct se_wwn *wwn) +{ + struct ft_lport_acl *lacl = container_of(wwn, + struct ft_lport_acl, fc_lport_wwn); + + FT_CONF_DBG("del lport %s\n", + config_item_name(&wwn->wwn_group.cg_item)); + mutex_lock(&ft_lport_lock); + list_del(&lacl->list); + mutex_unlock(&ft_lport_lock); + + kfree(lacl); +} + +static ssize_t ft_wwn_show_attr_version( + struct target_fabric_configfs *tf, + char *page) +{ + return sprintf(page, "TCM FC " FT_VERSION " on %s/%s on " + ""UTS_RELEASE"\n", utsname()->sysname, utsname()->machine); +} + +TF_WWN_ATTR_RO(ft, version); + +static struct configfs_attribute *ft_wwn_attrs[] = { + &ft_wwn_version.attr, + NULL, +}; + +static char *ft_get_fabric_name(void) +{ + return "fc"; +} + +static char *ft_get_fabric_wwn(struct se_portal_group *se_tpg) +{ + struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; + + return tpg->lport_acl->name; +} + +static u16 ft_get_tag(struct se_portal_group *se_tpg) +{ + struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; + + /* + * This tag is used when forming SCSI Name identifier in EVPD=1 0x83 + * to represent the SCSI Target Port. + */ + return tpg->index; +} + +static u32 ft_get_default_depth(struct se_portal_group *se_tpg) +{ + return 1; +} + +static int ft_check_false(struct se_portal_group *se_tpg) +{ + return 0; +} + +static void ft_set_default_node_attr(struct se_node_acl *se_nacl) +{ +} + +static u16 ft_get_fabric_sense_len(void) +{ + return 0; +} + +static u16 ft_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_len) +{ + return 0; +} + +static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg) +{ + struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; + + return tpg->index; +} + +static u64 ft_pack_lun(unsigned int index) +{ + WARN_ON(index >= 256); + /* Caller wants this byte-swapped */ + return cpu_to_le64((index & 0xff) << 8); +} + +static struct target_core_fabric_ops ft_fabric_ops = { + .get_fabric_name = ft_get_fabric_name, + .get_fabric_proto_ident = fc_get_fabric_proto_ident, + .tpg_get_wwn = ft_get_fabric_wwn, + .tpg_get_tag = ft_get_tag, + .tpg_get_default_depth = ft_get_default_depth, + .tpg_get_pr_transport_id = fc_get_pr_transport_id, + .tpg_get_pr_transport_id_len = fc_get_pr_transport_id_len, + .tpg_parse_pr_out_transport_id = fc_parse_pr_out_transport_id, + .tpg_check_demo_mode = ft_check_false, + .tpg_check_demo_mode_cache = ft_check_false, + .tpg_check_demo_mode_write_protect = ft_check_false, + .tpg_check_prod_mode_write_protect = ft_check_false, + .tpg_alloc_fabric_acl = ft_tpg_alloc_fabric_acl, + .tpg_release_fabric_acl = ft_tpg_release_fabric_acl, + .tpg_get_inst_index = ft_tpg_get_inst_index, + .check_stop_free = ft_check_stop_free, + .release_cmd_to_pool = ft_release_cmd, + .release_cmd_direct = ft_release_cmd, + .shutdown_session = ft_sess_shutdown, + .close_session = ft_sess_close, + .stop_session = ft_sess_stop, + .fall_back_to_erl0 = ft_sess_set_erl0, + .sess_logged_in = ft_sess_logged_in, + .sess_get_index = ft_sess_get_index, + .sess_get_initiator_sid = NULL, + .write_pending = ft_write_pending, + .write_pending_status = ft_write_pending_status, + .set_default_node_attributes = ft_set_default_node_attr, + .get_task_tag = ft_get_task_tag, + .get_cmd_state = ft_get_cmd_state, + .new_cmd_failure = ft_new_cmd_failure, + .queue_data_in = ft_queue_data_in, + .queue_status = ft_queue_status, + .queue_tm_rsp = ft_queue_tm_resp, + .get_fabric_sense_len = ft_get_fabric_sense_len, + .set_fabric_sense_len = ft_set_fabric_sense_len, + .is_state_remove = ft_is_state_remove, + .pack_lun = ft_pack_lun, + /* + * Setup function pointers for generic logic in + * target_core_fabric_configfs.c + */ + .fabric_make_wwn = &ft_add_lport, + .fabric_drop_wwn = &ft_del_lport, + .fabric_make_tpg = &ft_add_tpg, + .fabric_drop_tpg = &ft_del_tpg, + .fabric_post_link = NULL, + .fabric_pre_unlink = NULL, + .fabric_make_np = NULL, + .fabric_drop_np = NULL, + .fabric_make_nodeacl = &ft_add_acl, + .fabric_drop_nodeacl = &ft_del_acl, +}; + +int ft_register_configfs(void) +{ + struct target_fabric_configfs *fabric; + int ret; + + /* + * Register the top level struct config_item_type with TCM core + */ + fabric = target_fabric_configfs_init(THIS_MODULE, "fc"); + if (!fabric) { + printk(KERN_INFO "%s: target_fabric_configfs_init() failed!\n", + __func__); + return -1; + } + 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 + */ + TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = ft_wwn_attrs; + TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = NULL; + 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 = + ft_nacl_base_attrs; + 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; + /* + * register the fabric for use within TCM + */ + ret = target_fabric_configfs_register(fabric); + if (ret < 0) { + FT_CONF_DBG("target_fabric_configfs_register() for" + " FC Target failed!\n"); + printk(KERN_INFO + "%s: target_fabric_configfs_register() failed!\n", + __func__); + target_fabric_configfs_free(fabric); + return -1; + } + + /* + * Setup our local pointer to *fabric. + */ + ft_configfs = fabric; + return 0; +} + +void ft_deregister_configfs(void) +{ + if (!ft_configfs) + return; + target_fabric_configfs_deregister(ft_configfs); + ft_configfs = NULL; +} + +static struct notifier_block ft_notifier = { + .notifier_call = ft_lport_notify +}; + +static int __init ft_init(void) +{ + if (ft_register_configfs()) + return -1; + if (fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov)) { + ft_deregister_configfs(); + return -1; + } + blocking_notifier_chain_register(&fc_lport_notifier_head, &ft_notifier); + fc_lport_iterate(ft_lport_add, NULL); + return 0; +} + +static void __exit ft_exit(void) +{ + blocking_notifier_chain_unregister(&fc_lport_notifier_head, + &ft_notifier); + fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov); + fc_lport_iterate(ft_lport_del, NULL); + ft_deregister_configfs(); + synchronize_rcu(); +} + +#ifdef MODULE +MODULE_DESCRIPTION("FC TCM fabric driver " FT_VERSION); +MODULE_LICENSE("GPL"); +module_init(ft_init); +module_exit(ft_exit); +#endif /* MODULE */ diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c new file mode 100644 index 000000000000..4c3c0efbe13f --- /dev/null +++ b/drivers/target/tcm_fc/tfc_io.c @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2010 Cisco Systems, Inc. + * + * Portions based on tcm_loop_fabric_scsi.c and libfc/fc_fcp.c + * + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Red Hat, Inc. All rights reserved. + * Copyright (c) 2008 Mike Christie + * Copyright (c) 2009 Rising Tide, Inc. + * Copyright (c) 2009 Linux-iSCSI.org + * Copyright (c) 2009 Nicholas A. Bellinger + * + * 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. + */ + +/* XXX TBD some includes may be extraneous */ + +#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 "tcm_fc.h" + +/* + * Deliver read data back to initiator. + * XXX TBD handle resource problems later. + */ +int ft_queue_data_in(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + struct se_transport_task *task; + struct fc_frame *fp = NULL; + struct fc_exch *ep; + struct fc_lport *lport; + struct se_mem *mem; + size_t remaining; + u32 f_ctl = FC_FC_EX_CTX | FC_FC_REL_OFF; + u32 mem_off; + u32 fh_off = 0; + u32 frame_off = 0; + size_t frame_len = 0; + size_t mem_len; + size_t tlen; + size_t off_in_page; + struct page *page; + int use_sg; + int error; + void *page_addr; + void *from; + void *to = NULL; + + ep = fc_seq_exch(cmd->seq); + lport = ep->lp; + cmd->seq = lport->tt.seq_start_next(cmd->seq); + + task = T_TASK(se_cmd); + BUG_ON(!task); + remaining = se_cmd->data_length; + + /* + * Setup to use first mem list entry if any. + */ + if (task->t_tasks_se_num) { + mem = list_first_entry(task->t_mem_list, + struct se_mem, se_list); + mem_len = mem->se_len; + mem_off = mem->se_off; + page = mem->se_page; + } else { + mem = NULL; + mem_len = remaining; + mem_off = 0; + page = NULL; + } + + /* no scatter/gather in skb for odd word length due to fc_seq_send() */ + use_sg = !(remaining % 4); + + while (remaining) { + if (!mem_len) { + BUG_ON(!mem); + mem = list_entry(mem->se_list.next, + struct se_mem, se_list); + mem_len = min((size_t)mem->se_len, remaining); + mem_off = mem->se_off; + page = mem->se_page; + } + if (!frame_len) { + /* + * If lport's has capability of Large Send Offload LSO) + * , then allow 'frame_len' to be as big as 'lso_max' + * if indicated transfer length is >= lport->lso_max + */ + frame_len = (lport->seq_offload) ? lport->lso_max : + cmd->sess->max_frame; + frame_len = min(frame_len, remaining); + fp = fc_frame_alloc(lport, use_sg ? 0 : frame_len); + if (!fp) + return -ENOMEM; + to = fc_frame_payload_get(fp, 0); + fh_off = frame_off; + frame_off += frame_len; + /* + * Setup the frame's max payload which is used by base + * driver to indicate HW about max frame size, so that + * HW can do fragmentation appropriately based on + * "gso_max_size" of underline netdev. + */ + fr_max_payload(fp) = cmd->sess->max_frame; + } + tlen = min(mem_len, frame_len); + + if (use_sg) { + if (!mem) { + BUG_ON(!task->t_task_buf); + page_addr = task->t_task_buf + mem_off; + /* + * In this case, offset is 'offset_in_page' of + * (t_task_buf + mem_off) instead of 'mem_off'. + */ + off_in_page = offset_in_page(page_addr); + page = virt_to_page(page_addr); + tlen = min(tlen, PAGE_SIZE - off_in_page); + } else + off_in_page = mem_off; + BUG_ON(!page); + get_page(page); + skb_fill_page_desc(fp_skb(fp), + skb_shinfo(fp_skb(fp))->nr_frags, + page, off_in_page, tlen); + fr_len(fp) += tlen; + fp_skb(fp)->data_len += tlen; + fp_skb(fp)->truesize += + PAGE_SIZE << compound_order(page); + } else if (mem) { + BUG_ON(!page); + from = kmap_atomic(page + (mem_off >> PAGE_SHIFT), + KM_SOFTIRQ0); + page_addr = from; + from += mem_off & ~PAGE_MASK; + tlen = min(tlen, (size_t)(PAGE_SIZE - + (mem_off & ~PAGE_MASK))); + memcpy(to, from, tlen); + kunmap_atomic(page_addr, KM_SOFTIRQ0); + to += tlen; + } else { + from = task->t_task_buf + mem_off; + memcpy(to, from, tlen); + to += tlen; + } + + mem_off += tlen; + mem_len -= tlen; + frame_len -= tlen; + remaining -= tlen; + + if (frame_len && + (skb_shinfo(fp_skb(fp))->nr_frags < FC_FRAME_SG_LEN)) + continue; + if (!remaining) + f_ctl |= FC_FC_END_SEQ; + fc_fill_fc_hdr(fp, FC_RCTL_DD_SOL_DATA, ep->did, ep->sid, + FC_TYPE_FCP, f_ctl, fh_off); + error = lport->tt.seq_send(lport, cmd->seq, fp); + if (error) { + /* XXX For now, initiator will retry */ + if (printk_ratelimit()) + printk(KERN_ERR "%s: Failed to send frame %p, " + "xid <0x%x>, remaining <0x%x>, " + "lso_max <0x%x>\n", + __func__, fp, ep->xid, + remaining, lport->lso_max); + } + } + return ft_queue_status(se_cmd); +} + +/* + * Receive write data frame. + */ +void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) +{ + struct se_cmd *se_cmd = &cmd->se_cmd; + struct fc_seq *seq = cmd->seq; + struct fc_exch *ep; + struct fc_lport *lport; + struct se_transport_task *task; + struct fc_frame_header *fh; + struct se_mem *mem; + u32 mem_off; + u32 rel_off; + size_t frame_len; + size_t mem_len; + size_t tlen; + struct page *page; + void *page_addr; + void *from; + void *to; + u32 f_ctl; + void *buf; + + task = T_TASK(se_cmd); + BUG_ON(!task); + + fh = fc_frame_header_get(fp); + if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF)) + goto drop; + + /* + * Doesn't expect even single byte of payload. Payload + * is expected to be copied directly to user buffers + * due to DDP (Large Rx offload) feature, hence + * BUG_ON if BUF is non-NULL + */ + buf = fc_frame_payload_get(fp, 1); + if (cmd->was_ddp_setup && buf) { + printk(KERN_INFO "%s: When DDP was setup, not expected to" + "receive frame with payload, Payload shall be" + "copied directly to buffer instead of coming " + "via. legacy receive queues\n", __func__); + BUG_ON(buf); + } + + /* + * If ft_cmd indicated 'ddp_setup', in that case only the last frame + * should come with 'TSI bit being set'. If 'TSI bit is not set and if + * data frame appears here, means error condition. In both the cases + * release the DDP context (ddp_put) and in error case, as well + * initiate error recovery mechanism. + */ + ep = fc_seq_exch(seq); + if (cmd->was_ddp_setup) { + BUG_ON(!ep); + lport = ep->lp; + BUG_ON(!lport); + } + if (cmd->was_ddp_setup && ep->xid != FC_XID_UNKNOWN) { + f_ctl = ntoh24(fh->fh_f_ctl); + /* + * If TSI bit set in f_ctl, means last write data frame is + * received successfully where payload is posted directly + * to user buffer and only the last frame's header is posted + * in legacy receive queue + */ + if (f_ctl & FC_FC_SEQ_INIT) { /* TSI bit set in FC frame */ + cmd->write_data_len = lport->tt.ddp_done(lport, + ep->xid); + goto last_frame; + } else { + /* + * Updating the write_data_len may be meaningless at + * this point, but just in case if required in future + * for debugging or any other purpose + */ + printk(KERN_ERR "%s: Received frame with TSI bit not" + " being SET, dropping the frame, " + "cmd->sg <%p>, cmd->sg_cnt <0x%x>\n", + __func__, cmd->sg, cmd->sg_cnt); + cmd->write_data_len = lport->tt.ddp_done(lport, + ep->xid); + lport->tt.seq_exch_abort(cmd->seq, 0); + goto drop; + } + } + + rel_off = ntohl(fh->fh_parm_offset); + frame_len = fr_len(fp); + if (frame_len <= sizeof(*fh)) + goto drop; + frame_len -= sizeof(*fh); + from = fc_frame_payload_get(fp, 0); + if (rel_off >= se_cmd->data_length) + goto drop; + if (frame_len + rel_off > se_cmd->data_length) + frame_len = se_cmd->data_length - rel_off; + + /* + * Setup to use first mem list entry if any. + */ + if (task->t_tasks_se_num) { + mem = list_first_entry(task->t_mem_list, + struct se_mem, se_list); + mem_len = mem->se_len; + mem_off = mem->se_off; + page = mem->se_page; + } else { + mem = NULL; + page = NULL; + mem_off = 0; + mem_len = frame_len; + } + + while (frame_len) { + if (!mem_len) { + BUG_ON(!mem); + mem = list_entry(mem->se_list.next, + struct se_mem, se_list); + mem_len = mem->se_len; + mem_off = mem->se_off; + page = mem->se_page; + } + if (rel_off >= mem_len) { + rel_off -= mem_len; + mem_len = 0; + continue; + } + mem_off += rel_off; + mem_len -= rel_off; + rel_off = 0; + + tlen = min(mem_len, frame_len); + + if (mem) { + to = kmap_atomic(page + (mem_off >> PAGE_SHIFT), + KM_SOFTIRQ0); + page_addr = to; + to += mem_off & ~PAGE_MASK; + tlen = min(tlen, (size_t)(PAGE_SIZE - + (mem_off & ~PAGE_MASK))); + memcpy(to, from, tlen); + kunmap_atomic(page_addr, KM_SOFTIRQ0); + } else { + to = task->t_task_buf + mem_off; + memcpy(to, from, tlen); + } + from += tlen; + frame_len -= tlen; + mem_off += tlen; + mem_len -= tlen; + cmd->write_data_len += tlen; + } +last_frame: + if (cmd->write_data_len == se_cmd->data_length) + transport_generic_handle_data(se_cmd); +drop: + fc_frame_free(fp); +} diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c new file mode 100644 index 000000000000..a3bd57f2ea32 --- /dev/null +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -0,0 +1,541 @@ +/* + * Copyright (c) 2010 Cisco Systems, Inc. + * + * 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. + */ + +/* XXX TBD some includes may be extraneous */ + +#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 + +#include +#include "tcm_fc.h" + +static void ft_sess_delete_all(struct ft_tport *); + +/* + * Lookup or allocate target local port. + * Caller holds ft_lport_lock. + */ +static struct ft_tport *ft_tport_create(struct fc_lport *lport) +{ + struct ft_tpg *tpg; + struct ft_tport *tport; + int i; + + tport = rcu_dereference(lport->prov[FC_TYPE_FCP]); + if (tport && tport->tpg) + return tport; + + tpg = ft_lport_find_tpg(lport); + if (!tpg) + return NULL; + + if (tport) { + tport->tpg = tpg; + return tport; + } + + tport = kzalloc(sizeof(*tport), GFP_KERNEL); + if (!tport) + return NULL; + + tport->lport = lport; + tport->tpg = tpg; + tpg->tport = tport; + for (i = 0; i < FT_SESS_HASH_SIZE; i++) + INIT_HLIST_HEAD(&tport->hash[i]); + + rcu_assign_pointer(lport->prov[FC_TYPE_FCP], tport); + return tport; +} + +/* + * Free tport via RCU. + */ +static void ft_tport_rcu_free(struct rcu_head *rcu) +{ + struct ft_tport *tport = container_of(rcu, struct ft_tport, rcu); + + kfree(tport); +} + +/* + * Delete a target local port. + * Caller holds ft_lport_lock. + */ +static void ft_tport_delete(struct ft_tport *tport) +{ + struct fc_lport *lport; + struct ft_tpg *tpg; + + ft_sess_delete_all(tport); + lport = tport->lport; + BUG_ON(tport != lport->prov[FC_TYPE_FCP]); + rcu_assign_pointer(lport->prov[FC_TYPE_FCP], NULL); + + tpg = tport->tpg; + if (tpg) { + tpg->tport = NULL; + tport->tpg = NULL; + } + call_rcu(&tport->rcu, ft_tport_rcu_free); +} + +/* + * Add local port. + * Called thru fc_lport_iterate(). + */ +void ft_lport_add(struct fc_lport *lport, void *arg) +{ + mutex_lock(&ft_lport_lock); + ft_tport_create(lport); + mutex_unlock(&ft_lport_lock); +} + +/* + * Delete local port. + * Called thru fc_lport_iterate(). + */ +void ft_lport_del(struct fc_lport *lport, void *arg) +{ + struct ft_tport *tport; + + mutex_lock(&ft_lport_lock); + tport = lport->prov[FC_TYPE_FCP]; + if (tport) + ft_tport_delete(tport); + mutex_unlock(&ft_lport_lock); +} + +/* + * Notification of local port change from libfc. + * Create or delete local port and associated tport. + */ +int ft_lport_notify(struct notifier_block *nb, unsigned long event, void *arg) +{ + struct fc_lport *lport = arg; + + switch (event) { + case FC_LPORT_EV_ADD: + ft_lport_add(lport, NULL); + break; + case FC_LPORT_EV_DEL: + ft_lport_del(lport, NULL); + break; + } + return NOTIFY_DONE; +} + +/* + * Hash function for FC_IDs. + */ +static u32 ft_sess_hash(u32 port_id) +{ + return hash_32(port_id, FT_SESS_HASH_BITS); +} + +/* + * Find session in local port. + * Sessions and hash lists are RCU-protected. + * A reference is taken which must be eventually freed. + */ +static struct ft_sess *ft_sess_get(struct fc_lport *lport, u32 port_id) +{ + struct ft_tport *tport; + struct hlist_head *head; + struct hlist_node *pos; + struct ft_sess *sess; + + rcu_read_lock(); + tport = rcu_dereference(lport->prov[FC_TYPE_FCP]); + if (!tport) + goto out; + + head = &tport->hash[ft_sess_hash(port_id)]; + hlist_for_each_entry_rcu(sess, pos, head, hash) { + if (sess->port_id == port_id) { + kref_get(&sess->kref); + rcu_read_unlock(); + FT_SESS_DBG("port_id %x found %p\n", port_id, sess); + return sess; + } + } +out: + rcu_read_unlock(); + FT_SESS_DBG("port_id %x not found\n", port_id); + return NULL; +} + +/* + * Allocate session and enter it in the hash for the local port. + * Caller holds ft_lport_lock. + */ +static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, + struct ft_node_acl *acl) +{ + struct ft_sess *sess; + struct hlist_head *head; + struct hlist_node *pos; + + head = &tport->hash[ft_sess_hash(port_id)]; + hlist_for_each_entry_rcu(sess, pos, head, hash) + if (sess->port_id == port_id) + return sess; + + sess = kzalloc(sizeof(*sess), GFP_KERNEL); + if (!sess) + return NULL; + + sess->se_sess = transport_init_session(); + if (!sess->se_sess) { + kfree(sess); + return NULL; + } + sess->se_sess->se_node_acl = &acl->se_node_acl; + sess->tport = tport; + sess->port_id = port_id; + kref_init(&sess->kref); /* ref for table entry */ + hlist_add_head_rcu(&sess->hash, head); + tport->sess_count++; + + FT_SESS_DBG("port_id %x sess %p\n", port_id, sess); + + transport_register_session(&tport->tpg->se_tpg, &acl->se_node_acl, + sess->se_sess, sess); + return sess; +} + +/* + * Unhash the session. + * Caller holds ft_lport_lock. + */ +static void ft_sess_unhash(struct ft_sess *sess) +{ + struct ft_tport *tport = sess->tport; + + hlist_del_rcu(&sess->hash); + BUG_ON(!tport->sess_count); + tport->sess_count--; + sess->port_id = -1; + sess->params = 0; +} + +/* + * Delete session from hash. + * Caller holds ft_lport_lock. + */ +static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id) +{ + struct hlist_head *head; + struct hlist_node *pos; + struct ft_sess *sess; + + head = &tport->hash[ft_sess_hash(port_id)]; + hlist_for_each_entry_rcu(sess, pos, head, hash) { + if (sess->port_id == port_id) { + ft_sess_unhash(sess); + return sess; + } + } + return NULL; +} + +/* + * Delete all sessions from tport. + * Caller holds ft_lport_lock. + */ +static void ft_sess_delete_all(struct ft_tport *tport) +{ + struct hlist_head *head; + struct hlist_node *pos; + struct ft_sess *sess; + + for (head = tport->hash; + head < &tport->hash[FT_SESS_HASH_SIZE]; head++) { + hlist_for_each_entry_rcu(sess, pos, head, hash) { + ft_sess_unhash(sess); + transport_deregister_session_configfs(sess->se_sess); + ft_sess_put(sess); /* release from table */ + } + } +} + +/* + * TCM ops for sessions. + */ + +/* + * Determine whether session is allowed to be shutdown in the current context. + * Returns non-zero if the session should be shutdown. + */ +int ft_sess_shutdown(struct se_session *se_sess) +{ + struct ft_sess *sess = se_sess->fabric_sess_ptr; + + FT_SESS_DBG("port_id %x\n", sess->port_id); + return 1; +} + +/* + * Remove session and send PRLO. + * This is called when the ACL is being deleted or queue depth is changing. + */ +void ft_sess_close(struct se_session *se_sess) +{ + struct ft_sess *sess = se_sess->fabric_sess_ptr; + struct fc_lport *lport; + u32 port_id; + + mutex_lock(&ft_lport_lock); + lport = sess->tport->lport; + port_id = sess->port_id; + if (port_id == -1) { + mutex_lock(&ft_lport_lock); + return; + } + FT_SESS_DBG("port_id %x\n", port_id); + ft_sess_unhash(sess); + mutex_unlock(&ft_lport_lock); + transport_deregister_session_configfs(se_sess); + ft_sess_put(sess); + /* XXX Send LOGO or PRLO */ + synchronize_rcu(); /* let transport deregister happen */ +} + +void ft_sess_stop(struct se_session *se_sess, int sess_sleep, int conn_sleep) +{ + struct ft_sess *sess = se_sess->fabric_sess_ptr; + + FT_SESS_DBG("port_id %x\n", sess->port_id); +} + +int ft_sess_logged_in(struct se_session *se_sess) +{ + struct ft_sess *sess = se_sess->fabric_sess_ptr; + + return sess->port_id != -1; +} + +u32 ft_sess_get_index(struct se_session *se_sess) +{ + struct ft_sess *sess = se_sess->fabric_sess_ptr; + + return sess->port_id; /* XXX TBD probably not what is needed */ +} + +u32 ft_sess_get_port_name(struct se_session *se_sess, + unsigned char *buf, u32 len) +{ + struct ft_sess *sess = se_sess->fabric_sess_ptr; + + return ft_format_wwn(buf, len, sess->port_name); +} + +void ft_sess_set_erl0(struct se_session *se_sess) +{ + /* XXX TBD called when out of memory */ +} + +/* + * libfc ops involving sessions. + */ + +static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, + const struct fc_els_spp *rspp, struct fc_els_spp *spp) +{ + struct ft_tport *tport; + struct ft_sess *sess; + struct ft_node_acl *acl; + u32 fcp_parm; + + tport = ft_tport_create(rdata->local_port); + if (!tport) + return 0; /* not a target for this local port */ + + acl = ft_acl_get(tport->tpg, rdata); + if (!acl) + return 0; + + if (!rspp) + goto fill; + + if (rspp->spp_flags & (FC_SPP_OPA_VAL | FC_SPP_RPA_VAL)) + return FC_SPP_RESP_NO_PA; + + /* + * If both target and initiator bits are off, the SPP is invalid. + */ + fcp_parm = ntohl(rspp->spp_params); + if (!(fcp_parm & (FCP_SPPF_INIT_FCN | FCP_SPPF_TARG_FCN))) + return FC_SPP_RESP_INVL; + + /* + * Create session (image pair) only if requested by + * EST_IMG_PAIR flag and if the requestor is an initiator. + */ + if (rspp->spp_flags & FC_SPP_EST_IMG_PAIR) { + spp->spp_flags |= FC_SPP_EST_IMG_PAIR; + if (!(fcp_parm & FCP_SPPF_INIT_FCN)) + return FC_SPP_RESP_CONF; + sess = ft_sess_create(tport, rdata->ids.port_id, acl); + if (!sess) + return FC_SPP_RESP_RES; + if (!sess->params) + rdata->prli_count++; + sess->params = fcp_parm; + sess->port_name = rdata->ids.port_name; + sess->max_frame = rdata->maxframe_size; + + /* XXX TBD - clearing actions. unit attn, see 4.10 */ + } + + /* + * OR in our service parameters with other provider (initiator), if any. + * TBD XXX - indicate RETRY capability? + */ +fill: + fcp_parm = ntohl(spp->spp_params); + spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN); + return FC_SPP_RESP_ACK; +} + +/** + * tcm_fcp_prli() - Handle incoming or outgoing PRLI for the FCP target + * @rdata: remote port private + * @spp_len: service parameter page length + * @rspp: received service parameter page (NULL for outgoing PRLI) + * @spp: response service parameter page + * + * Returns spp response code. + */ +static int ft_prli(struct fc_rport_priv *rdata, u32 spp_len, + const struct fc_els_spp *rspp, struct fc_els_spp *spp) +{ + int ret; + + mutex_lock(&ft_lport_lock); + ret = ft_prli_locked(rdata, spp_len, rspp, spp); + mutex_unlock(&ft_lport_lock); + FT_SESS_DBG("port_id %x flags %x ret %x\n", + rdata->ids.port_id, rspp ? rspp->spp_flags : 0, ret); + return ret; +} + +static void ft_sess_rcu_free(struct rcu_head *rcu) +{ + struct ft_sess *sess = container_of(rcu, struct ft_sess, rcu); + + transport_deregister_session(sess->se_sess); + kfree(sess); +} + +static void ft_sess_free(struct kref *kref) +{ + struct ft_sess *sess = container_of(kref, struct ft_sess, kref); + + call_rcu(&sess->rcu, ft_sess_rcu_free); +} + +void ft_sess_put(struct ft_sess *sess) +{ + int sess_held = atomic_read(&sess->kref.refcount); + + BUG_ON(!sess_held); + kref_put(&sess->kref, ft_sess_free); +} + +static void ft_prlo(struct fc_rport_priv *rdata) +{ + struct ft_sess *sess; + struct ft_tport *tport; + + mutex_lock(&ft_lport_lock); + tport = rcu_dereference(rdata->local_port->prov[FC_TYPE_FCP]); + if (!tport) { + mutex_unlock(&ft_lport_lock); + return; + } + sess = ft_sess_delete(tport, rdata->ids.port_id); + if (!sess) { + mutex_unlock(&ft_lport_lock); + return; + } + mutex_unlock(&ft_lport_lock); + transport_deregister_session_configfs(sess->se_sess); + ft_sess_put(sess); /* release from table */ + rdata->prli_count--; + /* XXX TBD - clearing actions. unit attn, see 4.10 */ +} + +/* + * Handle incoming FCP request. + * Caller has verified that the frame is type FCP. + */ +static void ft_recv(struct fc_lport *lport, struct fc_frame *fp) +{ + struct ft_sess *sess; + u32 sid = fc_frame_sid(fp); + + FT_SESS_DBG("sid %x\n", sid); + + sess = ft_sess_get(lport, sid); + if (!sess) { + FT_SESS_DBG("sid %x sess lookup failed\n", sid); + /* TBD XXX - if FCP_CMND, send PRLO */ + fc_frame_free(fp); + return; + } + ft_recv_req(sess, fp); /* must do ft_sess_put() */ +} + +/* + * Provider ops for libfc. + */ +struct fc4_prov ft_prov = { + .prli = ft_prli, + .prlo = ft_prlo, + .recv = ft_recv, + .module = THIS_MODULE, +}; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 47f8cdb207f1..74273e638c0d 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1658,8 +1658,12 @@ static void gsm_queue(struct gsm_mux *gsm) if ((gsm->control & ~PF) == UI) gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len); - /* generate final CRC with received FCS */ - gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs); + if (gsm->encoding == 0){ + /* WARNING: gsm->received_fcs is used for gsm->encoding = 0 only. + In this case it contain the last piece of data + required to generate final CRC */ + gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs); + } if (gsm->fcs != GOOD_FCS) { gsm->bad_fcs++; if (debug & 4) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 80484af781e1..b1f0f83b870d 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1391,6 +1391,14 @@ config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE help Support for Console on the NWP serial ports. +config SERIAL_LANTIQ + bool "Lantiq serial driver" + depends on LANTIQ + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + help + Support for console and UART on Lantiq SoCs. + config SERIAL_QE tristate "Freescale QUICC Engine serial port support" depends on QUICC_ENGINE diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index fee0690ef8e3..35276043d9d1 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -94,3 +94,4 @@ obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o +obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index cb36b0d4ef3c..62df72d9f0aa 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -382,12 +382,13 @@ static void imx_start_tx(struct uart_port *port) static irqreturn_t imx_rtsint(int irq, void *dev_id) { struct imx_port *sport = dev_id; - unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS; + unsigned int val; unsigned long flags; spin_lock_irqsave(&sport->port.lock, flags); writel(USR1_RTSD, sport->port.membase + USR1); + val = readl(sport->port.membase + USR1) & USR1_RTSS; uart_handle_cts_change(&sport->port, !!val); wake_up_interruptible(&sport->port.state->port.delta_msr_wait); diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c new file mode 100644 index 000000000000..58cf279ed879 --- /dev/null +++ b/drivers/tty/serial/lantiq.c @@ -0,0 +1,756 @@ +/* + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2004 Infineon IFAP DC COM CPE + * Copyright (C) 2007 Felix Fietkau + * Copyright (C) 2007 John Crispin + * Copyright (C) 2010 Thomas Langer, + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PORT_LTQ_ASC 111 +#define MAXPORTS 2 +#define UART_DUMMY_UER_RX 1 +#define DRVNAME "ltq_asc" +#ifdef __BIG_ENDIAN +#define LTQ_ASC_TBUF (0x0020 + 3) +#define LTQ_ASC_RBUF (0x0024 + 3) +#else +#define LTQ_ASC_TBUF 0x0020 +#define LTQ_ASC_RBUF 0x0024 +#endif +#define LTQ_ASC_FSTAT 0x0048 +#define LTQ_ASC_WHBSTATE 0x0018 +#define LTQ_ASC_STATE 0x0014 +#define LTQ_ASC_IRNCR 0x00F8 +#define LTQ_ASC_CLC 0x0000 +#define LTQ_ASC_ID 0x0008 +#define LTQ_ASC_PISEL 0x0004 +#define LTQ_ASC_TXFCON 0x0044 +#define LTQ_ASC_RXFCON 0x0040 +#define LTQ_ASC_CON 0x0010 +#define LTQ_ASC_BG 0x0050 +#define LTQ_ASC_IRNREN 0x00F4 + +#define ASC_IRNREN_TX 0x1 +#define ASC_IRNREN_RX 0x2 +#define ASC_IRNREN_ERR 0x4 +#define ASC_IRNREN_TX_BUF 0x8 +#define ASC_IRNCR_TIR 0x1 +#define ASC_IRNCR_RIR 0x2 +#define ASC_IRNCR_EIR 0x4 + +#define ASCOPT_CSIZE 0x3 +#define TXFIFO_FL 1 +#define RXFIFO_FL 1 +#define ASCCLC_DISS 0x2 +#define ASCCLC_RMCMASK 0x0000FF00 +#define ASCCLC_RMCOFFSET 8 +#define ASCCON_M_8ASYNC 0x0 +#define ASCCON_M_7ASYNC 0x2 +#define ASCCON_ODD 0x00000020 +#define ASCCON_STP 0x00000080 +#define ASCCON_BRS 0x00000100 +#define ASCCON_FDE 0x00000200 +#define ASCCON_R 0x00008000 +#define ASCCON_FEN 0x00020000 +#define ASCCON_ROEN 0x00080000 +#define ASCCON_TOEN 0x00100000 +#define ASCSTATE_PE 0x00010000 +#define ASCSTATE_FE 0x00020000 +#define ASCSTATE_ROE 0x00080000 +#define ASCSTATE_ANY (ASCSTATE_ROE|ASCSTATE_PE|ASCSTATE_FE) +#define ASCWHBSTATE_CLRREN 0x00000001 +#define ASCWHBSTATE_SETREN 0x00000002 +#define ASCWHBSTATE_CLRPE 0x00000004 +#define ASCWHBSTATE_CLRFE 0x00000008 +#define ASCWHBSTATE_CLRROE 0x00000020 +#define ASCTXFCON_TXFEN 0x0001 +#define ASCTXFCON_TXFFLU 0x0002 +#define ASCTXFCON_TXFITLMASK 0x3F00 +#define ASCTXFCON_TXFITLOFF 8 +#define ASCRXFCON_RXFEN 0x0001 +#define ASCRXFCON_RXFFLU 0x0002 +#define ASCRXFCON_RXFITLMASK 0x3F00 +#define ASCRXFCON_RXFITLOFF 8 +#define ASCFSTAT_RXFFLMASK 0x003F +#define ASCFSTAT_TXFFLMASK 0x3F00 +#define ASCFSTAT_TXFREEMASK 0x3F000000 +#define ASCFSTAT_TXFREEOFF 24 + +static void lqasc_tx_chars(struct uart_port *port); +static struct ltq_uart_port *lqasc_port[MAXPORTS]; +static struct uart_driver lqasc_reg; +static DEFINE_SPINLOCK(ltq_asc_lock); + +struct ltq_uart_port { + struct uart_port port; + struct clk *clk; + unsigned int tx_irq; + unsigned int rx_irq; + unsigned int err_irq; +}; + +static inline struct +ltq_uart_port *to_ltq_uart_port(struct uart_port *port) +{ + return container_of(port, struct ltq_uart_port, port); +} + +static void +lqasc_stop_tx(struct uart_port *port) +{ + return; +} + +static void +lqasc_start_tx(struct uart_port *port) +{ + unsigned long flags; + spin_lock_irqsave(<q_asc_lock, flags); + lqasc_tx_chars(port); + spin_unlock_irqrestore(<q_asc_lock, flags); + return; +} + +static void +lqasc_stop_rx(struct uart_port *port) +{ + ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE); +} + +static void +lqasc_enable_ms(struct uart_port *port) +{ +} + +static int +lqasc_rx_chars(struct uart_port *port) +{ + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + unsigned int ch = 0, rsr = 0, fifocnt; + + if (!tty) { + dev_dbg(port->dev, "%s:tty is busy now", __func__); + return -EBUSY; + } + fifocnt = + ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK; + while (fifocnt--) { + u8 flag = TTY_NORMAL; + ch = ltq_r8(port->membase + LTQ_ASC_RBUF); + rsr = (ltq_r32(port->membase + LTQ_ASC_STATE) + & ASCSTATE_ANY) | UART_DUMMY_UER_RX; + tty_flip_buffer_push(tty); + port->icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + if (rsr & ASCSTATE_ANY) { + if (rsr & ASCSTATE_PE) { + port->icount.parity++; + ltq_w32_mask(0, ASCWHBSTATE_CLRPE, + port->membase + LTQ_ASC_WHBSTATE); + } else if (rsr & ASCSTATE_FE) { + port->icount.frame++; + ltq_w32_mask(0, ASCWHBSTATE_CLRFE, + port->membase + LTQ_ASC_WHBSTATE); + } + if (rsr & ASCSTATE_ROE) { + port->icount.overrun++; + ltq_w32_mask(0, ASCWHBSTATE_CLRROE, + port->membase + LTQ_ASC_WHBSTATE); + } + + rsr &= port->read_status_mask; + + if (rsr & ASCSTATE_PE) + flag = TTY_PARITY; + else if (rsr & ASCSTATE_FE) + flag = TTY_FRAME; + } + + if ((rsr & port->ignore_status_mask) == 0) + tty_insert_flip_char(tty, ch, flag); + + if (rsr & ASCSTATE_ROE) + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character + */ + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + if (ch != 0) + tty_flip_buffer_push(tty); + tty_kref_put(tty); + return 0; +} + +static void +lqasc_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + if (uart_tx_stopped(port)) { + lqasc_stop_tx(port); + return; + } + + while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) & + ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) { + if (port->x_char) { + ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF); + port->icount.tx++; + port->x_char = 0; + continue; + } + + if (uart_circ_empty(xmit)) + break; + + ltq_w8(port->state->xmit.buf[port->state->xmit.tail], + port->membase + LTQ_ASC_TBUF); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static irqreturn_t +lqasc_tx_int(int irq, void *_port) +{ + unsigned long flags; + struct uart_port *port = (struct uart_port *)_port; + spin_lock_irqsave(<q_asc_lock, flags); + ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR); + spin_unlock_irqrestore(<q_asc_lock, flags); + lqasc_start_tx(port); + return IRQ_HANDLED; +} + +static irqreturn_t +lqasc_err_int(int irq, void *_port) +{ + unsigned long flags; + struct uart_port *port = (struct uart_port *)_port; + spin_lock_irqsave(<q_asc_lock, flags); + /* clear any pending interrupts */ + ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE | + ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE); + spin_unlock_irqrestore(<q_asc_lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t +lqasc_rx_int(int irq, void *_port) +{ + unsigned long flags; + struct uart_port *port = (struct uart_port *)_port; + spin_lock_irqsave(<q_asc_lock, flags); + ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR); + lqasc_rx_chars(port); + spin_unlock_irqrestore(<q_asc_lock, flags); + return IRQ_HANDLED; +} + +static unsigned int +lqasc_tx_empty(struct uart_port *port) +{ + int status; + status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK; + return status ? 0 : TIOCSER_TEMT; +} + +static unsigned int +lqasc_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR; +} + +static void +lqasc_set_mctrl(struct uart_port *port, u_int mctrl) +{ +} + +static void +lqasc_break_ctl(struct uart_port *port, int break_state) +{ +} + +static int +lqasc_startup(struct uart_port *port) +{ + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + int retval; + + port->uartclk = clk_get_rate(ltq_port->clk); + + ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), + port->membase + LTQ_ASC_CLC); + + ltq_w32(0, port->membase + LTQ_ASC_PISEL); + ltq_w32( + ((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) | + ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU, + port->membase + LTQ_ASC_TXFCON); + ltq_w32( + ((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK) + | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU, + port->membase + LTQ_ASC_RXFCON); + /* make sure other settings are written to hardware before + * setting enable bits + */ + wmb(); + ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN | + ASCCON_ROEN, port->membase + LTQ_ASC_CON); + + retval = request_irq(ltq_port->tx_irq, lqasc_tx_int, + IRQF_DISABLED, "asc_tx", port); + if (retval) { + pr_err("failed to request lqasc_tx_int\n"); + return retval; + } + + retval = request_irq(ltq_port->rx_irq, lqasc_rx_int, + IRQF_DISABLED, "asc_rx", port); + if (retval) { + pr_err("failed to request lqasc_rx_int\n"); + goto err1; + } + + retval = request_irq(ltq_port->err_irq, lqasc_err_int, + IRQF_DISABLED, "asc_err", port); + if (retval) { + pr_err("failed to request lqasc_err_int\n"); + goto err2; + } + + ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX, + port->membase + LTQ_ASC_IRNREN); + return 0; + +err2: + free_irq(ltq_port->rx_irq, port); +err1: + free_irq(ltq_port->tx_irq, port); + return retval; +} + +static void +lqasc_shutdown(struct uart_port *port) +{ + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + free_irq(ltq_port->tx_irq, port); + free_irq(ltq_port->rx_irq, port); + free_irq(ltq_port->err_irq, port); + + ltq_w32(0, port->membase + LTQ_ASC_CON); + ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU, + port->membase + LTQ_ASC_RXFCON); + ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU, + port->membase + LTQ_ASC_TXFCON); +} + +static void +lqasc_set_termios(struct uart_port *port, + struct ktermios *new, struct ktermios *old) +{ + unsigned int cflag; + unsigned int iflag; + unsigned int divisor; + unsigned int baud; + unsigned int con = 0; + unsigned long flags; + + cflag = new->c_cflag; + iflag = new->c_iflag; + + switch (cflag & CSIZE) { + case CS7: + con = ASCCON_M_7ASYNC; + break; + + case CS5: + case CS6: + default: + new->c_cflag &= ~ CSIZE; + new->c_cflag |= CS8; + con = ASCCON_M_8ASYNC; + break; + } + + cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ + + if (cflag & CSTOPB) + con |= ASCCON_STP; + + if (cflag & PARENB) { + if (!(cflag & PARODD)) + con &= ~ASCCON_ODD; + else + con |= ASCCON_ODD; + } + + port->read_status_mask = ASCSTATE_ROE; + if (iflag & INPCK) + port->read_status_mask |= ASCSTATE_FE | ASCSTATE_PE; + + port->ignore_status_mask = 0; + if (iflag & IGNPAR) + port->ignore_status_mask |= ASCSTATE_FE | ASCSTATE_PE; + + if (iflag & IGNBRK) { + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (iflag & IGNPAR) + port->ignore_status_mask |= ASCSTATE_ROE; + } + + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_UER_RX; + + /* set error signals - framing, parity and overrun, enable receiver */ + con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN; + + spin_lock_irqsave(<q_asc_lock, flags); + + /* set up CON */ + ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON); + + /* Set baud rate - take a divider of 2 into account */ + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); + divisor = uart_get_divisor(port, baud); + divisor = divisor / 2 - 1; + + /* disable the baudrate generator */ + ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON); + + /* make sure the fractional divider is off */ + ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON); + + /* set up to use divisor of 2 */ + ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON); + + /* now we can write the new baudrate into the register */ + ltq_w32(divisor, port->membase + LTQ_ASC_BG); + + /* turn the baudrate generator back on */ + ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON); + + /* enable rx */ + ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE); + + spin_unlock_irqrestore(<q_asc_lock, flags); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(new)) + tty_termios_encode_baud_rate(new, baud, baud); +} + +static const char* +lqasc_type(struct uart_port *port) +{ + if (port->type == PORT_LTQ_ASC) + return DRVNAME; + else + return NULL; +} + +static void +lqasc_release_port(struct uart_port *port) +{ + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } +} + +static int +lqasc_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *res; + int size; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "cannot obtain I/O memory region"); + return -ENODEV; + } + size = resource_size(res); + + res = devm_request_mem_region(&pdev->dev, res->start, + size, dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, "cannot request I/O memory region"); + return -EBUSY; + } + + if (port->flags & UPF_IOREMAP) { + port->membase = devm_ioremap_nocache(&pdev->dev, + port->mapbase, size); + if (port->membase == NULL) + return -ENOMEM; + } + return 0; +} + +static void +lqasc_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_LTQ_ASC; + lqasc_request_port(port); + } +} + +static int +lqasc_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_LTQ_ASC) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= NR_IRQS) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +static struct uart_ops lqasc_pops = { + .tx_empty = lqasc_tx_empty, + .set_mctrl = lqasc_set_mctrl, + .get_mctrl = lqasc_get_mctrl, + .stop_tx = lqasc_stop_tx, + .start_tx = lqasc_start_tx, + .stop_rx = lqasc_stop_rx, + .enable_ms = lqasc_enable_ms, + .break_ctl = lqasc_break_ctl, + .startup = lqasc_startup, + .shutdown = lqasc_shutdown, + .set_termios = lqasc_set_termios, + .type = lqasc_type, + .release_port = lqasc_release_port, + .request_port = lqasc_request_port, + .config_port = lqasc_config_port, + .verify_port = lqasc_verify_port, +}; + +static void +lqasc_console_putchar(struct uart_port *port, int ch) +{ + int fifofree; + + if (!port->membase) + return; + + do { + fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT) + & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF; + } while (fifofree == 0); + ltq_w8(ch, port->membase + LTQ_ASC_TBUF); +} + + +static void +lqasc_console_write(struct console *co, const char *s, u_int count) +{ + struct ltq_uart_port *ltq_port; + struct uart_port *port; + unsigned long flags; + + if (co->index >= MAXPORTS) + return; + + ltq_port = lqasc_port[co->index]; + if (!ltq_port) + return; + + port = <q_port->port; + + spin_lock_irqsave(<q_asc_lock, flags); + uart_console_write(port, s, count, lqasc_console_putchar); + spin_unlock_irqrestore(<q_asc_lock, flags); +} + +static int __init +lqasc_console_setup(struct console *co, char *options) +{ + struct ltq_uart_port *ltq_port; + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= MAXPORTS) + return -ENODEV; + + ltq_port = lqasc_port[co->index]; + if (!ltq_port) + return -ENODEV; + + port = <q_port->port; + + port->uartclk = clk_get_rate(ltq_port->clk); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console lqasc_console = { + .name = "ttyLTQ", + .write = lqasc_console_write, + .device = uart_console_device, + .setup = lqasc_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &lqasc_reg, +}; + +static int __init +lqasc_console_init(void) +{ + register_console(&lqasc_console); + return 0; +} +console_initcall(lqasc_console_init); + +static struct uart_driver lqasc_reg = { + .owner = THIS_MODULE, + .driver_name = DRVNAME, + .dev_name = "ttyLTQ", + .major = 0, + .minor = 0, + .nr = MAXPORTS, + .cons = &lqasc_console, +}; + +static int __init +lqasc_probe(struct platform_device *pdev) +{ + struct ltq_uart_port *ltq_port; + struct uart_port *port; + struct resource *mmres, *irqres; + int tx_irq, rx_irq, err_irq; + struct clk *clk; + int ret; + + mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!mmres || !irqres) + return -ENODEV; + + if (pdev->id >= MAXPORTS) + return -EBUSY; + + if (lqasc_port[pdev->id] != NULL) + return -EBUSY; + + clk = clk_get(&pdev->dev, "fpi"); + if (IS_ERR(clk)) { + pr_err("failed to get fpi clk\n"); + return -ENOENT; + } + + tx_irq = platform_get_irq_byname(pdev, "tx"); + rx_irq = platform_get_irq_byname(pdev, "rx"); + err_irq = platform_get_irq_byname(pdev, "err"); + if ((tx_irq < 0) | (rx_irq < 0) | (err_irq < 0)) + return -ENODEV; + + ltq_port = kzalloc(sizeof(struct ltq_uart_port), GFP_KERNEL); + if (!ltq_port) + return -ENOMEM; + + port = <q_port->port; + + port->iotype = SERIAL_IO_MEM; + port->flags = ASYNC_BOOT_AUTOCONF | UPF_IOREMAP; + port->ops = &lqasc_pops; + port->fifosize = 16; + port->type = PORT_LTQ_ASC, + port->line = pdev->id; + port->dev = &pdev->dev; + + port->irq = tx_irq; /* unused, just to be backward-compatibe */ + port->mapbase = mmres->start; + + ltq_port->clk = clk; + + ltq_port->tx_irq = tx_irq; + ltq_port->rx_irq = rx_irq; + ltq_port->err_irq = err_irq; + + lqasc_port[pdev->id] = ltq_port; + platform_set_drvdata(pdev, ltq_port); + + ret = uart_add_one_port(&lqasc_reg, port); + + return ret; +} + +static struct platform_driver lqasc_driver = { + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +int __init +init_lqasc(void) +{ + int ret; + + ret = uart_register_driver(&lqasc_reg); + if (ret != 0) + return ret; + + ret = platform_driver_probe(&lqasc_driver, lqasc_probe); + if (ret != 0) + uart_unregister_driver(&lqasc_reg); + + return ret; +} + +module_init(init_lqasc); + +MODULE_DESCRIPTION("Lantiq serial port driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 0e8eec516df4..c911b2419abb 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -80,14 +80,17 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, /* * Try to register a serial port */ +static struct of_device_id of_platform_serial_table[]; static int __devinit of_platform_serial_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct of_serial_info *info; struct uart_port port; int port_type; int ret; - if (!ofdev->dev.of_match) + match = of_match_device(of_platform_serial_table, &ofdev->dev); + if (!match) return -EINVAL; if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL)) @@ -97,7 +100,7 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev) if (info == NULL) return -ENOMEM; - port_type = (unsigned long)ofdev->dev.of_match->data; + port_type = (unsigned long)match->data; ret = of_platform_serial_setup(ofdev, port_type, &port); if (ret) goto out; diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 51fe1795d5a8..d2efe823c20d 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -381,7 +381,13 @@ static int uio_get_minor(struct uio_device *idev) retval = -ENOMEM; goto exit; } - idev->minor = id & MAX_ID_MASK; + if (id < UIO_MAX_DEVICES) { + idev->minor = id; + } else { + dev_err(idev->dev, "too many uio devices\n"); + retval = -EINVAL; + idr_remove(&uio_idr, id); + } exit: mutex_unlock(&minor_lock); return retval; @@ -587,14 +593,12 @@ static ssize_t uio_write(struct file *filep, const char __user *buf, static int uio_find_mem_index(struct vm_area_struct *vma) { - int mi; struct uio_device *idev = vma->vm_private_data; - for (mi = 0; mi < MAX_UIO_MAPS; mi++) { - if (idev->info->mem[mi].size == 0) + if (vma->vm_pgoff < MAX_UIO_MAPS) { + if (idev->info->mem[vma->vm_pgoff].size == 0) return -1; - if (vma->vm_pgoff == mi) - return mi; + return (int)vma->vm_pgoff; } return -1; } diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c index 5ffdb483b015..a879fd5741f8 100644 --- a/drivers/uio/uio_netx.c +++ b/drivers/uio/uio_netx.c @@ -18,6 +18,9 @@ #define PCI_VENDOR_ID_HILSCHER 0x15CF #define PCI_DEVICE_ID_HILSCHER_NETX 0x0000 +#define PCI_DEVICE_ID_HILSCHER_NETPLC 0x0010 +#define PCI_SUBDEVICE_ID_NETPLC_RAM 0x0000 +#define PCI_SUBDEVICE_ID_NETPLC_FLASH 0x0001 #define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235 #define PCI_SUBDEVICE_ID_NXPCA 0x3335 @@ -66,6 +69,10 @@ static int __devinit netx_pci_probe(struct pci_dev *dev, bar = 0; info->name = "netx"; break; + case PCI_DEVICE_ID_HILSCHER_NETPLC: + bar = 0; + info->name = "netplc"; + break; default: bar = 2; info->name = "netx_plx"; @@ -133,6 +140,18 @@ static struct pci_device_id netx_pci_ids[] = { .subvendor = 0, .subdevice = 0, }, + { + .vendor = PCI_VENDOR_ID_HILSCHER, + .device = PCI_DEVICE_ID_HILSCHER_NETPLC, + .subvendor = PCI_VENDOR_ID_HILSCHER, + .subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM, + }, + { + .vendor = PCI_VENDOR_ID_HILSCHER, + .device = PCI_DEVICE_ID_HILSCHER_NETPLC, + .subvendor = PCI_VENDOR_ID_HILSCHER, + .subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH, + }, { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9030, diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 7174d518b8a6..0f424af7f109 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -189,6 +189,10 @@ static int uio_pdrv_genirq_remove(struct platform_device *pdev) uio_unregister_device(priv->uioinfo); pm_runtime_disable(&pdev->dev); + + priv->uioinfo->handler = NULL; + priv->uioinfo->irqcontrol = NULL; + kfree(priv); return 0; } diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 36613b37c504..3a68e09309f7 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2539,15 +2539,18 @@ static void qe_udc_release(struct device *dev) } /* Driver probe functions */ +static const struct of_device_id qe_udc_match[]; static int __devinit qe_udc_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct qe_ep *ep; unsigned int ret = 0; unsigned int i; const void *prop; - if (!ofdev->dev.of_match) + match = of_match_device(qe_udc_match, &ofdev->dev); + if (!match) return -EINVAL; prop = of_get_property(np, "mode", NULL); @@ -2561,7 +2564,7 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev) return -ENOMEM; } - udc_controller->soc_type = (unsigned long)ofdev->dev.of_match->data; + udc_controller->soc_type = (unsigned long)match->data; udc_controller->usb_regs = of_iomap(np, 0); if (!udc_controller->usb_regs) { ret = -ENOMEM; diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 48a760220baf..bf6e11c758d5 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index 5408186afc35..ade40066decf 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index cb5cd422f3f5..82fd24935332 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 444b60aa15e9..365c02fc25fc 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 78a39a41547d..57607696735c 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 7e41a95c5ceb..627f3a678759 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -40,6 +40,7 @@ #include #include #include +#include /* EHCI Register Set */ #define EHCI_INSNREG04 (0xA0) @@ -118,6 +119,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) struct ehci_hcd *omap_ehci; int ret = -ENODEV; int irq; + int i; + char supply[7]; if (usb_disabled()) return -ENODEV; @@ -158,6 +161,23 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) hcd->rsrc_len = resource_size(res); hcd->regs = regs; + /* get ehci regulator and enable */ + for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { + if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) { + pdata->regulator[i] = NULL; + continue; + } + snprintf(supply, sizeof(supply), "hsusb%d", i); + pdata->regulator[i] = regulator_get(dev, supply); + if (IS_ERR(pdata->regulator[i])) { + pdata->regulator[i] = NULL; + dev_dbg(dev, + "failed to get ehci port%d regulator\n", i); + } else { + regulator_enable(pdata->regulator[i]); + } + } + ret = omap_usbhs_enable(dev); if (ret) { dev_err(dev, "failed to start usbhs with err %d\n", ret); diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index f97570a847ca..9c37dad3e816 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -81,6 +81,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 795345ad45e6..7b2e69aa2e98 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1633,6 +1633,7 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) ints[i].qh = NULL; ints[i].qtd = NULL; + urb->status = status; isp1760_urb_done(hcd, urb); if (qtd) pe(hcd, qh, qtd); diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 18b7099a8125..fafccc2fd331 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index a78f2ebd11b7..73f75d26436c 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -777,7 +777,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) if (t1 != t2) xhci_writel(xhci, t2, port_array[port_index]); - if (DEV_HIGHSPEED(t1)) { + if (hcd->speed != HCD_USB3) { /* enable remote wake up for USB 2.0 */ u32 __iomem *addr; u32 tmp; @@ -866,6 +866,21 @@ int xhci_bus_resume(struct usb_hcd *hcd) temp |= PORT_LINK_STROBE | XDEV_U0; xhci_writel(xhci, temp, port_array[port_index]); } + /* wait for the port to enter U0 and report port link + * state change. + */ + spin_unlock_irqrestore(&xhci->lock, flags); + msleep(20); + spin_lock_irqsave(&xhci->lock, flags); + + /* Clear PLC */ + temp = xhci_readl(xhci, port_array[port_index]); + if (temp & PORT_PLC) { + temp = xhci_port_state_to_neutral(temp); + temp |= PORT_PLC; + xhci_writel(xhci, temp, port_array[port_index]); + } + slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1); if (slot_id) @@ -873,7 +888,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) } else xhci_writel(xhci, temp, port_array[port_index]); - if (DEV_HIGHSPEED(temp)) { + if (hcd->speed != HCD_USB3) { /* disable remote wake up for USB 2.0 */ u32 __iomem *addr; u32 tmp; diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 6dfbf9ffd7a6..f47c20197c61 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1887,11 +1887,9 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, otg_set_vbus(musb->xceiv, 1); hcd->self.uses_pio_for_control = 1; - - if (musb->xceiv->last_event == USB_EVENT_NONE) - pm_runtime_put(musb->controller); - } + if (musb->xceiv->last_event == USB_EVENT_NONE) + pm_runtime_put(musb->controller); return 0; diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 57a27fa954b4..e9e60b6e0583 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -270,7 +270,7 @@ static int musb_otg_notifications(struct notifier_block *nb, DBG(4, "VBUS Disconnect\n"); #ifdef CONFIG_USB_GADGET_MUSB_HDRC - if (is_otg_enabled(musb)) + if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) if (musb->gadget_driver) #endif { diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 09e52ba47ddf..ffc4193e9505 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -499,7 +499,6 @@ static int isd200_action( struct us_data *us, int action, memset(&ata, 0, sizeof(ata)); srb->cmnd = info->cmnd; srb->device = &srb_dev; - ++srb->serial_number; ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2ab291241635..7aa4eea930f1 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -4,7 +4,7 @@ * Author: Michael S. Tsirkin * * Inspiration, some code, and most witty comments come from - * Documentation/lguest/lguest.c, by Rusty Russell + * Documentation/virtual/lguest/lguest.c, by Rusty Russell * * This work is licensed under the terms of the GNU GPL, version 2. * diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index e6a8d8c0101d..6d139679eb7a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1562,6 +1562,17 @@ config FB_VIA_DIRECT_PROCFS correct output device configuration. Its use is strongly discouraged. +config FB_VIA_X_COMPATIBILITY + bool "X server compatibility" + depends on FB_VIA + default n + help + This option reduces the functionality (power saving, ...) of the + framebuffer to avoid negative impact on the OpenChrome X server. + If you use any X server other than fbdev you should enable this + otherwise it should be safe to disable it and allow using all + features. + endif config FB_NEOMAGIC diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 82acb8dc4aa1..6183a57eb69d 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -66,7 +66,7 @@ * have. Allow 1% either way on the nominal for TVs. */ #define NR_MONTYPES 6 -static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = { +static struct fb_monspecs monspecs[NR_MONTYPES] __devinitdata = { { /* TV */ .hfmin = 15469, .hfmax = 15781, @@ -873,7 +873,7 @@ static struct fb_ops acornfb_ops = { /* * Everything after here is initialisation!!! */ -static struct fb_videomode modedb[] __initdata = { +static struct fb_videomode modedb[] __devinitdata = { { /* 320x256 @ 50Hz */ NULL, 50, 320, 256, 125000, 92, 62, 35, 19, 38, 2, FB_SYNC_COMP_HIGH_ACT, @@ -925,8 +925,7 @@ static struct fb_videomode modedb[] __initdata = { } }; -static struct fb_videomode __initdata -acornfb_default_mode = { +static struct fb_videomode acornfb_default_mode __devinitdata = { .name = NULL, .refresh = 60, .xres = 640, @@ -942,7 +941,7 @@ acornfb_default_mode = { .vmode = FB_VMODE_NONINTERLACED }; -static void __init acornfb_init_fbinfo(void) +static void __devinit acornfb_init_fbinfo(void) { static int first = 1; @@ -1018,8 +1017,7 @@ static void __init acornfb_init_fbinfo(void) * size can optionally be followed by 'M' or 'K' for * MB or KB respectively. */ -static void __init -acornfb_parse_mon(char *opt) +static void __devinit acornfb_parse_mon(char *opt) { char *p = opt; @@ -1066,8 +1064,7 @@ acornfb_parse_mon(char *opt) current_par.montype = -1; } -static void __init -acornfb_parse_montype(char *opt) +static void __devinit acornfb_parse_montype(char *opt) { current_par.montype = -2; @@ -1108,8 +1105,7 @@ acornfb_parse_montype(char *opt) } } -static void __init -acornfb_parse_dram(char *opt) +static void __devinit acornfb_parse_dram(char *opt) { unsigned int size; @@ -1134,15 +1130,14 @@ acornfb_parse_dram(char *opt) static struct options { char *name; void (*parse)(char *opt); -} opt_table[] __initdata = { +} opt_table[] __devinitdata = { { "mon", acornfb_parse_mon }, { "montype", acornfb_parse_montype }, { "dram", acornfb_parse_dram }, { NULL, NULL } }; -int __init -acornfb_setup(char *options) +static int __devinit acornfb_setup(char *options) { struct options *optp; char *opt; @@ -1179,8 +1174,7 @@ acornfb_setup(char *options) * Detect type of monitor connected * For now, we just assume SVGA */ -static int __init -acornfb_detect_monitortype(void) +static int __devinit acornfb_detect_monitortype(void) { return 4; } diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 5b2b5ef4edba..64e41f5448c4 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -3117,7 +3117,7 @@ int __init atafb_init(void) atafb_ops.fb_setcolreg = &falcon_setcolreg; error = request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, - "framebuffer/modeswitch", + "framebuffer:modeswitch", falcon_vbl_switcher); if (error) return error; diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index e0c2284924b6..5aac00eb1830 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -42,9 +42,34 @@ #define FBPIXMAPSIZE (1024 * 8) +static DEFINE_MUTEX(registration_lock); struct fb_info *registered_fb[FB_MAX] __read_mostly; int num_registered_fb __read_mostly; +static struct fb_info *get_fb_info(unsigned int idx) +{ + struct fb_info *fb_info; + + if (idx >= FB_MAX) + return ERR_PTR(-ENODEV); + + mutex_lock(®istration_lock); + fb_info = registered_fb[idx]; + if (fb_info) + atomic_inc(&fb_info->count); + mutex_unlock(®istration_lock); + + return fb_info; +} + +static void put_fb_info(struct fb_info *fb_info) +{ + if (!atomic_dec_and_test(&fb_info->count)) + return; + if (fb_info->fbops->fb_destroy) + fb_info->fbops->fb_destroy(fb_info); +} + int lock_fb_info(struct fb_info *info) { mutex_lock(&info->lock); @@ -647,6 +672,7 @@ int fb_show_logo(struct fb_info *info, int rotate) { return 0; } static void *fb_seq_start(struct seq_file *m, loff_t *pos) { + mutex_lock(®istration_lock); return (*pos < FB_MAX) ? pos : NULL; } @@ -658,6 +684,7 @@ static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos) static void fb_seq_stop(struct seq_file *m, void *v) { + mutex_unlock(®istration_lock); } static int fb_seq_show(struct seq_file *m, void *v) @@ -690,13 +717,30 @@ static const struct file_operations fb_proc_fops = { .release = seq_release, }; +/* + * We hold a reference to the fb_info in file->private_data, + * but if the current registered fb has changed, we don't + * actually want to use it. + * + * So look up the fb_info using the inode minor number, + * and just verify it against the reference we have. + */ +static struct fb_info *file_fb_info(struct file *file) +{ + struct inode *inode = file->f_path.dentry->d_inode; + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + + if (info != file->private_data) + info = NULL; + return info; +} + static ssize_t fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; - struct inode *inode = file->f_path.dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; + struct fb_info *info = file_fb_info(file); u8 *buffer, *dst; u8 __iomem *src; int c, cnt = 0, err = 0; @@ -761,9 +805,7 @@ static ssize_t fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; - struct inode *inode = file->f_path.dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; + struct fb_info *info = file_fb_info(file); u8 *buffer, *src; u8 __iomem *dst; int c, cnt = 0, err = 0; @@ -1141,10 +1183,10 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; + struct fb_info *info = file_fb_info(file); + if (!info) + return -ENODEV; return do_fb_ioctl(info, cmd, arg); } @@ -1265,12 +1307,13 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd, static long fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; - struct fb_ops *fb = info->fbops; + struct fb_info *info = file_fb_info(file); + struct fb_ops *fb; long ret = -ENOIOCTLCMD; + if (!info) + return -ENODEV; + fb = info->fbops; switch(cmd) { case FBIOGET_VSCREENINFO: case FBIOPUT_VSCREENINFO: @@ -1303,16 +1346,18 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, static int fb_mmap(struct file *file, struct vm_area_struct * vma) { - int fbidx = iminor(file->f_path.dentry->d_inode); - struct fb_info *info = registered_fb[fbidx]; - struct fb_ops *fb = info->fbops; + struct fb_info *info = file_fb_info(file); + struct fb_ops *fb; unsigned long off; unsigned long start; u32 len; + if (!info) + return -ENODEV; if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; + fb = info->fbops; if (!fb) return -ENODEV; mutex_lock(&info->mm_lock); @@ -1361,14 +1406,16 @@ __releases(&info->lock) struct fb_info *info; int res = 0; - if (fbidx >= FB_MAX) - return -ENODEV; - info = registered_fb[fbidx]; - if (!info) + info = get_fb_info(fbidx); + if (!info) { request_module("fb%d", fbidx); - info = registered_fb[fbidx]; - if (!info) - return -ENODEV; + info = get_fb_info(fbidx); + if (!info) + return -ENODEV; + } + if (IS_ERR(info)) + return PTR_ERR(info); + mutex_lock(&info->lock); if (!try_module_get(info->fbops->owner)) { res = -ENODEV; @@ -1386,6 +1433,8 @@ __releases(&info->lock) #endif out: mutex_unlock(&info->lock); + if (res) + put_fb_info(info); return res; } @@ -1401,6 +1450,7 @@ __releases(&info->lock) info->fbops->fb_release(info,1); module_put(info->fbops->owner); mutex_unlock(&info->lock); + put_fb_info(info); return 0; } @@ -1487,8 +1537,10 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena, return false; } +static int do_unregister_framebuffer(struct fb_info *fb_info); + #define VGA_FB_PHYS 0xA0000 -void remove_conflicting_framebuffers(struct apertures_struct *a, +static void do_remove_conflicting_framebuffers(struct apertures_struct *a, const char *name, bool primary) { int i; @@ -1510,43 +1562,32 @@ void remove_conflicting_framebuffers(struct apertures_struct *a, printk(KERN_INFO "fb: conflicting fb hw usage " "%s vs %s - removing generic driver\n", name, registered_fb[i]->fix.id); - unregister_framebuffer(registered_fb[i]); + do_unregister_framebuffer(registered_fb[i]); } } } -EXPORT_SYMBOL(remove_conflicting_framebuffers); -/** - * register_framebuffer - registers a frame buffer device - * @fb_info: frame buffer info structure - * - * Registers a frame buffer device @fb_info. - * - * Returns negative errno on error, or zero for success. - * - */ - -int -register_framebuffer(struct fb_info *fb_info) +static int do_register_framebuffer(struct fb_info *fb_info) { int i; struct fb_event event; struct fb_videomode mode; - if (num_registered_fb == FB_MAX) - return -ENXIO; - if (fb_check_foreignness(fb_info)) return -ENOSYS; - remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, + do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, fb_is_primary_device(fb_info)); + if (num_registered_fb == FB_MAX) + return -ENXIO; + num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) break; fb_info->node = i; + atomic_set(&fb_info->count, 1); mutex_init(&fb_info->lock); mutex_init(&fb_info->mm_lock); @@ -1592,6 +1633,69 @@ register_framebuffer(struct fb_info *fb_info) return 0; } +static int do_unregister_framebuffer(struct fb_info *fb_info) +{ + struct fb_event event; + int i, ret = 0; + + i = fb_info->node; + if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) + return -EINVAL; + + if (!lock_fb_info(fb_info)) + return -ENODEV; + event.info = fb_info; + ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); + unlock_fb_info(fb_info); + + if (ret) + return -EINVAL; + + if (fb_info->pixmap.addr && + (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) + kfree(fb_info->pixmap.addr); + fb_destroy_modelist(&fb_info->modelist); + registered_fb[i] = NULL; + num_registered_fb--; + fb_cleanup_device(fb_info); + device_destroy(fb_class, MKDEV(FB_MAJOR, i)); + event.info = fb_info; + fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); + + /* this may free fb info */ + put_fb_info(fb_info); + return 0; +} + +void remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary) +{ + mutex_lock(®istration_lock); + do_remove_conflicting_framebuffers(a, name, primary); + mutex_unlock(®istration_lock); +} +EXPORT_SYMBOL(remove_conflicting_framebuffers); + +/** + * register_framebuffer - registers a frame buffer device + * @fb_info: frame buffer info structure + * + * Registers a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + */ +int +register_framebuffer(struct fb_info *fb_info) +{ + int ret; + + mutex_lock(®istration_lock); + ret = do_register_framebuffer(fb_info); + mutex_unlock(®istration_lock); + + return ret; +} /** * unregister_framebuffer - releases a frame buffer device @@ -1609,46 +1713,15 @@ register_framebuffer(struct fb_info *fb_info) * that the driver implements fb_open() and fb_release() to * check that no processes are using the device. */ - int unregister_framebuffer(struct fb_info *fb_info) { - struct fb_event event; - int i, ret = 0; + int ret; - i = fb_info->node; - if (!registered_fb[i]) { - ret = -EINVAL; - goto done; - } + mutex_lock(®istration_lock); + ret = do_unregister_framebuffer(fb_info); + mutex_unlock(®istration_lock); - - if (!lock_fb_info(fb_info)) - return -ENODEV; - event.info = fb_info; - ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); - unlock_fb_info(fb_info); - - if (ret) { - ret = -EINVAL; - goto done; - } - - if (fb_info->pixmap.addr && - (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) - kfree(fb_info->pixmap.addr); - fb_destroy_modelist(&fb_info->modelist); - registered_fb[i]=NULL; - num_registered_fb--; - fb_cleanup_device(fb_info); - device_destroy(fb_class, MKDEV(FB_MAJOR, i)); - event.info = fb_info; - fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); - - /* this may free fb info */ - if (fb_info->fbops->fb_destroy) - fb_info->fbops->fb_destroy(fb_info); -done: return ret; } diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index 68041d9dc260..695066b5b2e6 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include